From eb389b85803be1df11e829214646b284754797da Mon Sep 17 00:00:00 2001 From: openDAQ-dev Date: Mon, 16 Oct 2023 18:06:51 +0200 Subject: [PATCH 001/217] Initial commit --- external/open62541/CMakeLists.txt | 83 ++ modules/opcua_client_module/CMakeLists.txt | 9 + .../include/opcua_client_module/common.h | 21 + .../include/opcua_client_module/module_dll.h | 20 + .../opcua_client_module_impl.h | 47 + .../opcua_client_module/src/CMakeLists.txt | 39 + .../opcua_client_module/src/module_dll.cpp | 9 + .../src/opcua_client_module_impl.cpp | 257 +++++ .../opcua_client_module/tests/CMakeLists.txt | 22 + .../opcua_client_module/tests/test_app.cpp | 21 + .../tests/test_opcua_client_module.cpp | 199 ++++ modules/opcua_server_module/CMakeLists.txt | 9 + .../include/opcua_server_module/common.h | 21 + .../include/opcua_server_module/module_dll.h | 20 + .../opcua_server_module/opcua_server_impl.h | 49 + .../opcua_server_module_impl.h | 35 + .../opcua_server_module/src/CMakeLists.txt | 43 + .../opcua_server_module/src/module_dll.cpp | 9 + .../src/opcua_server_impl.cpp | 66 ++ .../src/opcua_server_module_impl.cpp | 40 + .../opcua_server_module/tests/CMakeLists.txt | 29 + .../opcua_server_module/tests/test_app.cpp | 22 + .../tests/test_opcua_server_module.cpp | 184 ++++ shared/libraries/opcua/CMakeLists.txt | 17 + shared/libraries/opcua/OWNERS.txt | 12 + .../opcua/opcuaclient/CMakeLists.txt | 9 + .../include/opcuaclient/browse_request.h | 36 + .../opcuaclient/browser/opcuabrowser.h | 84 ++ .../browser/opcuanodefactorybrowser.h | 79 ++ .../opcuaclient/browser/opcuanodevisitor.h | 67 ++ .../browser/opcuatransactionbrowser.h | 83 ++ .../chdatagather/_alignsyncchdatagather.h | 44 + .../opcuaclient/chdatagather/_chdatagather.h | 44 + .../include/opcuaclient/event_filter.h | 83 ++ .../monitored_item_create_request.h | 44 + .../opcuaclient/opcuaasyncexecthread.h | 41 + .../opcuaclient/opcuacallmethodrequest.h | 46 + .../include/opcuaclient/opcuaclient.h | 174 ++++ .../include/opcuaclient/opcuanodefactory.h | 56 ++ .../include/opcuaclient/opcuareadvalueid.h | 41 + .../opcuatimertaskcontextcollection.h | 97 ++ .../opcuaclient/opcuatimertaskhelper.h | 55 ++ .../include/opcuaclient/reference_utils.h | 60 ++ .../include/opcuaclient/request_handler.h | 31 + .../include/opcuaclient/subscriptions.h | 90 ++ .../taskprocessor/opcuataskprocessor.h | 74 ++ .../opcua/opcuaclient/src/CMakeLists.txt | 89 ++ .../opcua/opcuaclient/src/browse_request.cpp | 29 + .../opcuaclient/src/browser/opcuabrowser.cpp | 118 +++ .../src/browser/opcuanodefactorybrowser.cpp | 98 ++ .../src/browser/opcuanodevisitor.cpp | 121 +++ .../chdatagather/_alignsyncchdatagather.cpp | 117 +++ .../src/chdatagather/_chdatagather.cpp | 35 + .../opcua/opcuaclient/src/event_filter.cpp | 44 + .../src/monitored_item_create_request.cpp | 59 ++ .../opcuaclient/src/opcuaasyncexecthread.cpp | 37 + .../src/opcuacallmethodrequest.cpp | 28 + .../opcua/opcuaclient/src/opcuaclient.cpp | 583 +++++++++++ .../opcuaclient/src/opcuanodefactory.cpp | 102 ++ .../opcuaclient/src/opcuareadvalueid.cpp | 14 + .../src/opcuatimertaskcontextcollection.cpp | 62 ++ .../opcuaclient/src/opcuatimertaskhelper.cpp | 80 ++ .../opcua/opcuaclient/src/reference_utils.cpp | 124 +++ .../opcua/opcuaclient/src/request_handler.cpp | 9 + .../opcua/opcuaclient/src/subscriptions.cpp | 175 ++++ .../src/taskprocessor/opcuataskprocessor.cpp | 143 +++ .../opcua/opcuaclient/tests/CMakeLists.txt | 38 + .../tests/include/opcuaservertesthelper.h | 97 ++ .../opcua/opcuaclient/tests/src/main.cpp | 12 + .../tests/src/opcuaservertesthelper.cpp | 326 +++++++ .../tests/src/test_opcuaasyncexecthread.cpp | 63 ++ .../tests/src/test_opcuaclient.cpp | 236 +++++ .../tests/src/test_opcuanodefactory.cpp | 108 +++ .../src/test_opcuanodefactorybrowser.cpp | 60 ++ .../tests/src/test_opcuataskprocessor.cpp | 195 ++++ .../tests/src/test_opcuatimertaskhelper.cpp | 96 ++ .../opcua/opcuaserver/CMakeLists.txt | 13 + .../opcuaserver/include/opcuaserver/common.h | 26 + .../include/opcuaserver/event_attributes.h | 63 ++ .../include/opcuaserver/node_event_manager.h | 173 ++++ .../include/opcuaserver/opcuaaddnodeparams.h | 100 ++ .../include/opcuaserver/opcuaserver.h | 160 +++ .../include/opcuaserver/opcuaserverlock.h | 52 + .../include/opcuaserver/opcuaservernode.h | 143 +++ .../opcuaserver/opcuaservernodefactory.h | 37 + .../include/opcuaserver/opcuasession.h | 52 + .../include/opcuaserver/opcuataskqueue.h | 44 + .../include/opcuaserver/opcuatmstypes.h | 31 + .../opcuaserver/server_event_manager.h | 61 ++ .../opcua/opcuaserver/src/CMakeLists.txt | 61 ++ .../opcuaserver/src/event_attributes.cpp | 63 ++ .../opcuaserver/src/node_event_manager.cpp | 187 ++++ .../opcuaserver/src/opcuaaddnodeparams.cpp | 109 +++ .../opcua/opcuaserver/src/opcuaserver.cpp | 609 ++++++++++++ .../opcua/opcuaserver/src/opcuaserverlock.cpp | 91 ++ .../opcua/opcuaserver/src/opcuaservernode.cpp | 132 +++ .../src/opcuaservernodefactory.cpp | 42 + .../opcua/opcuaserver/src/opcuasession.cpp | 59 ++ .../opcua/opcuaserver/src/opcuataskqueue.cpp | 64 ++ .../opcua/opcuaserver/src/opcuatmstypes.cpp | 57 ++ .../opcuaserver/src/server_event_manager.cpp | 80 ++ .../opcua/opcuaserver/tests/CMakeLists.txt | 29 + .../opcuaserver/tests/common_test_functions.h | 45 + .../opcua/opcuaserver/tests/main.cpp | 14 + .../opcuaserver/tests/test_opcuaserver.cpp | 432 +++++++++ .../tests/test_opcuaserverlock.cpp | 332 +++++++ .../tests/test_opcuaservernode.cpp | 128 +++ .../tests/test_opcuaservernodefactory.cpp | 44 + .../opcuaserver/tests/test_opcuasession.cpp | 238 +++++ .../opcua/opcuashared/CMakeLists.txt | 9 + .../opcuashared/include/opcuashared/bcrypt.h | 121 +++ .../opcuashared/bcrypt/crypt_blowfish.h | 24 + .../include/opcuashared/node/opcuadatatype.h | 32 + .../include/opcuashared/node/opcuanode.h | 69 ++ .../opcuashared/node/opcuanodemethod.h | 79 ++ .../opcuashared/node/opcuanodeobject.h | 39 + .../opcuashared/node/opcuanodevariable.h | 50 + .../opcuashared/node/opcuaobjecttype.h | 32 + .../include/opcuashared/node/opcuatype.h | 31 + .../opcuashared/node/opcuavariabletype.h | 32 + .../opcuashared/include/opcuashared/opcua.h | 121 +++ .../opcuashared/opcuacallmethodresult.h | 43 + .../include/opcuashared/opcuacollection.h | 54 ++ .../include/opcuashared/opcuacommon.h | 48 + .../opcuashared/opcuadatatypearraylist.h | 36 + .../include/opcuashared/opcuadatavalue.h | 44 + .../include/opcuashared/opcuaendpoint.h | 69 ++ .../include/opcuashared/opcuaexception.h | 60 ++ .../include/opcuashared/opcualog.h | 25 + .../include/opcuashared/opcuanodecollection.h | 42 + .../include/opcuashared/opcuanodeid.h | 158 +++ .../include/opcuashared/opcuaobject.h | 341 +++++++ .../opcuashared/opcuasecurity_config.h | 69 ++ .../include/opcuashared/opcuasecuritycommon.h | 31 + .../include/opcuashared/opcuavariant.h | 187 ++++ .../include/opcuashared/opcuavector.h | 218 +++++ .../include/opcuashared/opcuaversion.h | 51 + .../opcua/opcuashared/src/CMakeLists.txt | 123 +++ .../opcua/opcuashared/src/OpcUaTypes.natvis | 9 + .../opcua/opcuashared/src/bcrypt.cpp | 100 ++ .../opcuashared/src/bcrypt/crypt_blowfish.c | 907 ++++++++++++++++++ .../opcuashared/src/cmake_globals.h.template | 20 + .../opcuashared/src/node/opcuadatatype.cpp | 14 + .../opcua/opcuashared/src/node/opcuanode.cpp | 86 ++ .../opcuashared/src/node/opcuanodemethod.cpp | 64 ++ .../opcuashared/src/node/opcuanodeobject.cpp | 30 + .../src/node/opcuanodevariable.cpp | 61 ++ .../opcuashared/src/node/opcuaobjecttype.cpp | 14 + .../opcua/opcuashared/src/node/opcuatype.cpp | 12 + .../src/node/opcuavariabletype.cpp | 14 + .../opcuashared/src/opcuacallmethodresult.cpp | 46 + .../opcua/opcuashared/src/opcuacommon.cpp | 147 +++ .../src/opcuadatatypearraylist.cpp | 42 + .../opcua/opcuashared/src/opcuadatavalue.cpp | 45 + .../opcua/opcuashared/src/opcuaendpoint.cpp | 69 ++ .../opcuashared/src/opcuanodecollection.cpp | 29 + .../opcua/opcuashared/src/opcuanodeid.cpp | 130 +++ .../opcuashared/src/opcuasecurity_config.cpp | 84 ++ .../opcuashared/src/opcuasecuritycommon.cpp | 62 ++ .../opcua/opcuashared/src/opcuavariant.cpp | 223 +++++ .../opcua/opcuashared/src/opcuaversion.cpp | 39 + .../opcua/opcuashared/tests/CMakeLists.txt | 37 + .../opcua/opcuashared/tests/main.cpp | 13 + .../opcua/opcuashared/tests/test_bcrypt.cpp | 115 +++ .../opcuashared/tests/test_opcua_object.cpp | 253 +++++ .../opcuashared/tests/test_opcua_security.cpp | 458 +++++++++ .../opcuashared/tests/test_opcua_variant.cpp | 205 ++++ .../opcuashared/tests/test_opcua_vector.cpp | 107 +++ .../tests/test_opcuacallmethodresult.cpp | 44 + .../tests/test_opcuadatatypearraylist.cpp | 140 +++ .../opcuashared/tests/test_opcuadatavalue.cpp | 69 ++ .../opcuashared/tests/test_opcuaendpoint.cpp | 20 + .../opcuashared/tests/test_opcuanodeid.cpp | 239 +++++ .../opcuashared/tests/test_opcuaversion.cpp | 99 ++ .../opcuashared/tests/test_status_code.cpp | 38 + .../opcuashared/tests/test_string_utils.cpp | 50 + .../opcuashared/tools/generate_datatypes.sh | 10 + .../opcuashared/tools/schema/BB.NodeIds.csv | 4 + .../tools/schema/BB.Opc.Ua.Types.bsd | 37 + shared/libraries/opcua/tests/CMakeLists.txt | 5 + .../opcua/tests/testopcua/CMakeLists.txt | 28 + .../libraries/opcua/tests/testopcua/main.cpp | 13 + .../tests/testopcua/test_opcua_security.cpp | 566 +++++++++++ shared/libraries/opcuatms/CMakeLists.txt | 9 + .../opcuatms/opcuatms/CMakeLists.txt | 9 + .../include/opcuatms/converter_maps.h | 301 ++++++ .../converters/list_conversion_utils.h | 173 ++++ .../opcuatms/converters/selection_converter.h | 40 + .../opcuatms/converters/struct_converter.h | 33 + .../opcuatms/converters/variant_converter.h | 42 + .../include/opcuatms/core_types_utils.h | 41 + .../opcuatms/include/opcuatms/errors.h | 24 + .../opcuatms/include/opcuatms/exceptions.h | 28 + .../include/opcuatms/extension_object.h | 50 + .../opcuatms/include/opcuatms/opcuatms.h | 28 + .../opcuatms/include/opcuatms/type_mappings.h | 39 + .../opcuatms/opcuatms/src/CMakeLists.txt | 74 ++ .../src/converters/argument_converter.cpp | 88 ++ .../src/converters/base_object_converter.cpp | 170 ++++ .../src/converters/core_types_converter.cpp | 398 ++++++++ .../converters/data_descriptor_converter.cpp | 320 ++++++ .../src/converters/data_rule_converter.cpp | 261 +++++ .../src/converters/dict_converter.cpp | 130 +++ .../src/converters/dimension_converter.cpp | 105 ++ .../converters/dimension_rule_converter.cpp | 298 ++++++ .../function_block_type_converter.cpp | 90 ++ .../converters/generic_struct_converter.cpp | 262 +++++ .../src/converters/number_converter.cpp | 67 ++ .../src/converters/range_converter.cpp | 75 ++ .../src/converters/ratio_converter.cpp | 116 +++ .../src/converters/scaling_converter.cpp | 170 ++++ .../src/converters/selection_converter.cpp | 112 +++ .../src/converters/unit_converter.cpp | 123 +++ .../opcuatms/src/core_types_utils.cpp | 265 +++++ .../opcuatms/src/extension_object.cpp | 55 ++ .../opcuatms/opcuatms/tests/CMakeLists.txt | 29 + .../opcuatms/tests/test_core_types_utils.cpp | 63 ++ .../opcuatms/tests/test_exception.cpp | 13 + .../opcuatms/tests/test_extension_object.cpp | 63 ++ .../tests/test_generic_struct_converter.cpp | 251 +++++ .../opcuatms/tests/test_variant_converter.cpp | 428 +++++++++ .../tests/test_variant_list_converter.cpp | 289 ++++++ .../opcuatms/opcuatms/tests/testapp.cpp | 13 + .../opcuatms/opcuatms_client/CMakeLists.txt | 9 + .../objects/tms_client_channel_factory.h | 35 + .../objects/tms_client_channel_impl.h | 33 + .../objects/tms_client_component_factory.h | 32 + .../objects/tms_client_component_impl.h | 60 ++ .../objects/tms_client_context.h | 62 ++ .../objects/tms_client_device_factory.h | 45 + .../objects/tms_client_device_impl.h | 77 ++ .../objects/tms_client_folder_factory.h | 34 + .../objects/tms_client_folder_impl.h | 37 + .../tms_client_function_block_factory.h | 34 + .../objects/tms_client_function_block_impl.h | 50 + .../objects/tms_client_function_factory.h | 32 + .../objects/tms_client_function_impl.h | 47 + .../objects/tms_client_input_port_factory.h | 33 + .../objects/tms_client_input_port_impl.h | 44 + .../objects/tms_client_io_folder_factory.h | 33 + .../objects/tms_client_io_folder_impl.h | 37 + .../objects/tms_client_object_impl.h | 98 ++ .../objects/tms_client_procedure_factory.h | 32 + .../objects/tms_client_procedure_impl.h | 45 + .../objects/tms_client_property_factory.h | 48 + .../objects/tms_client_property_impl.h | 34 + .../tms_client_property_object_factory.h | 50 + .../objects/tms_client_property_object_impl.h | 123 +++ .../objects/tms_client_signal_factory.h | 67 ++ .../objects/tms_client_signal_impl.h | 74 ++ .../tms_client_streaming_info_factory.h | 33 + .../objects/tms_client_streaming_info_impl.h | 32 + .../include/opcuatms_client/tms_client.h | 51 + .../opcuatms_client/src/CMakeLists.txt | 130 +++ .../src/objects/tms_client_channel_impl.cpp | 19 + .../src/objects/tms_client_component_impl.cpp | 53 + .../src/objects/tms_client_context.cpp | 51 + .../src/objects/tms_client_device_impl.cpp | 349 +++++++ .../src/objects/tms_client_folder_impl.cpp | 44 + .../tms_client_function_block_impl.cpp | 133 +++ .../src/objects/tms_client_function_impl.cpp | 61 ++ .../objects/tms_client_input_port_impl.cpp | 128 +++ .../src/objects/tms_client_io_folder_impl.cpp | 46 + .../src/objects/tms_client_object_impl.cpp | 110 +++ .../src/objects/tms_client_procedure_impl.cpp | 61 ++ .../src/objects/tms_client_property_impl.cpp | 180 ++++ .../tms_client_property_object_impl.cpp | 351 +++++++ .../src/objects/tms_client_signal_impl.cpp | 196 ++++ .../tms_client_streaming_info_impl.cpp | 15 + .../opcuatms_client/src/tms_client.cpp | 104 ++ .../opcuatms_client/tests/CMakeLists.txt | 29 + .../opcuatms_client/tests/test_app.cpp | 12 + .../tests/test_client_context.cpp | 100 ++ .../opcuatms/opcuatms_server/CMakeLists.txt | 9 + .../objects/tms_server_channel.h | 38 + .../objects/tms_server_component.h | 122 +++ .../objects/tms_server_device.h | 60 ++ .../objects/tms_server_eval_value.h | 58 ++ .../objects/tms_server_folder.h | 44 + .../objects/tms_server_function_block.h | 55 ++ .../objects/tms_server_input_port.h | 41 + .../objects/tms_server_object.h | 168 ++++ .../objects/tms_server_property.h | 77 ++ .../objects/tms_server_property_object.h | 72 ++ .../objects/tms_server_signal.h | 45 + .../objects/tms_server_variable.h | 36 + .../include/opcuatms_server/tms_server.h | 47 + .../opcuatms_server/src/CMakeLists.txt | 91 ++ .../src/objects/tms_server_channel.cpp | 20 + .../src/objects/tms_server_component.cpp | 0 .../src/objects/tms_server_device.cpp | 299 ++++++ .../src/objects/tms_server_eval_value.cpp | 124 +++ .../src/objects/tms_server_folder.cpp | 62 ++ .../src/objects/tms_server_function_block.cpp | 89 ++ .../src/objects/tms_server_input_port.cpp | 101 ++ .../src/objects/tms_server_object.cpp | 268 ++++++ .../src/objects/tms_server_property.cpp | 278 ++++++ .../objects/tms_server_property_object.cpp | 301 ++++++ .../src/objects/tms_server_signal.cpp | 100 ++ .../src/objects/tms_server_variable.cpp | 48 + .../opcuatms_server/src/tms_server.cpp | 77 ++ .../opcuatms_server/tests/CMakeLists.txt | 33 + .../opcuatms_server/tests/test_helpers.h | 132 +++ .../tests/test_tms_channel.cpp | 103 ++ .../opcuatms_server/tests/test_tms_device.cpp | 100 ++ .../tests/test_tms_function_block.cpp | 126 +++ .../tests/test_tms_input_port.cpp | 75 ++ .../tests/test_tms_property_object.cpp | 79 ++ .../opcuatms_server/tests/test_tms_server.cpp | 86 ++ .../opcuatms_server/tests/test_tms_signal.cpp | 65 ++ .../opcuatms_server/tests/testapp.cpp | 23 + .../libraries/opcuatms/tests/CMakeLists.txt | 6 + .../tests/opcuatms_integration/CMakeLists.txt | 73 ++ .../tests/opcuatms_integration/main.cpp | 30 + .../test_property_object_advanced.cpp | 751 +++++++++++++++ .../test_streaming_integration.cpp | 392 ++++++++ .../test_tms_amplifier.cpp | 747 +++++++++++++++ .../opcuatms_integration/test_tms_channel.cpp | 149 +++ .../test_tms_component.cpp | 92 ++ .../opcuatms_integration/test_tms_device.cpp | 342 +++++++ .../opcuatms_integration/test_tms_folder.cpp | 150 +++ .../test_tms_function_block.cpp | 233 +++++ .../test_tms_function_property.cpp | 301 ++++++ .../test_tms_input_port.cpp | 208 ++++ .../test_tms_integration.cpp | 238 +++++ .../test_tms_property.cpp | 232 +++++ .../test_tms_property_object.cpp | 199 ++++ .../opcuatms_integration/test_tms_signal.cpp | 316 ++++++ .../tms_object_integration_test.cpp | 23 + .../tms_object_integration_test.h | 31 + .../opcuatms/tests/test_utils/CMakeLists.txt | 21 + .../test_input_port_notifications.cpp | 29 + .../test_input_port_notifications.h | 40 + .../tests/test_utils/tms_object_test.cpp | 103 ++ .../tests/test_utils/tms_object_test.h | 45 + 335 files changed, 33766 insertions(+) create mode 100644 external/open62541/CMakeLists.txt create mode 100644 modules/opcua_client_module/CMakeLists.txt create mode 100644 modules/opcua_client_module/include/opcua_client_module/common.h create mode 100644 modules/opcua_client_module/include/opcua_client_module/module_dll.h create mode 100644 modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h create mode 100644 modules/opcua_client_module/src/CMakeLists.txt create mode 100644 modules/opcua_client_module/src/module_dll.cpp create mode 100644 modules/opcua_client_module/src/opcua_client_module_impl.cpp create mode 100644 modules/opcua_client_module/tests/CMakeLists.txt create mode 100644 modules/opcua_client_module/tests/test_app.cpp create mode 100644 modules/opcua_client_module/tests/test_opcua_client_module.cpp create mode 100644 modules/opcua_server_module/CMakeLists.txt create mode 100644 modules/opcua_server_module/include/opcua_server_module/common.h create mode 100644 modules/opcua_server_module/include/opcua_server_module/module_dll.h create mode 100644 modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h create mode 100644 modules/opcua_server_module/include/opcua_server_module/opcua_server_module_impl.h create mode 100644 modules/opcua_server_module/src/CMakeLists.txt create mode 100644 modules/opcua_server_module/src/module_dll.cpp create mode 100644 modules/opcua_server_module/src/opcua_server_impl.cpp create mode 100644 modules/opcua_server_module/src/opcua_server_module_impl.cpp create mode 100644 modules/opcua_server_module/tests/CMakeLists.txt create mode 100644 modules/opcua_server_module/tests/test_app.cpp create mode 100644 modules/opcua_server_module/tests/test_opcua_server_module.cpp create mode 100644 shared/libraries/opcua/CMakeLists.txt create mode 100644 shared/libraries/opcua/OWNERS.txt create mode 100644 shared/libraries/opcua/opcuaclient/CMakeLists.txt create mode 100644 shared/libraries/opcua/opcuaclient/include/opcuaclient/browse_request.h create mode 100644 shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuabrowser.h create mode 100644 shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodefactorybrowser.h create mode 100644 shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodevisitor.h create mode 100644 shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuatransactionbrowser.h create mode 100644 shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_alignsyncchdatagather.h create mode 100644 shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_chdatagather.h create mode 100644 shared/libraries/opcua/opcuaclient/include/opcuaclient/event_filter.h create mode 100644 shared/libraries/opcua/opcuaclient/include/opcuaclient/monitored_item_create_request.h create mode 100644 shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaasyncexecthread.h create mode 100644 shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuacallmethodrequest.h create mode 100644 shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h create mode 100644 shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuanodefactory.h create mode 100644 shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuareadvalueid.h create mode 100644 shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskcontextcollection.h create mode 100644 shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskhelper.h create mode 100644 shared/libraries/opcua/opcuaclient/include/opcuaclient/reference_utils.h create mode 100644 shared/libraries/opcua/opcuaclient/include/opcuaclient/request_handler.h create mode 100644 shared/libraries/opcua/opcuaclient/include/opcuaclient/subscriptions.h create mode 100644 shared/libraries/opcua/opcuaclient/include/opcuaclient/taskprocessor/opcuataskprocessor.h create mode 100644 shared/libraries/opcua/opcuaclient/src/CMakeLists.txt create mode 100644 shared/libraries/opcua/opcuaclient/src/browse_request.cpp create mode 100644 shared/libraries/opcua/opcuaclient/src/browser/opcuabrowser.cpp create mode 100644 shared/libraries/opcua/opcuaclient/src/browser/opcuanodefactorybrowser.cpp create mode 100644 shared/libraries/opcua/opcuaclient/src/browser/opcuanodevisitor.cpp create mode 100644 shared/libraries/opcua/opcuaclient/src/chdatagather/_alignsyncchdatagather.cpp create mode 100644 shared/libraries/opcua/opcuaclient/src/chdatagather/_chdatagather.cpp create mode 100644 shared/libraries/opcua/opcuaclient/src/event_filter.cpp create mode 100644 shared/libraries/opcua/opcuaclient/src/monitored_item_create_request.cpp create mode 100644 shared/libraries/opcua/opcuaclient/src/opcuaasyncexecthread.cpp create mode 100644 shared/libraries/opcua/opcuaclient/src/opcuacallmethodrequest.cpp create mode 100644 shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp create mode 100644 shared/libraries/opcua/opcuaclient/src/opcuanodefactory.cpp create mode 100644 shared/libraries/opcua/opcuaclient/src/opcuareadvalueid.cpp create mode 100644 shared/libraries/opcua/opcuaclient/src/opcuatimertaskcontextcollection.cpp create mode 100644 shared/libraries/opcua/opcuaclient/src/opcuatimertaskhelper.cpp create mode 100644 shared/libraries/opcua/opcuaclient/src/reference_utils.cpp create mode 100644 shared/libraries/opcua/opcuaclient/src/request_handler.cpp create mode 100644 shared/libraries/opcua/opcuaclient/src/subscriptions.cpp create mode 100644 shared/libraries/opcua/opcuaclient/src/taskprocessor/opcuataskprocessor.cpp create mode 100644 shared/libraries/opcua/opcuaclient/tests/CMakeLists.txt create mode 100644 shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h create mode 100644 shared/libraries/opcua/opcuaclient/tests/src/main.cpp create mode 100644 shared/libraries/opcua/opcuaclient/tests/src/opcuaservertesthelper.cpp create mode 100644 shared/libraries/opcua/opcuaclient/tests/src/test_opcuaasyncexecthread.cpp create mode 100644 shared/libraries/opcua/opcuaclient/tests/src/test_opcuaclient.cpp create mode 100644 shared/libraries/opcua/opcuaclient/tests/src/test_opcuanodefactory.cpp create mode 100644 shared/libraries/opcua/opcuaclient/tests/src/test_opcuanodefactorybrowser.cpp create mode 100644 shared/libraries/opcua/opcuaclient/tests/src/test_opcuataskprocessor.cpp create mode 100644 shared/libraries/opcua/opcuaclient/tests/src/test_opcuatimertaskhelper.cpp create mode 100644 shared/libraries/opcua/opcuaserver/CMakeLists.txt create mode 100644 shared/libraries/opcua/opcuaserver/include/opcuaserver/common.h create mode 100644 shared/libraries/opcua/opcuaserver/include/opcuaserver/event_attributes.h create mode 100644 shared/libraries/opcua/opcuaserver/include/opcuaserver/node_event_manager.h create mode 100644 shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h create mode 100644 shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h create mode 100644 shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserverlock.h create mode 100644 shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernode.h create mode 100644 shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernodefactory.h create mode 100644 shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuasession.h create mode 100644 shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuataskqueue.h create mode 100644 shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuatmstypes.h create mode 100644 shared/libraries/opcua/opcuaserver/include/opcuaserver/server_event_manager.h create mode 100644 shared/libraries/opcua/opcuaserver/src/CMakeLists.txt create mode 100644 shared/libraries/opcua/opcuaserver/src/event_attributes.cpp create mode 100644 shared/libraries/opcua/opcuaserver/src/node_event_manager.cpp create mode 100644 shared/libraries/opcua/opcuaserver/src/opcuaaddnodeparams.cpp create mode 100644 shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp create mode 100644 shared/libraries/opcua/opcuaserver/src/opcuaserverlock.cpp create mode 100644 shared/libraries/opcua/opcuaserver/src/opcuaservernode.cpp create mode 100644 shared/libraries/opcua/opcuaserver/src/opcuaservernodefactory.cpp create mode 100644 shared/libraries/opcua/opcuaserver/src/opcuasession.cpp create mode 100644 shared/libraries/opcua/opcuaserver/src/opcuataskqueue.cpp create mode 100644 shared/libraries/opcua/opcuaserver/src/opcuatmstypes.cpp create mode 100644 shared/libraries/opcua/opcuaserver/src/server_event_manager.cpp create mode 100644 shared/libraries/opcua/opcuaserver/tests/CMakeLists.txt create mode 100644 shared/libraries/opcua/opcuaserver/tests/common_test_functions.h create mode 100644 shared/libraries/opcua/opcuaserver/tests/main.cpp create mode 100644 shared/libraries/opcua/opcuaserver/tests/test_opcuaserver.cpp create mode 100644 shared/libraries/opcua/opcuaserver/tests/test_opcuaserverlock.cpp create mode 100644 shared/libraries/opcua/opcuaserver/tests/test_opcuaservernode.cpp create mode 100644 shared/libraries/opcua/opcuaserver/tests/test_opcuaservernodefactory.cpp create mode 100644 shared/libraries/opcua/opcuaserver/tests/test_opcuasession.cpp create mode 100644 shared/libraries/opcua/opcuashared/CMakeLists.txt create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/bcrypt.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/bcrypt/crypt_blowfish.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuadatatype.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanode.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodemethod.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodeobject.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodevariable.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuaobjecttype.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuatype.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuavariabletype.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/opcua.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/opcuacallmethodresult.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/opcuacollection.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/opcuacommon.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatatypearraylist.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatavalue.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/opcuaendpoint.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/opcuaexception.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/opcualog.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodecollection.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodeid.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/opcuaobject.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecurity_config.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecuritycommon.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/opcuavector.h create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/opcuaversion.h create mode 100644 shared/libraries/opcua/opcuashared/src/CMakeLists.txt create mode 100644 shared/libraries/opcua/opcuashared/src/OpcUaTypes.natvis create mode 100644 shared/libraries/opcua/opcuashared/src/bcrypt.cpp create mode 100644 shared/libraries/opcua/opcuashared/src/bcrypt/crypt_blowfish.c create mode 100644 shared/libraries/opcua/opcuashared/src/cmake_globals.h.template create mode 100644 shared/libraries/opcua/opcuashared/src/node/opcuadatatype.cpp create mode 100644 shared/libraries/opcua/opcuashared/src/node/opcuanode.cpp create mode 100644 shared/libraries/opcua/opcuashared/src/node/opcuanodemethod.cpp create mode 100644 shared/libraries/opcua/opcuashared/src/node/opcuanodeobject.cpp create mode 100644 shared/libraries/opcua/opcuashared/src/node/opcuanodevariable.cpp create mode 100644 shared/libraries/opcua/opcuashared/src/node/opcuaobjecttype.cpp create mode 100644 shared/libraries/opcua/opcuashared/src/node/opcuatype.cpp create mode 100644 shared/libraries/opcua/opcuashared/src/node/opcuavariabletype.cpp create mode 100644 shared/libraries/opcua/opcuashared/src/opcuacallmethodresult.cpp create mode 100644 shared/libraries/opcua/opcuashared/src/opcuacommon.cpp create mode 100644 shared/libraries/opcua/opcuashared/src/opcuadatatypearraylist.cpp create mode 100644 shared/libraries/opcua/opcuashared/src/opcuadatavalue.cpp create mode 100644 shared/libraries/opcua/opcuashared/src/opcuaendpoint.cpp create mode 100644 shared/libraries/opcua/opcuashared/src/opcuanodecollection.cpp create mode 100644 shared/libraries/opcua/opcuashared/src/opcuanodeid.cpp create mode 100644 shared/libraries/opcua/opcuashared/src/opcuasecurity_config.cpp create mode 100644 shared/libraries/opcua/opcuashared/src/opcuasecuritycommon.cpp create mode 100644 shared/libraries/opcua/opcuashared/src/opcuavariant.cpp create mode 100644 shared/libraries/opcua/opcuashared/src/opcuaversion.cpp create mode 100644 shared/libraries/opcua/opcuashared/tests/CMakeLists.txt create mode 100644 shared/libraries/opcua/opcuashared/tests/main.cpp create mode 100644 shared/libraries/opcua/opcuashared/tests/test_bcrypt.cpp create mode 100644 shared/libraries/opcua/opcuashared/tests/test_opcua_object.cpp create mode 100644 shared/libraries/opcua/opcuashared/tests/test_opcua_security.cpp create mode 100644 shared/libraries/opcua/opcuashared/tests/test_opcua_variant.cpp create mode 100644 shared/libraries/opcua/opcuashared/tests/test_opcua_vector.cpp create mode 100644 shared/libraries/opcua/opcuashared/tests/test_opcuacallmethodresult.cpp create mode 100644 shared/libraries/opcua/opcuashared/tests/test_opcuadatatypearraylist.cpp create mode 100644 shared/libraries/opcua/opcuashared/tests/test_opcuadatavalue.cpp create mode 100644 shared/libraries/opcua/opcuashared/tests/test_opcuaendpoint.cpp create mode 100644 shared/libraries/opcua/opcuashared/tests/test_opcuanodeid.cpp create mode 100644 shared/libraries/opcua/opcuashared/tests/test_opcuaversion.cpp create mode 100644 shared/libraries/opcua/opcuashared/tests/test_status_code.cpp create mode 100644 shared/libraries/opcua/opcuashared/tests/test_string_utils.cpp create mode 100644 shared/libraries/opcua/opcuashared/tools/generate_datatypes.sh create mode 100644 shared/libraries/opcua/opcuashared/tools/schema/BB.NodeIds.csv create mode 100644 shared/libraries/opcua/opcuashared/tools/schema/BB.Opc.Ua.Types.bsd create mode 100644 shared/libraries/opcua/tests/CMakeLists.txt create mode 100644 shared/libraries/opcua/tests/testopcua/CMakeLists.txt create mode 100644 shared/libraries/opcua/tests/testopcua/main.cpp create mode 100644 shared/libraries/opcua/tests/testopcua/test_opcua_security.cpp create mode 100644 shared/libraries/opcuatms/CMakeLists.txt create mode 100644 shared/libraries/opcuatms/opcuatms/CMakeLists.txt create mode 100644 shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h create mode 100644 shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/list_conversion_utils.h create mode 100644 shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/selection_converter.h create mode 100644 shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/struct_converter.h create mode 100644 shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/variant_converter.h create mode 100644 shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h create mode 100644 shared/libraries/opcuatms/opcuatms/include/opcuatms/errors.h create mode 100644 shared/libraries/opcuatms/opcuatms/include/opcuatms/exceptions.h create mode 100644 shared/libraries/opcuatms/opcuatms/include/opcuatms/extension_object.h create mode 100644 shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h create mode 100644 shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h create mode 100644 shared/libraries/opcuatms/opcuatms/src/CMakeLists.txt create mode 100644 shared/libraries/opcuatms/opcuatms/src/converters/argument_converter.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/src/converters/core_types_converter.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/src/converters/data_descriptor_converter.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/src/converters/data_rule_converter.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/src/converters/dict_converter.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/src/converters/dimension_converter.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/src/converters/dimension_rule_converter.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/src/converters/function_block_type_converter.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/src/converters/generic_struct_converter.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/src/converters/number_converter.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/src/converters/range_converter.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/src/converters/ratio_converter.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/src/converters/scaling_converter.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/src/converters/selection_converter.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/src/converters/unit_converter.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/src/extension_object.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/tests/CMakeLists.txt create mode 100644 shared/libraries/opcuatms/opcuatms/tests/test_core_types_utils.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/tests/test_exception.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/tests/test_extension_object.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/tests/test_generic_struct_converter.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/tests/test_variant_converter.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/tests/test_variant_list_converter.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/tests/testapp.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_factory.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_impl.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_factory.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_factory.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_factory.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_factory.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_factory.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_impl.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_factory.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_factory.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_factory.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_impl.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_factory.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_factory.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_factory.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_streaming_info_factory.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_streaming_info_impl.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt create mode 100644 shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_channel_impl.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_impl.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_object_impl.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_procedure_impl.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_streaming_info_impl.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_client/tests/CMakeLists.txt create mode 100644 shared/libraries/opcuatms/opcuatms_client/tests/test_app.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_client/tests/test_client_context.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt create mode 100644 shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_channel.h create mode 100644 shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h create mode 100644 shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h create mode 100644 shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_eval_value.h create mode 100644 shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_folder.h create mode 100644 shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block.h create mode 100644 shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h create mode 100644 shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h create mode 100644 shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h create mode 100644 shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h create mode 100644 shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h create mode 100644 shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h create mode 100644 shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h create mode 100644 shared/libraries/opcuatms/opcuatms_server/src/CMakeLists.txt create mode 100644 shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_channel.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_component.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_eval_value.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt create mode 100644 shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h create mode 100644 shared/libraries/opcuatms/opcuatms_server/tests/test_tms_channel.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/tests/test_tms_device.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/tests/test_tms_property_object.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/tests/test_tms_server.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/tests/test_tms_signal.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/tests/testapp.cpp create mode 100644 shared/libraries/opcuatms/tests/CMakeLists.txt create mode 100644 shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt create mode 100644 shared/libraries/opcuatms/tests/opcuatms_integration/main.cpp create mode 100644 shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp create mode 100644 shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp create mode 100644 shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp create mode 100644 shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_channel.cpp create mode 100644 shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_component.cpp create mode 100644 shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp create mode 100644 shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp create mode 100644 shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp create mode 100644 shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_property.cpp create mode 100644 shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp create mode 100644 shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp create mode 100644 shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property.cpp create mode 100644 shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp create mode 100644 shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp create mode 100644 shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp create mode 100644 shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h create mode 100644 shared/libraries/opcuatms/tests/test_utils/CMakeLists.txt create mode 100644 shared/libraries/opcuatms/tests/test_utils/test_input_port_notifications.cpp create mode 100644 shared/libraries/opcuatms/tests/test_utils/test_input_port_notifications.h create mode 100644 shared/libraries/opcuatms/tests/test_utils/tms_object_test.cpp create mode 100644 shared/libraries/opcuatms/tests/test_utils/tms_object_test.h diff --git a/external/open62541/CMakeLists.txt b/external/open62541/CMakeLists.txt new file mode 100644 index 0000000..6e24638 --- /dev/null +++ b/external/open62541/CMakeLists.txt @@ -0,0 +1,83 @@ +if (UNIX AND CMAKE_COMPILER_IS_CLANGXX) + # Round about way of disabling clang sanitizers as open62541 doesn't have a way to do that properly + set(UA_BUILD_UNIT_TESTS OFF CACHE BOOL "Build the unit tests") + set(UA_ENABLE_UNIT_TESTS_MEMCHECK ON CACHE BOOL "Use Valgrind (Linux) or DrMemory (Windows) to detect memory leaks when running the unit tests") +endif() + +set(UA_NAMESPACE_ZERO FULL CACHE STRING "" FORCE) +set(UA_ENABLE_TYPEDESCRIPTION ON CACHE STRING "" FORCE) +set(UA_ENABLE_STATUSCODE_DESCRIPTIONS ON CACHE STRING "" FORCE) +set(UA_MULTITHREADING 100 CACHE STRING "" FORCE) + +set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL YES) + +opendaq_dependency( + NAME open62541 + REQUIRED_VERSION 1.3.6 + GIT_REPOSITORY https://github.com/openDAQ/open62541.git + GIT_REF v1.3.6-opendaq-2 + GIT_SUBMODULES "" + EXPECT_TARGET open62541 +) + +if (open62541_FETCHED) + + target_compile_definitions(open62541 PRIVATE UA_ENABLE_AMALGAMATION=OFF) + + if (WIN32) + target_compile_definitions(open62541 PUBLIC UA_ARCHITECTURE="win32") + endif() + + # dont treat warnings as errors + + set(OPEN62541_DISABLED_WARNINGS "-Wno-error") + if(MSVC) + set(OPEN62541_DISABLED_WARNINGS /WX- /wd4100 /wd4214 /wd4200 /wd4204 /wd4057 /wd4701 /wd4133) + endif() + + target_compile_options(open62541 PRIVATE ${OPEN62541_DISABLED_WARNINGS}) + target_compile_options(open62541-plugins PRIVATE ${OPEN62541_DISABLED_WARNINGS}) + target_compile_options(open62541-object PRIVATE ${OPEN62541_DISABLED_WARNINGS}) + + set(OPEN62541_DISABLED_WARNINGS ${OPEN62541_DISABLED_WARNINGS} PARENT_SCOPE) + + # fix library folders + + set_target_properties(doc doc_latex doc_pdf PROPERTIES FOLDER "${CMAKE_FOLDER}/doc") + + set(LIB_TARGETS + open62541-plugins + open62541 + open62541-object + ) + + foreach(LIB_TARGET ${LIB_TARGETS}) + set_target_properties(${LIB_TARGET} PROPERTIES FOLDER "${CMAKE_FOLDER}/lib") + + if (UNIX) + set_target_properties(${LIB_TARGET} PROPERTIES INTERPROCEDURAL_OPTIMIZATION OFF) + endif() + endforeach() + + if (UA_ENABLE_AMALGAMATION) + set_target_properties(open62541-amalgamation-header PROPERTIES FOLDER "${CMAKE_FOLDER}/lib") + set_target_properties(open62541-amalgamation-source PROPERTIES FOLDER "${CMAKE_FOLDER}/lib") + endif() + + set(GENERATOR_TARGETS + open62541-generator-namespace + open62541-generator-statuscode + open62541-generator-transport + open62541-generator-types + open62541-code-generation + ) + + foreach(TARGET_NAME ${GENERATOR_TARGETS}) + set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "${CMAKE_FOLDER}/generators") + endforeach() + + set(open62541_TOOLS_DIR "${open62541_SOURCE_DIR}/tools" PARENT_SCOPE) + set(open62541_NODESET_DIR "${open62541_SOURCE_DIR}/deps/ua-nodeset" PARENT_SCOPE) + include("${open62541_BINARY_DIR}/open62541Macros.cmake") + +endif() diff --git a/modules/opcua_client_module/CMakeLists.txt b/modules/opcua_client_module/CMakeLists.txt new file mode 100644 index 0000000..166a257 --- /dev/null +++ b/modules/opcua_client_module/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.2) +set_cmake_folder_context(TARGET_FOLDER_NAME) +project(ClientModule VERSION 2.0.0 LANGUAGES C CXX) + +add_subdirectory(src) + +if (OPENDAQ_ENABLE_TESTS) + add_subdirectory(tests) +endif() diff --git a/modules/opcua_client_module/include/opcua_client_module/common.h b/modules/opcua_client_module/include/opcua_client_module/common.h new file mode 100644 index 0000000..2475862 --- /dev/null +++ b/modules/opcua_client_module/include/opcua_client_module/common.h @@ -0,0 +1,21 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include + +#define BEGIN_NAMESPACE_OPENDAQ_OPCUA_CLIENT_MODULE BEGIN_NAMESPACE_OPENDAQ_MODULE(opcua_client_module) +#define END_NAMESPACE_OPENDAQ_OPCUA_CLIENT_MODULE END_NAMESPACE_OPENDAQ_MODULE diff --git a/modules/opcua_client_module/include/opcua_client_module/module_dll.h b/modules/opcua_client_module/include/opcua_client_module/module_dll.h new file mode 100644 index 0000000..b20d47b --- /dev/null +++ b/modules/opcua_client_module/include/opcua_client_module/module_dll.h @@ -0,0 +1,20 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include + +DECLARE_MODULE_EXPORTS(OpcUaClientModule) diff --git a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h new file mode 100644 index 0000000..f5968be --- /dev/null +++ b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h @@ -0,0 +1,47 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_CLIENT_MODULE + +class OpcUaClientModule final : public Module +{ +public: + OpcUaClientModule(ContextPtr context); + + ListPtr onGetAvailableDevices() override; + DictPtr onGetAvailableDeviceTypes() override; + DevicePtr onCreateDevice(const StringPtr& connectionString, + const ComponentPtr& parent, + const PropertyObjectPtr& config) override; + bool onAcceptsConnectionParameters(const StringPtr& connectionString, const PropertyObjectPtr& config) override; + +private: + static std::string GetUrlFromConnectionString(const StringPtr& connectionString); + static bool acceptDeviceProperties(const PropertyObjectPtr& config); + static PropertyObjectPtr createDeviceDefaultConfig(); + static void configureStreamingSources(const PropertyObjectPtr& deviceConfig, const DevicePtr& device); + static DeviceTypePtr createDeviceType(); + discovery::DiscoveryClient discoveryClient; + + std::mutex sync; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_CLIENT_MODULE diff --git a/modules/opcua_client_module/src/CMakeLists.txt b/modules/opcua_client_module/src/CMakeLists.txt new file mode 100644 index 0000000..6d483c8 --- /dev/null +++ b/modules/opcua_client_module/src/CMakeLists.txt @@ -0,0 +1,39 @@ +set(LIB_NAME opcua_client_module) +set(MODULE_HEADERS_DIR ../include/${TARGET_FOLDER_NAME}) + +set(SRC_Include common.h + module_dll.h + opcua_client_module_impl.h +) + +set(SRC_Srcs module_dll.cpp + opcua_client_module_impl.cpp +) + +prepend_include(${TARGET_FOLDER_NAME} SRC_Include) + +source_group("module" FILES ${MODULE_HEADERS_DIR}/opcua_client_module_impl.h + ${MODULE_HEADERS_DIR}/module_dll.h + module_dll.cpp + opcua_client_module_impl.cpp +) + + +add_library(${LIB_NAME} SHARED ${SRC_Include} + ${SRC_Srcs} +) +add_library(${SDK_TARGET_NAMESPACE}::${LIB_NAME} ALIAS ${LIB_NAME}) + +target_link_libraries(${LIB_NAME} PUBLIC daq::opendaq + PRIVATE daq::discovery + daq::opcuatms_client +) + +target_include_directories(${LIB_NAME} PUBLIC $ + $ + $ +) + +opendaq_set_module_properties(${LIB_NAME} ${PROJECT_VERSION_MAJOR}) +create_version_header(${LIB_NAME}) + diff --git a/modules/opcua_client_module/src/module_dll.cpp b/modules/opcua_client_module/src/module_dll.cpp new file mode 100644 index 0000000..71987e6 --- /dev/null +++ b/modules/opcua_client_module/src/module_dll.cpp @@ -0,0 +1,9 @@ +#include +#include + +#include + +using namespace daq::modules::opcua_client_module; + +DEFINE_MODULE_EXPORTS(OpcUaClientModule) + diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp new file mode 100644 index 0000000..44be87a --- /dev/null +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -0,0 +1,257 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_CLIENT_MODULE + +static const char* DaqOpcUaDeviceTypeId = "daq.opcua"; +static const char* DaqOpcUaDevicePrefix = "daq.opcua://"; +static const char* OpcUaScheme = "opc.tcp://"; + +using namespace discovery; +using namespace daq::opcua; + +OpcUaClientModule::OpcUaClientModule(ContextPtr context) + : Module("openDAQ OpcUa client module", + daq::VersionInfo(OPCUA_CLIENT_MODULE_MAJOR_VERSION, OPCUA_CLIENT_MODULE_MINOR_VERSION, OPCUA_CLIENT_MODULE_PATCH_VERSION), + std::move(context)) + , discoveryClient([](const MdnsDiscoveredDevice& discoveredDevice) + { + return DaqOpcUaDevicePrefix + discoveredDevice.ipv4Address + "/"; + }, + {"OPENDAQ"}) +{ + discoveryClient.initMdnsClient("_opcua-tcp._tcp.local."); +} + +ListPtr OpcUaClientModule::onGetAvailableDevices() +{ + auto availableDevices = discoveryClient.discoverDevices(); + for (auto device : availableDevices) + { + device.asPtr().setDeviceType(createDeviceType()); + } + return availableDevices; +} + +DictPtr OpcUaClientModule::onGetAvailableDeviceTypes() +{ + auto result = Dict(); + + auto deviceType = createDeviceType(); + result.set(deviceType.getId(), deviceType); + + return result; +} + +DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, + const ComponentPtr& parent, + const PropertyObjectPtr& config) +{ + if (!connectionString.assigned()) + throw ArgumentNullException(); + + PropertyObjectPtr deviceConfig = config; + if (!deviceConfig.assigned()) + deviceConfig = createDeviceDefaultConfig(); + + if (!onAcceptsConnectionParameters(connectionString, deviceConfig)) + throw InvalidParameterException(); + + if (!context.assigned()) + throw InvalidParameterException{"Context is not available."}; + + + + const auto deviceUrl = GetUrlFromConnectionString(connectionString); + StringPtr rootDeviceAddress; + std::smatch match; + auto regexHostname = std::regex("^(.*:\\/\\/)?([^:\\/\\s]+)"); + if (std::regex_search(deviceUrl, match, regexHostname)) + rootDeviceAddress = String(match[2]); + + FunctionPtr createStreamingCallback = [&](const StreamingInfoPtr& streamingInfo, + bool isRootDevice) -> StreamingPtr + { + if (isRootDevice) + streamingInfo.template asPtr().setPrimaryAddress(rootDeviceAddress); + + const StringPtr streamingHeuristic = deviceConfig.getPropertySelectionValue("StreamingConnectionHeuristic"); + const ListPtr allowedStreamingProtocols = deviceConfig.getPropertyValue("AllowedStreamingProtocols"); + + if (const auto it = std::find(allowedStreamingProtocols.begin(), + allowedStreamingProtocols.end(), + streamingInfo.getProtocolId()); + it == allowedStreamingProtocols.end()) + return nullptr; + + if (streamingHeuristic == "MinHops" || + streamingHeuristic == "Fallbacks" || + streamingHeuristic == "MinConnections" && isRootDevice) + return this->createStreamingFromAnotherModule(nullptr, streamingInfo); + else + return nullptr; + }; + + std::scoped_lock lock(sync); + TmsClient client(context, parent, OpcUaScheme + deviceUrl, createStreamingCallback); + auto device = client.connect(); + this->configureStreamingSources(deviceConfig, device); + return device; +} + +std::string OpcUaClientModule::GetUrlFromConnectionString(const StringPtr& connectionString) +{ + std::string connStr = connectionString; + std::string prefixWithDeviceStr = DaqOpcUaDevicePrefix; + auto found = connStr.find(prefixWithDeviceStr); + if (found != 0) + throw InvalidParameterException(); + + return connStr.substr(prefixWithDeviceStr.size(), std::string::npos); +} + +bool OpcUaClientModule::onAcceptsConnectionParameters(const StringPtr& connectionString, const PropertyObjectPtr& config) +{ + std::string connStr = connectionString; + auto found = connStr.find(DaqOpcUaDevicePrefix); + if (found != 0) + return false; + + if ( config.assigned() && !acceptDeviceProperties(config)) + { + LOG_W("Connection string \"{}\" is accepted but config is incomplete", connectionString); + return false; + } + else + { + return true; + } +} + +bool OpcUaClientModule::acceptDeviceProperties(const PropertyObjectPtr& config) +{ + bool hasRequiredProperties = config.hasProperty("StreamingConnectionHeuristic") && + config.hasProperty("AllowedStreamingProtocols") && + config.hasProperty("PrimaryStreamingProtocol"); + if (!hasRequiredProperties) + return false; + + const StringPtr primaryStreamingProtocol = config.getPropertyValue("PrimaryStreamingProtocol"); + const ListPtr allowedStreamingProtocols = config.getPropertyValue("AllowedStreamingProtocols"); + if (const auto it = std::find(allowedStreamingProtocols.begin(), + allowedStreamingProtocols.end(), + primaryStreamingProtocol); + it == allowedStreamingProtocols.end()) + return false; + + return true; +} + +PropertyObjectPtr OpcUaClientModule::createDeviceDefaultConfig() +{ + auto defaultConfig = PropertyObject(); + + const auto streamingConnectionHeuristicProp = SelectionProperty("StreamingConnectionHeuristic", + List("MinConnections", + "MinHops", + "Fallbacks", + "NotConnected"), + 0); + defaultConfig.addProperty(streamingConnectionHeuristicProp); + + auto allowedStreamingProtocols = List(); + StringPtr primaryStreamingProtocol = "none"; + +#if defined(OPENDAQ_ENABLE_NATIVE_STREAMING) + allowedStreamingProtocols.pushBack("daq.ns"); + primaryStreamingProtocol = "daq.ns"; +// TODO add websocket streaming to default list of allowed protocols +// when it will have subscribe/unsubscribe support +//#if defined(OPENDAQ_ENABLE_WEBSOCKET_STREAMING) +// allowedStreamingProtocols.pushBack("daq.wss"); +//#endif +#elif defined(OPENDAQ_ENABLE_WEBSOCKET_STREAMING) + allowedStreamingProtocols.pushBack("daq.wss"); + primaryStreamingProtocol = "daq.wss"; +#endif + + defaultConfig.addProperty(ListProperty("AllowedStreamingProtocols", allowedStreamingProtocols)); + defaultConfig.addProperty(StringProperty("PrimaryStreamingProtocol", primaryStreamingProtocol)); + + return defaultConfig; +} + +DeviceTypePtr OpcUaClientModule::createDeviceType() +{ + auto configurationCallback = [](IBaseObject* input, IBaseObject** output) -> ErrCode + { + PropertyObjectPtr propObjPtr; + ErrCode errCode = wrapHandlerReturn(&OpcUaClientModule::createDeviceDefaultConfig, propObjPtr); + *output = propObjPtr.detach(); + return errCode; + }; + + return DeviceType(DaqOpcUaDeviceTypeId, + "OpcUa enabled device", + "Network device connected over OpcUa protocol", + configurationCallback); +} + +void OpcUaClientModule::configureStreamingSources(const PropertyObjectPtr& deviceConfig, const DevicePtr& device) +{ + const StringPtr streamingHeuristic = deviceConfig.getPropertySelectionValue("StreamingConnectionHeuristic"); + if (streamingHeuristic == "NotConnected") + return; + + const StringPtr primaryStreamingProtocol = deviceConfig.getPropertyValue("PrimaryStreamingProtocol"); + + for (const auto& signal : device.getSignalsRecursive()) + { + auto signalConfigPtr = signal.asPtr(); + + auto streamingSources = signalConfigPtr.getStreamingSources(); + if (streamingSources.empty()) + continue; + + // TODO this may raise bugs + // since sub-devices are being created recursively it is expected that + // the leaf device direct streaming is the first-one of available sources + // and root streaming is the last-one + StringPtr leafStreaming; + StringPtr rootStreaming; + for (const auto& streamingConnectionString : streamingSources) + { + std::string connectionString = streamingConnectionString.toStdString(); + std::string protocolPrefix = primaryStreamingProtocol.toStdString(); + if (connectionString.find(protocolPrefix) == 0) + { + // save the first streaming source as the leaf streaming + if (!leafStreaming.assigned()) + leafStreaming = streamingConnectionString; + + // save the last streaming source as the root streaming + rootStreaming = streamingConnectionString; + } + } + if (!leafStreaming.assigned() || !rootStreaming.assigned()) + continue; + + if (streamingHeuristic == "MinConnections" || streamingHeuristic == "Fallbacks") + { + signalConfigPtr.setActiveStreamingSource(rootStreaming); + } + else if (streamingHeuristic == "MinHops") + { + signalConfigPtr.setActiveStreamingSource(leafStreaming); + } + } +} + +END_NAMESPACE_OPENDAQ_OPCUA_CLIENT_MODULE diff --git a/modules/opcua_client_module/tests/CMakeLists.txt b/modules/opcua_client_module/tests/CMakeLists.txt new file mode 100644 index 0000000..365da57 --- /dev/null +++ b/modules/opcua_client_module/tests/CMakeLists.txt @@ -0,0 +1,22 @@ +set(MODULE_NAME opcua_client_module) +set(TEST_APP test_${MODULE_NAME}) + +set(TEST_SOURCES test_opcua_client_module.cpp + test_app.cpp +) + +add_executable(${TEST_APP} ${TEST_SOURCES} +) + +target_link_libraries(${TEST_APP} PRIVATE daq::test_utils + ${SDK_TARGET_NAMESPACE}::${MODULE_NAME} +) + +add_test(NAME ${TEST_APP} + COMMAND $ + WORKING_DIRECTORY bin +) + +if (OPENDAQ_ENABLE_COVERAGE) + setup_target_for_coverage(${TEST_APP}coverage ${TEST_APP} ${TEST_APP}coverage) +endif() diff --git a/modules/opcua_client_module/tests/test_app.cpp b/modules/opcua_client_module/tests/test_app.cpp new file mode 100644 index 0000000..546baf7 --- /dev/null +++ b/modules/opcua_client_module/tests/test_app.cpp @@ -0,0 +1,21 @@ +#include +#include + +#include +#include +#include + +int main(int argc, char** args) +{ + daq::daqInitializeCoreObjectsTesting(); + daqInitModuleManagerLibrary(); + + testing::InitGoogleTest(&argc, args); + + testing::TestEventListeners& listeners = testing::UnitTest::GetInstance()->listeners(); + listeners.Append(new DaqMemCheckListener()); + + auto res = RUN_ALL_TESTS(); + + return res; +} diff --git a/modules/opcua_client_module/tests/test_opcua_client_module.cpp b/modules/opcua_client_module/tests/test_opcua_client_module.cpp new file mode 100644 index 0000000..4573324 --- /dev/null +++ b/modules/opcua_client_module/tests/test_opcua_client_module.cpp @@ -0,0 +1,199 @@ +#include +#include +#include +#include + +#include +#include +#include + +#include + +using OpcUaClientModuleTest = testing::Test; +using namespace daq; + +static ModulePtr CreateModule() +{ + ModulePtr module; + createModule(&module, NullContext()); + return module; +} + +TEST_F(OpcUaClientModuleTest, CreateModule) +{ + IModule* module = nullptr; + ErrCode errCode = createModule(&module, NullContext()); + ASSERT_TRUE(OPENDAQ_SUCCEEDED(errCode)); + + ASSERT_NE(module, nullptr); + module->releaseRef(); +} + +TEST_F(OpcUaClientModuleTest, ModuleName) +{ + auto module = CreateModule(); + ASSERT_EQ(module.getName(), "openDAQ OpcUa client module"); +} + +TEST_F(OpcUaClientModuleTest, VersionAvailable) +{ + auto module = CreateModule(); + ASSERT_TRUE(module.getVersionInfo().assigned()); +} + +TEST_F(OpcUaClientModuleTest, VersionCorrect) +{ + auto module = CreateModule(); + auto version = module.getVersionInfo(); + + ASSERT_EQ(version.getMajor(), OPCUA_CLIENT_MODULE_MAJOR_VERSION); + ASSERT_EQ(version.getMinor(), OPCUA_CLIENT_MODULE_MINOR_VERSION); + ASSERT_EQ(version.getPatch(), OPCUA_CLIENT_MODULE_PATCH_VERSION); +} + +TEST_F(OpcUaClientModuleTest, EnumerateDevices) +{ + auto module = CreateModule(); + + ListPtr deviceInfo; + ASSERT_NO_THROW(deviceInfo = module.getAvailableDevices()); +} + +TEST_F(OpcUaClientModuleTest, AcceptsConnectionStringNull) +{ + auto module = CreateModule(); + ASSERT_THROW(module.acceptsConnectionParameters(nullptr), ArgumentNullException); +} + +TEST_F(OpcUaClientModuleTest, AcceptsConnectionStringEmpty) +{ + auto module = CreateModule(); + + bool accepts = true; + ASSERT_NO_THROW(accepts = module.acceptsConnectionParameters("")); + ASSERT_FALSE(accepts); +} + +TEST_F(OpcUaClientModuleTest, AcceptsConnectionStringInvalid) +{ + auto module = CreateModule(); + + bool accepts = true; + ASSERT_NO_THROW(accepts = module.acceptsConnectionParameters("drfrfgt")); + ASSERT_FALSE(accepts); +} + +TEST_F(OpcUaClientModuleTest, AcceptsConnectionStringCorrect) +{ + auto module = CreateModule(); + + ASSERT_TRUE(module.acceptsConnectionParameters("daq.opcua://device8")); +} + +TEST_F(OpcUaClientModuleTest, CreateDeviceConnectionStringNull) +{ + auto module = CreateModule(); + + DevicePtr device; + ASSERT_THROW(device = module.createDevice(nullptr, nullptr), ArgumentNullException); +} + +TEST_F(OpcUaClientModuleTest, CreateDeviceConnectionStringEmpty) +{ + auto module = CreateModule(); + + ASSERT_THROW(module.createDevice("", nullptr), InvalidParameterException); +} + +TEST_F(OpcUaClientModuleTest, CreateDeviceConnectionStringInvalid) +{ + auto module = CreateModule(); + + ASSERT_THROW(module.createDevice("fdfdfdfdde", nullptr), InvalidParameterException); +} + +TEST_F(OpcUaClientModuleTest, CreateDeviceConnectionStringInvalidId) +{ + auto module = CreateModule(); + + ASSERT_THROW(module.createDevice("daqref://devicett3axxr1", nullptr), InvalidParameterException); +} + +TEST_F(OpcUaClientModuleTest, CreateDeviceConfigInvalid) +{ + auto module = CreateModule(); + auto config = PropertyObject(); + + ASSERT_THROW(module.createDevice("daq.opcua://device8", nullptr, config), InvalidParameterException); +} + +TEST_F(OpcUaClientModuleTest, GetAvailableComponentTypes) +{ + const auto module = CreateModule(); + + DictPtr functionBlockTypes; + ASSERT_NO_THROW(functionBlockTypes = module.getAvailableFunctionBlockTypes()); + ASSERT_EQ(functionBlockTypes.getCount(), 0u); + + DictPtr deviceTypes; + ASSERT_NO_THROW(deviceTypes = module.getAvailableDeviceTypes()); + ASSERT_EQ(deviceTypes.getCount(), 1u); + ASSERT_TRUE(deviceTypes.hasKey("daq.opcua")); + ASSERT_EQ(deviceTypes.get("daq.opcua").getId(), "daq.opcua"); + + DictPtr serverTypes; + ASSERT_NO_THROW(serverTypes = module.getAvailableServerTypes()); + ASSERT_EQ(serverTypes.getCount(), 0u); +} + +TEST_F(OpcUaClientModuleTest, DefaultDeviceConfig) +{ + const auto module = CreateModule(); + + DictPtr deviceTypes; + ASSERT_NO_THROW(deviceTypes = module.getAvailableDeviceTypes()); + ASSERT_EQ(deviceTypes.getCount(), 1u); + ASSERT_TRUE(deviceTypes.hasKey("daq.opcua")); + auto config = deviceTypes.get("daq.opcua").createDefaultConfig(); + ASSERT_TRUE(config.assigned()); + + ASSERT_TRUE(config.hasProperty("StreamingConnectionHeuristic")); + ASSERT_EQ(config.getPropertySelectionValue("StreamingConnectionHeuristic"), "MinConnections"); + +#if defined(OPENDAQ_ENABLE_NATIVE_STREAMING) + ASSERT_TRUE(config.hasProperty("AllowedStreamingProtocols")); + ASSERT_EQ(config.getPropertyValue("AllowedStreamingProtocols"), List("daq.ns")); + + ASSERT_TRUE(config.hasProperty("PrimaryStreamingProtocol")); + ASSERT_EQ(config.getPropertyValue("PrimaryStreamingProtocol"), "daq.ns"); +#elif defined(OPENDAQ_ENABLE_WEBSOCKET_STREAMING) && !defined(OPENDAQ_ENABLE_NATIVE_STREAMING) + ASSERT_TRUE(config.hasProperty("AllowedStreamingProtocols")); + ASSERT_EQ(config.getPropertyValue("AllowedStreamingProtocols"), List("daq.wss")); + + ASSERT_TRUE(config.hasProperty("PrimaryStreamingProtocol")); + ASSERT_EQ(config.getPropertyValue("PrimaryStreamingProtocol"), "daq.wss"); +#endif +} + +TEST_F(OpcUaClientModuleTest, InvalidDeviceConfig) +{ + auto module = CreateModule(); + auto config = PropertyObject(); + + ASSERT_FALSE(module.acceptsConnectionParameters("daq.opcua://device8", config)); +} + +TEST_F(OpcUaClientModuleTest, CreateFunctionBlockIdNull) +{ + auto module = CreateModule(); + + FunctionBlockPtr functionBlock; + ASSERT_THROW(functionBlock = module.createFunctionBlock(nullptr, nullptr, "fb"), ArgumentNullException); +} + +TEST_F(OpcUaClientModuleTest, CreateFunctionBlockIdEmpty) +{ + auto module = CreateModule(); + + ASSERT_THROW(module.createFunctionBlock("", nullptr, "fb"), NotFoundException); +} diff --git a/modules/opcua_server_module/CMakeLists.txt b/modules/opcua_server_module/CMakeLists.txt new file mode 100644 index 0000000..62b116d --- /dev/null +++ b/modules/opcua_server_module/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.2) +set_cmake_folder_context(TARGET_FOLDER_NAME) +project(ServerModule VERSION 2.0.0 LANGUAGES CXX) + +add_subdirectory(src) + +if (OPENDAQ_ENABLE_TESTS) + add_subdirectory(tests) +endif() diff --git a/modules/opcua_server_module/include/opcua_server_module/common.h b/modules/opcua_server_module/include/opcua_server_module/common.h new file mode 100644 index 0000000..06191fa --- /dev/null +++ b/modules/opcua_server_module/include/opcua_server_module/common.h @@ -0,0 +1,21 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include + +#define BEGIN_NAMESPACE_OPENDAQ_OPCUA_SERVER_MODULE BEGIN_NAMESPACE_OPENDAQ_MODULE(opcua_server_module) +#define END_NAMESPACE_OPENDAQ_OPCUA_SERVER_MODULE END_NAMESPACE_OPENDAQ_MODULE diff --git a/modules/opcua_server_module/include/opcua_server_module/module_dll.h b/modules/opcua_server_module/include/opcua_server_module/module_dll.h new file mode 100644 index 0000000..17e37aa --- /dev/null +++ b/modules/opcua_server_module/include/opcua_server_module/module_dll.h @@ -0,0 +1,20 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include + +DECLARE_MODULE_EXPORTS(OpcUaServerModule) diff --git a/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h b/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h new file mode 100644 index 0000000..1fea1b7 --- /dev/null +++ b/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h @@ -0,0 +1,49 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_SERVER_MODULE + +class OpcUaServerImpl : public daq::Server +{ +public: + explicit OpcUaServerImpl(daq::DevicePtr rootDevice, PropertyObjectPtr config, const ContextPtr& context); + static PropertyObjectPtr createDefaultConfig(); + static ServerTypePtr createType(); + +protected: + void onStopServer() override; + + daq::opcua::TmsServer server; + PropertyObjectPtr config; + ContextPtr context; +}; + +OPENDAQ_DECLARE_CLASS_FACTORY_WITH_INTERFACE( + INTERNAL_FACTORY, OpcUaServer, daq::IServer, + DevicePtr, rootDevice, + PropertyObjectPtr, config, + const ContextPtr&, context +) + +END_NAMESPACE_OPENDAQ_OPCUA_SERVER_MODULE diff --git a/modules/opcua_server_module/include/opcua_server_module/opcua_server_module_impl.h b/modules/opcua_server_module/include/opcua_server_module/opcua_server_module_impl.h new file mode 100644 index 0000000..2c04dd6 --- /dev/null +++ b/modules/opcua_server_module/include/opcua_server_module/opcua_server_module_impl.h @@ -0,0 +1,35 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_SERVER_MODULE + +class OpcUaServerModule final : public Module +{ +public: + OpcUaServerModule(ContextPtr context); + + DictPtr onGetAvailableServerTypes() override; + ServerPtr onCreateServer(StringPtr serverType, PropertyObjectPtr serverConfig, DevicePtr rootDevice) override; + +private: + std::mutex sync; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_SERVER_MODULE diff --git a/modules/opcua_server_module/src/CMakeLists.txt b/modules/opcua_server_module/src/CMakeLists.txt new file mode 100644 index 0000000..4582636 --- /dev/null +++ b/modules/opcua_server_module/src/CMakeLists.txt @@ -0,0 +1,43 @@ +set(LIB_NAME opcua_server_module) +set(MODULE_HEADERS_DIR ../include/${TARGET_FOLDER_NAME}) + +set(SRC_Include common.h + module_dll.h + opcua_server_module_impl.h + opcua_server_impl.h +) + +set(SRC_Srcs module_dll.cpp + opcua_server_module_impl.cpp + opcua_server_impl.cpp +) + +prepend_include(${TARGET_FOLDER_NAME} SRC_Include) + +source_group("module" FILES ${MODULE_HEADERS_DIR}/opcua_server_module_impl.h + ${MODULE_HEADERS_DIR}/opcua_server_impl.h + ${MODULE_HEADERS_DIR}/module_dll.h + module_dll.cpp + opcua_server_module_impl.cpp + opcua_server_impl.cpp +) + + +add_library(${LIB_NAME} SHARED ${SRC_Include} + ${SRC_Srcs} +) + +add_library(${SDK_TARGET_NAMESPACE}::${LIB_NAME} ALIAS ${LIB_NAME}) + +target_link_libraries(${LIB_NAME} PUBLIC daq::opendaq + PRIVATE daq::opcuatms_server +) + +target_include_directories(${LIB_NAME} PUBLIC $ + $ + $ +) + +opendaq_set_module_properties(${LIB_NAME} ${PROJECT_VERSION_MAJOR}) +create_version_header(${LIB_NAME}) + diff --git a/modules/opcua_server_module/src/module_dll.cpp b/modules/opcua_server_module/src/module_dll.cpp new file mode 100644 index 0000000..f6b2849 --- /dev/null +++ b/modules/opcua_server_module/src/module_dll.cpp @@ -0,0 +1,9 @@ +#include +#include + +#include + +using namespace daq::modules::opcua_server_module; + +DEFINE_MODULE_EXPORTS(OpcUaServerModule) + diff --git a/modules/opcua_server_module/src/opcua_server_impl.cpp b/modules/opcua_server_module/src/opcua_server_impl.cpp new file mode 100644 index 0000000..ce5c8f1 --- /dev/null +++ b/modules/opcua_server_module/src/opcua_server_impl.cpp @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_SERVER_MODULE + +using namespace daq; +using namespace daq::opcua; + +OpcUaServerImpl::OpcUaServerImpl(DevicePtr rootDevice, PropertyObjectPtr config, const ContextPtr& context) + : Server(nullptr, rootDevice, nullptr, nullptr) + , server(rootDevice, context) + , config(config) + , context(context) +{ + const uint16_t port = config.getPropertyValue("Port"); + + server.setOpendaqVersion(OPENDAQ_PACKAGE_VERSION); + server.setOpcUaPort(port); + server.start(); +} + +PropertyObjectPtr OpcUaServerImpl::createDefaultConfig() +{ + constexpr Int minPortValue = 0; + constexpr Int maxPortValue = 65535; + + auto defaultConfig = PropertyObject(); + + const auto portProp = IntPropertyBuilder("Port", 4840).setMinValue(minPortValue).setMaxValue(maxPortValue).build(); + defaultConfig.addProperty(portProp); + + return defaultConfig; +} + +ServerTypePtr OpcUaServerImpl::createType() +{ + auto configurationCallback = [](IBaseObject* input, IBaseObject** output) -> ErrCode + { + PropertyObjectPtr propObjPtr; + ErrCode errCode = wrapHandlerReturn(&OpcUaServerImpl::createDefaultConfig, propObjPtr); + *output = propObjPtr.detach(); + return errCode; + }; + + return ServerType("openDAQ OpcUa", + "openDAQ OpcUa server", + "Publishes device structure over OpcUa protocol", + configurationCallback); +} + +void OpcUaServerImpl::onStopServer() +{ + server.stop(); +} + +OPENDAQ_DEFINE_CLASS_FACTORY_WITH_INTERFACE( + INTERNAL_FACTORY, OpcUaServer, daq::IServer, + daq::DevicePtr, rootDevice, + PropertyObjectPtr, config, + const ContextPtr&, context +) + +END_NAMESPACE_OPENDAQ_OPCUA_SERVER_MODULE diff --git a/modules/opcua_server_module/src/opcua_server_module_impl.cpp b/modules/opcua_server_module/src/opcua_server_module_impl.cpp new file mode 100644 index 0000000..4cb6b78 --- /dev/null +++ b/modules/opcua_server_module/src/opcua_server_module_impl.cpp @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_SERVER_MODULE + +OpcUaServerModule::OpcUaServerModule(ContextPtr context) + : Module("openDAQ OpcUa server module", + daq::VersionInfo(OPCUA_SERVER_MODULE_MAJOR_VERSION, OPCUA_SERVER_MODULE_MINOR_VERSION, OPCUA_SERVER_MODULE_PATCH_VERSION), + std::move(context)) +{ +} + +DictPtr OpcUaServerModule::onGetAvailableServerTypes() +{ + auto result = Dict(); + + auto serverType = OpcUaServerImpl::createType(); + result.set(serverType.getId(), serverType); + + return result; +} + +ServerPtr OpcUaServerModule::onCreateServer(StringPtr serverType, + PropertyObjectPtr serverConfig, + DevicePtr rootDevice) +{ + if (!context.assigned()) + throw InvalidParameterException{"Context parameter cannot be null."}; + + if (!serverConfig.assigned()) + serverConfig = OpcUaServerImpl::createDefaultConfig(); + + ServerPtr server(OpcUaServer_Create(rootDevice, serverConfig, context)); + return server; +} + +END_NAMESPACE_OPENDAQ_OPCUA_SERVER_MODULE diff --git a/modules/opcua_server_module/tests/CMakeLists.txt b/modules/opcua_server_module/tests/CMakeLists.txt new file mode 100644 index 0000000..860e24c --- /dev/null +++ b/modules/opcua_server_module/tests/CMakeLists.txt @@ -0,0 +1,29 @@ +set(MODULE_NAME opcua_server_module) +set(TEST_APP test_${MODULE_NAME}) + +set(TEST_SOURCES test_opcua_server_module.cpp + test_app.cpp +) + +add_executable(${TEST_APP} ${TEST_SOURCES} +) + +target_link_libraries(${TEST_APP} PRIVATE daq::test_utils + daq::opcuaclient + daq::opendaq_mocks + ${SDK_TARGET_NAMESPACE}::${MODULE_NAME} + Taskflow::Taskflow +) + +add_test(NAME ${TEST_APP} + COMMAND $ + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +) + +if (MSVC) # Ignoring warning for the Taskflow + target_compile_options(${TEST_APP} PRIVATE /wd4324) +endif() + +if (OPENDAQ_ENABLE_COVERAGE) + setup_target_for_coverage(${TEST_APP}coverage ${TEST_APP} ${TEST_APP}coverage) +endif() diff --git a/modules/opcua_server_module/tests/test_app.cpp b/modules/opcua_server_module/tests/test_app.cpp new file mode 100644 index 0000000..64dd0cc --- /dev/null +++ b/modules/opcua_server_module/tests/test_app.cpp @@ -0,0 +1,22 @@ +#include +#include +#include +#include +#include +#include + +int main(int argc, char** args) +{ + daq::daqInitializeCoreObjectsTesting(); + daqInitModuleManagerLibrary(); + daqInitOpenDaqLibrary(); + + testing::InitGoogleTest(&argc, args); + + testing::TestEventListeners& listeners = testing::UnitTest::GetInstance()->listeners(); + listeners.Append(new DaqMemCheckListener()); + + auto res = RUN_ALL_TESTS(); + + return res; +} diff --git a/modules/opcua_server_module/tests/test_opcua_server_module.cpp b/modules/opcua_server_module/tests/test_opcua_server_module.cpp new file mode 100644 index 0000000..938842f --- /dev/null +++ b/modules/opcua_server_module/tests/test_opcua_server_module.cpp @@ -0,0 +1,184 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +class OpcUaServerModuleTest : public testing::Test +{ +public: + void TearDown() override + { + } +}; + +using namespace daq; +using namespace daq::opcua; + +static ModulePtr CreateModule(ContextPtr context = NullContext()) +{ + ModulePtr module; + createOpcUaServerModule(&module, context); + return module; +} + +static InstancePtr CreateTestInstance() +{ + const auto logger = Logger(); + const auto moduleManager = ModuleManager("[[none]]"); + const auto context = Context(Scheduler(logger), logger, TypeManager(), moduleManager); + + const ModulePtr deviceModule(MockDeviceModule_Create(context)); + moduleManager.addModule(deviceModule); + + const ModulePtr fbModule(MockFunctionBlockModule_Create(context)); + moduleManager.addModule(fbModule); + + const ModulePtr daqServerModule = CreateModule(context); + moduleManager.addModule(daqServerModule); + + auto instance = InstanceCustom(context, "localInstance"); + for (const auto& deviceInfo : instance.getAvailableDevices()) + instance.addDevice(deviceInfo.getConnectionString()); + + for (const auto& [id, _] : instance.getAvailableFunctionBlockTypes()) + instance.addFunctionBlock(id); + + return instance; +} + +static PropertyObjectPtr CreateServerConfig(const InstancePtr& instance) +{ + auto config = instance.getAvailableServerTypes().get("openDAQ OpcUa").createDefaultConfig(); + return config; +} + +TEST_F(OpcUaServerModuleTest, CreateModule) +{ + IModule* module = nullptr; + ErrCode errCode = createModule(&module, NullContext()); + ASSERT_TRUE(OPENDAQ_SUCCEEDED(errCode)); + + ASSERT_NE(module, nullptr); + module->releaseRef(); +} + +TEST_F(OpcUaServerModuleTest, ModuleName) +{ + auto module = CreateModule(); + ASSERT_EQ(module.getName(), "openDAQ OpcUa server module"); +} + +TEST_F(OpcUaServerModuleTest, VersionAvailable) +{ + auto module = CreateModule(); + ASSERT_TRUE(module.getVersionInfo().assigned()); +} + +TEST_F(OpcUaServerModuleTest, VersionCorrect) +{ + auto module = CreateModule(); + auto version = module.getVersionInfo(); + + ASSERT_EQ(version.getMajor(), OPCUA_SERVER_MODULE_MAJOR_VERSION); + ASSERT_EQ(version.getMinor(), OPCUA_SERVER_MODULE_MINOR_VERSION); + ASSERT_EQ(version.getPatch(), OPCUA_SERVER_MODULE_PATCH_VERSION); +} + +TEST_F(OpcUaServerModuleTest, GetAvailableComponentTypes) +{ + const auto module = CreateModule(); + + DictPtr functionBlockTypes; + ASSERT_NO_THROW(functionBlockTypes = module.getAvailableFunctionBlockTypes()); + ASSERT_EQ(functionBlockTypes.getCount(), 0u); + + DictPtr deviceTypes; + ASSERT_NO_THROW(deviceTypes = module.getAvailableDeviceTypes()); + ASSERT_EQ(deviceTypes.getCount(), 0u); + + DictPtr serverTypes; + ASSERT_NO_THROW(serverTypes = module.getAvailableServerTypes()); + ASSERT_EQ(serverTypes.getCount(), 1u); + ASSERT_TRUE(serverTypes.hasKey("openDAQ OpcUa")); + ASSERT_EQ(serverTypes.get("openDAQ OpcUa").getId(), "openDAQ OpcUa"); +} + +TEST_F(OpcUaServerModuleTest, ServerConfig) +{ + auto module = CreateModule(); + + DictPtr serverTypes = module.getAvailableServerTypes(); + ASSERT_TRUE(serverTypes.hasKey("openDAQ OpcUa")); + auto config = serverTypes.get("openDAQ OpcUa").createDefaultConfig(); + ASSERT_TRUE(config.assigned()); + + ASSERT_TRUE(config.hasProperty("Port")); + ASSERT_EQ(config.getPropertyValue("Port"), 4840); +} + +TEST_F(OpcUaServerModuleTest, CreateServer) +{ + auto device = CreateTestInstance(); + auto module = CreateModule(device.getContext()); + auto config = CreateServerConfig(device); + + ASSERT_NO_THROW(module.createServer("openDAQ OpcUa", device.getRootDevice(), config)); +} + +TEST_F(OpcUaServerModuleTest, CreateServerFromInstance) +{ + auto device = CreateTestInstance(); + auto config = CreateServerConfig(device); + + ASSERT_NO_THROW(device.addServer("openDAQ OpcUa", config)); +} + +TEST_F(OpcUaServerModuleTest, TestConnection) +{ + auto device = CreateTestInstance(); + auto config = CreateServerConfig(device); + device.addServer("openDAQ OpcUa", config); + + OpcUaClient client("opc.tcp://localhost/"); + ASSERT_TRUE(client.connect()); +} + +TEST_F(OpcUaServerModuleTest, TestConnectionDifferentPort) +{ + auto device = CreateTestInstance(); + auto module = CreateModule(device.getContext()); + auto config = CreateServerConfig(device); + + config.setPropertyValue("Port", 4841); + + auto serverPtr = module.createServer("openDAQ OpcUa", device.getRootDevice(), config); + + OpcUaClient client("opc.tcp://localhost:4841/"); + ASSERT_TRUE(client.connect()); +} + +TEST_F(OpcUaServerModuleTest, StopServer) +{ + auto device = CreateTestInstance(); + auto module = CreateModule(device.getContext()); + auto config = CreateServerConfig(device); + + auto serverPtr = module.createServer("openDAQ OpcUa", device.getRootDevice(), config); + + OpcUaClient client("opc.tcp://localhost/"); + ASSERT_TRUE(client.connect()); + client.disconnect(); + + serverPtr.stop(); + ASSERT_FALSE(client.connect()); +} diff --git a/shared/libraries/opcua/CMakeLists.txt b/shared/libraries/opcua/CMakeLists.txt new file mode 100644 index 0000000..5b96f8e --- /dev/null +++ b/shared/libraries/opcua/CMakeLists.txt @@ -0,0 +1,17 @@ +set_cmake_folder_context(TARGET_FOLDER_NAME) + +add_subdirectory(opcuashared) +add_subdirectory(opcuaserver) +add_subdirectory(opcuaclient) + +if (OPENDAQ_ENABLE_TESTS) + add_subdirectory(tests) +endif() + +#GENERATE_DOCUMENTATION( +# NAME "OpcUa" +# INPUT +# opcuashared/include +# opcuaserver/include +# opcuaclient/include +#) diff --git a/shared/libraries/opcua/OWNERS.txt b/shared/libraries/opcua/OWNERS.txt new file mode 100644 index 0000000..48c5c08 --- /dev/null +++ b/shared/libraries/opcua/OWNERS.txt @@ -0,0 +1,12 @@ +# This is a list of owners of the subtree. + +# if any of the changes are made to this subtree at least one +# of the owners should review and confirm those changes. + +# Owners are listed at the bottom of this file. + +# Names should be added to this file like so: +# Name or Organization + +Dewesoft d.o.o. +Anže Škerjanc diff --git a/shared/libraries/opcua/opcuaclient/CMakeLists.txt b/shared/libraries/opcua/opcuaclient/CMakeLists.txt new file mode 100644 index 0000000..079968e --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.2) +set_cmake_folder_context(TARGET_FOLDER_NAME client) +project(OpcUaClient CXX) + +add_subdirectory(src) + +if (OPENDAQ_ENABLE_TESTS) + add_subdirectory(tests) +endif() diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browse_request.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browse_request.h new file mode 100644 index 0000000..e3f3ca7 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browse_request.h @@ -0,0 +1,36 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +struct BrowseRequest : public OpcUaObject +{ + using OpcUaObject::OpcUaObject; + +public: + + explicit BrowseRequest(size_t nodesToBrowseSize); + BrowseRequest(const OpcUaNodeId& nodeId, OpcUaNodeClass nodeClassMask = OpcUaNodeClass::All, const OpcUaNodeId& referenceTypeId = OpcUaNodeId(UA_NS0ID_REFERENCES), const OpcUaBrowseDirection browseDirection = OpcUaBrowseDirection::Forward); + + void resizeNodesToBrowse(size_t newNodesToBrowseSize); +}; + + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuabrowser.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuabrowser.h new file mode 100644 index 0000000..c326b6f --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuabrowser.h @@ -0,0 +1,84 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "opcuashared/opcua.h" +#include "opcuashared/opcuanodeid.h" +#include "opcuaclient/opcuaclient.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +struct OpcUaBrowseTransaction +{ + virtual UA_BrowseResult* getResults() = 0; + virtual size_t getResultsSize() const = 0; + virtual const UA_ResponseHeader& getResponseHeader() const = 0; +}; + +template +struct OpcUaBrowseTransactionT : public OpcUaBrowseTransaction +{ + OpcUaObject response; + + UA_BrowseResult* getResults() override + { + return response->results; + }; + + size_t getResultsSize() const override + { + return response->resultsSize; + }; + + const UA_ResponseHeader& getResponseHeader() const override + { + return response->responseHeader; + }; +}; + +using OpcUaBrowseTransactionPtr = std::shared_ptr; +using OpcUaBrowseTransaction_First = OpcUaBrowseTransactionT; +using OpcUaBrowseTransaction_FirstPtr = std::shared_ptr; +using OpcUaBrowseTransaction_Next = OpcUaBrowseTransactionT; +using OpcUaBrowseTransaction_NextPtr = std::shared_ptr; + +class OpcUaBrowser +{ +public: + OpcUaBrowser(const OpcUaNodeId& nodeId, const OpcUaClientPtr& client); + OpcUaBrowser(const OpcUaObject& request, const OpcUaClientPtr& client); + std::vector& browse(); + tsl::ordered_map> referencesByNodeId(); + tsl::ordered_map> referencesByBrowseName(); + +private: + OpcUaBrowseTransactionPtr browseTransaction(); + OpcUaBrowseTransactionPtr browseNextTransaction(UA_ByteString* contPoint); + OpcUaObject prepareNextRequest(UA_ByteString* contPoint); + void validateTransactionStatus(const OpcUaBrowseTransactionPtr& transaction); + + OpcUaObject request; + OpcUaClientPtr client; + std::vector transactions; + std::vector references; + +}; + + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodefactorybrowser.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodefactorybrowser.h new file mode 100644 index 0000000..42d5b41 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodefactorybrowser.h @@ -0,0 +1,79 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include "opcuashared/node/opcuanodemethod.h" +#include "opcuashared/opcuanodecollection.h" +#include "opcuaclient/browser/opcuanodevisitor.h" +#include "opcuaclient/opcuanodefactory.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +struct OpcUaBrowserResults +{ + OpcUaNodeCollection nodes; + void clear() + { + nodes.clear(); + } +}; + +class OpcUaNodeFactoryBrowser; +using OpcUaNodeFactoryBrowserPtr = std::shared_ptr; + +class OpcUaNodeFactoryBrowser : public OpcUaNodeVisitor +{ +public: + OpcUaNodeFactoryBrowser(const IOpcUaNodeFactoryPtr& nodeFactory, const OpcUaClientPtr& client); + ~OpcUaNodeFactoryBrowser(); + + void browseTree(); + + void browseTree(const OpcUaNodePtr& startNodeFolder); + + void browseTree(const OpcUaNodeId& startNodeId); + + void browse(const OpcUaNodePtr& startNodeFolder); + + void browse(const OpcUaNodeId& startNodeId); + + void browse(const OpcUaNodePtr& startNodeFolder, bool recursive, OpcUaNodeClass nodeClassMask); + + void browse(const OpcUaNodeId& startNodeId, bool recursive, OpcUaNodeClass nodeClassMask); + + void addToList(const OpcUaNodePtr& node); + + const OpcUaNodeCollection& getNodes() const; + size_t getNodesSize(); + + const IOpcUaNodeFactoryPtr& getNodeFactory(); + +protected: + void traverse(const UA_ReferenceDescription& reference) override; + void applyNode(const UA_ReferenceDescription& referenceDescription) override; + + OpcUaBrowserResults results; + IOpcUaNodeFactoryPtr nodeFactory; + + OpcUaNodeId currentParent; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodevisitor.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodevisitor.h new file mode 100644 index 0000000..736d13d --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodevisitor.h @@ -0,0 +1,67 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +/* + Builds tree of nodes of given server by using browse service +*/ +#include + +#include +#include "opcuaclient/browser/opcuabrowser.h" +#include "opcuaclient/opcuaclient.h" +#include "opcuashared/node/opcuanodemethod.h" +#include "opcuashared/opcua.h" +#include "opcuashared/opcuanodeid.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaNodeVisitor +{ +public: + explicit OpcUaNodeVisitor(const OpcUaClientPtr& client, OpcUaNodeClass nodeClassMask = OpcUaNodeClass::All, bool recursive = true); + virtual ~OpcUaNodeVisitor(); + + OpcUaNodeClass getBrowseMask(); + void setBrowseMask(OpcUaNodeClass nodeClassMask); + + bool getRecursive(); + void setRecursive(bool recursive); + void setRequestedMaxReferencesPerNode(uint32_t requestedMaxReferencesPerNode); + + const OpcUaClientPtr& getClient(); + virtual void traverse(const OpcUaNodeId& nodeId); + +protected: + virtual void traverse(const UA_ReferenceDescription& reference); + void browseAndApplyNodes(const OpcUaNodeId& startNodeId, OpcUaBrowser& browser); + virtual void applyNode(const UA_ReferenceDescription& referenceDescription); + virtual void applyVariable(const UA_ReferenceDescription& referenceDescription); + virtual void applyObject(const UA_ReferenceDescription& referenceDescription); + virtual void applyMethod(const UA_ReferenceDescription& referenceDescription); + + OpcUaNodeId getOpcUaNodeId(const UA_ReferenceDescription& referenceDescription); + + OpcUaClientPtr client; + uint32_t requestedMaxReferencesPerNode{0}; + +private: + OpcUaNodeClass browseMask; + bool recursive; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuatransactionbrowser.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuatransactionbrowser.h new file mode 100644 index 0000000..063e096 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuatransactionbrowser.h @@ -0,0 +1,83 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "opcuashared/opcua.h" +#include "opcuashared/node/opcuanodeid.h" +#include "opcuaclient/opcuaconnectionbroker.h" +#include + +BEGIN_NAMESPACE_OPCUA + +struct OpcUaBrowseTransaction +{ + virtual UA_BrowseResult* getResults() = 0; + virtual size_t getResultsSize() = 0; + virtual const UA_ResponseHeader& getResponseHeader() = 0; +}; + +template +struct OpcUaBrowseTransactionT : public OpcUaBrowseTransaction +{ + OpcUaObject response; + + UA_BrowseResult* getResults() override + { + return response->results; + }; + + size_t getResultsSize() override + { + return response->resultsSize; + }; + + const UA_ResponseHeader& getResponseHeader() override + { + return response->responseHeader; + }; +}; + +using OpcUaBrowseTransactionPtr = std::shared_ptr; +using OpcUaBrowseTransaction_First = OpcUaBrowseTransactionT; +using OpcUaBrowseTransaction_FirstPtr = std::shared_ptr; +using OpcUaBrowseTransaction_Next = OpcUaBrowseTransactionT; +using OpcUaBrowseTransaction_NextPtr = std::shared_ptr; + +class OpcUaBrowser +{ +public: + OpcUaBrowser(OpcUaObject& request, const OpcUaConnectionBrokerPtr& connection); + std::vector browse(); + +private: + OpcUaBrowseTransactionPtr browseTransaction(); + void dummy(); + void browseNextTransaction2(); + //OpcUaBrowseTransactionPtr browseNextTransaction1(); + //OpcUaBrowseTransactionPtr browseNextTransaction(UA_ByteString* contPoint); + //std::unique_ptr> prepareNextRequest(UA_ByteString* contPoint); + void validateTransactionStatus(const OpcUaBrowseTransactionPtr& transaction); + void validateTransactionStatus(UA_StatusCode status); + + OpcUaObject& request; + const OpcUaConnectionBrokerPtr& connection; + std::vector transactions; +}; + +END_NAMESPACE_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_alignsyncchdatagather.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_alignsyncchdatagather.h new file mode 100644 index 0000000..f64e3a8 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_alignsyncchdatagather.h @@ -0,0 +1,44 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include "chdatagather.h" +#include "opcuaclient/node/opcuanodevalueclient.h" + +BEGIN_NAMESPACE_OPCUA + +class AlignSyncChannelDataGather : public ChDataGather +{ +public: + AlignSyncChannelDataGather(OpcUaClient* client); + + virtual int64_t getSamplesAcquired(); + + void start() override; + + void getData(RelativeTimeInSeconds seconds) override; + +protected: + void fillSyncChannelList(); + std::unordered_set syncChannelList; + int64_t srLCMDiv; + OpcUaRatio maxSyncSampleRate; + int64_t previousSamplesAcquired; +}; + +END_NAMESPACE_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_chdatagather.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_chdatagather.h new file mode 100644 index 0000000..35a95df --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_chdatagather.h @@ -0,0 +1,44 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "opcuashared/opcua.h" + +BEGIN_NAMESPACE_OPCUA + +class OpcUaClient; + +class ChDataGather; +using ChDataGatherPtr = std::shared_ptr; + +class ChDataGather +{ +public: + ChDataGather(OpcUaClient* client); + + OpcUaClient* getClient(); + + virtual void start(); + + virtual void getData(RelativeTimeInSeconds seconds); + + virtual void stop(); +protected: + OpcUaClient* client; +}; + +END_NAMESPACE_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/event_filter.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/event_filter.h new file mode 100644 index 0000000..9ffa7cc --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/event_filter.h @@ -0,0 +1,83 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class EventFilter : public OpcUaObject +{ +public: + using OpcUaObject::OpcUaObject; + + EventFilter(size_t selectClausesSize); + + void resizeSelectClauses(size_t selectClausesSize); + + void setSelectClause(size_t index, const OpcUaObject& simpleAttributeOperand); + void setSelectClause(size_t index, OpcUaObject&& simpleAttributeOperand); +}; + +class SimpleAttributeOperand +{ +public: + static OpcUaObject CreateEventIdValue() + { + return CreateStandardEventValue("EventId"); + } + + static OpcUaObject CreateEventTypeValue() + + { + return CreateStandardEventValue("EventType"); + } + + static OpcUaObject CreateSourceNodeValue() + { + return CreateStandardEventValue("SourceNode"); + } + + static OpcUaObject CreateSourceNameValue() + { + return CreateStandardEventValue("SourceName"); + } + + static OpcUaObject CreateTimeValue() + { + return CreateStandardEventValue("Time"); + } + + static OpcUaObject CreateReceiveTimeValue() + { + return CreateStandardEventValue("ReceiveTime"); + } + + static OpcUaObject CreateMessageValue() + { + return CreateStandardEventValue("Message"); + } + + static OpcUaObject CreateSeverityValue() + { + return CreateStandardEventValue("Severity"); + } + + static OpcUaObject CreateStandardEventValue(const char* attributeName); +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/monitored_item_create_request.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/monitored_item_create_request.h new file mode 100644 index 0000000..0b0a9e0 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/monitored_item_create_request.h @@ -0,0 +1,44 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class MonitoredItemCreateRequest : public OpcUaObject +{ +public: + using OpcUaObject::OpcUaObject; + MonitoredItemCreateRequest(); +}; + +class EventMonitoredItemCreateRequest : public MonitoredItemCreateRequest +{ +public: + using MonitoredItemCreateRequest::MonitoredItemCreateRequest; + EventMonitoredItemCreateRequest(); + EventMonitoredItemCreateRequest(const OpcUaNodeId& nodeId); + + void setItemToMonitor(const OpcUaNodeId& nodeId); + + void setEventFilter(const OpcUaObject& eventFilter); + void setEventFilter(OpcUaObject&& eventFilter); + void setEventFilter(UA_EventFilter* eventFilter); +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaasyncexecthread.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaasyncexecthread.h new file mode 100644 index 0000000..816903a --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaasyncexecthread.h @@ -0,0 +1,41 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaAsyncExecThread +{ +public: + OpcUaAsyncExecThread(); + OpcUaAsyncExecThread(std::thread&& thread); + ~OpcUaAsyncExecThread(); + + void reset(); + + OpcUaAsyncExecThread& operator=(std::thread&& thread); + +protected: + void joinThread(); + + std::thread thread; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuacallmethodrequest.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuacallmethodrequest.h new file mode 100644 index 0000000..f982fe9 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuacallmethodrequest.h @@ -0,0 +1,46 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +struct OpcUaCallMethodRequest : public OpcUaObject +{ + using OpcUaObject::OpcUaObject; + +public: + OpcUaCallMethodRequest(const OpcUaNodeId& methodId, + const OpcUaNodeId& objectId, + size_t inputArgumentsSize = 0, + UA_Variant* inputArguments = nullptr); +}; + +struct OpcUaCallMethodRequestWithCallback : public OpcUaCallMethodRequest +{ +public: + using ProcessFunctionType = std::function; + OpcUaCallMethodRequestWithCallback(const OpcUaNodeId& methodId, + const OpcUaNodeId& objectId, + const ProcessFunctionType& processFunction, + size_t inputArgumentsSize = 0, + UA_Variant* inputArguments = nullptr); + ProcessFunctionType processFunction = nullptr; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h new file mode 100644 index 0000000..24acc1c --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h @@ -0,0 +1,174 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * + * Handles client / server communication. Separated implementation for two reasons: 1) it can be instantiated by client or browser and + * shared 2) connection issues are isolated from OPC UA services implementation. + */ + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "opcuashared/node/opcuanodemethod.h" + +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaClient; +using OpcUaClientPtr = std::shared_ptr; + +class ClientLockGuard +{ +public: + ClientLockGuard(OpcUaClient* client = nullptr) noexcept; + virtual ~ClientLockGuard() noexcept; + operator UA_Client*(); + + ClientLockGuard(ClientLockGuard&& other) noexcept; + ClientLockGuard& operator=(ClientLockGuard&& other) noexcept; + + ClientLockGuard(const ClientLockGuard&) = delete; + ClientLockGuard& operator=(const ClientLockGuard&) = delete; + +protected: + OpcUaClient* client; +}; + +class UaClientFactory +{ +public: + UaClientFactory(); + static UA_Client* Create(const OpcUaClientSecurityConfig* securityConfig = nullptr, + UA_LogLevel logLevel = UA_LOGLEVEL_WARNING, + const UA_DataTypeArray* customDataTypes = nullptr); + + void setSecurityConfig(const OpcUaClientSecurityConfig* securityConfig); + void setCustomDataTypes(const UA_DataTypeArray* customDataTypes); + void setLogLevel(const UA_LogLevel logLevel); + + UA_Client* build(); + +private: + void configureClient(); + void configureClientSecurity(); + void configureClientAppUri(); + void configureClientConfigDefaults(); + + UA_ClientConfig* config; + const OpcUaClientSecurityConfig* securityConfig = nullptr; + const UA_DataTypeArray* customDataTypes = nullptr; + UA_Client* client; + UA_LogLevel logLevel; +}; + +class OpcUaClient +{ +public: + explicit OpcUaClient(const std::string& url); + explicit OpcUaClient(const OpcUaEndpoint& endpoint); + ~OpcUaClient(); + + static constexpr size_t CONNECTION_TIMEOUT_SECONDS = 10; + + void initialize(); + bool connect(); + void disconnect(); + void clear(); + bool isConnected(); + UA_Client* getUaClient(); + ClientLockGuard getLockedUaClient(); + const OpcUaEndpoint& getEndpoint() const; + void setUrl(const std::string& url); + void setTimeout(uint32_t timoutMs); + uint32_t getTimeout() const; + void setConnectivityCheckInterval(uint32_t connectivityCheckInterval); + + std::recursive_mutex& getLock(); + + void runIterate(std::chrono::milliseconds period = std::chrono::milliseconds(20), std::chrono::milliseconds iterateTimeout = std::chrono::milliseconds(0)); + void stopIterate(); + + UA_StatusCode iterate(std::chrono::milliseconds timeout = std::chrono::milliseconds(0)); + + OpcUaCallbackIdent scheduleTimerTask(double intervalMs, const OpcUaTimerTaskType& task); + void removeTimerTask(OpcUaCallbackIdent ident); + bool timerTaskExists(OpcUaCallbackIdent ident); + + bool nodeExists(const OpcUaNodeId& nodeId); + OpcUaVariant readValue(const OpcUaNodeId& node); + UA_NodeClass readNodeClass(const OpcUaNodeId& nodeId); + std::string readBrowseName(const OpcUaNodeId& nodeId); + std::string readDisplayName(const OpcUaNodeId& nodeId); + size_t readDimension(const OpcUaNodeId& nodeId); + void writeDisplayName(const OpcUaNodeId& nodeId, const std::string& displayName); + void writeDisplayName(const OpcUaNodeId& nodeId, const OpcUaObject& displayName); + std::string readDescription(const OpcUaNodeId& nodeId); + void writeDescription(const OpcUaNodeId& nodeId, const std::string& description); + void writeDescription(const OpcUaNodeId& nodeId, const OpcUaObject& description); + OpcUaNodeId readDataType(const OpcUaNodeId& nodeId); + + OpcUaObject callMethods(const OpcUaObject& request); + + OpcUaObject callMethod(const OpcUaCallMethodRequest& callRequest); + + void callMethods(const std::vector& container); + + void writeValue(const OpcUaNodeId& nodeId, const OpcUaVariant& value); + + OpcUaObject readNodeAttributes(const OpcUaObject& request); + + void readNodeAttributes(const std::vector& request); + + Subscription* createSubscription(const OpcUaObject& request, + const StatusChangeNotificationCallbackType& statusChangeCallback = nullptr); + +protected: + static void timerTaskCallback(UA_Client* client, void* data); + + void executeIterateCallback(); + + UA_Client* uaclient{}; + OpcUaEndpoint endpoint; + uint32_t timeoutMs{CONNECTION_TIMEOUT_SECONDS * 1000}; + uint32_t connectivityCheckInterval{CONNECTION_TIMEOUT_SECONDS * 1000}; + + std::recursive_mutex lock; + + TimerTaskContextCollection timerTasks; + + std::chrono::milliseconds iterateTimeout; + + daq::utils::TimerThread iterateThread; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuanodefactory.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuanodefactory.h new file mode 100644 index 0000000..0114108 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuanodefactory.h @@ -0,0 +1,56 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class IOpcUaNodeFactory; +using IOpcUaNodeFactoryPtr = std::shared_ptr; + +class IOpcUaNodeFactory +{ +public: + virtual ~IOpcUaNodeFactory() = default; + virtual OpcUaNodePtr instantiateNode(const UA_ReferenceDescription& reference, const OpcUaNodeId& parentNodeId, bool& traverseChild) = 0; +protected: + static OpcUaNodeId GetOpcUaNodeId(const UA_ReferenceDescription& referenceDescription); +}; + +class OpcUaNodeFactory; +using OpcUaNodeFactoryPtr = std::shared_ptr; + +class OpcUaNodeFactory : public IOpcUaNodeFactory +{ +public: + explicit OpcUaNodeFactory(const OpcUaClientPtr& client); + + OpcUaNodePtr instantiateNode(const UA_ReferenceDescription& reference, const OpcUaNodeId& parentNodeId, bool& traverseChild) override; + +protected: + void prepareMethodParams(OpcUaNodeMethodPtr nodeMethod); + void browseAndApplyMethodParams(OpcUaBrowser& browser, const OpcUaNodeMethodPtr& nodeMethod); + void applyMethodParam(const UA_ReferenceDescription& reference, const OpcUaNodeMethodPtr& nodeMethod); + + OpcUaClientPtr client; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuareadvalueid.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuareadvalueid.h new file mode 100644 index 0000000..91664be --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuareadvalueid.h @@ -0,0 +1,41 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +struct OpcUaReadValueId : public OpcUaObject +{ +public: + using AttributeIdType = decltype(UA_ReadValueId::attributeId); +}; + +struct OpcUaReadValueIdWithCallback : public OpcUaReadValueId +{ + using ProcessFunctionType = std::function; + OpcUaReadValueIdWithCallback(const OpcUaNodeId& nodeId, + const ProcessFunctionType& processFunction, + AttributeIdType attributeId = UA_ATTRIBUTEID_VALUE); + + ProcessFunctionType processFunction; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskcontextcollection.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskcontextcollection.h new file mode 100644 index 0000000..b053d6f --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskcontextcollection.h @@ -0,0 +1,97 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* +Helper class for OpcUaTaskProcessor +*/ + +#pragma once + +#include + +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaClient; + +struct TimerTaskControl +{ + bool terminate{false}; + void terminateTimerTask() + { + terminate = true; + } +}; + +using OpcUaTaskType = std::function; +using OpcUaTimerTaskType = std::function; +using OpcUaCallbackIdent = UA_UInt64; + +class TimerTaskContextCollection +{ +public: + explicit TimerTaskContextCollection(); + + void* createContext(); + void deleteContext(void* context); + + void insertTimerTask(void* context, OpcUaCallbackIdent ident, const OpcUaTimerTaskType& task); + void removeTimerTask(OpcUaCallbackIdent ident); + + bool timerTaskExists(OpcUaCallbackIdent ident) const; + + static void getTaskExecData(void* context, OpcUaCallbackIdent* callbackIdent, OpcUaTimerTaskType** task); + +protected: + struct KeyType + { + KeyType() + : owner(nullptr) + { + } + + explicit KeyType(TimerTaskContextCollection* owner) + : owner(owner) + { + } + OpcUaCallbackIdent ident{}; + TimerTaskContextCollection* owner; + }; + + struct KeyTypeHash + { + std::size_t operator()(const KeyType* k) const + { + return std::hash()(k->ident); + } + }; + + struct KeyTypeEqualTo + { + bool operator()(const KeyType* a, const KeyType* b) const + { + assert(a != nullptr && b != nullptr); + return a->ident == b->ident; + } + }; + + std::unordered_map taskCallbacks; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskhelper.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskhelper.h new file mode 100644 index 0000000..e483951 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskhelper.h @@ -0,0 +1,55 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaTimerTaskHelper; +using OpcUaTimerTaskHelperPtr = std::shared_ptr; + +class OpcUaTimerTaskHelper // Similar API as CommonLib::TimerThread +{ +public: + using CallbackFunction = std::function; + + explicit OpcUaTimerTaskHelper(OpcUaClient& client, int intervalMs, const CallbackFunction& callback); + virtual ~OpcUaTimerTaskHelper(); + + virtual void start(); + virtual void stop(); + + double getIntervalMs() const; + void setIntervalMs(const double value); + + void terminate(); + const std::atomic& getTerminated() const; + + bool getStarted() const; + +protected: + virtual void execute(OpcUaClient& client, TimerTaskControl& control); + + double intervalMs; + std::atomic terminated; + std::optional callbackIdent; + OpcUaClient& client; + CallbackFunction callback; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/reference_utils.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/reference_utils.h new file mode 100644 index 0000000..73a7c27 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/reference_utils.h @@ -0,0 +1,60 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class ReferenceUtils; +using ReferenceUtilsPtr = std::shared_ptr; + +class ReferenceUtils +{ +public: + using ReferenceMap = tsl::ordered_map>; + + explicit ReferenceUtils(const OpcUaClientPtr& client); + + void updateReferences(const OpcUaNodeId& nodeId); + const ReferenceMap& getReferences(const OpcUaNodeId& nodeId); + tsl::ordered_set getReferencedNodes(const OpcUaNodeId& nodeId, + const OpcUaNodeId& referenceTypeId, + bool isForward, + const OpcUaNodeId& typeDefinition = OpcUaNodeId()); + bool hasReference(const OpcUaNodeId& nodeId, const std::string& browseName); + bool isInstanceOf(const OpcUaNodeId& typeInQuestion, const OpcUaNodeId& baseType); + tsl::ordered_set getVariableNodes(const OpcUaNodeId& nodeId); + OpcUaNodeId getChildNodeId(const OpcUaNodeId& nodeId, const std::string& browseName); + std::string getBrowseName(const OpcUaObject& reference); + void clearCache(); + +protected: + using BrowseNameMap = std::unordered_map; + + void browseNodeReferences(const OpcUaNodeId& nodeId); + void buildBrowseNameMap(const OpcUaNodeId& nodeId); + bool isHasSubType(const OpcUaObject& reference); + + OpcUaClientPtr client; + std::unordered_map referenceCache; + std::unordered_map browseNameCache; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/request_handler.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/request_handler.h new file mode 100644 index 0000000..4bad7ff --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/request_handler.h @@ -0,0 +1,31 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class RequestHandler +{ +public: + explicit RequestHandler(const OpcUaClientPtr& client); + + // to be implemented + // this class should handle methods connected to UA_ReadRequest UA_WriteRequest UA_CallRequest +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/subscriptions.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/subscriptions.h new file mode 100644 index 0000000..3cb5f5a --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/subscriptions.h @@ -0,0 +1,90 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaClient; +class Subscription; +class MonitoredItem; + +using StatusChangeNotificationCallbackType = + std::function; + +using EventNotificationCallbackType = std::function; + +using DataChangeNotificationCallbackType = + std::function; + +class Subscription +{ +protected: + Subscription(OpcUaClient* client, const StatusChangeNotificationCallbackType& statusChangeNotificationCallback = nullptr); + +public: + UA_UInt32 getSubscriptionId() const; + UA_Double getRevisedPublishingInterval() const; + UA_UInt32 getRevisedLifetimeCount() const; + UA_UInt32 getRevisedMaxKeepAliveCount() const; + + MonitoredItem* monitoredItemsCreateEvent(UA_TimestampsToReturn timestampsToReturn, + const UA_MonitoredItemCreateRequest& item, + const EventNotificationCallbackType& eventNotificationCallback); + + MonitoredItem* monitoredItemsCreateDataChange(UA_TimestampsToReturn timestampsToReturn, + const UA_MonitoredItemCreateRequest& item, + const DataChangeNotificationCallbackType& dataChangeNotificationCallback); + + const StatusChangeNotificationCallbackType& getStatusChangeNotificationCallback() const; + + static Subscription* CreateSubscription(OpcUaClient* client, + const OpcUaObject& request, + const StatusChangeNotificationCallbackType& statusChangeCallback); + +protected: + OpcUaClient* client; + OpcUaObject subscriptionResponse; + StatusChangeNotificationCallbackType statusChangeNotificationCallback; +}; + +class MonitoredItem +{ +public: + MonitoredItem(OpcUaClient* client, const EventNotificationCallbackType& eventNotificationCallback = nullptr); + MonitoredItem(OpcUaClient* client, const DataChangeNotificationCallbackType& dataChangeNotificationCallback = nullptr); + + UA_UInt32 getMonitoredItemId() const; + + const EventNotificationCallbackType& getEventNotificationCallback() const; + const DataChangeNotificationCallbackType& getDataChangeNotificationCallback() const; + +protected: + OpcUaClient* client; + OpcUaObject response; + EventNotificationCallbackType eventNotificationCallback; + DataChangeNotificationCallbackType dataChangeNotificationCallback; + + friend class Subscription; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/taskprocessor/opcuataskprocessor.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/taskprocessor/opcuataskprocessor.h new file mode 100644 index 0000000..622188a --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/taskprocessor/opcuataskprocessor.h @@ -0,0 +1,74 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include + +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + + +class OpcUaTaskProcessor; +using OpcUaTaskProcessorPtr = std::shared_ptr; + +class OpcUaTaskProcessor : protected daq::utils::ThreadEx +{ +public: + explicit OpcUaTaskProcessor(const OpcUaClientPtr& client); + virtual ~OpcUaTaskProcessor(); + + void start() override; + void stop() override; + + bool connect(); + bool isConnected(); + void setConnectionTimeout(uint32_t timeoutMs); + const OpcUaClientPtr& getClient() const noexcept; + + void executeTask(const OpcUaTaskType& task); + + std::future executeTaskAwait(const OpcUaTaskType& task); + +protected: + using QueueItemType = std::pair, OpcUaTaskType>; + + void executeTask(std::promise& promise, const OpcUaTaskType& task) const; + + void execute() override; + + QueueItemType getNextTask(); + + OpcUaClientPtr client; + + std::atomic executingThreadId; + + std::queue queue; + std::mutex mutex; + + std::atomic connected; + UA_StatusCode prevStatus; + + std::condition_variable cvWait; + std::mutex waitMutex; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/src/CMakeLists.txt b/shared/libraries/opcua/opcuaclient/src/CMakeLists.txt new file mode 100644 index 0000000..39ef487 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/src/CMakeLists.txt @@ -0,0 +1,89 @@ +SET(MODULE_NAME opcuaclient) + +set(SOURCE_CPPS opcuaclient.cpp + opcuatimertaskcontextcollection.cpp + opcuatimertaskhelper.cpp + opcuanodefactory.cpp + opcuaasyncexecthread.cpp + opcuareadvalueid.cpp + opcuacallmethodrequest.cpp + subscriptions.cpp + monitored_item_create_request.cpp + event_filter.cpp + browse_request.cpp + reference_utils.cpp + request_handler.cpp +) + +set(SOURCE_BROWSER_CPPS browser/opcuanodevisitor.cpp + browser/opcuanodefactorybrowser.cpp + browser/opcuabrowser.cpp) + +set(SOURCE_TASKPROCESSOR_CPPS taskprocessor/opcuataskprocessor.cpp) + +set(SOURCE_HEADERS opcuaclient.h + opcuatimertaskcontextcollection.h + opcuatimertaskhelper.h + opcuanodefactory.h + opcuaasyncexecthread.h + opcuareadvalueid.h + opcuacallmethodrequest.h + subscriptions.h + monitored_item_create_request.h + event_filter.h + browse_request.h + reference_utils.h + request_handler.h +) + +set(SOURCE_BROWSER_HEADERS + browser/opcuanodevisitor.h + browser/opcuanodefactorybrowser.h + browser/opcuabrowser.h) + +set(SOURCE_TASKPROCESSOR_HEADERS taskprocessor/opcuataskprocessor.h) + +set(INCLUDE_DIR ../include/${MODULE_NAME}) + +prepend_include(${INCLUDE_DIR} SOURCE_HEADERS) +prepend_include(${INCLUDE_DIR} SOURCE_BROWSER_HEADERS) +prepend_include(${INCLUDE_DIR} SOURCE_TASKPROCESSOR_HEADERS) + +set(ALL_SOURCES ${SOURCE_CPPS} + ${SOURCE_BROWSER_CPPS} + ${SOURCE_TASKPROCESSOR_CPPS} + ${SOURCE_HEADERS} + ${SOURCE_BROWSER_HEADERS} + ${SOURCE_TASKPROCESSOR_HEADERS} +) + +set(SOURCE_FILES ${ALL_SOURCES}) +add_library(${MODULE_NAME} STATIC ${ALL_SOURCES}) +add_library(${SDK_TARGET_NAMESPACE}::${MODULE_NAME} ALIAS ${MODULE_NAME}) + +target_include_directories(${MODULE_NAME} PUBLIC $ + $ +) + +target_link_libraries(${MODULE_NAME} PUBLIC daq::opcuashared + daq::opendaq_utils + tsl::ordered_map +) + +if(BUILD_64Bit) + set_target_properties(${MODULE_NAME} PROPERTIES OUTPUT_NAME "${MODULE_NAME}64") +endif() + +if(BUILD_64Bit OR BUILD_ARM) + set_target_properties(${MODULE_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON) +else() + set_target_properties(${MODULE_NAME} PROPERTIES POSITION_INDEPENDENT_CODE OFF) +endif() + +if (MSVC) + source_group("Header Files\\Browser" "browser/.+[.]h") + source_group("Source Files\\Browser" "browser/.+[.]cpp") + + source_group("Header Files\\Taskprocessor" "taskprocessor/.+[.]h") + source_group("Source Files\\Taskprocessor" "taskprocessor/.+[.]cpp") +endif() diff --git a/shared/libraries/opcua/opcuaclient/src/browse_request.cpp b/shared/libraries/opcua/opcuaclient/src/browse_request.cpp new file mode 100644 index 0000000..b730db9 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/src/browse_request.cpp @@ -0,0 +1,29 @@ +#include "opcuaclient/browse_request.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +BrowseRequest::BrowseRequest(size_t nodesToBrowseSize) + : OpcUaObject() +{ + resizeNodesToBrowse(nodesToBrowseSize); +} + +BrowseRequest::BrowseRequest(const OpcUaNodeId& nodeId, OpcUaNodeClass nodeClassMask, const OpcUaNodeId& referenceTypeId, const OpcUaBrowseDirection browseDirection) + : BrowseRequest(1u) +{ + value.nodesToBrowse[0].nodeId = nodeId.copyAndGetDetachedValue(); + value.nodesToBrowse[0].browseDirection = (UA_BrowseDirection) browseDirection; + value.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL; + value.nodesToBrowse[0].referenceTypeId = referenceTypeId.copyAndGetDetachedValue(); + + value.nodesToBrowse[0].nodeClassMask = (UA_UInt32) nodeClassMask; + value.nodesToBrowse[0].includeSubtypes = UA_TRUE; +} + +void BrowseRequest::resizeNodesToBrowse(size_t newNodesToBrowseSize) +{ + CheckStatusCodeException(UA_Array_resize( + (void**) &value.nodesToBrowse, &value.nodesToBrowseSize, newNodesToBrowseSize, &UA_TYPES[UA_TYPES_BROWSEDESCRIPTION])); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/src/browser/opcuabrowser.cpp b/shared/libraries/opcua/opcuaclient/src/browser/opcuabrowser.cpp new file mode 100644 index 0000000..b2699a4 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/src/browser/opcuabrowser.cpp @@ -0,0 +1,118 @@ +#include "opcuaclient/browser/opcuabrowser.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaBrowser::OpcUaBrowser(const OpcUaNodeId& nodeId, const OpcUaClientPtr& client) + : request(OpcUaObject()) + , client(client) +{ + request->requestedMaxReferencesPerNode = 0; + request->nodesToBrowse = UA_BrowseDescription_new(); + request->nodesToBrowseSize = 1; + request->nodesToBrowse[0].nodeId = nodeId.copyAndGetDetachedValue(); + request->nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL; +} + +OpcUaBrowser::OpcUaBrowser(const OpcUaObject& request, const OpcUaClientPtr& client) + : request(request) + , client(client) +{ +} + +std::vector& OpcUaBrowser::browse() +{ + transactions.clear(); + references.clear(); + + OpcUaBrowseTransactionPtr tr = browseTransaction(); + + while (tr->getResultsSize() > 0) + { + validateTransactionStatus(tr); + transactions.push_back(tr); + + for (size_t i = 0; i < tr->getResultsSize(); i++) + { + UA_BrowseResult& result = tr->getResults()[i]; + + if (result.statusCode == UA_STATUSCODE_BADUSERACCESSDENIED) + continue; + if (result.statusCode == UA_STATUSCODE_BADNODEIDUNKNOWN) + continue; + + CheckStatusCodeException(result.statusCode, "Browse result error"); + references.insert(references.end(), &result.references[0], &result.references[result.referencesSize]); + } + + UA_ByteString* contPoint = &tr->getResults()[0].continuationPoint; + if (contPoint->length == 0) + break; + + tr = this->browseNextTransaction(contPoint); + } + + return references; +} + +tsl::ordered_map> OpcUaBrowser::referencesByNodeId() +{ + auto refMap = tsl::ordered_map>(); + + for (const auto& ref : references) + { + OpcUaNodeId nodeId = ref.nodeId.nodeId; + refMap.insert({nodeId, OpcUaObject(ref)}); + } + + return refMap; +} + +tsl::ordered_map> OpcUaBrowser::referencesByBrowseName() +{ + auto refMap = tsl::ordered_map>(); + + for (const auto& ref : references) + { + std::string name = utils::ToStdString(ref.displayName.text); + refMap.insert({name, OpcUaObject(ref)}); + } + + return refMap; +} + +OpcUaBrowseTransactionPtr OpcUaBrowser::browseTransaction() +{ + auto transaction = std::make_shared(); + transaction->response = UA_Client_Service_browse(client->getLockedUaClient(), *request); + + return transaction; +} + +OpcUaBrowseTransactionPtr OpcUaBrowser::browseNextTransaction(UA_ByteString* contPoint) +{ + auto nextRequest = prepareNextRequest(contPoint); + + auto transaction = std::make_shared(); + transaction->response = UA_Client_Service_browseNext(client->getLockedUaClient(), *nextRequest); + + return transaction; +} + +OpcUaObject OpcUaBrowser::prepareNextRequest(UA_ByteString* contPoint) +{ + OpcUaObject nextRequest; + + nextRequest->releaseContinuationPoints = UA_FALSE; + nextRequest->continuationPointsSize = 1u; + nextRequest->continuationPoints = contPoint; + + return nextRequest; +} + +void OpcUaBrowser::validateTransactionStatus(const OpcUaBrowseTransactionPtr& transaction) +{ + CheckStatusCodeException(transaction->getResponseHeader().serviceResult, + "Browse transaction error, transaction:" + std::to_string(transactions.size() + 1)); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/src/browser/opcuanodefactorybrowser.cpp b/shared/libraries/opcua/opcuaclient/src/browser/opcuanodefactorybrowser.cpp new file mode 100644 index 0000000..85a7048 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/src/browser/opcuanodefactorybrowser.cpp @@ -0,0 +1,98 @@ +#include "opcuaclient/browser/opcuanodefactorybrowser.h" +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaNodeFactoryBrowser::OpcUaNodeFactoryBrowser(const IOpcUaNodeFactoryPtr& nodeFactory, const OpcUaClientPtr& client) + : OpcUaNodeVisitor(client) + , nodeFactory(nodeFactory) +{ +} + +OpcUaNodeFactoryBrowser::~OpcUaNodeFactoryBrowser() +{ +} + +void OpcUaNodeFactoryBrowser::browseTree() +{ + auto startNode = OpcUaNodeObject::instantiateRoot(); + browseTree(startNode->getNodeId()); +} + +void OpcUaNodeFactoryBrowser::browseTree(const OpcUaNodePtr& startNodeFolder) +{ + browseTree(startNodeFolder->getNodeId()); +} + +void OpcUaNodeFactoryBrowser::browseTree(const OpcUaNodeId& startNodeId) +{ + browse(startNodeId, true, OpcUaNodeClass::All); +} + +void OpcUaNodeFactoryBrowser::browse(const OpcUaNodePtr& startNodeFolder) +{ + browse(startNodeFolder->getNodeId()); +} + +void OpcUaNodeFactoryBrowser::browse(const OpcUaNodeId& startNodeId) +{ + browse(startNodeId, false, OpcUaNodeClass::All); +} + +void OpcUaNodeFactoryBrowser::browse(const OpcUaNodePtr& startNodeFolder, bool recursive, OpcUaNodeClass nodeClassMask) +{ + browse(startNodeFolder->getNodeId(), recursive, nodeClassMask); +} + +void OpcUaNodeFactoryBrowser::browse(const OpcUaNodeId& startNodeId, bool recursive, OpcUaNodeClass nodeClassMask) +{ + results.clear(); + setBrowseMask(nodeClassMask); + setRecursive(recursive); + currentParent = startNodeId; + OpcUaNodeVisitor::traverse(startNodeId); +} + +void OpcUaNodeFactoryBrowser::addToList(const OpcUaNodePtr& node) +{ + if (node) + results.nodes.push_back(node); +} + +void OpcUaNodeFactoryBrowser::traverse(const UA_ReferenceDescription& reference) +{ + auto parent = currentParent; + currentParent = getOpcUaNodeId(reference); + OpcUaNodeVisitor::traverse(reference); + + currentParent = parent; +} + +void OpcUaNodeFactoryBrowser::applyNode(const UA_ReferenceDescription& reference) +{ + bool traverseChild; + auto node = nodeFactory->instantiateNode(reference, currentParent, traverseChild); + + if (traverseChild) + OpcUaNodeVisitor::applyNode(reference); + + addToList(node); +} + +const OpcUaNodeCollection& OpcUaNodeFactoryBrowser::getNodes() const +{ + return results.nodes; +} + +size_t OpcUaNodeFactoryBrowser::getNodesSize() +{ + return results.nodes.size(); +} + +const IOpcUaNodeFactoryPtr& OpcUaNodeFactoryBrowser::getNodeFactory() +{ + return nodeFactory; +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/src/browser/opcuanodevisitor.cpp b/shared/libraries/opcua/opcuaclient/src/browser/opcuanodevisitor.cpp new file mode 100644 index 0000000..3f24911 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/src/browser/opcuanodevisitor.cpp @@ -0,0 +1,121 @@ +#include "opcuaclient/browser/opcuanodevisitor.h" +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaNodeVisitor::OpcUaNodeVisitor(const OpcUaClientPtr& client, OpcUaNodeClass nodeClassMask, bool recursive) + : client(client) + , browseMask(nodeClassMask) + , recursive(recursive) +{ +} + +OpcUaNodeVisitor::~OpcUaNodeVisitor() +{ +} + +OpcUaNodeId OpcUaNodeVisitor::getOpcUaNodeId(const UA_ReferenceDescription& referenceDescription) +{ + return OpcUaNodeId(referenceDescription.nodeId.nodeId); +} + +const OpcUaClientPtr& OpcUaNodeVisitor::getClient() +{ + return client; +} + +void OpcUaNodeVisitor::setRequestedMaxReferencesPerNode(uint32_t requestedMaxReferencesPerNode) +{ + this->requestedMaxReferencesPerNode = requestedMaxReferencesPerNode; +} + +void OpcUaNodeVisitor::traverse(const UA_ReferenceDescription& reference) +{ + if (recursive) + traverse(getOpcUaNodeId(reference)); +} + +void OpcUaNodeVisitor::traverse(const OpcUaNodeId& startNodeId) +{ + BrowseRequest request(startNodeId, browseMask); + OpcUaBrowser browser(request, client); + + browseAndApplyNodes(startNodeId, browser); +} + +void OpcUaNodeVisitor::browseAndApplyNodes(const OpcUaNodeId& startNodeId, OpcUaBrowser& browser) +{ + try + { + auto& references = browser.browse(); + + for (auto& ref : references) + applyNode(ref); + } + catch (const OpcUaException& ex) + { + throw OpcUaException(ex.getStatusCode(), std::string(ex.what()) + ". Node: " + startNodeId.toString()); + } +} + +void OpcUaNodeVisitor::applyNode(const UA_ReferenceDescription& referenceDescription) +{ + switch (referenceDescription.nodeClass) + { + case UA_NODECLASS_VARIABLE: + applyVariable(referenceDescription); + break; + case UA_NODECLASS_OBJECT: + applyObject(referenceDescription); + break; + case UA_NODECLASS_METHOD: + applyMethod(referenceDescription); + break; + case UA_NODECLASS_UNSPECIFIED: + case UA_NODECLASS_OBJECTTYPE: + case UA_NODECLASS_VARIABLETYPE: + case UA_NODECLASS_REFERENCETYPE: + case UA_NODECLASS_DATATYPE: + case UA_NODECLASS_VIEW: + default: + break; + } +} + +void OpcUaNodeVisitor::applyVariable(const UA_ReferenceDescription& referenceDescription) +{ + traverse(referenceDescription); +} + +void OpcUaNodeVisitor::applyObject(const UA_ReferenceDescription& referenceDescription) +{ + traverse(referenceDescription); +} + +void OpcUaNodeVisitor::applyMethod(const UA_ReferenceDescription& referenceDescription) +{ + traverse(referenceDescription); +} + +OpcUaNodeClass OpcUaNodeVisitor::getBrowseMask() +{ + return browseMask; +} + +void OpcUaNodeVisitor::setBrowseMask(OpcUaNodeClass nodeClassMask) +{ + this->browseMask = nodeClassMask; +} + +bool OpcUaNodeVisitor::getRecursive() +{ + return recursive; +} + +void OpcUaNodeVisitor::setRecursive(bool recursive) +{ + this->recursive = recursive; +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/src/chdatagather/_alignsyncchdatagather.cpp b/shared/libraries/opcua/opcuaclient/src/chdatagather/_alignsyncchdatagather.cpp new file mode 100644 index 0000000..d4f26f6 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/src/chdatagather/_alignsyncchdatagather.cpp @@ -0,0 +1,117 @@ +#include +#include "opcuaclient/chdatagather/alignsyncchdatagather.h" +#include "opcuaclient/opcuaclient.h" + +BEGIN_NAMESPACE_OPCUA + +AlignSyncChannelDataGather::AlignSyncChannelDataGather(OpcUaClient* client) + : ChDataGather(client) + , previousSamplesAcquired(0) +{ +} + +void AlignSyncChannelDataGather::fillSyncChannelList() +{ + syncChannelList.clear(); + + for (const auto& clientBase : *getClient()) + { + if (clientBase->getClockMode() == ClockMode::MasterClock && + clientBase->getConnection()->getEndpoint().getServerType() == OpcUaServerType::Dewesoft) + { + for (const auto& node : clientBase->getAcqNodes()) + { + if (node->getChannelType() == ChannelType::Sync) + syncChannelList.insert(node); + } + } + } +} + +void AlignSyncChannelDataGather::start() +{ + fillSyncChannelList(); + + maxSyncSampleRate = OpcUaRatio(); + + for (const auto& node : syncChannelList) + { + OpcUaRatio rSR = node->getRemoteSampleRate(); + if (!maxSyncSampleRate.isValid() || maxSyncSampleRate < rSR) + maxSyncSampleRate = rSR; + } + + srLCMDiv = 1; + + for (const auto& node : syncChannelList) + { + OpcUaRatio rSR = node->getRemoteSampleRate(); + OpcUaRatio div = maxSyncSampleRate / rSR; + + if ((div.numerator % div.denominator) != 0) + { + throw std::runtime_error("Can't align channels with sample rate " + rSR.toString() + " and " + div.toString()); + } + + srLCMDiv = std::lcm(srLCMDiv, div.intVal()); + } +} + +void AlignSyncChannelDataGather::getData(RelativeTimeInSeconds seconds) +{ + auto samplesAcq = (getSamplesAcquired() / srLCMDiv) * srLCMDiv; + + for (const auto& c : *client) + { + for (const auto& node : c->getAcqNodes()) + { + if (syncChannelList.find(node) != syncChannelList.end()) + { + if (node->getTiming() && !node->getTiming()->masterClockDetails.isBufferOverrun()) // check if data are incomplete + { + OpcUaRatio rSR = node->getRemoteSampleRate(); + int64_t divider = (maxSyncSampleRate / rSR).intVal(); + int64_t totalSyncSamples = node->getChannel()->getBufferProxy()->getTotalSyncSamples(); + auto samplesAcqNode = samplesAcq / divider - totalSyncSamples; + node->getData(seconds, (size_t) samplesAcqNode); + + assert(totalSyncSamples + samplesAcqNode == node->getChannel()->getBufferProxy()->getTotalSyncSamples()); + } + } + else + node->getData(seconds); + } + } + previousSamplesAcquired = samplesAcq; +} + +int64_t AlignSyncChannelDataGather::getSamplesAcquired() +{ + int64_t samplesCountSync = INT64_MAX; + + for (const auto& node : syncChannelList) + { + if (node->getTiming()) + { + OpcUaRatio rSR = node->getRemoteSampleRate(); + int64_t divider = (maxSyncSampleRate / rSR).intVal(); + int64_t samplesCnt = node->getTiming()->masterClockDetails.getSamplesAcquired() * divider; + samplesCnt = + std::min(samplesCnt, + previousSamplesAcquired + + (node->getChannel()->getBufferProxy()->getDBBufSize() - 1) * + divider); // limit to channel buffer size, so you move datalost error handling only to daqthread + if (samplesCnt < samplesCountSync) + samplesCountSync = samplesCnt; + } + else + { + samplesCountSync = 0; + break; + } + } + + return (samplesCountSync < INT64_MAX) ? samplesCountSync : 0; +} + +END_NAMESPACE_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/src/chdatagather/_chdatagather.cpp b/shared/libraries/opcua/opcuaclient/src/chdatagather/_chdatagather.cpp new file mode 100644 index 0000000..25e2c7e --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/src/chdatagather/_chdatagather.cpp @@ -0,0 +1,35 @@ +#include "opcuaclient/chdatagather/chdatagather.h" +#include "opcuaclient/opcuaclient.h" + +BEGIN_NAMESPACE_OPCUA + +ChDataGather::ChDataGather(OpcUaClient* client) +{ + this->client = client; +} + +OpcUaClient* ChDataGather::getClient() +{ + return client; +} + +void ChDataGather::start() +{ +} + +void ChDataGather::getData(RelativeTimeInSeconds seconds) //TODO align start... yes/no +{ + for (const auto& c : *getClient()) + { + for (const auto& node : c->getAcqNodes()) + { + node->getData(seconds); + } + } +} + +void ChDataGather::stop() +{ +} + +END_NAMESPACE_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/src/event_filter.cpp b/shared/libraries/opcua/opcuaclient/src/event_filter.cpp new file mode 100644 index 0000000..849c0db --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/src/event_filter.cpp @@ -0,0 +1,44 @@ +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +EventFilter::EventFilter(size_t selectClausesSize) + : OpcUaObject() +{ + resizeSelectClauses(selectClausesSize); +} + +void EventFilter::resizeSelectClauses(size_t selectClausesSize) +{ + CheckStatusCodeException(UA_Array_resize((void**) &value.selectClauses, &value.selectClausesSize, selectClausesSize, &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND])); +} + +void EventFilter::setSelectClause(size_t index, const OpcUaObject& simpleAttributeOperand) +{ + value.selectClauses[index] = simpleAttributeOperand.copyAndGetDetachedValue(); +} +void EventFilter::setSelectClause(size_t index, OpcUaObject&& simpleAttributeOperand) +{ + value.selectClauses[index] = simpleAttributeOperand.getDetachedValue(); +} + +/*SimpleAttributeOperand*/ + +OpcUaObject SimpleAttributeOperand::CreateStandardEventValue(const char* attributeName) +{ + OpcUaObject simpleAttributeOperand; + + simpleAttributeOperand->typeDefinitionId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE); + simpleAttributeOperand->browsePathSize = 1; + simpleAttributeOperand->browsePath = + (UA_QualifiedName*)UA_Array_new(simpleAttributeOperand->browsePathSize, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]); + + simpleAttributeOperand->attributeId = UA_ATTRIBUTEID_VALUE; + simpleAttributeOperand->browsePath[0] = UA_QUALIFIEDNAME_ALLOC(0, attributeName); + + return simpleAttributeOperand; +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/src/monitored_item_create_request.cpp b/shared/libraries/opcua/opcuaclient/src/monitored_item_create_request.cpp new file mode 100644 index 0000000..d4018dc --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/src/monitored_item_create_request.cpp @@ -0,0 +1,59 @@ +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +/*MonitoredItemCreateRequest*/ + +MonitoredItemCreateRequest::MonitoredItemCreateRequest() + : OpcUaObject(UA_MonitoredItemCreateRequest_default(UA_NODEID_NULL)) +{ +} + +/*EventMonitoredItemCreateRequest*/ + +EventMonitoredItemCreateRequest::EventMonitoredItemCreateRequest() + : MonitoredItemCreateRequest() +{ + value.itemToMonitor.attributeId = UA_ATTRIBUTEID_EVENTNOTIFIER; + value.monitoringMode = UA_MONITORINGMODE_REPORTING; +} + +EventMonitoredItemCreateRequest::EventMonitoredItemCreateRequest(const OpcUaNodeId& nodeId) + : EventMonitoredItemCreateRequest() +{ + setItemToMonitor(nodeId); +} + +void EventMonitoredItemCreateRequest::setItemToMonitor(const OpcUaNodeId& nodeId) +{ + UA_NodeId_clear(&value.itemToMonitor.nodeId); + value.itemToMonitor.nodeId = nodeId.copyAndGetDetachedValue(); +} + +void EventMonitoredItemCreateRequest::setEventFilter(const OpcUaObject& eventFilter) +{ + UA_EventFilter* uaEventFilter = UA_EventFilter_new(); + *uaEventFilter = eventFilter.copyAndGetDetachedValue(); + + setEventFilter(uaEventFilter); +} + +void EventMonitoredItemCreateRequest::setEventFilter(OpcUaObject&& eventFilter) +{ + UA_EventFilter* uaEventFilter = UA_EventFilter_new(); + *uaEventFilter = eventFilter.getDetachedValue(); + + setEventFilter(uaEventFilter); +} + +void EventMonitoredItemCreateRequest::setEventFilter(UA_EventFilter* eventFilter) +{ + UA_ExtensionObject_clear(&value.requestedParameters.filter); + + value.requestedParameters.filter.encoding = UA_EXTENSIONOBJECT_DECODED; + value.requestedParameters.filter.content.decoded.data = eventFilter; + value.requestedParameters.filter.content.decoded.type = &UA_TYPES[UA_TYPES_EVENTFILTER]; +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/src/opcuaasyncexecthread.cpp b/shared/libraries/opcua/opcuaclient/src/opcuaasyncexecthread.cpp new file mode 100644 index 0000000..edda861 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/src/opcuaasyncexecthread.cpp @@ -0,0 +1,37 @@ +#include "opcuaclient/opcuaasyncexecthread.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaAsyncExecThread::OpcUaAsyncExecThread() +{ +} + +OpcUaAsyncExecThread::OpcUaAsyncExecThread(std::thread&& thread) + : thread(std::move(thread)) +{ +} + +OpcUaAsyncExecThread::~OpcUaAsyncExecThread() +{ + joinThread(); +} + +void OpcUaAsyncExecThread::reset() +{ + joinThread(); +} + +void OpcUaAsyncExecThread::joinThread() +{ + if (thread.joinable()) + thread.join(); +} + +OpcUaAsyncExecThread& OpcUaAsyncExecThread::operator=(std::thread&& thread) +{ + joinThread(); + this->thread = std::move(thread); + return *this; +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/src/opcuacallmethodrequest.cpp b/shared/libraries/opcua/opcuaclient/src/opcuacallmethodrequest.cpp new file mode 100644 index 0000000..4b9b560 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/src/opcuacallmethodrequest.cpp @@ -0,0 +1,28 @@ +#include "opcuaclient/opcuacallmethodrequest.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaCallMethodRequest::OpcUaCallMethodRequest(const OpcUaNodeId& methodId, + const OpcUaNodeId& objectId, + size_t inputArgumentsSize, + UA_Variant* inputArguments) + : OpcUaObject() +{ + value.methodId = methodId.copyAndGetDetachedValue(); + value.objectId = objectId.copyAndGetDetachedValue(); + value.inputArgumentsSize = inputArgumentsSize; + CheckStatusCodeException( + UA_Array_copy(inputArguments, inputArgumentsSize, (void**) &value.inputArguments, &UA_TYPES[UA_TYPES_VARIANT])); +} + +OpcUaCallMethodRequestWithCallback::OpcUaCallMethodRequestWithCallback(const OpcUaNodeId& methodId, + const OpcUaNodeId& objectId, + const ProcessFunctionType& processFunction, + size_t inputArgumentsSize, + UA_Variant* inputArguments) + : OpcUaCallMethodRequest(methodId, objectId, inputArgumentsSize, inputArguments) + , processFunction(processFunction) +{ +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp b/shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp new file mode 100644 index 0000000..f355b7c --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp @@ -0,0 +1,583 @@ +#include "opcuaclient/opcuaclient.h" +#include +#include + +#include +#include +#include +#include "opcuashared/opcuasecuritycommon.h" + +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using namespace daq::utils; + +// LockedClient +ClientLockGuard::ClientLockGuard(OpcUaClient* client) noexcept + : client(client) +{ + if (client != nullptr) + client->getLock().lock(); +} + +ClientLockGuard::ClientLockGuard(ClientLockGuard&& other) noexcept +{ + this->client = other.client; + other.client = nullptr; +} + +ClientLockGuard& ClientLockGuard::operator=(ClientLockGuard&& other) noexcept +{ + this->client = other.client; + other.client = nullptr; + return *this; +} + +ClientLockGuard::~ClientLockGuard() noexcept +{ + if (client != nullptr) + client->getLock().unlock(); +} + +ClientLockGuard::operator UA_Client*() +{ + return client != nullptr ? client->getUaClient() : nullptr; +} + +// OpcUaClient +OpcUaClient::OpcUaClient(const OpcUaEndpoint& endpoint) + : endpoint(endpoint) + , timerTasks() +{ + iterateThread.setCallback(std::bind(&OpcUaClient::executeIterateCallback, this)); + initialize(); +} + +OpcUaClient::OpcUaClient(const std::string& url) + : OpcUaClient(OpcUaEndpoint("", url)) +{ +} + +OpcUaClient::~OpcUaClient() +{ + stopIterate(); + disconnect(); + clear(); +} + +void OpcUaClient::initialize() +{ + std::lock_guard guard(getLock()); + + uaclient = UaClientFactory::Create(endpoint.getSecurityConfig(), endpoint.getLogLevel(), endpoint.getCustomDataTypes()); + + UA_Client_getConfig(uaclient)->clientContext = this; + + setTimeout(timeoutMs); + + setConnectivityCheckInterval(connectivityCheckInterval); +} + +UaClientFactory::UaClientFactory() +{ +} + +UA_Client* UaClientFactory::Create(const OpcUaClientSecurityConfig* securityConfig, + UA_LogLevel logLevel, + const UA_DataTypeArray* customDataTypes) +{ + UaClientFactory factory; + factory.setSecurityConfig(securityConfig); + factory.setLogLevel(logLevel); + factory.setCustomDataTypes(customDataTypes); + return factory.build(); +} + +void UaClientFactory::setSecurityConfig(const OpcUaClientSecurityConfig* securityConfig) +{ + this->securityConfig = securityConfig; +} + +void UaClientFactory::setLogLevel(const UA_LogLevel logLevel) +{ + this->logLevel = logLevel; +} + +void UaClientFactory::setCustomDataTypes(const UA_DataTypeArray* customDataTypes) +{ + this->customDataTypes = customDataTypes; +} + +void UaClientFactory::configureClient() +{ + // config->logger = UA_Log_Plog_withLevel(logLevel); + + if (securityConfig == NULL) + { + UA_StatusCode retval = UA_ClientConfig_setDefault(config); + if (retval != UA_STATUSCODE_GOOD) + throw OpcUaException(retval, "Failed to configure client defaults."); + } + else + configureClientSecurity(); + + config->customDataTypes = customDataTypes; + + configureClientConfigDefaults(); +} + +void UaClientFactory::configureClientSecurity() +{ + securityConfig->validate(); + + if (!securityConfig->hasCertificate()) + { + UA_StatusCode retval = UA_ClientConfig_setDefault(config); + if (retval != UA_STATUSCODE_GOOD) + throw OpcUaException(retval, "Failed to configure client defaults."); + } + else + { +#ifdef OPCUA_ENABLE_ENCRYPTION + UA_StatusCode retval = UA_ClientConfig_setDefaultEncryption(config, + securityConfig->certificate.getValue(), + securityConfig->privateKey.getValue(), + (securityConfig->trustAll) ? NULL : securityConfig->trustList.data(), + (securityConfig->trustAll) ? 0 : securityConfig->trustList.size(), + securityConfig->revocationList.data(), + securityConfig->revocationList.size()); + + if (retval != UA_STATUSCODE_GOOD) + throw OpcUaException(retval, "Failed to configure client encryption."); + + if (!securityConfig->trustAll && securityConfig->trustList.size() == 0) + config->certificateVerification.verifyCertificate = OpcUaSecurityCommon::verifyCertificateRejectAll; + + config->securityMode = securityConfig->securityMode; + configureClientAppUri(); +#else + throw OpcUaException(UA_STATUSCODE_BADINTERNALERROR, "Encryption was not enabled when building the project."); +#endif + } +} + +void UaClientFactory::configureClientAppUri() +{ + std::optional appUri = securityConfig->getAppUriOrParseFromCertificate(); + if (appUri.has_value()) + { + UA_String_clear(&config->clientDescription.applicationUri); + config->clientDescription.applicationUri = UA_STRING_ALLOC(appUri.value().c_str()); + } +} + +void UaClientFactory::configureClientConfigDefaults() +{ + config->timeout = OpcUaClient::CONNECTION_TIMEOUT_SECONDS * 1000; + config->connectivityCheckInterval = OpcUaClient::CONNECTION_TIMEOUT_SECONDS; +} + +UA_Client* UaClientFactory::build() +{ + client = UA_Client_new(); + config = UA_Client_getConfig(client); + + try + { + configureClient(); + } + catch (const OpcUaException&) + { + UA_Client_delete(client); + throw; + } + + return client; +} + +bool OpcUaClient::connect() +{ + std::lock_guard guard(getLock()); + if (!uaclient) + initialize(); + + const OpcUaClientSecurityConfig* securityConfig = endpoint.getSecurityConfig(); + + UA_StatusCode status; + + if (securityConfig == NULL || securityConfig->isAnonymous()) + status = UA_Client_connect(uaclient, endpoint.getUrl().c_str()); + else + { + status = UA_Client_connectUsername(uaclient, + endpoint.getUrl().c_str(), + securityConfig->username.value_or("").c_str(), + securityConfig->password.value_or("").c_str()); + } + + return OPCUA_STATUSCODE_SUCCEEDED(status); +} + +void OpcUaClient::disconnect() +{ + std::lock_guard guard(getLock()); + if (!uaclient) + return; + + stopIterate(); + + UA_Client_disconnect(uaclient); + + clear(); // to clear all internal states +} + +void OpcUaClient::clear() +{ + if (uaclient) + { + UA_Client_delete(uaclient); + uaclient = nullptr; + } +} + +UA_Client* OpcUaClient::getUaClient() +{ + return uaclient; +} + +ClientLockGuard OpcUaClient::getLockedUaClient() +{ + return ClientLockGuard(this); +} + +bool OpcUaClient::isConnected() +{ + std::lock_guard guard(getLock()); + if (!uaclient) + return false; + + UA_SecureChannelState channelState; + UA_SessionState sessionState; + UA_StatusCode connectStatus; + UA_Client_getState(uaclient, &channelState, &sessionState, &connectStatus); + + return OPCUA_STATUSCODE_SUCCEEDED(connectStatus) && channelState == UA_SECURECHANNELSTATE_OPEN; +} + +const OpcUaEndpoint& OpcUaClient::getEndpoint() const +{ + return endpoint; +} + +void OpcUaClient::setUrl(const std::string& url) +{ + if (isConnected()) + throw std::runtime_error("Cannot setUrl. Disconnect connection broker first."); + endpoint.setUrl(url); +} + +void OpcUaClient::setTimeout(uint32_t timeoutMs) +{ + std::lock_guard guard(getLock()); + this->timeoutMs = timeoutMs; + if (uaclient) + UA_Client_getConfig(uaclient)->timeout = timeoutMs; +} + +uint32_t OpcUaClient::getTimeout() const +{ + return this->timeoutMs; +} + +void OpcUaClient::setConnectivityCheckInterval(uint32_t connectivityCheckInterval) +{ + std::lock_guard guard(getLock()); + this->connectivityCheckInterval = connectivityCheckInterval; + if (uaclient) + { + auto* config = UA_Client_getConfig(uaclient); + + if (connectivityCheckInterval > config->secureChannelLifeTime) + THROW_RUNTIME_ERROR("Connectivity check interval [" << connectivityCheckInterval << "] exceeds secure channel life time [" + << config->secureChannelLifeTime << "]"); + + UA_Client_getConfig(uaclient)->connectivityCheckInterval = connectivityCheckInterval; + } +} + +std::recursive_mutex& OpcUaClient::getLock() +{ + return lock; +} + +void OpcUaClient::runIterate(std::chrono::milliseconds period, std::chrono::milliseconds iterateTimeout) +{ + assert(period.count() >= 0); + assert(iterateTimeout.count() >= 0); + + if (iterateThread.getStarted()) + throw std::runtime_error("Iterate already started."); + + iterateThread.setIntervalMs(period.count()); + this->iterateTimeout = iterateTimeout; + iterateThread.start(); +} + +void OpcUaClient::stopIterate() +{ + iterateThread.stop(); +} + +void OpcUaClient::executeIterateCallback() +{ + auto statusCode = iterate(iterateTimeout); + if (OPCUA_STATUSCODE_FAILED(statusCode)) + iterateThread.terminate(); +} + +UA_StatusCode OpcUaClient::iterate(std::chrono::milliseconds timeout) +{ + assert(timeout.count() >= 0); + UA_Int32 timeoutMs = timeout.count(); + return UA_Client_run_iterate_timer_tasks(getLockedUaClient(), timeoutMs, true); +} + +OpcUaCallbackIdent OpcUaClient::scheduleTimerTask(double intervalMs, const OpcUaTimerTaskType& task) +{ + OpcUaCallbackIdent callbackId; + + auto client = getLockedUaClient(); + + void* context = timerTasks.createContext(); + + UA_StatusCode status = UA_Client_addRepeatedCallback(client, OpcUaClient::timerTaskCallback, context, intervalMs, &callbackId); + + if (OPCUA_STATUSCODE_FAILED(status)) + { + timerTasks.deleteContext(context); + throw OpcUaException(status, "Failed to add repeated callback"); + } + + timerTasks.insertTimerTask(context, callbackId, task); + + return callbackId; +} + +void OpcUaClient::removeTimerTask(OpcUaCallbackIdent ident) +{ + auto client = getLockedUaClient(); + UA_Client_removeCallback(client, ident); + timerTasks.removeTimerTask(ident); +} + +bool OpcUaClient::timerTaskExists(OpcUaCallbackIdent ident) +{ + std::lock_guard guard(lock); + return timerTasks.timerTaskExists(ident); +} + +void OpcUaClient::timerTaskCallback(UA_Client* client, void* data) +{ + OpcUaCallbackIdent callbackIdent; + OpcUaTimerTaskType* task; + TimerTaskContextCollection::getTaskExecData(data, &callbackIdent, &task); + + OpcUaClient* opcUaClient = static_cast(UA_Client_getConfig(client)->clientContext); + TimerTaskControl control; + try + { + (*task)(*opcUaClient, control); + } + catch (const std::exception& e) + { + LOGE << "Error occured during executing user task. " << e.what(); + } + if (control.terminate) + opcUaClient->removeTimerTask(callbackIdent); +} + +OpcUaVariant OpcUaClient::readValue(const OpcUaNodeId& node) +{ + OpcUaVariant val; + CheckStatusCodeException(UA_Client_readValueAttribute(getLockedUaClient(), *node, val.get())); + + return val; +} + +OpcUaObject OpcUaClient::readNodeAttributes(const OpcUaObject& request) +{ + return UA_Client_Service_read(getLockedUaClient(), *request); +} + +void OpcUaClient::readNodeAttributes(const std::vector& requests) +{ + size_t requestCnt = std::size(requests); + if (requestCnt == 0) + return; + + OpcUaObject readRequest; + CheckStatusCodeException( + UA_Array_resize((void**) &readRequest->nodesToRead, &readRequest->nodesToReadSize, requestCnt, &UA_TYPES[UA_TYPES_READVALUEID])); + + for (size_t i = 0; i < requestCnt; i++) + UA_ReadValueId_copy(requests[i].get(), &readRequest->nodesToRead[i]); + + readRequest->timestampsToReturn = UA_TimestampsToReturn::UA_TIMESTAMPSTORETURN_NEITHER; + + OpcUaObject response = readNodeAttributes(readRequest); + CheckStatusCodeException(response->responseHeader.serviceResult); + + for (size_t i = 0; i < requestCnt; i++) + { + UA_DataValue* v = &response->results[i]; + requests[i].processFunction(v); + } +} + +OpcUaObject OpcUaClient::callMethods(const OpcUaObject& request) +{ + return UA_Client_Service_call(getLockedUaClient(), *request); +} + +UA_NodeClass OpcUaClient::readNodeClass(const OpcUaNodeId& nodeId) +{ + UA_NodeClass nodeClass; + CheckStatusCodeException(UA_Client_readNodeClassAttribute(getLockedUaClient(), *nodeId, &nodeClass)); + return nodeClass; +} + +bool OpcUaClient::nodeExists(const OpcUaNodeId& node) +{ + UA_NodeClass nodeClass; + auto status = UA_Client_readNodeClassAttribute(getLockedUaClient(), *node, &nodeClass); + if (status == UA_STATUSCODE_BADNODEIDUNKNOWN) + return false; + + CheckStatusCodeException(status); + + return true; +} + +std::string OpcUaClient::readBrowseName(const OpcUaNodeId& nodeId) +{ + OpcUaObject browseName; + CheckStatusCodeException(UA_Client_readBrowseNameAttribute(getLockedUaClient(), *nodeId, browseName.get())); + + return OpcUaNode::GetBrowseName(*browseName); +} + +std::string OpcUaClient::readDisplayName(const OpcUaNodeId& nodeId) +{ + OpcUaObject displayName; + CheckStatusCodeException(UA_Client_readDisplayNameAttribute(getLockedUaClient(), *nodeId, displayName.get())); + + return utils::ToStdString(displayName->text); +} + +size_t OpcUaClient::readDimension(const OpcUaNodeId& nodeId) +{ + OpcUaObject uaVar; + CheckStatusCodeException(UA_Client_readValueAttribute(getLockedUaClient(), *nodeId, uaVar.get())); + + if (uaVar->arrayLength > 0) + return uaVar->arrayLength; + else + return 1; +} + +void OpcUaClient::writeDisplayName(const OpcUaNodeId& nodeId, const std::string& displayName) +{ + OpcUaObject uaDisplayName = UA_LOCALIZEDTEXT_ALLOC("", displayName.c_str()); + writeDisplayName(nodeId, uaDisplayName); +} + +void OpcUaClient::writeDisplayName(const OpcUaNodeId& nodeId, const OpcUaObject& displayName) +{ + auto status = UA_Client_writeDisplayNameAttribute(getLockedUaClient(), *nodeId, displayName.get()); + CheckStatusCodeException(status); +} + +std::string OpcUaClient::readDescription(const OpcUaNodeId& nodeId) +{ + OpcUaObject description; + auto status = UA_Client_readDescriptionAttribute(getLockedUaClient(), *nodeId, description.get()); + CheckStatusCodeException(status); + return utils::ToStdString(description->text); +} + +void OpcUaClient::writeDescription(const OpcUaNodeId& nodeId, const std::string& description) +{ + OpcUaObject uaDescription = UA_LOCALIZEDTEXT_ALLOC("", description.c_str()); + writeDescription(nodeId, uaDescription); +} + +void OpcUaClient::writeDescription(const OpcUaNodeId& nodeId, const OpcUaObject& description) +{ + auto status = UA_Client_writeDescriptionAttribute(getLockedUaClient(), *nodeId, description.get()); + CheckStatusCodeException(status); +} + +OpcUaNodeId OpcUaClient::readDataType(const OpcUaNodeId& nodeId) +{ + OpcUaNodeId dataTypeId; + const auto status = UA_Client_readDataTypeAttribute(getLockedUaClient(), *nodeId, dataTypeId.get()); + CheckStatusCodeException(status); + return dataTypeId; +} + +OpcUaObject OpcUaClient::callMethod(const OpcUaCallMethodRequest& callRequest) +{ + OpcUaObject request; + + auto copyCallRequest = callRequest.copy(); + request->methodsToCall = copyCallRequest.get(); + request->methodsToCallSize = 1; + + OpcUaObject response = callMethods(request); + + request->methodsToCall = nullptr; + request->methodsToCallSize = 0; + + CheckStatusCodeException(response->responseHeader.serviceResult); + return response->results[0]; +} + +void OpcUaClient::callMethods(const std::vector& container) +{ + size_t nodesCnt = std::size(container); + if (nodesCnt == 0) + return; + + UA_CallMethodRequest* items = (UA_CallMethodRequest*) UA_Array_new(nodesCnt, &UA_TYPES[UA_TYPES_CALLMETHODREQUEST]); + for (size_t i = 0; i < nodesCnt; i++) + items[i] = *container[i]; // optimization. reinit before delete + + OpcUaObject request; + + request->methodsToCall = items; + request->methodsToCallSize = nodesCnt; + + OpcUaObject response = callMethods(request); + + for (size_t i = 0; i < nodesCnt; i++) + UA_CallMethodRequest_init(&items[i]); + + CheckStatusCodeException(response->responseHeader.serviceResult); + + for (size_t i = 0; i < nodesCnt; i++) + container[i].processFunction(response->results[i]); +} + +void OpcUaClient::writeValue(const OpcUaNodeId& nodeId, const OpcUaVariant& value) +{ + CheckStatusCodeException(UA_Client_writeValueAttribute(getLockedUaClient(), *nodeId, value.get())); +} + +Subscription* OpcUaClient::createSubscription(const OpcUaObject& request, + const StatusChangeNotificationCallbackType& statusChangeCallback) +{ + return Subscription::CreateSubscription(this, request, statusChangeCallback); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/src/opcuanodefactory.cpp b/shared/libraries/opcua/opcuaclient/src/opcuanodefactory.cpp new file mode 100644 index 0000000..959be7f --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/src/opcuanodefactory.cpp @@ -0,0 +1,102 @@ +#include + +#include "opcuaclient/opcuanodefactory.h" +#include "opcuashared/node/opcuanodeobject.h" +#include "opcuashared/node/opcuadatatype.h" +#include +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +/*IOpcUaNodeFactory*/ + +OpcUaNodeId IOpcUaNodeFactory::GetOpcUaNodeId(const UA_ReferenceDescription& referenceDescription) +{ + return OpcUaNodeId(referenceDescription.nodeId.nodeId); +} + +/*OpcUaNodeFactory*/ + +OpcUaNodeFactory::OpcUaNodeFactory(const OpcUaClientPtr& client) + : client(client) +{ +} + +OpcUaNodePtr OpcUaNodeFactory::instantiateNode(const UA_ReferenceDescription& reference, + const OpcUaNodeId& parentNodeId, + bool& traverseChild) +{ + traverseChild = true; + switch (reference.nodeClass) + { + case UA_NODECLASS_VARIABLE: + { + OpcUaNodeId uaTypeNodeId; + UA_StatusCode status = + UA_Client_readDataTypeAttribute(client->getLockedUaClient(), reference.nodeId.nodeId, uaTypeNodeId.get()); + + if (OPCUA_STATUSCODE_SUCCEEDED(status)) + return std::make_shared(reference, uaTypeNodeId); + else + return nullptr; + } + case UA_NODECLASS_METHOD: + { + assert(!parentNodeId.isNull()); + OpcUaNodeMethodPtr nodeMethod = std::make_shared(reference, parentNodeId); + + prepareMethodParams(nodeMethod); + + return nodeMethod; + } + case UA_NODECLASS_OBJECT: + return std::make_shared(reference); + case UA_NODECLASS_DATATYPE: + return std::make_shared(reference); + default: + return nullptr; + } +} + +void OpcUaNodeFactory::prepareMethodParams(OpcUaNodeMethodPtr nodeMethod) +{ + // conditions to browse the method argument nodes: referencetype = UA_NS0ID_HASPROPERTY (=46) && brosweName = InputArguments | + // OutputArguments + + BrowseRequest request(nodeMethod->getNodeId(), OpcUaNodeClass::Variable, OpcUaNodeId(UA_NS0ID_HASPROPERTY)); + + OpcUaBrowser browser(request, client); + browseAndApplyMethodParams(browser, nodeMethod); + + nodeMethod->initTypeDescription(); +} + +void OpcUaNodeFactory::browseAndApplyMethodParams(OpcUaBrowser& browser, const OpcUaNodeMethodPtr& nodeMethod) +{ + try + { + auto& references = browser.browse(); + + for (auto& ref : references) + applyMethodParam(ref, nodeMethod); + } + catch (const OpcUaException& ex) + { + throw OpcUaException(ex.getStatusCode(), + "Method initialization: " + std::string(ex.what()) + ". Node: " + nodeMethod->getNodeId().toString()); + } +} + +void OpcUaNodeFactory::applyMethodParam(const UA_ReferenceDescription& reference, const OpcUaNodeMethodPtr& nodeMethod) +{ + auto browseName = OpcUaNode::GetBrowseName(reference.browseName); + + if (browseName == "InputArguments") + nodeMethod->addInputParameter("", OpcUaNodeId()); + else if (browseName == "OutputArguments") + nodeMethod->addOutputParameter("", OpcUaNodeId()); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/src/opcuareadvalueid.cpp b/shared/libraries/opcua/opcuaclient/src/opcuareadvalueid.cpp new file mode 100644 index 0000000..735f9b7 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/src/opcuareadvalueid.cpp @@ -0,0 +1,14 @@ +#include "opcuaclient/opcuareadvalueid.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaReadValueIdWithCallback::OpcUaReadValueIdWithCallback(const OpcUaNodeId& nodeId, + const ProcessFunctionType& processFunction, + AttributeIdType attributeId) + : processFunction(processFunction) +{ + getValue().nodeId = nodeId.copyAndGetDetachedValue(); + getValue().attributeId = attributeId; +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/src/opcuatimertaskcontextcollection.cpp b/shared/libraries/opcua/opcuaclient/src/opcuatimertaskcontextcollection.cpp new file mode 100644 index 0000000..f8c1ba5 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/src/opcuatimertaskcontextcollection.cpp @@ -0,0 +1,62 @@ +#include "opcuaclient/opcuatimertaskcontextcollection.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +TimerTaskContextCollection::TimerTaskContextCollection() +{ +} + +void* TimerTaskContextCollection::createContext() +{ + return new KeyType(this); +} + +void TimerTaskContextCollection::deleteContext(void* context) +{ + delete static_cast(context); +} + +void TimerTaskContextCollection::insertTimerTask(void* context, OpcUaCallbackIdent ident, const OpcUaTimerTaskType& task) +{ + assert(context != nullptr); + auto keyType = static_cast(context); + assert(keyType->owner == this); + + keyType->ident = ident; + + taskCallbacks.insert(std::pair(keyType, task)); +} + +void TimerTaskContextCollection::removeTimerTask(OpcUaCallbackIdent ident) +{ + KeyType keyType; + keyType.ident = ident; + + auto it = taskCallbacks.find(&keyType); + if (it != taskCallbacks.end()) + { + KeyType* kt = it->first; + taskCallbacks.erase(&keyType); + deleteContext(kt); + } +} + +bool TimerTaskContextCollection::timerTaskExists(OpcUaCallbackIdent ident) const +{ + KeyType keyType; + keyType.ident = ident; + + return taskCallbacks.find(&keyType) != taskCallbacks.end(); +} + +void TimerTaskContextCollection::getTaskExecData(void* context, + OpcUaCallbackIdent* callbackIdent, + OpcUaTimerTaskType** task) +{ + KeyType* keyType = static_cast(context); + + *callbackIdent = keyType->ident; + *task = &keyType->owner->taskCallbacks[keyType]; +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/src/opcuatimertaskhelper.cpp b/shared/libraries/opcua/opcuaclient/src/opcuatimertaskhelper.cpp new file mode 100644 index 0000000..6bb2589 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/src/opcuatimertaskhelper.cpp @@ -0,0 +1,80 @@ +#include "opcuaclient/opcuatimertaskhelper.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using namespace daq::utils; + +OpcUaTimerTaskHelper::OpcUaTimerTaskHelper(OpcUaClient& client, int intervalMs, const CallbackFunction& callback) + : intervalMs(intervalMs) + , terminated{} + , client(client) + , callback(callback) +{ + assert(callback); +} + +OpcUaTimerTaskHelper::~OpcUaTimerTaskHelper() +{ + stop(); +} + +void OpcUaTimerTaskHelper::start() +{ + if (!getStarted()) + { + terminated = false; + + using namespace std::placeholders; + callbackIdent = client.scheduleTimerTask(intervalMs, std::bind(&OpcUaTimerTaskHelper::execute, this, _1, _2)); + } +} + +void OpcUaTimerTaskHelper::stop() +{ + if (getStarted()) + { + terminated = true; + client.removeTimerTask(callbackIdent.value()); + } + callbackIdent.reset(); +} + +double OpcUaTimerTaskHelper::getIntervalMs() const +{ + return intervalMs; +} + +void OpcUaTimerTaskHelper::setIntervalMs(const double value) +{ + intervalMs = value; +} + +void OpcUaTimerTaskHelper::terminate() +{ + terminated = true; +} + +const std::atomic& OpcUaTimerTaskHelper::getTerminated() const +{ + return terminated; +} + +bool OpcUaTimerTaskHelper::getStarted() const +{ + return callbackIdent.has_value(); +} + +void OpcUaTimerTaskHelper::execute(OpcUaClient& client, TimerTaskControl& control) +{ + daq::utils::Finally checkTerminate( + [this, &control]() + { + if (this->terminated) + control.terminateTimerTask(); + }); + + callback(client); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/src/reference_utils.cpp b/shared/libraries/opcua/opcuaclient/src/reference_utils.cpp new file mode 100644 index 0000000..c688e5d --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/src/reference_utils.cpp @@ -0,0 +1,124 @@ +#include "opcuaclient/reference_utils.h" +#include "opcuaclient/browser/opcuabrowser.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +ReferenceUtils::ReferenceUtils(const OpcUaClientPtr& client) + : client(client) +{ +} + +const ReferenceUtils::ReferenceMap& ReferenceUtils::getReferences(const OpcUaNodeId& nodeId) +{ + browseNodeReferences(nodeId); + return referenceCache[nodeId]; +} + +tsl::ordered_set ReferenceUtils::getReferencedNodes(const OpcUaNodeId& nodeId, + const OpcUaNodeId& referenceTypeId, + bool isForward, + const OpcUaNodeId& typeDefinition) +{ + browseNodeReferences(nodeId); + tsl::ordered_set nodeIds; + const auto& references = referenceCache[nodeId]; + for (const auto& [refNodeId, ref] : references) + { + auto refId = OpcUaNodeId(ref->referenceTypeId); + if (ref->isForward == isForward && refId == referenceTypeId && + (typeDefinition.isNull() || isInstanceOf(ref->typeDefinition.nodeId, typeDefinition))) + nodeIds.insert(OpcUaNodeId(ref->nodeId.nodeId)); + } + return nodeIds; +} + +bool ReferenceUtils::hasReference(const OpcUaNodeId& nodeId, const std::string& browseName) +{ + browseNodeReferences(nodeId); + return browseNameCache[nodeId].count(browseName) > 0; +} + +bool ReferenceUtils::isInstanceOf(const OpcUaNodeId& typeInQuestion, const OpcUaNodeId& baseType) +{ + if (typeInQuestion == baseType) + return true; + + browseNodeReferences(baseType); + if (referenceCache[baseType].count(typeInQuestion) > 0) + { + const auto& ref = referenceCache[baseType][typeInQuestion]; + return isHasSubType(ref); + } + + return false; +} + +tsl::ordered_set ReferenceUtils::getVariableNodes(const OpcUaNodeId& nodeId) +{ + browseNodeReferences(nodeId); + tsl::ordered_set variableNodes; + + const auto& references = referenceCache[nodeId]; + for (const auto& [refNodeId, ref] : references) + { + if (ref->nodeClass == UA_NODECLASS_VARIABLE) + variableNodes.insert(refNodeId); + } + + return variableNodes; +} + +OpcUaNodeId ReferenceUtils::getChildNodeId(const OpcUaNodeId& nodeId, const std::string& browseName) +{ + browseNodeReferences(nodeId); + return browseNameCache[nodeId][browseName]; +} + +void ReferenceUtils::clearCache() +{ + referenceCache.clear(); + browseNameCache.clear(); +} + +void ReferenceUtils::updateReferences(const OpcUaNodeId& nodeId) +{ + auto browser = OpcUaBrowser(nodeId, client); + auto references = browser.browse(); + referenceCache[nodeId] = browser.referencesByNodeId(); + buildBrowseNameMap(nodeId); +} + +void ReferenceUtils::browseNodeReferences(const OpcUaNodeId& nodeId) +{ + if (referenceCache.count(nodeId) > 0) + return; + + updateReferences(nodeId); +} + +void ReferenceUtils::buildBrowseNameMap(const OpcUaNodeId& nodeId) +{ + const auto& referenceMap = referenceCache[nodeId]; + BrowseNameMap browseNameMap; + + for (const auto& [refNodeId, ref] : referenceMap) + { + const auto browseName = getBrowseName(ref); + browseNameMap.insert({browseName, refNodeId}); + } + + browseNameCache.insert({nodeId, browseNameMap}); +} + +std::string ReferenceUtils::getBrowseName(const OpcUaObject& reference) +{ + return utils::ToStdString(reference->browseName.name); +} + +bool ReferenceUtils::isHasSubType(const OpcUaObject& reference) +{ + return OpcUaNodeId(reference->referenceTypeId) == OpcUaNodeId(UA_NS0ID_HASSUBTYPE); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/src/request_handler.cpp b/shared/libraries/opcua/opcuaclient/src/request_handler.cpp new file mode 100644 index 0000000..3a886b3 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/src/request_handler.cpp @@ -0,0 +1,9 @@ +#include "opcuaclient/request_handler.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +RequestHandler::RequestHandler(const OpcUaClientPtr& client) +{ +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/src/subscriptions.cpp b/shared/libraries/opcua/opcuaclient/src/subscriptions.cpp new file mode 100644 index 0000000..2deca10 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/src/subscriptions.cpp @@ -0,0 +1,175 @@ +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +/*Subscription*/ + +Subscription::Subscription(OpcUaClient* client, const StatusChangeNotificationCallbackType& statusChangeNotificationCallback) + : client(client) + , statusChangeNotificationCallback(statusChangeNotificationCallback) +{ +} + +UA_UInt32 Subscription::getSubscriptionId() const +{ + return subscriptionResponse->subscriptionId; +} + +UA_Double Subscription::getRevisedPublishingInterval() const +{ + return subscriptionResponse->revisedPublishingInterval; +} + +UA_UInt32 Subscription::getRevisedLifetimeCount() const +{ + return subscriptionResponse->revisedLifetimeCount; +} + +UA_UInt32 Subscription::getRevisedMaxKeepAliveCount() const +{ + return subscriptionResponse->revisedMaxKeepAliveCount; +} + +const StatusChangeNotificationCallbackType& Subscription::getStatusChangeNotificationCallback() const +{ + return statusChangeNotificationCallback; +} + +static void DeleteSubscriptionCallback(UA_Client* client, UA_UInt32 subId, void* subContext) +{ + delete (Subscription*) subContext; +} + +static void StatusChangeNotificationCallback(UA_Client* client, + UA_UInt32 subId, + void* subContext, + UA_StatusChangeNotification* notification) +{ + auto subscription = (Subscription*) subContext; + if (subscription->getStatusChangeNotificationCallback()) + { + OpcUaClient* opcUaClient = static_cast(UA_Client_getContext(client)); + subscription->getStatusChangeNotificationCallback()(opcUaClient, subscription, notification); + } +} + +Subscription* Subscription::CreateSubscription(OpcUaClient* client, + const OpcUaObject& request, + const StatusChangeNotificationCallbackType& statusChangeCallback) +{ + auto subscription = new Subscription(client, statusChangeCallback); + + OpcUaObject response = UA_Client_Subscriptions_create( + client->getLockedUaClient(), *request, subscription, StatusChangeNotificationCallback, DeleteSubscriptionCallback); + + subscription->subscriptionResponse = response; + + CheckStatusCodeException(response->responseHeader.serviceResult, "Failed to create subscription"); + + return subscription; +} + +/*MonitoredItem*/ + +static void DeleteMonitoredItemCallback(UA_Client* client, UA_UInt32 subId, void* subContext, UA_UInt32 monId, void* monContext) +{ + delete (MonitoredItem*) monContext; +} + +static void EventNotificationCallback( + UA_Client* client, UA_UInt32 subId, void* subContext, UA_UInt32 monId, void* monContext, size_t nEventFields, UA_Variant* eventFields) +{ + auto monitoredItem = (MonitoredItem*) monContext; + if (monitoredItem->getEventNotificationCallback()) + { + OpcUaClient* opcUaClient = static_cast(UA_Client_getContext(client)); + auto subscription = (Subscription*) subContext; + monitoredItem->getEventNotificationCallback()(opcUaClient, subscription, monitoredItem, nEventFields, eventFields); + } +} + +static void DataChangeNotificationCallback( + UA_Client* client, UA_UInt32 subId, void* subContext, UA_UInt32 monId, void* monContext, UA_DataValue* value) +{ + auto monitoredItem = (MonitoredItem*) monContext; + if (monitoredItem->getDataChangeNotificationCallback()) + { + OpcUaClient* opcUaClient = static_cast(UA_Client_getContext(client)); + auto subscription = (Subscription*) subContext; + monitoredItem->getDataChangeNotificationCallback()(opcUaClient, subscription, monitoredItem, value); + } +} + +MonitoredItem* Subscription::monitoredItemsCreateEvent(UA_TimestampsToReturn timestampsToReturn, + const UA_MonitoredItemCreateRequest& item, + const EventNotificationCallbackType& eventNotificationCallback) +{ + auto monitoredItem = new MonitoredItem(client, eventNotificationCallback); + + UA_MonitoredItemCreateResult result = UA_Client_MonitoredItems_createEvent(client->getLockedUaClient(), + getSubscriptionId(), + UA_TIMESTAMPSTORETURN_BOTH, + item, + monitoredItem, + EventNotificationCallback, + DeleteMonitoredItemCallback); + + monitoredItem->response = result; + + CheckStatusCodeException(result.statusCode, "Failed to create monitored item"); + + return monitoredItem; +} + +MonitoredItem* Subscription::monitoredItemsCreateDataChange(UA_TimestampsToReturn timestampsToReturn, + const UA_MonitoredItemCreateRequest& item, + const DataChangeNotificationCallbackType& dataChangeNotificationCallback) +{ + auto monitoredItem = new MonitoredItem(client, dataChangeNotificationCallback); + + UA_MonitoredItemCreateResult result = UA_Client_MonitoredItems_createDataChange(client->getLockedUaClient(), + getSubscriptionId(), + UA_TIMESTAMPSTORETURN_BOTH, + item, + monitoredItem, + DataChangeNotificationCallback, + DeleteMonitoredItemCallback); + + monitoredItem->response = result; + + CheckStatusCodeException(result.statusCode, "Failed to create monitored item"); + + return monitoredItem; +} + +/*MonitoredItem*/ + +MonitoredItem::MonitoredItem(OpcUaClient* client, const EventNotificationCallbackType& eventNotificationCallback) + : client(client) + , eventNotificationCallback(eventNotificationCallback) +{ +} + +MonitoredItem::MonitoredItem(OpcUaClient* client, const DataChangeNotificationCallbackType& dataChangeNotificationCallback) + : client(client) + , dataChangeNotificationCallback(dataChangeNotificationCallback) +{ +} + +UA_UInt32 MonitoredItem::getMonitoredItemId() const +{ + return response->monitoredItemId; +} + +const EventNotificationCallbackType& MonitoredItem::getEventNotificationCallback() const +{ + return eventNotificationCallback; +} + +const DataChangeNotificationCallbackType& MonitoredItem::getDataChangeNotificationCallback() const +{ + return dataChangeNotificationCallback; +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/src/taskprocessor/opcuataskprocessor.cpp b/shared/libraries/opcua/opcuaclient/src/taskprocessor/opcuataskprocessor.cpp new file mode 100644 index 0000000..51e007d --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/src/taskprocessor/opcuataskprocessor.cpp @@ -0,0 +1,143 @@ +#include "opcuaclient/taskprocessor/opcuataskprocessor.h" + +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using namespace daq::utils; + +OpcUaTaskProcessor::OpcUaTaskProcessor(const OpcUaClientPtr& client) + : ThreadEx() + , client(client) + , prevStatus(UA_STATUSCODE_GOOD) +{ + setPriority(ThreadExPriority::timeCritical); +} + +OpcUaTaskProcessor::~OpcUaTaskProcessor() +{ + OpcUaTaskProcessor::stop(); +} + +bool OpcUaTaskProcessor::isConnected() +{ + return connected; +} + +void OpcUaTaskProcessor::start() +{ + connected = client->isConnected(); + ThreadEx::start(); +} + +void OpcUaTaskProcessor::stop() +{ + terminate(); + cvWait.notify_one(); + ThreadEx::stop(); +} + +void OpcUaTaskProcessor::executeTask(const OpcUaTaskType& task) +{ + auto future = executeTaskAwait(task); + future.get(); +} + +void OpcUaTaskProcessor::executeTask(std::promise& promise, const OpcUaTaskType& task) const +{ + try + { + task(*client); + promise.set_value(); + } + catch (...) + { + try + { + promise.set_exception(std::current_exception()); + } + catch (...) // set_exception() may throw too + { + } + } +} + +bool OpcUaTaskProcessor::connect() +{ + bool result = false; + executeTask([&result](OpcUaClient& client) { result = client.connect(); }); + return result; +} + +void OpcUaTaskProcessor::setConnectionTimeout(uint32_t timeoutMs) +{ + executeTask([timeoutMs](OpcUaClient& client) { client.setTimeout(timeoutMs); }); +} + +const OpcUaClientPtr& OpcUaTaskProcessor::getClient() const noexcept +{ + return client; +} + +std::future OpcUaTaskProcessor::executeTaskAwait(const OpcUaTaskType& task) +{ + if (std::this_thread::get_id() == executingThreadId) // to prevent deadlock. if its called inside task + { + std::promise promise; + executeTask(promise, task); + return promise.get_future(); + } + else + { + std::lock_guard guard(mutex); + queue.push(std::make_pair(std::promise(), task)); + return queue.back().first.get_future(); + } +} + +OpcUaTaskProcessor::QueueItemType OpcUaTaskProcessor::getNextTask() +{ + std::lock_guard guard(mutex); + OpcUaTaskProcessor::QueueItemType task; + if (!queue.empty()) + { + task = std::move(queue.front()); + queue.pop(); + } + + return task; +} + +void OpcUaTaskProcessor::execute() +{ + executingThreadId = std::this_thread::get_id(); + setThreadName("OpcUaTaskProcessor_Normal"); + while (!terminated) + { + QueueItemType task = getNextTask(); + if (task.second) + { + executeTask(task.first, task.second); + } + else + { + static constexpr std::chrono::milliseconds timeout(1); + UA_StatusCode status = client->iterate(timeout); + + if (OPCUA_STATUSCODE_FAILED(status) && prevStatus != status) // don't log repeating errors + LOGE << "OpcUa error occured during client iterate " << OPCUA_STATUSCODE_LOG_MESSAGE(status); + + prevStatus = status; + + if (OPCUA_STATUSCODE_FAILED(status)) // If client disconnects, we don't wait on UA_SELECT. So wait here + { + auto uniqueLock = std::unique_lock(waitMutex); + cvWait.wait_for(uniqueLock, std::chrono::milliseconds(timeout)); + } + } + + connected = client->isConnected(); + } +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/tests/CMakeLists.txt b/shared/libraries/opcua/opcuaclient/tests/CMakeLists.txt new file mode 100644 index 0000000..b893a20 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/tests/CMakeLists.txt @@ -0,0 +1,38 @@ +set(MODULE_NAME opcuaclient) +set(TEST_APP test_${MODULE_NAME}) + +set(SRC_Cpp main.cpp + opcuaservertesthelper.cpp + test_opcuanodefactory.cpp + test_opcuanodefactorybrowser.cpp + test_opcuaasyncexecthread.cpp + test_opcuataskprocessor.cpp + test_opcuatimertaskhelper.cpp + test_opcuaclient.cpp +) + +set(SRC_Include opcuaservertesthelper.h +) + +opendaq_prepend_path("include" SRC_Include) +opendaq_prepend_path("src" SRC_Cpp) + +add_executable(${TEST_APP} ${SRC_Cpp} + ${SRC_Include} +) + +target_link_libraries(${TEST_APP} PRIVATE ${SDK_TARGET_NAMESPACE}::${MODULE_NAME} + daq::test_utils + daq::opcuaserver #remove after moving test_opcuaclientbasedsacqcontrol to opcua server/client integration tests +) + +target_include_directories(${TEST_APP} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include") + +add_test(NAME ${TEST_APP} + COMMAND $ + WORKING_DIRECTORY bin +) + +if(OPENDAQ_ENABLE_COVERAGE) + setup_target_for_coverage(${MODULE_NAME}coverage ${TEST_APP} ${MODULE_NAME}coverage) +endif() diff --git a/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h b/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h new file mode 100644 index 0000000..5d05d13 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h @@ -0,0 +1,97 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include "opcuaclient/opcuaclient.h" +#include "opcuashared/opcua.h" +#include "opcuashared/opcuacommon.h" + +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +#define ASSERT_EQ_STATUS(status, expectedStatus) ASSERT_EQ(status, (UA_StatusCode) expectedStatus) + +class OpcUaServerTestHelper final +{ +public: + OpcUaServerTestHelper(); + ~OpcUaServerTestHelper(); + + void setSessionTimeout(double sessionTimeoutMs); + + void startServer(); + void stop(); + + std::string getServerUrl() const; + +private: + void runServer(); + void createModel(); + void publishVariable(std::string identifier, + const void* value, + const UA_DataType* type, + UA_NodeId* parentNodeId, + const char* locale = "en_US", + int nodeIndex = 1, + size_t dimension = 1); + void publishFolder(const char* identifier, UA_NodeId* parentNodeId, const char* locale = "en_US", int nodeIndex = 1); + void publishMethod(std::string identifier, UA_NodeId* parentNodeId, const char* locale = "en_US", int nodeIndex = 1); + static UA_StatusCode helloMethodCallback(UA_Server* server, + const UA_NodeId* sessionId, + void* sessionHandle, + const UA_NodeId* methodId, + void* methodContext, + const UA_NodeId* objectId, + void* objectContext, + size_t inputSize, + const UA_Variant* input, + size_t outputSize, + UA_Variant* output); + + double sessionTimeoutMs; + UA_Server* server{}; + std::unique_ptr serverThreadPtr; + std::atomic serverRunning = false; + + UA_UInt16 port = 4842u; +}; + +class BaseClientTest : public testing::Test +{ +protected: + void SetUp() override; + void TearDown() override; + OpcUaServerTestHelper testHelper; + + std::string getServerUrl() const; + + static void IterateAndWaitForPromise(OpcUaClient& client, const std::future& future) + { + using namespace std::chrono; + while (client.iterate(milliseconds(10)) == UA_STATUSCODE_GOOD && + future.wait_for(milliseconds(1)) != std::future_status::ready) + { + }; + } + + OpcUaClientPtr prepareAndConnectClient(int timeout = -1); +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/tests/src/main.cpp b/shared/libraries/opcua/opcuaclient/tests/src/main.cpp new file mode 100644 index 0000000..457eff2 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/tests/src/main.cpp @@ -0,0 +1,12 @@ +#include +#include + +int main(int argc, char** args) +{ + testing::InitGoogleTest(&argc, args); + + testing::TestEventListeners& listeners = testing::UnitTest::GetInstance()->listeners(); + listeners.Append(new MemCheckListener()); + + return RUN_ALL_TESTS(); +} diff --git a/shared/libraries/opcua/opcuaclient/tests/src/opcuaservertesthelper.cpp b/shared/libraries/opcua/opcuaclient/tests/src/opcuaservertesthelper.cpp new file mode 100644 index 0000000..26be1fe --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/tests/src/opcuaservertesthelper.cpp @@ -0,0 +1,326 @@ +#include "opcuaservertesthelper.h" +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaServerTestHelper::OpcUaServerTestHelper() + : sessionTimeoutMs(-1) +{ +} + +OpcUaServerTestHelper::~OpcUaServerTestHelper() +{ + stop(); +} + +void OpcUaServerTestHelper::setSessionTimeout(double sessionTimeoutMs) +{ + this->sessionTimeoutMs = sessionTimeoutMs; +} + +void OpcUaServerTestHelper::runServer() +{ + while (serverRunning) + UA_Server_run_iterate(server, true); + + UA_Server_run_shutdown(server); + UA_Server_delete(server); +} + +void OpcUaServerTestHelper::startServer() +{ + serverRunning = true; + + server = UA_Server_new(); + UA_ServerConfig* config = UA_Server_getConfig(server); + + UA_ServerConfig_setMinimal(config, port, nullptr); + + if (sessionTimeoutMs > 0) + config->maxSessionTimeout = sessionTimeoutMs; + +#ifdef UA_ENABLE_WEBSOCKET_SERVER + UA_ServerConfig_addNetworkLayerWS(config, 80, 0, 0); +#endif // UA_ENABLE_WEBSOCKET_SERVER + + createModel(); + + UA_Server_run_startup(server); + +#if SYNTH_SERVER_DEBUG + runServer(); +#else + serverThreadPtr = std::make_unique(&OpcUaServerTestHelper::runServer, this); +#endif +} + +void OpcUaServerTestHelper::stop() +{ + serverRunning = false; + if (serverThreadPtr) + { + serverThreadPtr->join(); + serverThreadPtr.reset(); + } +} + +std::string OpcUaServerTestHelper::getServerUrl() const +{ + std::stringstream ss; + ss << "opc.tcp://127.0.0.1"; + ss << ":"; + ss << port; + return ss.str(); +} + +void OpcUaServerTestHelper::createModel() +{ + auto uaObjectsFolder = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); + + publishFolder("f1", &uaObjectsFolder); + + UA_Int32 myInt32; + + myInt32 = 33; + publishVariable("f1.i", &myInt32, &UA_TYPES[UA_TYPES_INT32], OpcUaNodeId(1, "f1").getPtr()); + + myInt32 = 41; + publishVariable(".i32", &myInt32, &UA_TYPES[UA_TYPES_INT32], &uaObjectsFolder); + + UA_UInt32 myUInt32 = 19; + publishVariable(".ui32", &myUInt32, &UA_TYPES[UA_TYPES_UINT32], &uaObjectsFolder); + + UA_Int16 myInt16 = 16; + publishVariable(".i16", &myInt16, &UA_TYPES[UA_TYPES_INT16], &uaObjectsFolder); + + UA_UInt16 myUInt16 = 33; + publishVariable(".ui16", &myUInt16, &UA_TYPES[UA_TYPES_UINT16], &uaObjectsFolder); + + UA_Int64 myInt64 = 64; + publishVariable(".i64", &myInt64, &UA_TYPES[UA_TYPES_INT64], &uaObjectsFolder); + + UA_Boolean myBool = true; + publishVariable(".b", &myBool, &UA_TYPES[UA_TYPES_BOOLEAN], &uaObjectsFolder); + + UA_Double myDouble = (UA_Double) 1885 / (UA_Double) 14442; + publishVariable(".d", &myDouble, &UA_TYPES[UA_TYPES_DOUBLE], &uaObjectsFolder); + + UA_Float myFloat = (UA_Float) 1 / (UA_Float) 3; + publishVariable(".f", &myFloat, &UA_TYPES[UA_TYPES_FLOAT], &uaObjectsFolder); + + UA_String myString = UA_STRING_ALLOC("Hello Dewesoft"); + publishVariable(".s", &myString, &UA_TYPES[UA_TYPES_STRING], &uaObjectsFolder); + UA_String_clear(&myString); + + UA_Guid myGuid = UA_GUID("8a336ac1-8632-482c-a565-23e6a9ad1abc"); + publishVariable(".g", &myGuid, &UA_TYPES[UA_TYPES_GUID], &uaObjectsFolder); + + UA_StatusCode myStatus = UA_STATUSCODE_GOODSUBSCRIPTIONTRANSFERRED; + publishVariable(".sc", &myStatus, &UA_TYPES[UA_TYPES_STATUSCODE], &uaObjectsFolder); + + // vectors + + UA_Int32 myVecInt32[] = {12, 13, 15, 18}; + publishVariable(".i32v", &myVecInt32, &UA_TYPES[UA_TYPES_INT32], &uaObjectsFolder, "en_US", 1, 4); + + UA_Int16 myVecInt16[] = {65, 18, 12, 17, 33, 10023, 12, 1, 0, -1}; + publishVariable(".i16v", &myVecInt16, &UA_TYPES[UA_TYPES_INT16], &uaObjectsFolder, "en_US", 1, 10); + + UA_Int64 myVecInt64[] = {55, 1993}; + publishVariable(".i64v", &myVecInt64, &UA_TYPES[UA_TYPES_INT64], &uaObjectsFolder, "en_US", 1, 2); + + UA_Boolean myVecBool[] = {true, false}; + publishVariable(".bv", &myVecBool, &UA_TYPES[UA_TYPES_BOOLEAN], &uaObjectsFolder, "en_US", 1, 2); + + UA_Double myVecDouble[] = {(UA_Double) 1993 / (UA_Double) 6625, (UA_Double) 185 / (UA_Double) 1443, (UA_Double) 1.44, (UA_Double) 9948}; + publishVariable(".dv", &myVecDouble, &UA_TYPES[UA_TYPES_DOUBLE], &uaObjectsFolder, "en_US", 1, 4); + + UA_Float myVecFloat[] = {(UA_Float) 7 / (UA_Float) 2, (UA_Float) 1 / (UA_Float) 5}; + publishVariable(".fv", &myVecFloat, &UA_TYPES[UA_TYPES_FLOAT], &uaObjectsFolder, "en_US", 1, 2); + + // methods + + publishMethod("hello.dewesoft", &uaObjectsFolder); + + // structures + + OpcUaNodeId structureNodeId(1, ".sctA"); + + myInt32 = 56; + publishVariable(".sctA", &myInt32, &UA_TYPES[UA_TYPES_INT32], &uaObjectsFolder); + + myInt32 = 5641; + publishVariable(".sctA.i32", &myInt32, &UA_TYPES[UA_TYPES_INT32], structureNodeId.getPtr()); + + UA_Double mySctDouble = (UA_Double) 9844 / (UA_Double) 19774; + publishVariable(".sctA.d", &mySctDouble, &UA_TYPES[UA_TYPES_DOUBLE], structureNodeId.getPtr()); + + UA_String mySctString = UA_STRING_ALLOC("Hello Dewesoft @ struct"); + publishVariable(".sctA.s", &mySctString, &UA_TYPES[UA_TYPES_STRING], structureNodeId.getPtr()); + UA_String_clear(&mySctString); +} + +void OpcUaServerTestHelper::publishVariable(std::string identifier, + const void* value, + const UA_DataType* type, + UA_NodeId* parentNodeId, + const char* locale, + int nodeIndex, + size_t dimension) +{ + OpcUaObject attr = UA_VariableAttributes_default; + attr->description = UA_LOCALIZEDTEXT_ALLOC(locale, identifier.c_str()); + attr->displayName = UA_LOCALIZEDTEXT_ALLOC(locale, identifier.c_str()); + attr->dataType = type->typeId; + attr->accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; + + OpcUaNodeId newNodeId(nodeIndex, identifier); + + OpcUaObject qualifiedName = UA_QUALIFIEDNAME_ALLOC(UA_UInt16(nodeIndex), identifier.c_str()); + + if (dimension > 1) + { + attr->valueRank = 1; + attr->arrayDimensionsSize = 1; + attr->arrayDimensions = static_cast(UA_Array_new(1, &UA_TYPES[UA_TYPES_UINT32])); + attr->arrayDimensions[0] = UA_UInt32(dimension); + UA_Variant_setArrayCopy(&attr->value, value, dimension, type); + } + else + { + UA_Variant_setScalarCopy(&attr->value, value, type); + } + auto status = UA_Server_addVariableNode(server, + *newNodeId, + *parentNodeId, + UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), + *qualifiedName, + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + *attr, + NULL, + NULL); + + CheckStatusCodeException(status); +} + +void OpcUaServerTestHelper::publishFolder(const char* identifier, UA_NodeId* parentNodeId, const char* locale, int nodeIndex) +{ + OpcUaObject attr = UA_ObjectAttributes_default; + attr->description = UA_LOCALIZEDTEXT_ALLOC(locale, identifier); + attr->displayName = UA_LOCALIZEDTEXT_ALLOC(locale, identifier); + + OpcUaNodeId newNodeId(nodeIndex, identifier); + + OpcUaObject qualifiedName = UA_QUALIFIEDNAME_ALLOC(UA_UInt16(nodeIndex), identifier); + + auto status = UA_Server_addObjectNode(server, + *newNodeId, + *parentNodeId, + UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), + *qualifiedName, + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE), + *attr, + NULL, + NULL); + + CheckStatusCodeException(status); +} + +void OpcUaServerTestHelper::publishMethod(std::string identifier, UA_NodeId* parentNodeId, const char* locale, int nodeIndex) +{ + OpcUaObject inputArgument; + inputArgument->description = UA_LOCALIZEDTEXT_ALLOC("en-US", "Input"); + inputArgument->name = UA_STRING_ALLOC("Input"); + inputArgument->dataType = UA_TYPES[UA_TYPES_STRING].typeId; + inputArgument->valueRank = -1; + + OpcUaObject outputArgument; + outputArgument->description = UA_LOCALIZEDTEXT_ALLOC("en-US", "Output"); + outputArgument->name = UA_STRING_ALLOC("Output"); + outputArgument->dataType = UA_TYPES[UA_TYPES_STRING].typeId; + outputArgument->valueRank = -1; + + OpcUaObject attr = UA_MethodAttributes_default; + attr->description = UA_LOCALIZEDTEXT_ALLOC(locale, identifier.c_str()); + attr->displayName = UA_LOCALIZEDTEXT_ALLOC(locale, identifier.c_str()); + attr->executable = true; + attr->userExecutable = true; + + OpcUaNodeId newNodeId(nodeIndex, identifier); + + UA_Server_addMethodNode(server, + *newNodeId, + *parentNodeId, + UA_NODEID_NUMERIC(0, UA_NS0ID_HASORDEREDCOMPONENT), + UA_QUALIFIEDNAME(1, (char*) identifier.c_str()), + *attr, + helloMethodCallback, + 1, + inputArgument.get(), + 1, + outputArgument.get(), + NULL, + NULL); +} + +UA_StatusCode OpcUaServerTestHelper::helloMethodCallback(UA_Server* server, + const UA_NodeId* sessionId, + void* sessionHandle, + const UA_NodeId* methodId, + void* methodContext, + const UA_NodeId* objectId, + void* objectContext, + size_t inputSize, + const UA_Variant* input, + size_t outputSize, + UA_Variant* output) +{ + UA_String* inputStr = (UA_String*) input->data; + std::string out = "Hello!"; + + if (inputStr->length > 0) + { + std::string in = utils::ToStdString(*inputStr); + std::stringstream ss; + ss << out << " (R:" << in << ")"; + out = ss.str(); + } + + UA_String tmp = UA_STRING_ALLOC(out.c_str()); + UA_Variant_setScalarCopy(output, &tmp, &UA_TYPES[UA_TYPES_STRING]); + UA_String_clear(&tmp); + return UA_STATUSCODE_GOOD; +} + +/*SampleServerTest*/ + +void BaseClientTest::SetUp() +{ + testing::Test::SetUp(); + testHelper.startServer(); +} +void BaseClientTest::TearDown() +{ + testHelper.stop(); + testing::Test::TearDown(); +} + +std::string BaseClientTest::getServerUrl() const +{ + return testHelper.getServerUrl(); +} + +OpcUaClientPtr BaseClientTest::prepareAndConnectClient(int timeout) +{ + std::shared_ptr client = std::make_shared(getServerUrl()); + + if (timeout >= 0) + client->setTimeout(timeout); + + client->connect(); + return client; +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/tests/src/test_opcuaasyncexecthread.cpp b/shared/libraries/opcua/opcuaclient/tests/src/test_opcuaasyncexecthread.cpp new file mode 100644 index 0000000..05a34ba --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/tests/src/test_opcuaasyncexecthread.cpp @@ -0,0 +1,63 @@ +#include "gtest/gtest.h" + +#include "opcuaclient/opcuaasyncexecthread.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using OpcUaAsyncExecThreadTest = testing::Test; + +TEST_F(OpcUaAsyncExecThreadTest, Create) +{ + OpcUaAsyncExecThread asyncExecThread; +} + +TEST_F(OpcUaAsyncExecThreadTest, CreateAndRun) +{ + bool executed = false; + OpcUaAsyncExecThread asyncExecThread = std::thread([&executed]() { executed = true; }); +} + +TEST_F(OpcUaAsyncExecThreadTest, WaitOnReassign) +{ + bool executed = false; + OpcUaAsyncExecThread asyncExecThread = std::thread([&executed]() { + using namespace std::chrono_literals; + std::this_thread::sleep_for(50ms); + executed = true; + }); + asyncExecThread.reset(); + ASSERT_TRUE(executed); +} + +TEST_F(OpcUaAsyncExecThreadTest, WaitOnDestructor) +{ + bool executed = false; + { + OpcUaAsyncExecThread asyncExecThread = std::thread([&executed]() { + using namespace std::chrono_literals; + std::this_thread::sleep_for(50ms); + executed = true; + }); + } + ASSERT_TRUE(executed); +} + +TEST_F(OpcUaAsyncExecThreadTest, TwoThreads) +{ + bool executed1 = false; + bool executed2 = false; + + OpcUaAsyncExecThread asyncExecThread = std::thread([&executed1]() { + using namespace std::chrono_literals; + std::this_thread::sleep_for(50ms); + executed1 = true; + }); + + asyncExecThread = std::thread([&executed2]() { executed2 = true; }); + ASSERT_TRUE(executed1); + + asyncExecThread.reset(); + ASSERT_TRUE(executed2); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/tests/src/test_opcuaclient.cpp b/shared/libraries/opcua/opcuaclient/tests/src/test_opcuaclient.cpp new file mode 100644 index 0000000..0c8bc53 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/tests/src/test_opcuaclient.cpp @@ -0,0 +1,236 @@ +#include +#include +#include "opcuaclient/opcuaclient.h" +#include "opcuaservertesthelper.h" +#include "opcuashared/opcua.h" +#include "opcuashared/opcuacommon.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +#define ASSERT_EQ_STATUS(status, expectedStatus) ASSERT_EQ(status, (UA_StatusCode) expectedStatus) + +using OpcUaClientTest = BaseClientTest; + +static void lockThread(OpcUaClient& client, bool& locked) +{ + locked = client.getLock().try_lock(); + if (locked) + client.getLock().unlock(); +} + +static void TestLock(OpcUaClient& client, bool expectedResult) +{ + bool locked; + std::thread t1(lockThread, std::ref(client), std::ref(locked)); + t1.join(); + ASSERT_EQ(locked, expectedResult); +} + +TEST_F(OpcUaClientTest, Lock) +{ + OpcUaClient client(getServerUrl()); + + TestLock(client, true); + { + auto lockedClient = client.getLockedUaClient(); + TestLock(client, false); + ASSERT_NE(lockedClient.operator UA_Client*(), nullptr); + { + auto lockedClient1 = std::move(lockedClient); + ASSERT_EQ(lockedClient.operator UA_Client*(), nullptr); + ASSERT_NE(lockedClient1.operator UA_Client*(), nullptr); + + TestLock(client, false); + } + TestLock(client, true); + } + TestLock(client, true); +} + +TEST_F(OpcUaClientTest, Connect) +{ + OpcUaClient client(getServerUrl()); + + ASSERT_TRUE(client.connect()); + ASSERT_TRUE(client.isConnected()); + client.disconnect(); + ASSERT_FALSE(client.isConnected()); +} + +TEST_F_OPTIONAL(OpcUaClientTest, FirstConnectFails) +{ + testHelper.stop(); + + OpcUaClient client(getServerUrl()); + + client.setTimeout(500); + + ASSERT_FALSE(client.connect()); + ASSERT_FALSE(client.isConnected()); + + testHelper.startServer(); + + client.disconnect(); + ASSERT_TRUE(client.connect()); + ASSERT_TRUE(client.isConnected()); + + client.disconnect(); + ASSERT_FALSE(client.isConnected()); +} + +TEST_F(OpcUaClientTest, Timeout) +{ + OpcUaClient client(getServerUrl()); + + client.setTimeout(1234u); + ASSERT_EQ(client.getTimeout(), 1234u); + + client.connect(); + + client.setTimeout(1235u); + ASSERT_EQ(client.getTimeout(), 1235u); + + client.disconnect(); + + client.setTimeout(1236u); + ASSERT_EQ(client.getTimeout(), 1236u); +} + +TEST_F(OpcUaClientTest, CheckConnectedStatus) +{ + OpcUaClient client(getServerUrl()); + + client.connect(); + ASSERT_TRUE(client.isConnected()); + client.clear(); + ASSERT_FALSE(client.isConnected()); + + client.connect(); + client.disconnect(); + ASSERT_FALSE(client.isConnected()); +} + +TEST_F_OPTIONAL(OpcUaClientTest, ConnectTimeout) +{ + testHelper.stop(); + testHelper.setSessionTimeout(3000); + testHelper.startServer(); + + OpcUaClient client(getServerUrl()); + + ASSERT_TRUE(client.connect()); + ASSERT_TRUE(client.isConnected()); + + auto uaNode = OpcUaNodeId(1, ".d"); + ASSERT_TRUE(client.nodeExists(uaNode)); + + using namespace std::chrono_literals; + std::this_thread::sleep_for(70s); + + ASSERT_THROW(client.nodeExists(uaNode), OpcUaException); + + client.disconnect(); + ASSERT_TRUE(client.connect()); + ASSERT_TRUE(client.isConnected()); + + ASSERT_TRUE(client.nodeExists(uaNode)); + + client.disconnect(); + ASSERT_FALSE(client.isConnected()); +} + +TEST_F(OpcUaClientTest, ScheduleTimerTask) +{ + auto client = prepareAndConnectClient(); + + ASSERT_FALSE(client->timerTaskExists(1234)); + + std::promise promise; + bool executed = false; + auto ident1 = client->scheduleTimerTask(1, [&promise, &executed](const OpcUaClient& client, TimerTaskControl& control) { + if (!executed) + promise.set_value(); + executed = true; + }); + + ASSERT_TRUE(client->timerTaskExists(ident1)); + + IterateAndWaitForPromise(*client, promise.get_future()); // wait until task is executed at least once + + ASSERT_TRUE(client->timerTaskExists(ident1)); + + client->removeTimerTask(ident1); + + ASSERT_FALSE(client->timerTaskExists(ident1)); +} + +TEST_F(OpcUaClientTest, RemoveCurrentTimerTask) +{ + auto client = prepareAndConnectClient(); + + std::promise promise; + auto ident1 = client->scheduleTimerTask(1, [&promise](OpcUaClient& client, TimerTaskControl& control) { + control.terminateTimerTask(); + promise.set_value(); + }); + + IterateAndWaitForPromise(*client, promise.get_future()); // wait until task is executed at least once + + ASSERT_FALSE(client->timerTaskExists(ident1)); +} + +TEST_F(OpcUaClientTest, NodeExist) +{ + auto client = prepareAndConnectClient(); + + OpcUaNodeId uaNode(1, "hello.dewesoft"); + ASSERT_TRUE(client->nodeExists(uaNode)); + + uaNode = OpcUaNodeId(1, "f1"); + ASSERT_TRUE(client->nodeExists(uaNode)); + + uaNode = OpcUaNodeId(1, "unknown"); + ASSERT_FALSE(client->nodeExists(uaNode)); +} + +TEST_F(OpcUaClientTest, CallMethod) +{ + auto client = prepareAndConnectClient(); + + OpcUaVariant inputArg("Test"); + + auto callMethodResult = client->callMethod( + OpcUaCallMethodRequest(OpcUaNodeId(1, "hello.dewesoft"), OpcUaNodeId(UA_NS0ID_OBJECTSFOLDER), 1, inputArg.get())); + + ASSERT_EQ(callMethodResult->outputArgumentsSize, 1u); + ASSERT_EQ(OpcUaVariant(callMethodResult->outputArguments[0]).toString(), "Hello! (R:Test)"); +} + +TEST_F(OpcUaClientTest, CallMethodsWithCallback) +{ + auto client = prepareAndConnectClient(); + + std::vector callRequests; + std::string outputArgs; + + OpcUaVariant inputArg("Test"); + + callRequests.push_back(OpcUaCallMethodRequestWithCallback( + OpcUaNodeId(1, "hello.dewesoft"), + OpcUaNodeId(UA_NS0ID_OBJECTSFOLDER), + [&](const OpcUaCallMethodResult& callMethodResult) { + if (!callMethodResult.isStatusOK()) + throw std::runtime_error("call failed with status " + std::to_string(callMethodResult.getStatusCode())); + else if (!(callMethodResult.getOutputArgumentsSize() == 1 && callMethodResult.getOutputArgument(0).isString())) + throw std::runtime_error("First argument should be string"); + else + outputArgs = callMethodResult.getOutputArgument(0).toString(); + }, + 1, + inputArg.get())); + + ASSERT_NO_THROW(client->callMethods(callRequests)); + ASSERT_EQ(outputArgs, "Hello! (R:Test)"); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/tests/src/test_opcuanodefactory.cpp b/shared/libraries/opcua/opcuaclient/tests/src/test_opcuanodefactory.cpp new file mode 100644 index 0000000..928e4a4 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/tests/src/test_opcuanodefactory.cpp @@ -0,0 +1,108 @@ +#include +#include "opcuaservertesthelper.h" +#include +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +#if IGNORE_FOR_DEVELOPMENT <= 0 + +using OpcUaNodeFactoryTest = BaseClientTest; + +static OpcUaObject PrepareReferenceDescription(OpcUaNodeClass nodeClass, const std::string& name, const OpcUaNodeId& nodeId, const OpcUaNodeId& typeId) +{ + OpcUaObject desc; + desc->nodeClass = static_cast(nodeClass); + desc->browseName = UA_QUALIFIEDNAME_ALLOC(1, name.c_str()); + desc->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", name.c_str()); + desc->nodeId = UA_EXPANDEDNODEID_NODEID(nodeId.copyAndGetDetachedValue()); + desc->typeDefinition = UA_EXPANDEDNODEID_NODEID(typeId.copyAndGetDetachedValue()); + return desc; +} + +TEST_F_OPTIONAL(OpcUaNodeFactoryTest, Create) +{ + auto client = prepareAndConnectClient(); + ASSERT_NO_THROW(OpcUaNodeFactory factory(client)); +} + +TEST_F_OPTIONAL(OpcUaNodeFactoryTest, InstatinateObject) +{ + auto client = prepareAndConnectClient(); + OpcUaNodeFactory factory(client); + + auto referenceDescription = PrepareReferenceDescription(OpcUaNodeClass::Object, "f1", OpcUaNodeId(1, "f1"), OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE))); + + bool traverse; + auto node = factory.instantiateNode(*referenceDescription, OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER)), traverse); + ASSERT_NE(node, nullptr); + ASSERT_EQ(node->getBrowseName(), "f1"); + ASSERT_EQ(node->getDisplayName(), "f1"); + ASSERT_EQ(node->getNodeId(), OpcUaNodeId(1, "f1")); + + auto nodeObject = std::dynamic_pointer_cast(node); + ASSERT_NE(nodeObject, nullptr); +} + +TEST_F_OPTIONAL(OpcUaNodeFactoryTest, InstatinateVariable) +{ + auto client = prepareAndConnectClient(); + OpcUaNodeFactory factory(client); + + auto referenceDescription = PrepareReferenceDescription(OpcUaNodeClass::Variable, ".i32", OpcUaNodeId(1, ".i32"), OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_BASEVARIABLETYPE))); + + bool traverse; + auto node = factory.instantiateNode(*referenceDescription, OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER)), traverse); + ASSERT_NE(node, nullptr); + ASSERT_EQ(node->getBrowseName(), ".i32"); + ASSERT_EQ(node->getDisplayName(), ".i32"); + ASSERT_EQ(node->getNodeId(), OpcUaNodeId(1, ".i32")); + + auto nodeValue = std::dynamic_pointer_cast(node); + ASSERT_NE(nodeValue, nullptr); + ASSERT_EQ(nodeValue->getDataTypeNodeId(), UA_TYPES[UA_TYPES_INT32].typeId); +} + +TEST_F_OPTIONAL(OpcUaNodeFactoryTest, InstatinateMethod) +{ + auto client = prepareAndConnectClient(); + OpcUaNodeFactory factory(client); + + auto referenceDescription = PrepareReferenceDescription(OpcUaNodeClass::Method, "hello.dewesoft", OpcUaNodeId(1, "hello.dewesoft"), OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_METHODATTRIBUTES))); // TODO TYPES + + bool traverse; + auto node = factory.instantiateNode(*referenceDescription, OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER)), traverse); + ASSERT_NE(node, nullptr); + ASSERT_EQ(node->getBrowseName(), "hello.dewesoft"); + ASSERT_EQ(node->getDisplayName(), "hello.dewesoft"); + ASSERT_EQ(node->getNodeId(), OpcUaNodeId(1, "hello.dewesoft")); + + auto nodeMethod = std::dynamic_pointer_cast(node); + ASSERT_NE(nodeMethod, nullptr); + ASSERT_EQ(nodeMethod->inputParameters.size(), 1u); + ASSERT_EQ(nodeMethod->outputParameters.size(), 1u); +} + +TEST_F_OPTIONAL(OpcUaNodeFactoryTest, InstatinateDataType) +{ + auto client = prepareAndConnectClient(); + OpcUaNodeFactory factory(client); + + auto referenceDescription = PrepareReferenceDescription(OpcUaNodeClass::DataType, "Boolean", OpcUaNodeId(0, 1), OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE))); + + bool traverse; + auto node = factory.instantiateNode(*referenceDescription, OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER)), traverse); + ASSERT_NE(node, nullptr); + ASSERT_EQ(node->getBrowseName(), "Boolean"); + ASSERT_EQ(node->getDisplayName(), "Boolean"); + ASSERT_EQ(node->getNodeId(), OpcUaNodeId(0, 1)); + + auto dataType = std::dynamic_pointer_cast(node); + ASSERT_NE(dataType, nullptr); +} + +#endif + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/tests/src/test_opcuanodefactorybrowser.cpp b/shared/libraries/opcua/opcuaclient/tests/src/test_opcuanodefactorybrowser.cpp new file mode 100644 index 0000000..21497d6 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/tests/src/test_opcuanodefactorybrowser.cpp @@ -0,0 +1,60 @@ +#include + +#include "opcuashared/opcua.h" +#include "opcuashared/opcuacommon.h" +#include "opcuaservertesthelper.h" +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using OpcUaNodeFactoryBrowserTest = BaseClientTest; + +TEST_F_OPTIONAL(OpcUaNodeFactoryBrowserTest, Create) +{ + auto client = prepareAndConnectClient(); + auto nodeFactory = std::make_shared(client); + + ASSERT_NO_THROW(OpcUaNodeFactoryBrowser(nodeFactory, client)); +} + +TEST_F_OPTIONAL(OpcUaNodeFactoryBrowserTest, Browse) +{ + auto client = prepareAndConnectClient(); + auto nodeFactory = std::make_shared(client); + OpcUaNodeFactoryBrowser browser(nodeFactory, client); + browser.browseTree(OpcUaNodeId(1, "f1")); + + ASSERT_EQ(browser.getNodes().size(), 1u); + + auto node = browser.getNodes()[0]; + ASSERT_EQ(node->getBrowseName(), "f1.i"); + ASSERT_EQ(node->getNodeClass(), OpcUaNodeClass::Variable); + + auto nodeVariable = std::dynamic_pointer_cast(node); + ASSERT_NE(nodeVariable, nullptr); + ASSERT_EQ(nodeVariable->getDataTypeNodeId(), UA_TYPES[UA_TYPES_INT32].typeId); +} + +TEST_F_OPTIONAL(OpcUaNodeFactoryBrowserTest, BrowseDataTypes) +{ + auto client = prepareAndConnectClient(); + auto nodeFactory = std::make_shared(client); + OpcUaNodeFactoryBrowser browser(nodeFactory, client); + browser.browseTree(OpcUaNodeId(UA_NS0ID_BASEDATATYPE)); + + ASSERT_GE(browser.getNodes().size(), 16u); + + auto nodes = browser.getNodes(); + auto it = std::find_if(nodes.cbegin(), nodes.cend(), [](const OpcUaNodePtr& node) {return node->getBrowseName() == "Boolean"; }); + ASSERT_NE(it, nodes.cend()); + + const auto& booleanNode = *it; + + ASSERT_EQ(booleanNode->getBrowseName(), "Boolean"); + ASSERT_EQ(booleanNode->getDisplayName(), "Boolean"); + ASSERT_EQ(booleanNode->getNodeId(), OpcUaNodeId(0, 1)); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/tests/src/test_opcuataskprocessor.cpp b/shared/libraries/opcua/opcuaclient/tests/src/test_opcuataskprocessor.cpp new file mode 100644 index 0000000..4e06527 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/tests/src/test_opcuataskprocessor.cpp @@ -0,0 +1,195 @@ +#include + +#include +#include "opcuaclient/taskprocessor/opcuataskprocessor.h" +#include "opcuaservertesthelper.h" + +using namespace std::chrono_literals; + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using OpcUaTaskProcessorTest = BaseClientTest; + +static void TestRequest(OpcUaTaskProcessor& taskProcessor) +{ + std::exception_ptr exception; + taskProcessor.executeTask( + [&exception](OpcUaClient& client) + { + OpcUaNodeId uaNode(1, "hello.dewesoft"); + try + { + client.nodeExists(uaNode); + } + catch (const OpcUaException&) + { + exception = std::current_exception(); + } + }); + + if (exception) + std::rethrow_exception(exception); +} + +TEST_F(OpcUaTaskProcessorTest, Create) +{ + auto client = prepareAndConnectClient(); + OpcUaTaskProcessor taskProcessor(client); + + ASSERT_EQ(taskProcessor.getClient(), client); + + taskProcessor.start(); + + ASSERT_TRUE(taskProcessor.isConnected()); + + taskProcessor.stop(); +} + +TEST_F(OpcUaTaskProcessorTest, CreateAndStopInDestructor) +{ + auto client = prepareAndConnectClient(); + OpcUaTaskProcessor taskProcessor(client); + + taskProcessor.start(); +} + +TEST_F(OpcUaTaskProcessorTest, ExecuteTaskAwait) +{ + auto client = prepareAndConnectClient(); + OpcUaTaskProcessor taskProcessor(client); + + taskProcessor.start(); + + bool executed = false; + std::future future = taskProcessor.executeTaskAwait([&executed](const OpcUaClient& client) { executed = true; }); + + future.get(); + + ASSERT_TRUE(executed); + + taskProcessor.stop(); +} + +TEST_F(OpcUaTaskProcessorTest, ExecuteTask) +{ + auto client = prepareAndConnectClient(); + OpcUaTaskProcessor taskProcessor(client); + + taskProcessor.start(); + + bool executed = false; + taskProcessor.executeTask([&executed](const OpcUaClient& client) { executed = true; }); + + ASSERT_TRUE(executed); + + taskProcessor.stop(); +} + +TEST_F(OpcUaTaskProcessorTest, ExceptionInTask) +{ + auto client = prepareAndConnectClient(); + OpcUaTaskProcessor taskProcessor(client); + + taskProcessor.start(); + + ASSERT_THROW(taskProcessor.executeTask([](const OpcUaClient& client) { throw std::runtime_error("test exception"); }), + std::runtime_error); + + std::future future = + taskProcessor.executeTaskAwait([](const OpcUaClient& client) { throw std::runtime_error("test exception"); }); + + ASSERT_THROW(future.get(), std::runtime_error); + + bool executed = false; + taskProcessor.executeTask([&executed](const OpcUaClient& client) { executed = true; }); + + ASSERT_TRUE(executed); + + taskProcessor.stop(); +} + +TEST_F(OpcUaTaskProcessorTest, AddTaskInsideOfTask) // test for possible deadlock +{ + auto client = prepareAndConnectClient(); + OpcUaTaskProcessor taskProcessor(client); + + taskProcessor.start(); + + int number = 0; + taskProcessor.executeTask( + [&taskProcessor, &number](const OpcUaClient& client) + { + taskProcessor.executeTask([&number](const OpcUaClient& client) { number++; }); + number++; + }); + + ASSERT_EQ(number, 2); + + taskProcessor.stop(); +} + +TEST_F(OpcUaTaskProcessorTest, Disconnect) +{ + auto client = prepareAndConnectClient(); + OpcUaTaskProcessor taskProcessor(client); + + taskProcessor.start(); + + ASSERT_TRUE(taskProcessor.isConnected()); + + testHelper.stop(); + + ASSERT_THROW(TestRequest(taskProcessor), OpcUaException); + + ASSERT_FALSE(taskProcessor.isConnected()); + + taskProcessor.stop(); +} + +TEST_F(OpcUaTaskProcessorTest, SetTimeout) +{ + auto client = prepareAndConnectClient(); + OpcUaTaskProcessor taskProcessor(client); + + taskProcessor.start(); + + taskProcessor.setConnectionTimeout(1234u); + + uint32_t timeout{}; + taskProcessor.executeTask([&timeout](OpcUaClient& client) { timeout = client.getTimeout(); }); + + ASSERT_EQ(timeout, 1234u); + + taskProcessor.stop(); +} + +TEST_F(OpcUaTaskProcessorTest, AddTaskInsideOfTimerTask) +{ + auto client = prepareAndConnectClient(); + OpcUaTaskProcessor taskProcessor(client); + + taskProcessor.start(); + + std::promise promise; + int number = 0; + auto ident1 = client->scheduleTimerTask(1, + [&taskProcessor, &promise, &number](OpcUaClient& client, TimerTaskControl& control) + { + control.terminateTimerTask(); + + taskProcessor.executeTask([&number](const OpcUaClient& client) { number++; }); + number++; + + promise.set_value(); + }); + + ASSERT_NE(promise.get_future().wait_for(2s), std::future_status::timeout); // wait until task is executed + + ASSERT_EQ(number, 2); + + ASSERT_FALSE(client->timerTaskExists(ident1)); + + taskProcessor.stop(); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/tests/src/test_opcuatimertaskhelper.cpp b/shared/libraries/opcua/opcuaclient/tests/src/test_opcuatimertaskhelper.cpp new file mode 100644 index 0000000..6bb311e --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/tests/src/test_opcuatimertaskhelper.cpp @@ -0,0 +1,96 @@ +#include + +#include +#include "opcuaclient/opcuatimertaskhelper.h" + +#include "opcuaclient/taskprocessor/opcuataskprocessor.h" +#include "opcuaservertesthelper.h" + +using namespace daq::utils; +using namespace std::chrono_literals; + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using OpcUaTimerTaskHelperTest = BaseClientTest; + +TEST_F(OpcUaTimerTaskHelperTest, Create) +{ + OpcUaClientPtr client = std::make_unique(getServerUrl()); + client->connect(); + + OpcUaTaskProcessor taskProcessor(client); + taskProcessor.start(); + + std::promise promise; + std::atomic promiseIsSet = false; + OpcUaTimerTaskHelper timerTaskHelper(*client, 1, [&promise, &promiseIsSet](OpcUaClient& client) { + if (!promiseIsSet) + promise.set_value(); + promiseIsSet = true; + }); + + ASSERT_EQ(timerTaskHelper.getIntervalMs(), 1); + ASSERT_FALSE(timerTaskHelper.getTerminated()); + ASSERT_FALSE(timerTaskHelper.getStarted()); + + timerTaskHelper.start(); + + ASSERT_FALSE(timerTaskHelper.getTerminated()); + ASSERT_TRUE(timerTaskHelper.getStarted()); + + ASSERT_NE(promise.get_future().wait_for(2s), std::future_status::timeout); // wait until task is executed + + timerTaskHelper.terminate(); + + ASSERT_TRUE(timerTaskHelper.getTerminated()); + ASSERT_TRUE(timerTaskHelper.getStarted()); + + timerTaskHelper.stop(); + + ASSERT_FALSE(timerTaskHelper.getStarted()); + + taskProcessor.stop(); +} + +TEST_F(OpcUaTimerTaskHelperTest, ThrowExceptionInTask) +{ + OpcUaClientPtr client = std::make_unique(getServerUrl()); + client->connect(); + + OpcUaTaskProcessor taskProcessor(client); + taskProcessor.start(); + + std::promise promise; + std::atomic promiseIsSet = false; + OpcUaTimerTaskHelper timerTaskHelper(*client, 1, [&promise, &promiseIsSet](OpcUaClient& client) { + Finally finnaly([&promise, &promiseIsSet]() { + if (!promiseIsSet) + promise.set_value(); + promiseIsSet = true; + }); + + throw std::runtime_error("test error"); + }); + + ASSERT_EQ(timerTaskHelper.getIntervalMs(), 1); + ASSERT_FALSE(timerTaskHelper.getTerminated()); + ASSERT_FALSE(timerTaskHelper.getStarted()); + + timerTaskHelper.start(); + + ASSERT_FALSE(timerTaskHelper.getTerminated()); + ASSERT_TRUE(timerTaskHelper.getStarted()); + + ASSERT_NE(promise.get_future().wait_for(2s), std::future_status::timeout); // wait until task is executed + + timerTaskHelper.terminate(); + + ASSERT_TRUE(timerTaskHelper.getTerminated()); + ASSERT_TRUE(timerTaskHelper.getStarted()); + + timerTaskHelper.stop(); + + ASSERT_FALSE(timerTaskHelper.getStarted()); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/CMakeLists.txt b/shared/libraries/opcua/opcuaserver/CMakeLists.txt new file mode 100644 index 0000000..1692623 --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.2) +set_cmake_folder_context(TARGET_FOLDER_NAME server) +project(OpcUaServer CXX) + +if (POLICY CMP0076) + cmake_policy(SET CMP0076 NEW) +endif() + +add_subdirectory(src) + +if (OPENDAQ_ENABLE_TESTS) + add_subdirectory(tests) +endif() diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/common.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/common.h new file mode 100644 index 0000000..7be3140 --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/common.h @@ -0,0 +1,26 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "opcuashared/opcua.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaServer; +using OpcUaServerPtr = std::shared_ptr; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/event_attributes.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/event_attributes.h new file mode 100644 index 0000000..07dd9f2 --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/event_attributes.h @@ -0,0 +1,63 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +template <> +struct std::hash> +{ + std::size_t operator()(daq::opcua::OpcUaObject const& s) const noexcept + { + return UA_QualifiedName_hash(s.get()); + } +}; + +inline bool operator==(const daq::opcua::OpcUaObject& lhs, + const daq::opcua::OpcUaObject& rhs) +{ + return UA_QualifiedName_equal(lhs.get(), rhs.get()); +} + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class EventAttributes +{ +public: + EventAttributes(); + + using AttributesType = std::unordered_map, OpcUaObject>; + + const AttributesType& getAttributes() const; + + void setTime(UA_UtcTime time); + void setSeverity(UA_UInt16 eventSeverity); + + void setMessage(const std::string& message); + void setMessage(const char *locale, const char *text); + void setMessage(const OpcUaObject& message); + void setSourceName(const std::string& eventSource); + + void setAttribute(const OpcUaObject& attribute, const OpcUaObject& value); + void setAttribute(const std::string& attribute, const OpcUaObject& value); + +private: + AttributesType attributes; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/node_event_manager.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/node_event_manager.h new file mode 100644 index 0000000..3fdac1b --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/node_event_manager.h @@ -0,0 +1,173 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include "opcuaserver/opcuaserver.h" +#include "opcuaserver/server_event_manager.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class NodeEventManager; +using NodeEventManagerPtr = std::shared_ptr; + +struct NodeValueCallbackArgs; +using NodeValueCallback = std::function; + +class NodeEventManager +{ +public: + struct ReadArgs; + struct WriteArgs; + struct DataSourceReadArgs; + struct DataSourceWriteArgs; + struct MethodArgs; + + using ReadCallback = std::function; + using WriteCallback = std::function; + using DataSourceReadCallback = std::function; + using DataSourceWriteCallback = std::function; + using MethodCallback = std::function; + + NodeEventManager(const OpcUaNodeId& nodeId, OpcUaServerPtr& server); + + void onRead(ReadCallback callback); + void onWrite(WriteCallback callback); + void onDataSourceRead(DataSourceReadCallback callback); + void onDataSourceWrite(DataSourceWriteCallback callback); + void onMethodCall(MethodCallback callback); + void onDisplayNameChanged(DisplayNameChangedCallback callback); + +protected: + OpcUaNodeId nodeId; + OpcUaServerPtr server; + + WriteCallback writeCallback; + ReadCallback readCallback; + DataSourceWriteCallback dataSourceWriteCallback; + DataSourceReadCallback dataSourceReadCallback; + MethodCallback methodCallback; + +private: + static void OnWrite(UA_Server* server, + const UA_NodeId* sessionId, + void* sessionContext, + const UA_NodeId* nodeId, + void* nodeContext, + const UA_NumericRange* range, + const UA_DataValue* value); + + static void OnRead(UA_Server* server, + const UA_NodeId* sessionId, + void* sessionContext, + const UA_NodeId* nodeid, + void* nodeContext, + const UA_NumericRange* range, + const UA_DataValue* value); + + static UA_StatusCode OnDataSourceRead(UA_Server* server, + const UA_NodeId* sessionId, + void* sessionContext, + const UA_NodeId* nodeId, + void* nodeContext, + UA_Boolean includeSourceTimeStamp, + const UA_NumericRange* range, + UA_DataValue* value); + + static UA_StatusCode OnDataSourceWrite(UA_Server* server, + const UA_NodeId* sessionId, + void* sessionContext, + const UA_NodeId* nodeId, + void* nodeContext, + const UA_NumericRange* range, + const UA_DataValue* value); + + static UA_StatusCode OnMethod(UA_Server* server, + const UA_NodeId* sessionId, + void* sessionContext, + const UA_NodeId* methodId, + void* methodContext, + const UA_NodeId* objectId, + void* objectContext, + size_t inputSize, + const UA_Variant* input, + size_t outputSize, + UA_Variant* output); +}; + +struct NodeEventManager::ReadArgs +{ + UA_Server* server; + const UA_NodeId* sessionId; + void* sessionContext; + const UA_NodeId* nodeId; + void* nodeContext; + const UA_NumericRange* range; + const UA_DataValue* value; +}; + +struct NodeEventManager::WriteArgs +{ + UA_Server* server; + const UA_NodeId* sessionId; + void* sessionContext; + const UA_NodeId* nodeId; + void* nodeContext; + const UA_NumericRange* range; + const UA_DataValue* value; +}; + +struct NodeEventManager::DataSourceReadArgs +{ + UA_Server* server; + const UA_NodeId* sessionId; + void* sessionContext; + const UA_NodeId* nodeId; + void* nodeContext; + UA_Boolean includeSourceTimeStamp; + const UA_NumericRange* range; + UA_DataValue* value; +}; + +struct NodeEventManager::DataSourceWriteArgs +{ + UA_Server* server; + const UA_NodeId* sessionId; + void* sessionContext; + const UA_NodeId* nodeId; + void* nodeContext; + const UA_NumericRange* range; + const UA_DataValue* value; +}; + +struct NodeEventManager::MethodArgs +{ + UA_Server* server; + const UA_NodeId* sessionId; + void* sessionContext; + const UA_NodeId* methodId; + void* methodContext; + const UA_NodeId* objectId; + void* objectContext; + size_t inputSize; + const UA_Variant* input; + size_t outputSize; + UA_Variant* output; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h new file mode 100644 index 0000000..017fed5 --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h @@ -0,0 +1,100 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using CreateOptionalNodeCallback = std::function; + +class AddNodeParams +{ +public: + AddNodeParams(const OpcUaNodeId& requestedNewNodeId, const OpcUaNodeId& parentNodeId, const OpcUaNodeId& referenceTypeId); + void setBrowseName(const std::string& browseName); + + OpcUaNodeId requestedNewNodeId; + OpcUaNodeId parentNodeId; + OpcUaNodeId referenceTypeId; + OpcUaObject browseName{}; + void* nodeContext{}; +}; + +template +class GenericAddNodeParams : public AddNodeParams +{ +public: + GenericAddNodeParams(const OpcUaNodeId& requestedNewNodeId, const OpcUaNodeId& parentNodeId, const OpcUaNodeId& referenceTypeId, const T& defaultAttributes); + + OpcUaObject attr; + CreateOptionalNodeCallback addOptionalNodeCallback; +}; + +class AddObjectNodeParams : public GenericAddNodeParams +{ +public: + AddObjectNodeParams(const OpcUaNodeId& requestedNewNodeId); + AddObjectNodeParams(const OpcUaNodeId& requestedNewNodeId, const OpcUaNodeId& parentNodeId); + + OpcUaNodeId typeDefinition = OpcUaNodeId(UA_NS0ID_BASEOBJECTTYPE); +}; + +class AddVariableNodeParams : public GenericAddNodeParams +{ +public: + AddVariableNodeParams(const OpcUaNodeId& requestedNewNodeId); + AddVariableNodeParams(const OpcUaNodeId& requestedNewNodeId, const OpcUaNodeId& parentNodeId); + + void setDataType(const OpcUaNodeId& dataTypeId); + + OpcUaNodeId typeDefinition = OpcUaNodeId(UA_NS0ID_BASEDATAVARIABLETYPE); +}; + +class AddMethodNodeParams : public GenericAddNodeParams +{ +public: + AddMethodNodeParams(const OpcUaNodeId& requestedNewNodeId); + AddMethodNodeParams(const OpcUaNodeId& requestedNewNodeId, const OpcUaNodeId& parentNodeId); + ~AddMethodNodeParams(); + + UA_MethodCallback method{}; + size_t inputArgumentsSize{}; + UA_Argument* inputArguments{}; + size_t outputArgumentsSize{}; + UA_Argument* outputArguments{}; +}; + +class AddVariableTypeNodeParams : public GenericAddNodeParams +{ +public: + AddVariableTypeNodeParams(const OpcUaNodeId& requestedNewNodeId); + AddVariableTypeNodeParams(const OpcUaNodeId& requestedNewNodeId, const OpcUaNodeId& parentNodeId); + + OpcUaNodeId typeDefinition = OpcUaNodeId(UA_NS0ID_BASEDATAVARIABLETYPE); +}; + +struct AddObjectTypeNodeParams : public GenericAddNodeParams +{ + AddObjectTypeNodeParams(const OpcUaNodeId& requestedNewNodeId); + AddObjectTypeNodeParams(const OpcUaNodeId& requestedNewNodeId, const OpcUaNodeId& parentNodeId); +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h new file mode 100644 index 0000000..eb6e2f6 --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h @@ -0,0 +1,160 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaServer final : public daq::utils::ThreadEx +{ +public: + OpcUaServer(); + ~OpcUaServer(); + + static constexpr uint16_t OPCUA_DEFAULT_PORT = 4840; + + uint16_t& getPort(); + void setPort(uint16_t port); + + void setSecurityConfig(OpcUaServerSecurityConfig* config); + const OpcUaServerSecurityConfig* getSecurityConfig() const; + void prepare(); + bool isPrepared(); + + void start() override; + void stop() override; + + OpcUaServerNode getNode(const OpcUaNodeId& nodeId); + OpcUaServerObjectNode getRootNode(); + OpcUaServerObjectNode getObjectsNode(); + OpcUaServerObjectNode getTypesNode(); + OpcUaServerObjectNode getViewsNode(); + OpcUaServerObjectNode getObjectTypesNode(); + OpcUaServerObjectNode getVariableTypesNode(); + OpcUaServerObjectNode getDataTypesNode(); + OpcUaServerObjectNode getReferenceTypesNode(); + ServerEventManagerPtr getEventManager(); + + bool nodeExists(const OpcUaNodeId& nodeId); + bool nodeExists(const UA_NodeId& nodeId); + + OpcUaObject browse(const OpcUaObject& browseDescription); + + OpcUaNodeId addObjectNode(const AddObjectNodeParams& params); + OpcUaNodeId addVariableNode(const AddVariableNodeParams& params); + OpcUaNodeId addMethodNode(const AddMethodNodeParams& params); + OpcUaNodeId addObjectTypeNode(const AddObjectTypeNodeParams& params); + OpcUaNodeId addVariableTypeNode(const AddVariableTypeNodeParams& params); + + void triggerEvent(const OpcUaNodeId& eventType, const OpcUaNodeId& originNodeId, const EventAttributes& eventAttributes); + + void deleteNode(const OpcUaNode& node); + void deleteNode(const OpcUaNodeId& nodeId); + + OpcUaNodeClass readNodeClass(const OpcUaNodeId& nodeId) const; + OpcUaObject readBrowseName(const OpcUaNodeId& nodeId) const; + std::string readBrowseNameString(const OpcUaNodeId& nodeId) const; + + void setDisplayName(const OpcUaNodeId& nodeId, const OpcUaObject& localizedText); + void setDisplayName(const OpcUaNodeId& nodeId, const std::string& text); + OpcUaObject readDisplayName(const OpcUaNodeId& nodeId) const; + + void writeValue(const OpcUaNodeId& nodeId, const OpcUaVariant& var); + OpcUaVariant readValue(const OpcUaNodeId& nodeId); + OpcUaNodeId readDataType(const OpcUaNodeId& typeNodeId); + + void addReference(const OpcUaNodeId& sourceId, const OpcUaNodeId& refTypeId, const OpcUaNodeId& targetId, bool isForward = true); + void deleteReference(const OpcUaNodeId& sourceId, const OpcUaNodeId& refTypeId, const OpcUaNodeId& targetId, bool isForward = true); + bool referenceExists(const OpcUaNodeId& sourceId, const OpcUaNodeId& refTypeId, const OpcUaNodeId& targetId, bool isForward = true); + + // session context + typedef std::function CreateSessionContextCallbackType; + CreateSessionContextCallbackType createSessionContextCallback; + typedef std::function DeleteSessionContextCallbackType; + DeleteSessionContextCallbackType deleteSessionContextCallback; + + std::unordered_set& getSessions(); // use only in server thread + + void* createSessionContextCallbackImp(const OpcUaNodeId& sessionId); + void deleteSessionContextCallbackImp(void* context); + + // TODO move locking to model + bool passwordLock(const std::string& password); + bool passwordUnlock(const std::string& password); + bool isPasswordLocked(); + + UA_Server* getUaServer() const noexcept; + +protected: + void execute() override; + +private: + UA_Server* createServer(); + void prepareServer(); + void prepareServerMinimal(UA_ServerConfig* config); + void prepareServerSecured(UA_ServerConfig* config); + void prepareEncryption(UA_ServerConfig* config); + void prepareAccessControl(UA_ServerConfig* config); + void configureAppUri(UA_ServerConfig* config); + void shutdownServer(); + + static UA_StatusCode activateSession(UA_Server* server, + UA_AccessControl* ac, + const UA_EndpointDescription* endpointDescription, + const UA_ByteString* secureChannelRemoteCertificate, + const UA_NodeId* sessionId, + const UA_ExtensionObject* userIdentityToken, + void** sessionContext); + static void closeSession(UA_Server* server, UA_AccessControl* ac, const UA_NodeId* sessionId, void* sessionContext); + static UA_StatusCode authenticateUser(OpcUaServer* serverInstance, const UA_ExtensionObject* userIdentityToken); + + // missing UA_Server void* member workaround... + static OpcUaServer* getServer(UA_Server* server); + + UA_StatusCode (*activateSession_default)(UA_Server* server, + UA_AccessControl* ac, + const UA_EndpointDescription* endpointDescription, + const UA_ByteString* secureChannelRemoteCertificate, + const UA_NodeId* sessionId, + const UA_ExtensionObject* userIdentityToken, + void** sessionContext){}; + + OpcUaServerLock serverLock; + uint16_t port{OPCUA_DEFAULT_PORT}; + UA_Server* server{}; + std::optional securityConfig; + std::unordered_set sessionContext; + ServerEventManagerPtr eventManager; + static std::mutex serverMappingMutex; + static std::map serverMapping; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserverlock.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserverlock.h new file mode 100644 index 0000000..533c067 --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserverlock.h @@ -0,0 +1,52 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "opcuashared/opcua.h" +#include "opcuashared/opcuanodeid.h" +#include "opcuashared/opcuacommon.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaServerLock +{ +public: + OpcUaServerLock(); + ~OpcUaServerLock(); + + bool canControlAcq(const OpcUaNodeId& sessionId); + + bool passwordLock(const std::string& password, const OpcUaNodeId& sessionId = OpcUaNodeId()); + bool passwordUnlock(const std::string& password, const OpcUaNodeId& sessionId = OpcUaNodeId()); + bool isPasswordLocked(); + + bool hasConfigurationControlLock(const OpcUaNodeId& sessionId) const; + void refuseConfigurationControlLock(const OpcUaNodeId& sessionId); + bool lockConfigurationControl(const OpcUaNodeId& sessionId, const std::chrono::seconds timeout); + + bool hasActiveConfigurationControlLock() const; + +private: + bool hasConfigurationControlAccess(const OpcUaNodeId& sessionId) const; + bool canEditPasswordLock(const OpcUaNodeId& sessionId); + + std::string password; + + OpcUaNodeId configurationControlLockSessionId; + utils::DurationTimeStamp configurationControlLockValidTo; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernode.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernode.h new file mode 100644 index 0000000..a971fbf --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernode.h @@ -0,0 +1,143 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +// forward declaration +class OpcUaServer; + +class OpcUaServerObjectNode; +class OpcUaServerVariableNode; +class OpcUaServerMethodNode; +class OpcUaServerViewNode; + +class OpcUaServerDataTypeNode; +class OpcUaServerObjectTypeNode; +class OpcUaServerVariableTypeNode; +class OpcUaServerReferenceTypeNode; +class OpcUaServerEventTypeNode; + +class OpcUaServerNode +{ +public: + OpcUaServerNode(OpcUaServer& server, const OpcUaNodeId& nodeId); + virtual ~OpcUaServerNode() = default; + + OpcUaNodeId getNodeId() const; + + OpcUaNodeClass getNodeClass(); + OpcUaObject getBrowseName(); + + void setDisplayName(const std::string& displayName); + OpcUaObject getDisplayName(); + + std::vector> browse( + const OpcUaNodeId& referenceTypeId, + bool includeSubtypes = true, + OpcUaNodeClass nodeClassMask = OpcUaNodeClass::All, + UA_BrowseDirection browseDirection = UA_BrowseDirection::UA_BROWSEDIRECTION_FORWARD); + std::vector> browseChildNodes(); + std::unique_ptr getChildNode(const OpcUaObject& qualifiedName); + + OpcUaServerObjectNode addObject(AddObjectNodeParams& params); + OpcUaServerObjectNode addObject(const OpcUaNodeId& id, const std::string& browseName); + OpcUaServerVariableNode addVariable(AddVariableNodeParams& params); + OpcUaServerVariableNode addVariable(const OpcUaNodeId& id, const std::string& browseName); + + void remove(); + +protected: + OpcUaServer& server; + OpcUaNodeId nodeId; +}; + +class OpcUaServerObjectNode : public OpcUaServerNode +{ +public: + using OpcUaServerNode::OpcUaServerNode; // inherit constructors +}; + +class OpcUaServerVariableNode : public OpcUaServerNode +{ +public: + using OpcUaServerNode::OpcUaServerNode; // inherit constructors + + template + void write(Arg&& arg) + { + OpcUaVariant var; + var.setScalar(std::forward(arg)); + writeVariantToServer(var); + } + + template + T read() + { + OpcUaVariant var = readVariantFromServer(); + return var.readScalar(); + } + +private: + void writeVariantToServer(const OpcUaVariant& var); + OpcUaVariant readVariantFromServer(); +}; + +class OpcUaServerMethodNode : public OpcUaServerNode +{ +public: + using OpcUaServerNode::OpcUaServerNode; // inherit constructors +}; + +class OpcUaServerViewNode : public OpcUaServerNode +{ +public: + using OpcUaServerNode::OpcUaServerNode; // inherit constructors +}; + +class OpcUaServerDataTypeNode : public OpcUaServerNode +{ +public: + using OpcUaServerNode::OpcUaServerNode; // inherit constructors +}; + +class OpcUaServerObjectTypeNode : public OpcUaServerNode +{ +public: + using OpcUaServerNode::OpcUaServerNode; // inherit constructors +}; + +class OpcUaServerVariableTypeNode : public OpcUaServerNode +{ +public: + using OpcUaServerNode::OpcUaServerNode; // inherit constructors +}; + +class OpcUaServerReferenceTypeNode : public OpcUaServerNode +{ +public: + using OpcUaServerNode::OpcUaServerNode; // inherit constructors +}; + +} // namespace opcua diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernodefactory.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernodefactory.h new file mode 100644 index 0000000..c956006 --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernodefactory.h @@ -0,0 +1,37 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaServerNodeFactory +{ +public: + OpcUaServerNodeFactory(OpcUaServer& server); + + std::unique_ptr createServerNode(const OpcUaNodeId& nodeId); + std::unique_ptr createServerNode(const OpcUaNodeId& nodeId, OpcUaNodeClass nodeClass); + std::unique_ptr createServerNode(const OpcUaNodeId& nodeId, UA_NodeClass nodeClass); + +protected: + OpcUaServer& server; +}; + +} // namespace opcua diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuasession.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuasession.h new file mode 100644 index 0000000..9cd0826 --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuasession.h @@ -0,0 +1,52 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include "opcuashared/opcuanodeid.h" +#include "opcuaserver/opcuaserverlock.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaSession; +using OpcUaSessionPtr = std::shared_ptr; + +class OpcUaSession +{ +public: + explicit OpcUaSession(const OpcUaNodeId& sessionId, OpcUaServerLock* serverLock); + ~OpcUaSession(); + + bool canControlAcq(); + + bool hasConfigurationControlLock() const; + bool lockConfigurationControl(std::chrono::seconds timeout); + void refuseConfigurationControlLock(); + + bool passwordLock(const std::string& password); + bool passwordUnlock(const std::string& password); + + void setConfigurationLockTokenId(const OpcUaNodeId& configurationLockTokenId); + const OpcUaNodeId& getConfigurationLockTokenId() const; + +private: + OpcUaNodeId sessionId; + OpcUaServerLock* serverLock; + OpcUaNodeId configurationLockTokenId; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuataskqueue.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuataskqueue.h new file mode 100644 index 0000000..1a90c64 --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuataskqueue.h @@ -0,0 +1,44 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaTaskQueue +{ +public: + static constexpr unsigned int infinity = 0; + using Function = std::function; + + void push(Function&& func); + bool pop(Function& func); + bool pop(Function& func, unsigned int timeout_ms); + + void processTaskQueue(); + +private: + std::mutex mutex_; + std::condition_variable cv_; + std::deque q_; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuatmstypes.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuatmstypes.h new file mode 100644 index 0000000..3b51c8e --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuatmstypes.h @@ -0,0 +1,31 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include + +#include "opcuashared/opcua.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +void addTmsTypes(UA_Server *server); + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/server_event_manager.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/server_event_manager.h new file mode 100644 index 0000000..915c71e --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/server_event_manager.h @@ -0,0 +1,61 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "opcuaserver/common.h" +#include "opcuaserver/opcuaservernode.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class ServerEventManager; +using ServerEventManagerPtr = std::shared_ptr; + +using CreatOptionalNodeCallback = std::function; +using DisplayNameChangedCallback = std::function& name)>; + +class ServerEventManager +{ +public: + ServerEventManager(const OpcUaServerPtr& server); + ServerEventManager(OpcUaServer* server); + + void registerEvents(); + + void onCreateOptionalNode(const CreatOptionalNodeCallback& callback); + + void onDisplayNameChanged(const OpcUaNodeId& nodeId, const DisplayNameChangedCallback& callback); + void removeOnDisplayNameChanged(const OpcUaNodeId& nodeId); + +private: + OpcUaServer* server; + CreatOptionalNodeCallback createOptionalNodeCallback; + std::unordered_map displayNameCallbacks; + + UA_Boolean triggerCreateOptionalNode(const UA_NodeId* nodeId); + void triggerDisplayNameChanged(const UA_NodeId* nodeId, UA_LocalizedText* name); + + static UA_Boolean CreateOptionalNode(UA_Server* server, + const UA_NodeId* sessionId, + void* sessionContext, + const UA_NodeId* sourceNodeId, + const UA_NodeId* targetParentNodeId, + const UA_NodeId* referenceTypeId); + + static void DisplayNameChanged(UA_Server* server, UA_NodeId* nodeId, UA_LocalizedText* newDisplayName); +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/src/CMakeLists.txt b/shared/libraries/opcua/opcuaserver/src/CMakeLists.txt new file mode 100644 index 0000000..e7723f3 --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/src/CMakeLists.txt @@ -0,0 +1,61 @@ +SET(MODULE_NAME opcuaserver) + +set(SOURCE_CPPS opcuaserver.cpp + opcuaserverlock.cpp + opcuasession.cpp + opcuataskqueue.cpp + opcuaaddnodeparams.cpp + opcuatmstypes.cpp + node_event_manager.cpp + opcuaservernode.cpp + opcuaservernodefactory.cpp + event_attributes.cpp + server_event_manager.cpp +) + +set(SOURCE_HEADERS common.h + opcuaserver.h + opcuaserverlock.h + opcuasession.h + opcuataskqueue.h + opcuatmstypes.h + opcuaaddnodeparams.h + node_event_manager.h + opcuaservernode.h + opcuaservernodefactory.h + event_attributes.h + server_event_manager.h +) + +set(INCLUDE_DIR ../include/${MODULE_NAME}) + +prepend_include(${INCLUDE_DIR} SOURCE_HEADERS) + +set(ALL_SOURCES ${SOURCE_CPPS} + ${SOURCE_HEADERS}) + +set(SOURCE_FILES ${ALL_SOURCES}) + +add_library(${MODULE_NAME} STATIC ${ALL_SOURCES}) +add_library(${SDK_TARGET_NAMESPACE}::${MODULE_NAME} ALIAS ${MODULE_NAME}) + +target_include_directories(${MODULE_NAME} PUBLIC $ + $ +) + +target_link_libraries(${MODULE_NAME} PUBLIC daq::opcuashared + daq::opendaq_utils + PRIVATE daq::opcua_tms_types +) + +set_target_properties(${MODULE_NAME} PROPERTIES PUBLIC_HEADER "${SOURCE_HEADERS}") + +if(BUILD_64Bit) + set_target_properties(${MODULE_NAME} PROPERTIES OUTPUT_NAME "${MODULE_NAME}64") +endif() + +if(BUILD_64Bit OR BUILD_ARM) + set_target_properties(${MODULE_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON) +else() + set_target_properties(${MODULE_NAME} PROPERTIES POSITION_INDEPENDENT_CODE OFF) +endif() \ No newline at end of file diff --git a/shared/libraries/opcua/opcuaserver/src/event_attributes.cpp b/shared/libraries/opcua/opcuaserver/src/event_attributes.cpp new file mode 100644 index 0000000..6d43aae --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/src/event_attributes.cpp @@ -0,0 +1,63 @@ +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +EventAttributes::EventAttributes() +{ +} + +void EventAttributes::setTime(UA_UtcTime time) +{ + OpcUaVariant variant; + variant.setScalar(time); + setAttribute("Time", variant); +} + +void EventAttributes::setSeverity(UA_UInt16 eventSeverity) +{ + OpcUaVariant variant; + variant.setScalar(eventSeverity); + setAttribute("Severity", variant); +} + +void EventAttributes::setMessage(const std::string& message) +{ + setMessage("", message.c_str()); +} + +void EventAttributes::setMessage(const char* locale, const char* text) +{ + OpcUaObject message = UA_LOCALIZEDTEXT_ALLOC(locale, text); + setMessage(message); +} + +void EventAttributes::setMessage(const OpcUaObject& message) +{ + OpcUaVariant variant; + variant.setScalar(*message); + setAttribute("Message", variant); +} + +void EventAttributes::setSourceName(const std::string& eventSource) +{ + OpcUaVariant variant(eventSource.c_str()); + setAttribute("SourceName", variant); +} + +void EventAttributes::setAttribute(const std::string& attribute, const OpcUaObject& value) +{ + setAttribute(UA_QUALIFIEDNAME_ALLOC(0, attribute.c_str()), value); +} + +void EventAttributes::setAttribute(const OpcUaObject& attribute, const OpcUaObject& value) +{ + attributes[attribute] = value; +} + +const EventAttributes::AttributesType& EventAttributes::getAttributes() const +{ + return attributes; +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/src/node_event_manager.cpp b/shared/libraries/opcua/opcuaserver/src/node_event_manager.cpp new file mode 100644 index 0000000..167cbb0 --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/src/node_event_manager.cpp @@ -0,0 +1,187 @@ +#include "opcuaserver/node_event_manager.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +NodeEventManager::NodeEventManager(const OpcUaNodeId& nodeId, OpcUaServerPtr& server) + : nodeId(nodeId) + , server(server) +{ + UA_Server_setNodeContext(server->getUaServer(), *nodeId, this); +} + +void NodeEventManager::onRead(ReadCallback callback) +{ + readCallback = std::move(callback); + + UA_ValueCallback valueCallback; + UA_Server_getVariableNode_valueCallback(server->getUaServer(), *nodeId, &valueCallback); + valueCallback.onRead = OnRead; + UA_Server_setVariableNode_valueCallback(server->getUaServer(), *nodeId, valueCallback); +} + +void NodeEventManager::onWrite(WriteCallback callback) +{ + writeCallback = std::move(callback); + + UA_ValueCallback valueCallback; + + UA_Server_getVariableNode_valueCallback(server->getUaServer(), *nodeId, &valueCallback); + valueCallback.onWrite = OnWrite; + UA_Server_setVariableNode_valueCallback(server->getUaServer(), *nodeId, valueCallback); +} + +void NodeEventManager::onDataSourceRead(DataSourceReadCallback callback) +{ + dataSourceReadCallback = std::move(callback); + + UA_DataSource dataSource; + UA_Server_getVariableNode_dataSource(server->getUaServer(), *nodeId, &dataSource); + dataSource.read = OnDataSourceRead; + UA_Server_setVariableNode_dataSource(server->getUaServer(), *nodeId, dataSource); +} + +void NodeEventManager::onDataSourceWrite(DataSourceWriteCallback callback) +{ + dataSourceWriteCallback = std::move(callback); + + UA_DataSource dataSource; + UA_Server_getVariableNode_dataSource(server->getUaServer(), *nodeId, &dataSource); + dataSource.write = OnDataSourceWrite; + UA_Server_setVariableNode_dataSource(server->getUaServer(), *nodeId, dataSource); +} + +void NodeEventManager::onMethodCall(MethodCallback callback) +{ + methodCallback = std::move(callback); + + UA_Server_setMethodNodeCallback(server->getUaServer(), *nodeId, OnMethod); +} + +void NodeEventManager::onDisplayNameChanged(DisplayNameChangedCallback callback) +{ + server->getEventManager()->onDisplayNameChanged(nodeId, callback); +} + +// c-style callback, required by open62541 interface + +void NodeEventManager::OnWrite(UA_Server* server, + const UA_NodeId* sessionId, + void* sessionContext, + const UA_NodeId* nodeId, + void* nodeContext, + const UA_NumericRange* range, + const UA_DataValue* value) +{ + auto manager = (NodeEventManager*) nodeContext; + + WriteArgs args; + args.server = server; + args.sessionId = sessionId; + args.sessionContext = sessionContext; + args.nodeId = nodeId; + args.nodeContext = nodeContext; + args.range = range; + args.value = value; + + manager->writeCallback(args); +} + +void NodeEventManager::OnRead(UA_Server* server, + const UA_NodeId* sessionId, + void* sessionContext, + const UA_NodeId* nodeId, + void* nodeContext, + const UA_NumericRange* range, + const UA_DataValue* value) +{ + auto manager = (NodeEventManager*) nodeContext; + + ReadArgs args; + args.server = server; + args.sessionId = sessionId; + args.sessionContext = sessionContext; + args.nodeId = nodeId; + args.nodeContext = nodeContext; + args.range = range; + args.value = value; + + manager->readCallback(args); +} + +UA_StatusCode NodeEventManager::OnDataSourceRead(UA_Server* server, + const UA_NodeId* sessionId, + void* sessionContext, + const UA_NodeId* nodeId, + void* nodeContext, + UA_Boolean includeSourceTimeStamp, + const UA_NumericRange* range, + UA_DataValue* value) +{ + auto manager = (NodeEventManager*) nodeContext; + + DataSourceReadArgs args; + args.server = server; + args.sessionId = sessionId; + args.sessionContext = sessionContext; + args.nodeId = nodeId; + args.nodeContext = nodeContext; + args.includeSourceTimeStamp = includeSourceTimeStamp; + args.range = range; + args.value = value; + + return manager->dataSourceReadCallback(args); +} + +UA_StatusCode NodeEventManager::OnDataSourceWrite(UA_Server* server, + const UA_NodeId* sessionId, + void* sessionContext, + const UA_NodeId* nodeId, + void* nodeContext, + const UA_NumericRange* range, + const UA_DataValue* value) +{ + auto manager = (NodeEventManager*) nodeContext; + + DataSourceWriteArgs args; + args.server = server; + args.sessionId = sessionId; + args.sessionContext = sessionContext; + args.nodeId = nodeId; + args.nodeContext = nodeContext; + args.range = range; + args.value = value; + + return manager->dataSourceWriteCallback(args); +} + +UA_StatusCode NodeEventManager::OnMethod(UA_Server* server, + const UA_NodeId* sessionId, + void* sessionContext, + const UA_NodeId* methodId, + void* methodContext, + const UA_NodeId* objectId, + void* objectContext, + size_t inputSize, + const UA_Variant* input, + size_t outputSize, + UA_Variant* output) +{ + auto manager = (NodeEventManager*) methodContext; + + MethodArgs args; + args.server = server; + args.sessionId = sessionId; + args.sessionContext = sessionContext; + args.methodId = methodId; + args.methodContext = methodContext; + args.objectId = objectId; + args.objectContext = objectContext; + args.inputSize = inputSize; + args.input = input; + args.outputSize = outputSize; + args.output = output; + + return manager->methodCallback(args); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/src/opcuaaddnodeparams.cpp b/shared/libraries/opcua/opcuaserver/src/opcuaaddnodeparams.cpp new file mode 100644 index 0000000..c2b7df5 --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/src/opcuaaddnodeparams.cpp @@ -0,0 +1,109 @@ +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +/*AddNodeParams*/ + +AddNodeParams::AddNodeParams(const OpcUaNodeId& requestedNewNodeId, const OpcUaNodeId& parentNodeId, const OpcUaNodeId& referenceTypeId) + : requestedNewNodeId(requestedNewNodeId) + , parentNodeId(parentNodeId) + , referenceTypeId(referenceTypeId) +{ +} + +void AddNodeParams::setBrowseName(const std::string& browseName) +{ + this->browseName = UA_QUALIFIEDNAME_ALLOC(0, browseName.c_str()); +} + +/*GenericAddNodeParams*/ + +template +GenericAddNodeParams::GenericAddNodeParams(const OpcUaNodeId& requestedNewNodeId, + const OpcUaNodeId& parentNodeId, + const OpcUaNodeId& referenceTypeId, + const T& defaultAttributes) + : AddNodeParams(requestedNewNodeId, parentNodeId, referenceTypeId) + , attr(defaultAttributes) +{ +} + +/*AddObjectNodeParams*/ + +AddObjectNodeParams::AddObjectNodeParams(const OpcUaNodeId& requestedNewNodeId) + : AddObjectNodeParams(requestedNewNodeId, OpcUaNodeId()) +{ +} + +AddObjectNodeParams::AddObjectNodeParams(const OpcUaNodeId& requestedNewNodeId, const OpcUaNodeId& parentNodeId) + : GenericAddNodeParams( + requestedNewNodeId, parentNodeId, OpcUaNodeId(UA_NS0ID_HASCOMPONENT), UA_ObjectAttributes_default) +{ +} + +/*AddVariableNodeParams*/ + +AddVariableNodeParams::AddVariableNodeParams(const OpcUaNodeId& requestedNewNodeId) + : AddVariableNodeParams(requestedNewNodeId, OpcUaNodeId()) +{ +} + +AddVariableNodeParams::AddVariableNodeParams(const OpcUaNodeId& requestedNewNodeId, const OpcUaNodeId& parentNodeId) + : GenericAddNodeParams( + requestedNewNodeId, parentNodeId, OpcUaNodeId(UA_NS0ID_HASPROPERTY), UA_VariableAttributes_default) +{ +} + +void AddVariableNodeParams::setDataType(const OpcUaNodeId& dataTypeId) +{ + attr->dataType = *dataTypeId; +} + +/*AddMethodNodeParams*/ + +AddMethodNodeParams::AddMethodNodeParams(const OpcUaNodeId& requestedNewNodeId) + : AddMethodNodeParams(requestedNewNodeId, OpcUaNodeId()) +{ +} + +AddMethodNodeParams::AddMethodNodeParams(const OpcUaNodeId& requestedNewNodeId, const OpcUaNodeId& parentNodeId) + : GenericAddNodeParams( + requestedNewNodeId, parentNodeId, OpcUaNodeId(UA_NS0ID_HASPROPERTY), UA_MethodAttributes_default) +{ +} + +AddMethodNodeParams::~AddMethodNodeParams() +{ + if(outputArguments) + UA_Array_delete(outputArguments, outputArgumentsSize, GetUaDataType()); + if(inputArguments) + UA_Array_delete(inputArguments, inputArgumentsSize, GetUaDataType()); +} + +/*AddVariableTypeNodeParams*/ + +AddVariableTypeNodeParams::AddVariableTypeNodeParams(const OpcUaNodeId& requestedNewNodeId) + : AddVariableTypeNodeParams(requestedNewNodeId, OpcUaNodeId()) +{ +} + +AddVariableTypeNodeParams::AddVariableTypeNodeParams(const OpcUaNodeId& requestedNewNodeId, const OpcUaNodeId& parentNodeId) + : GenericAddNodeParams( + requestedNewNodeId, parentNodeId, OpcUaNodeId(UA_NS0ID_HASSUBTYPE), UA_VariableTypeAttributes_default) +{ +} + +/*AddObjectTypeNodeParams*/ + +AddObjectTypeNodeParams::AddObjectTypeNodeParams(const OpcUaNodeId& requestedNewNodeId) + : AddObjectTypeNodeParams(requestedNewNodeId, OpcUaNodeId()) +{ +} + +AddObjectTypeNodeParams::AddObjectTypeNodeParams(const OpcUaNodeId& requestedNewNodeId, const OpcUaNodeId& parentNodeId) + : GenericAddNodeParams( + requestedNewNodeId, parentNodeId, OpcUaNodeId(UA_NS0ID_HASSUBTYPE), UA_ObjectTypeAttributes_default) +{ +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp b/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp new file mode 100644 index 0000000..94cf675 --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp @@ -0,0 +1,609 @@ +#include +#include +#include +#include +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaServer::OpcUaServer() + : eventManager(std::make_shared(this)) +{ + setPort(OPCUA_DEFAULT_PORT); + createSessionContextCallback = [this](const OpcUaNodeId& sessionId) { return createSessionContextCallbackImp(sessionId); }; + deleteSessionContextCallback = [this](void* context) { deleteSessionContextCallbackImp(context); }; +} + +void* OpcUaServer::createSessionContextCallbackImp(const OpcUaNodeId& sessionId) +{ + return new OpcUaSession(sessionId, &serverLock); +} + +void OpcUaServer::deleteSessionContextCallbackImp(void* context) +{ + delete static_cast(context); +} + +std::unordered_set& OpcUaServer::getSessions() +{ + return sessionContext; +} + +OpcUaServer::~OpcUaServer() +{ + OpcUaServer::stop(); +} + +uint16_t& OpcUaServer::getPort() +{ + return port; +} + +void OpcUaServer::setPort(uint16_t port) +{ + this->port = port; +} + +void OpcUaServer::setSecurityConfig(OpcUaServerSecurityConfig* config) +{ + if (config == nullptr) + this->securityConfig.reset(); + else + this->securityConfig = *config; +} + +const OpcUaServerSecurityConfig* OpcUaServer::getSecurityConfig() const +{ + return this->securityConfig.has_value() ? &this->securityConfig.value() : nullptr; +} + +void OpcUaServer::start() +{ + if (getStarted()) + throw OpcUaException(UA_STATUSCODE_BADINVALIDSTATE, "Thread is already started."); + + if (!isPrepared()) + prepare(); + + UA_StatusCode retval = UA_Server_run_startup(server); + CheckStatusCodeException(retval, "Failed to start server"); + + ThreadEx::start(); +} + +void OpcUaServer::stop() +{ + ThreadEx::stop(); + shutdownServer(); +} + +void OpcUaServer::prepare() +{ + try + { + if (getStarted()) + throw OpcUaException(UA_STATUSCODE_BADINVALIDSTATE, "Server is running"); + + if (isPrepared()) + shutdownServer(); + + prepareServer(); + + std::lock_guard guard(serverMappingMutex); + serverMapping[server] = this; + } + catch (const OpcUaException&) + { + shutdownServer(); + throw; + } +} + +bool OpcUaServer::isPrepared() +{ + return server != nullptr; +} + +UA_Server* OpcUaServer::createServer() +{ + UA_ServerConfig config; + memset(&config, 0, sizeof(UA_ServerConfig)); + config.logger = UA_Log_Stdout_withLevel(UA_LOGLEVEL_WARNING); + UA_Nodestore_HashMap(&config.nodestore); + return UA_Server_newWithConfig(&config); +} + +void OpcUaServer::prepareServer() +{ + server = createServer(); + UA_ServerConfig* config = UA_Server_getConfig(server); + + if (!securityConfig.has_value()) + prepareServerMinimal(config); + else + prepareServerSecured(config); + + addTmsTypes(server); + activateSession_default = config->accessControl.activateSession; + config->accessControl.activateSession = activateSession; + config->accessControl.closeSession = closeSession; + eventManager->registerEvents(); +} + +void OpcUaServer::prepareServerMinimal(UA_ServerConfig* config) +{ + UA_StatusCode retval = UA_ServerConfig_setMinimal(config, getPort(), nullptr); + CheckStatusCodeException(retval, "Failed to configure server minimal."); +} + +void OpcUaServer::prepareServerSecured(UA_ServerConfig* config) +{ + securityConfig->validate(); + + if (!securityConfig->hasCertificate()) + prepareServerMinimal(config); + else + prepareEncryption(config); + + configureAppUri(config); + prepareAccessControl(config); +} + +void OpcUaServer::prepareEncryption(UA_ServerConfig* config) +{ +#ifdef OPCUA_ENABLE_ENCRYPTION + UA_StatusCode retval = + UA_ServerConfig_setDefaultWithSecurityPolicies(config, + portUsed, + &securityConfig->certificate.getValue(), + &securityConfig->privateKey.getValue(), + (securityConfig->trustAll) ? NULL : securityConfig->trustList.data(), + (securityConfig->trustAll) ? 0 : securityConfig->trustList.size(), + NULL, + 0, + securityConfig->revocationList.data(), + securityConfig->revocationList.size()); + + if (!securityConfig->trustAll && securityConfig->trustList.size() == 0) + config->certificateVerification.verifyCertificate = OpcUaSecurityCommon::verifyCertificateRejectAll; + + if (retval != UA_STATUSCODE_GOOD) + throw OpcUaException(retval, "Failed to configure security policies."); +#else + throw OpcUaException(UA_STATUSCODE_BADINTERNALERROR, "Encryption was not enabled when building the project."); +#endif +} + +void OpcUaServer::prepareAccessControl(UA_ServerConfig* config) +{ + config->accessControl.clear(&config->accessControl); + UA_StatusCode retval = + UA_AccessControl_default(config, true, NULL, &config->securityPolicies[config->securityPoliciesSize - 1].policyUri, 0, NULL); + + if (retval != UA_STATUSCODE_GOOD) + throw OpcUaException(retval, "Failed to configure server access control."); +} + +void OpcUaServer::configureAppUri(UA_ServerConfig* config) +{ + std::optional appUri = securityConfig->getAppUriOrParseFromCertificate(); + if (appUri.has_value()) + { + UA_String_clear(&config->applicationDescription.applicationUri); + config->applicationDescription.applicationUri = UA_STRING_ALLOC(appUri.value().c_str()); + } +} + +void OpcUaServer::shutdownServer() +{ + if (getStarted()) + { + UA_StatusCode status = UA_Server_run_shutdown(server); + CheckStatusCodeException(status); + } + + if (isPrepared()) + { + UA_Server_delete(server); + std::lock_guard guard(serverMappingMutex); + serverMapping.erase(server); + server = nullptr; + } + + assert(sessionContext.size() == 0); +} + +void OpcUaServer::execute() +{ + setThreadName("OpcUaServer"); + while (!terminated) + { + UA_Server_run_iterate(server, true); + } + shutdownServer(); +} + +OpcUaServerNode OpcUaServer::getNode(const OpcUaNodeId& nodeId) +{ + return OpcUaServerNode(*this, nodeId); +} +OpcUaServerObjectNode OpcUaServer::getRootNode() +{ + return OpcUaServerObjectNode(*this, OpcUaNodeId(UA_NS0ID_ROOTFOLDER)); +} +OpcUaServerObjectNode OpcUaServer::getObjectsNode() +{ + return OpcUaServerObjectNode(*this, OpcUaNodeId(UA_NS0ID_OBJECTSFOLDER)); +} +OpcUaServerObjectNode OpcUaServer::getTypesNode() +{ + return OpcUaServerObjectNode(*this, OpcUaNodeId(UA_NS0ID_TYPESFOLDER)); +} +OpcUaServerObjectNode OpcUaServer::getViewsNode() +{ + return OpcUaServerObjectNode(*this, OpcUaNodeId(UA_NS0ID_VIEWSFOLDER)); +} +OpcUaServerObjectNode OpcUaServer::getObjectTypesNode() +{ + return OpcUaServerObjectNode(*this, OpcUaNodeId(UA_NS0ID_OBJECTTYPESFOLDER)); +} +OpcUaServerObjectNode OpcUaServer::getVariableTypesNode() +{ + return OpcUaServerObjectNode(*this, OpcUaNodeId(UA_NS0ID_VARIABLETYPESFOLDER)); +} +OpcUaServerObjectNode OpcUaServer::getDataTypesNode() +{ + return OpcUaServerObjectNode(*this, OpcUaNodeId(UA_NS0ID_DATATYPESFOLDER)); +} +OpcUaServerObjectNode OpcUaServer::getReferenceTypesNode() +{ + return OpcUaServerObjectNode(*this, OpcUaNodeId(UA_NS0ID_REFERENCETYPESFOLDER)); +} + +ServerEventManagerPtr OpcUaServer::getEventManager() +{ + return eventManager; +} + +bool OpcUaServer::nodeExists(const OpcUaNodeId& nodeId) +{ + return nodeExists(*nodeId); +} + +bool OpcUaServer::nodeExists(const UA_NodeId& nodeId) +{ + UA_NodeClass nodeClass; + return UA_Server_readNodeClass(server, nodeId, &nodeClass) == UA_STATUSCODE_GOOD; +} + +OpcUaObject OpcUaServer::browse(const OpcUaObject& browseDescription) +{ + const size_t MAX_REFERENCES = 0; // All + return UA_Server_browse(server, MAX_REFERENCES, browseDescription.get()); +} + +OpcUaNodeId OpcUaServer::addObjectNode(const AddObjectNodeParams& params) +{ + auto lock = std::lock_guard(getLock()); + eventManager->onCreateOptionalNode(params.addOptionalNodeCallback); + UA_NodeId outNodeId; + + auto status = UA_Server_addObjectNode(server, + *params.requestedNewNodeId, + *params.parentNodeId, + *params.referenceTypeId, + *params.browseName, + *params.typeDefinition, + *params.attr, + params.nodeContext, + &outNodeId); + + CheckStatusCodeException(status); + + return outNodeId; +} + +OpcUaNodeId OpcUaServer::addVariableNode(const AddVariableNodeParams& params) +{ + auto lock = std::lock_guard(getLock()); + eventManager->onCreateOptionalNode(params.addOptionalNodeCallback); + UA_NodeId outNodeId; + + auto status = UA_Server_addVariableNode(server, + *params.requestedNewNodeId, + *params.parentNodeId, + *params.referenceTypeId, + *params.browseName, + *params.typeDefinition, + *params.attr, + params.nodeContext, + &outNodeId); + + CheckStatusCodeException(status); + return outNodeId; +} + +OpcUaNodeId OpcUaServer::addMethodNode(const AddMethodNodeParams& params) +{ + UA_NodeId outNodeId; + CheckStatusCodeException(UA_Server_addMethodNode(server, + *params.requestedNewNodeId, + *params.parentNodeId, + *params.referenceTypeId, + *params.browseName, + *params.attr, + params.method, + params.inputArgumentsSize, + params.inputArguments, + params.outputArgumentsSize, + params.outputArguments, + params.nodeContext, + &outNodeId)); + + return outNodeId; +} + +OpcUaNodeId OpcUaServer::addObjectTypeNode(const AddObjectTypeNodeParams& params) +{ + UA_NodeId outNodeId; + CheckStatusCodeException(UA_Server_addObjectTypeNode(server, + *params.requestedNewNodeId, + *params.parentNodeId, + *params.referenceTypeId, + *params.browseName, + *params.attr, + params.nodeContext, + &outNodeId)); + + return outNodeId; +} + +OpcUaNodeId OpcUaServer::addVariableTypeNode(const AddVariableTypeNodeParams& params) +{ + UA_NodeId outNodeId; + CheckStatusCodeException(UA_Server_addVariableTypeNode(server, + *params.requestedNewNodeId, + *params.parentNodeId, + *params.referenceTypeId, + *params.browseName, + *params.typeDefinition, + *params.attr, + params.nodeContext, + &outNodeId)); + + return outNodeId; +} + +void OpcUaServer::triggerEvent(const OpcUaNodeId& eventType, const OpcUaNodeId& originNodeId, const EventAttributes& eventAttributes) +{ + OpcUaNodeId eventNodeId; + CheckStatusCodeException(UA_Server_createEvent(server, *eventType, eventNodeId.get()), "createEvent failed"); + + const auto& attributes = eventAttributes.getAttributes(); + for (const auto& attribute : attributes) + { + const OpcUaObject& propertyName = attribute.first; + const OpcUaObject& value = attribute.second; + CheckStatusCodeException(UA_Server_writeObjectProperty(server, *eventNodeId, *propertyName, *value), + "setting event attribute fails"); + } + + CheckStatusCodeException(UA_Server_triggerEvent(server, *eventNodeId, *originNodeId, NULL, UA_TRUE), "triggerEvent failed"); +} + +OpcUaObject OpcUaServer::readBrowseName(const OpcUaNodeId& nodeId) const +{ + OpcUaObject qualifiedName; + CheckStatusCodeException(UA_Server_readBrowseName(server, *nodeId, qualifiedName.get())); + return qualifiedName; +} + +std::string OpcUaServer::readBrowseNameString(const OpcUaNodeId& nodeId) const +{ + auto browseName = readBrowseName(nodeId); + return utils::ToStdString(browseName->name); +} + +OpcUaNodeClass OpcUaServer::readNodeClass(const OpcUaNodeId& nodeId) const +{ + UA_NodeClass nodeClass; + CheckStatusCodeException(UA_Server_readNodeClass(server, *nodeId, &nodeClass)); + return static_cast(nodeClass); +} + +void OpcUaServer::setDisplayName(const OpcUaNodeId& nodeId, const OpcUaObject& localizedText) +{ + const auto status = UA_Server_writeDisplayName(server, *nodeId, *localizedText); + CheckStatusCodeException(status); +} + +void OpcUaServer::setDisplayName(const OpcUaNodeId& nodeId, const std::string& text) +{ + OpcUaObject localizedText = UA_LOCALIZEDTEXT_ALLOC("", text.c_str()); + setDisplayName(nodeId, localizedText); +} + +OpcUaObject OpcUaServer::readDisplayName(const OpcUaNodeId& nodeId) const +{ + OpcUaObject localizedText; + CheckStatusCodeException(UA_Server_readDisplayName(server, *nodeId, localizedText.get())); + return localizedText; +} + +void OpcUaServer::writeValue(const OpcUaNodeId& nodeId, const OpcUaVariant& value) +{ + CheckStatusCodeException(UA_Server_writeValue(server, *nodeId, *value)); +} + +OpcUaVariant OpcUaServer::readValue(const OpcUaNodeId& nodeId) +{ + OpcUaVariant value; + CheckStatusCodeException(UA_Server_readValue(server, *nodeId, value.get())); + return value; +} + +OpcUaNodeId OpcUaServer::readDataType(const OpcUaNodeId& typeNodeId) +{ + OpcUaNodeId dataTypeId; + const auto status = UA_Server_readDataType(getUaServer(), *typeNodeId, dataTypeId.get()); + CheckStatusCodeException(status); + return dataTypeId; +} + +void OpcUaServer::deleteNode(const OpcUaNode& node) +{ + deleteNode(node.getNodeId()); +} + +void OpcUaServer::deleteNode(const OpcUaNodeId& nodeId) +{ + UA_StatusCode status = UA_Server_deleteNode(server, *nodeId, true); + CheckStatusCodeException(status); +} + +void OpcUaServer::addReference(const OpcUaNodeId& sourceId, const OpcUaNodeId& refTypeId, const OpcUaNodeId& targetId, bool isForward) +{ + OpcUaObject extendedTargetId; + extendedTargetId->nodeId = targetId.copyAndGetDetachedValue(); + + UA_StatusCode status = UA_Server_addReference(server, *sourceId, *refTypeId, *extendedTargetId, isForward); + CheckStatusCodeException(status); +} + +void OpcUaServer::deleteReference(const OpcUaNodeId& sourceId, const OpcUaNodeId& refTypeId, const OpcUaNodeId& targetId, bool isForward) +{ + OpcUaObject extendedTargetId; + extendedTargetId->nodeId = targetId.copyAndGetDetachedValue(); + + UA_StatusCode status = UA_Server_deleteReference(server, *sourceId, *refTypeId, isForward, *extendedTargetId, true); + CheckStatusCodeException(status); +} + +bool OpcUaServer::referenceExists(const OpcUaNodeId& sourceId, const OpcUaNodeId& refTypeId, const OpcUaNodeId& targetId, bool isForward) +{ + OpcUaObject browseDesc; + browseDesc->browseDirection = UA_BROWSEDIRECTION_BOTH; + browseDesc->nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE | UA_NODECLASS_METHOD; + browseDesc->includeSubtypes = false; + browseDesc->nodeId = sourceId.copyAndGetDetachedValue(); + browseDesc->referenceTypeId = refTypeId.copyAndGetDetachedValue(); + browseDesc->resultMask = UA_BROWSERESULTMASK_ISFORWARD; + + OpcUaObject browseResult = UA_Server_browse(server, 0, browseDesc.get()); + + UA_NodeId_init(&browseDesc->nodeId); + UA_NodeId_init(&browseDesc->referenceTypeId); + + for (size_t i = 0; i < browseResult->referencesSize; i++) + { + const auto& referenceDesc = browseResult->references[i]; + if (referenceDesc.isForward == isForward && targetId == referenceDesc.nodeId.nodeId) + return true; + } + return false; +} + +std::mutex OpcUaServer::serverMappingMutex; +std::map OpcUaServer::serverMapping; + +OpcUaServer* OpcUaServer::getServer(UA_Server* server) +{ + std::lock_guard guard(serverMappingMutex); + auto it = serverMapping.find(server); + if (it != serverMapping.end()) + return (*it).second; + return nullptr; +} + +UA_StatusCode OpcUaServer::authenticateUser(OpcUaServer* serverInstance, const UA_ExtensionObject* userIdentityToken) +{ + UA_StatusCode status = UA_STATUSCODE_BADUSERACCESSDENIED; + + if (userIdentityToken->content.decoded.type == &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]) + status = serverInstance->securityConfig->authenticateUser(true, "", ""); + else if (userIdentityToken->content.decoded.type == &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]) + { + const UA_UserNameIdentityToken* userToken = (UA_UserNameIdentityToken*) userIdentityToken->content.decoded.data; + std::string username = utils::ToStdString(userToken->userName); + std::string password = utils::ToStdString(userToken->password); + status = serverInstance->securityConfig->authenticateUser(false, username, password); + } + + return status; +} + +UA_StatusCode OpcUaServer::activateSession(UA_Server* server, + UA_AccessControl* ac, + const UA_EndpointDescription* endpointDescription, + const UA_ByteString* secureChannelRemoteCertificate, + const UA_NodeId* sessionId, + const UA_ExtensionObject* userIdentityToken, + void** sessionContext) +{ + OpcUaServer* serverInstance = getServer(server); + OpcUaSecurityConfig* securityConfig = serverInstance->securityConfig.has_value() ? &serverInstance->securityConfig.value() : nullptr; + + if (securityConfig != nullptr && securityConfig->securityMode != endpointDescription->securityMode) + return UA_STATUSCODE_BADSECURITYMODEREJECTED; + + void* unusedSessionContext = nullptr; // activateSession_default resets sessionContext. Subsequent calls should keep the session + // context + UA_StatusCode status = serverInstance->activateSession_default( + server, ac, endpointDescription, secureChannelRemoteCertificate, sessionId, userIdentityToken, &unusedSessionContext); + assert(unusedSessionContext == nullptr); + + if (securityConfig != nullptr && (status == UA_STATUSCODE_GOOD || status == UA_STATUSCODE_BADUSERACCESSDENIED)) + status = authenticateUser(serverInstance, userIdentityToken); + + if (status != UA_STATUSCODE_GOOD) + return status; + + bool sessionContextAlreadyCreated = *sessionContext != nullptr; + if (serverInstance->createSessionContextCallback && !sessionContextAlreadyCreated) + { + OpcUaNodeId sessionNodeId(*sessionId, true); + *sessionContext = serverInstance->createSessionContextCallback(sessionNodeId); + if (*sessionContext != nullptr) + serverInstance->sessionContext.insert(*sessionContext); + } + + return status; +} + +void OpcUaServer::closeSession(UA_Server* server, UA_AccessControl* ac, const UA_NodeId* sessionId, void* sessionContext) +{ + OpcUaNodeId sessionNodeId(*sessionId, true); + OpcUaServer* serverInstance = getServer(server); + + serverInstance->serverLock.refuseConfigurationControlLock(sessionNodeId); + + if (sessionContext != nullptr) + serverInstance->sessionContext.erase(sessionContext); + + if (serverInstance->deleteSessionContextCallback) + serverInstance->deleteSessionContextCallback(sessionContext); +} + +bool OpcUaServer::passwordLock(const std::string& password) +{ + return serverLock.passwordLock(password); +} + +bool OpcUaServer::passwordUnlock(const std::string& password) +{ + return serverLock.passwordUnlock(password); +} + +bool OpcUaServer::isPasswordLocked() +{ + return serverLock.isPasswordLocked(); +} + +UA_Server* OpcUaServer::getUaServer() const noexcept +{ + return server; +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/src/opcuaserverlock.cpp b/shared/libraries/opcua/opcuaserver/src/opcuaserverlock.cpp new file mode 100644 index 0000000..8755f20 --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/src/opcuaserverlock.cpp @@ -0,0 +1,91 @@ +#include "opcuaserver/opcuaserverlock.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaServerLock::OpcUaServerLock() +{ + configurationControlLockSessionId = OpcUaNodeId(); + refuseConfigurationControlLock(configurationControlLockSessionId); +} + +OpcUaServerLock::~OpcUaServerLock() +{ +} + +bool OpcUaServerLock::passwordLock(const std::string& password, const OpcUaNodeId& sessionId) +{ + if (!canEditPasswordLock(sessionId)) + return false; + + if (isPasswordLocked()) + return false; + + this->password = password; + return true; +} + +bool OpcUaServerLock::passwordUnlock(const std::string& password, const OpcUaNodeId& sessionId) +{ + if (!canEditPasswordLock(sessionId)) + return false; + + if (isPasswordLocked() && this->password != password) + return false; + + this->password = ""; + return true; +} + +bool OpcUaServerLock::isPasswordLocked() +{ + return password != ""; +} + +bool OpcUaServerLock::hasConfigurationControlLock(const OpcUaNodeId& sessionId) const +{ + return sessionId == configurationControlLockSessionId && hasActiveConfigurationControlLock(); +} + +void OpcUaServerLock::refuseConfigurationControlLock(const OpcUaNodeId& sessionId) +{ + if (sessionId == configurationControlLockSessionId) + lockConfigurationControl(sessionId, std::chrono::seconds(-1)); +} + +bool OpcUaServerLock::lockConfigurationControl(const OpcUaNodeId& sessionId, const std::chrono::seconds timeout) +{ + if (hasConfigurationControlAccess(sessionId)) + { + configurationControlLockSessionId = sessionId; + configurationControlLockValidTo = utils::GetDurationTimeStamp() + timeout; + return true; + } + return false; +} + +bool OpcUaServerLock::hasConfigurationControlAccess(const OpcUaNodeId& sessionId) const +{ + return hasConfigurationControlLock(sessionId) || !hasActiveConfigurationControlLock(); +} + +bool OpcUaServerLock::hasActiveConfigurationControlLock() const +{ + return utils::GetDurationTimeStamp() < configurationControlLockValidTo; +} + +bool OpcUaServerLock::canControlAcq(const OpcUaNodeId& sessionId) +{ + return !isPasswordLocked() && hasConfigurationControlAccess(sessionId); +} + +bool OpcUaServerLock::canEditPasswordLock(const OpcUaNodeId& sessionId) +{ + if (this->hasConfigurationControlLock(sessionId)) + return true; + + return !hasActiveConfigurationControlLock(); +} + + + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/src/opcuaservernode.cpp b/shared/libraries/opcua/opcuaserver/src/opcuaservernode.cpp new file mode 100644 index 0000000..89d1097 --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/src/opcuaservernode.cpp @@ -0,0 +1,132 @@ +#include +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaServerNode::OpcUaServerNode(OpcUaServer& server, const OpcUaNodeId& nodeId) + : server(server) + , nodeId(nodeId) +{ + // check if node exists + server.readNodeClass(nodeId); +} + +OpcUaNodeId OpcUaServerNode::getNodeId() const +{ + return nodeId; +} + +OpcUaNodeClass OpcUaServerNode::getNodeClass() +{ + return server.readNodeClass(getNodeId()); +} + +OpcUaObject OpcUaServerNode::getBrowseName() +{ + return server.readBrowseName(getNodeId()); +} + +void OpcUaServerNode::setDisplayName(const std::string& displayName) +{ + OpcUaObject localizedText; + localizedText->text = UA_STRING_ALLOC(displayName.c_str()); + + server.setDisplayName(getNodeId(), localizedText); +} + +OpcUaObject OpcUaServerNode::getDisplayName() +{ + return server.readDisplayName(getNodeId()); +} + +std::vector> OpcUaServerNode::browse(const OpcUaNodeId& referenceTypeId, + bool includeSubtypes, + OpcUaNodeClass nodeClassMask, + UA_BrowseDirection browseDirection) +{ + OpcUaObject browseDescription; + browseDescription->nodeId = nodeId.copyAndGetDetachedValue(); + browseDescription->browseDirection = browseDirection; + browseDescription->referenceTypeId = referenceTypeId.copyAndGetDetachedValue(); + browseDescription->nodeClassMask = (UA_UInt32) nodeClassMask; + browseDescription->includeSubtypes = includeSubtypes; + browseDescription->resultMask = UA_BROWSERESULTMASK_NODECLASS; + + auto browseResult = server.browse(browseDescription); + CheckStatusCodeException(browseResult->statusCode, "Browse failed"); + + OpcUaServerNodeFactory nodeFactory(server); + + std::vector> result; + for (size_t i = 0; i < browseResult->referencesSize; i++) + { + const auto reference = browseResult->references[i]; + + OpcUaNodeId nodeId(reference.nodeId.nodeId); + result.push_back(nodeFactory.createServerNode(nodeId, reference.nodeClass)); + } + + return result; +} + +std::vector> OpcUaServerNode::browseChildNodes() +{ + return browse(OpcUaNodeId(UA_NS0ID_HIERARCHICALREFERENCES)); +} + +std::unique_ptr OpcUaServerNode::getChildNode(const OpcUaObject& qualifiedName) +{ + OpcUaObject result = UA_Server_browseSimplifiedBrowsePath(server.getUaServer(), *nodeId, 1, qualifiedName.get()); + CheckStatusCodeException(result->statusCode, "Browse failed"); + assert(result->targetsSize == 1); + OpcUaServerNodeFactory factory(server); + return factory.createServerNode(result->targets[0].targetId.nodeId); +} + +OpcUaServerObjectNode OpcUaServerNode::addObject(AddObjectNodeParams& params) +{ + params.parentNodeId = getNodeId(); + auto newNodeId = server.addObjectNode(params); + return OpcUaServerObjectNode(server, newNodeId); +} + +OpcUaServerObjectNode OpcUaServerNode::addObject(const OpcUaNodeId& nodeId, const std::string& browseName) +{ + AddObjectNodeParams nodeParams(nodeId); + nodeParams.setBrowseName(browseName); + return addObject(nodeParams); +} + +OpcUaServerVariableNode OpcUaServerNode::addVariable(AddVariableNodeParams& params) +{ + params.parentNodeId = getNodeId(); + auto newNodeId = server.addVariableNode(params); + return OpcUaServerVariableNode(server, newNodeId); +} + +OpcUaServerVariableNode OpcUaServerNode::addVariable(const OpcUaNodeId& nodeId, const std::string& browseName) +{ + AddVariableNodeParams nodeParams(nodeId); + nodeParams.setBrowseName(browseName); + + return addVariable(nodeParams); +} + +void OpcUaServerVariableNode::writeVariantToServer(const OpcUaVariant& var) +{ + server.writeValue(getNodeId(), var); +} + +OpcUaVariant OpcUaServerVariableNode::readVariantFromServer() +{ + return server.readValue(getNodeId()); +} + +void OpcUaServerNode::remove() +{ + server.deleteNode(nodeId); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/src/opcuaservernodefactory.cpp b/shared/libraries/opcua/opcuaserver/src/opcuaservernodefactory.cpp new file mode 100644 index 0000000..f0afa58 --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/src/opcuaservernodefactory.cpp @@ -0,0 +1,42 @@ +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaServerNodeFactory::OpcUaServerNodeFactory(OpcUaServer& server) + : server(server) +{ +} + +std::unique_ptr OpcUaServerNodeFactory::createServerNode(const OpcUaNodeId& nodeId) +{ + return createServerNode(nodeId, server.readNodeClass(nodeId)); +} + +std::unique_ptr OpcUaServerNodeFactory::createServerNode(const OpcUaNodeId& nodeId, OpcUaNodeClass nodeClass) +{ + switch (nodeClass) + { + case OpcUaNodeClass::Object: + return std::make_unique(server, nodeId); + case OpcUaNodeClass::Variable: + return std::make_unique(server, nodeId); + case OpcUaNodeClass::Method: + return std::make_unique(server, nodeId); + case OpcUaNodeClass::ObjectType: + return std::make_unique(server, nodeId); + case OpcUaNodeClass::VariableType: + return std::make_unique(server, nodeId); + case OpcUaNodeClass::DataType: + return std::make_unique(server, nodeId); + default: + return std::make_unique(server, nodeId); + } +} + +std::unique_ptr OpcUaServerNodeFactory::createServerNode(const OpcUaNodeId& nodeId, UA_NodeClass nodeClass) +{ + return createServerNode(nodeId, static_cast(nodeClass)); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/src/opcuasession.cpp b/shared/libraries/opcua/opcuaserver/src/opcuasession.cpp new file mode 100644 index 0000000..7a049df --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/src/opcuasession.cpp @@ -0,0 +1,59 @@ +#include "opcuaserver/opcuasession.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaSession::OpcUaSession(const OpcUaNodeId& sessionId, OpcUaServerLock* serverLock) + : sessionId(sessionId) + , serverLock(serverLock) +{ +} + +OpcUaSession::~OpcUaSession() +{ +} + +bool OpcUaSession::hasConfigurationControlLock() const +{ + return serverLock->hasConfigurationControlLock(getConfigurationLockTokenId()); +} + +void OpcUaSession::refuseConfigurationControlLock() +{ + serverLock->refuseConfigurationControlLock(getConfigurationLockTokenId()); +} + +bool OpcUaSession::lockConfigurationControl(const std::chrono::seconds timeout) +{ + return serverLock->lockConfigurationControl(getConfigurationLockTokenId(), timeout); +} + +bool OpcUaSession::canControlAcq() +{ + return serverLock->canControlAcq(getConfigurationLockTokenId()); +} + +bool OpcUaSession::passwordLock(const std::string& password) +{ + return serverLock->passwordLock(password, getConfigurationLockTokenId()); +} + +bool OpcUaSession::passwordUnlock(const std::string& password) +{ + return serverLock->passwordUnlock(password, getConfigurationLockTokenId()); +} + +void OpcUaSession::setConfigurationLockTokenId(const OpcUaNodeId& configurationLockTokenId) +{ + this->configurationLockTokenId = configurationLockTokenId; +} + +const OpcUaNodeId& OpcUaSession::getConfigurationLockTokenId() const +{ + if (!configurationLockTokenId.isNull()) + return configurationLockTokenId; + + return sessionId; +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/src/opcuataskqueue.cpp b/shared/libraries/opcua/opcuaserver/src/opcuataskqueue.cpp new file mode 100644 index 0000000..4f4831d --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/src/opcuataskqueue.cpp @@ -0,0 +1,64 @@ +#include "opcuaserver/opcuataskqueue.h" +#include "opcuashared/opcua.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +void OpcUaTaskQueue::push(Function&& func) +{ + { + std::lock_guard guard(mutex_); + q_.emplace_back(func); + } + cv_.notify_one(); +} + +bool OpcUaTaskQueue::pop(Function& func) +{ + std::lock_guard guard(mutex_); + if (q_.empty()) + { + return false; + } + else + { + func = q_.front(); + q_.pop_front(); + return true; + } +} + +bool OpcUaTaskQueue::pop(Function& func, const unsigned int timeout_ms) +{ + std::unique_lock lock(mutex_); + if (timeout_ms == infinity) + { + cv_.wait(lock, [& q = q_]() { return !q.empty(); }); + } + else + { + cv_.wait_for(lock, std::chrono::milliseconds(timeout_ms), [& q = q_]() { return !q.empty(); }); + } + + if (q_.empty()) + { + return false; + } + else + { + func = q_.front(); + q_.pop_front(); + return true; + } +} + +void OpcUaTaskQueue::processTaskQueue() +{ + OpcUaTaskQueue::Function func; + + while (pop(func)) + { + func(); + } +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/src/opcuatmstypes.cpp b/shared/libraries/opcua/opcuaserver/src/opcuatmstypes.cpp new file mode 100644 index 0000000..e721b45 --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/src/opcuatmstypes.cpp @@ -0,0 +1,57 @@ + +#include +#include +#ifdef NAMESPACE_TMSBT + #include + #include +#endif +#ifdef NAMESPACE_TMSBSP + #include + #include +#endif +#ifdef NAMESPACE_TMSDEVICE + #include + #include +#endif +#ifdef NAMESPACE_TMSESP + #include + #include +#endif +#include "opcuashared/opcuaexception.h" +#include "opcuashared/opcualog.h" +#include "opcuaserver/opcuatmstypes.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +void addTmsTypes(UA_Server *server) +{ + UA_StatusCode uaStatus = namespace_di_generated(server); + CheckStatusCodeException(uaStatus, "Failed to add OPC-UA for devices nodeset."); + LOGD << "OPC-UA for devices nodeSet was added successfully."; + +#ifdef NAMESPACE_TMSBT + uaStatus = namespace_tmsbt_generated(server); + CheckStatusCodeException(uaStatus, "Failed to add TMS BT nodeset."); + LOGD << "TMS BT nodeset was added successfully."; +#endif + +#ifdef NAMESPACE_TMSBSP + uaStatus = namespace_tmsbsp_generated(server); + CheckStatusCodeException(uaStatus, "Failed to add TMS BSP nodeset."); + LOGD << "TMS BSP nodeset was added successfully."; +#endif + +#ifdef NAMESPACE_TMSDEVICE + uaStatus = namespace_tmsdevice_generated(server); + CheckStatusCodeException(uaStatus, "Failed to add TMS DEVICE nodeset."); + LOGD << "TMS DEVICE nodeset was added successfully."; +#endif + +#ifdef NAMESPACE_TMSESP + uaStatus = namespace_tmsesp_generated(server); + CheckStatusCodeException(uaStatus, "Failed to add TMS ESP nodeset."); + LOGD << "TMS ESP nodeset was added successfully."; +#endif +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/src/server_event_manager.cpp b/shared/libraries/opcua/opcuaserver/src/server_event_manager.cpp new file mode 100644 index 0000000..89f755a --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/src/server_event_manager.cpp @@ -0,0 +1,80 @@ +#include "opcuaserver/server_event_manager.h" +#include "opcuaserver/opcuaserver.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +ServerEventManager::ServerEventManager(const OpcUaServerPtr& server) + : server(server.get()) +{ +} + +ServerEventManager::ServerEventManager(OpcUaServer* server) + : server(server) +{ +} + +void ServerEventManager::registerEvents() +{ + auto config = UA_Server_getConfig(server->getUaServer()); + + config->nodeLifecycle.context = this; + config->displayNameChanged = DisplayNameChanged; + config->nodeLifecycle.createOptionalChild = CreateOptionalNode; +} + +UA_Boolean ServerEventManager::triggerCreateOptionalNode(const UA_NodeId* nodeId) +{ + const auto nodeIdObj = OpcUaNodeId(*nodeId); + if (createOptionalNodeCallback == nullptr) + return false; + + return createOptionalNodeCallback(nodeIdObj); +} + +void ServerEventManager::triggerDisplayNameChanged(const UA_NodeId* nodeId, UA_LocalizedText* name) +{ + const auto nodeIdObj = OpcUaNodeId(*nodeId); + if (displayNameCallbacks.count(nodeIdObj) == 0) + return; + + auto callback = displayNameCallbacks[nodeIdObj]; + callback(nodeIdObj, OpcUaObject(*name)); +} + +void ServerEventManager::onCreateOptionalNode(const CreatOptionalNodeCallback& callback) +{ + createOptionalNodeCallback = callback; +} + +void ServerEventManager::onDisplayNameChanged(const OpcUaNodeId& nodeId, const DisplayNameChangedCallback& callback) +{ + displayNameCallbacks.insert({nodeId, callback}); +} + +void ServerEventManager::removeOnDisplayNameChanged(const OpcUaNodeId& nodeId) +{ + displayNameCallbacks.erase(nodeId); +} + +// Static callbacks + +UA_Boolean ServerEventManager::CreateOptionalNode(UA_Server* server, + const UA_NodeId* sessionId, + void* sessionContext, + const UA_NodeId* sourceNodeId, + const UA_NodeId* targetParentNodeId, + const UA_NodeId* referenceTypeId) +{ + auto& lifecycle = UA_Server_getConfig(server)->nodeLifecycle; + auto eventManager = (ServerEventManager*) lifecycle.context; + return eventManager->triggerCreateOptionalNode(sourceNodeId); +} + +void ServerEventManager::DisplayNameChanged(UA_Server* server, UA_NodeId* nodeId, UA_LocalizedText* newDisplayName) +{ + auto& lifecycle = UA_Server_getConfig(server)->nodeLifecycle; + auto eventManager = (ServerEventManager*) lifecycle.context; + eventManager->triggerDisplayNameChanged(nodeId, newDisplayName); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/tests/CMakeLists.txt b/shared/libraries/opcua/opcuaserver/tests/CMakeLists.txt new file mode 100644 index 0000000..0602c50 --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/tests/CMakeLists.txt @@ -0,0 +1,29 @@ +set(MODULE_NAME opcuaserver) +set(TEST_APP test_${MODULE_NAME}) + +set(SRC_Cpp main.cpp + common_test_functions.h + test_opcuaserver.cpp + test_opcuaservernode.cpp + test_opcuaservernodefactory.cpp + test_opcuaserverlock.cpp + test_opcuasession.cpp +) + +add_executable(${TEST_APP} ${SRC_Cpp}) + +target_link_libraries(${TEST_APP} PRIVATE ${SDK_TARGET_NAMESPACE}::${MODULE_NAME} + daq::opendaq_utils + daq::test_utils + daq::opcuaclient + daq::opcua_tms_types +) + +add_test(NAME ${TEST_APP} + COMMAND $ + WORKING_DIRECTORY bin +) + +if(OPENDAQ_ENABLE_COVERAGE) + setup_target_for_coverage(${MODULE_NAME}coverage ${TEST_APP} ${MODULE_NAME}coverage) +endif() diff --git a/shared/libraries/opcua/opcuaserver/tests/common_test_functions.h b/shared/libraries/opcua/opcuaserver/tests/common_test_functions.h new file mode 100644 index 0000000..4afa6e9 --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/tests/common_test_functions.h @@ -0,0 +1,45 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +static constexpr const char SERVER_URL[] = "opc.tcp://localhost"; + +inline OpcUaServer createServer() +{ + return OpcUaServer(); +} + +inline UA_Client* CreateClient() +{ + UA_Client* client = UA_Client_new(); + UA_ClientConfig_setDefault(UA_Client_getConfig(client)); + return client; +} + +inline std::shared_ptr CreateClientAndConnect() +{ + auto client = std::make_shared(SERVER_URL); + if (!client->connect()) + throw std::runtime_error("Fail to connect"); + return client; +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/tests/main.cpp b/shared/libraries/opcua/opcuaserver/tests/main.cpp new file mode 100644 index 0000000..abe4b12 --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/tests/main.cpp @@ -0,0 +1,14 @@ +#include +#include + +int main(int argc, char** args) +{ + ::testing::InitGoogleTest(&argc, args); + + testing::TestEventListeners& listeners = testing::UnitTest::GetInstance()->listeners(); + listeners.Append(new MemCheckListener()); + + int res = RUN_ALL_TESTS(); + + return res; +} diff --git a/shared/libraries/opcua/opcuaserver/tests/test_opcuaserver.cpp b/shared/libraries/opcua/opcuaserver/tests/test_opcuaserver.cpp new file mode 100644 index 0000000..0e13ee8 --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/tests/test_opcuaserver.cpp @@ -0,0 +1,432 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "common_test_functions.h" +#include +#include +#include + +#include +#ifdef NAMESPACE_TMSBT + #include +#endif +#ifdef NAMESPACE_TMSBSP + #include +#endif +#ifdef NAMESPACE_TMSDEVICE + #include +#endif + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using namespace utils; +using namespace std::chrono_literals; + +using OpcUaServerTest = testing::Test; + +#define ASSERT_EQ_STATUS(status, expectedStatus) ASSERT_EQ(status, (UA_StatusCode) expectedStatus) +#define ASSERT_STATUSCODE_GOOD(status) ASSERT_EQ_STATUS(status, UA_STATUSCODE_GOOD) + +TEST_F(OpcUaServerTest, StartStopTest) +{ + OpcUaServer server = createServer(); + ASSERT_FALSE(server.isPrepared()); + ASSERT_FALSE(server.getStarted()); + + server.prepare(); + ASSERT_TRUE(server.isPrepared()); + ASSERT_FALSE(server.getStarted()); + + server.start(); + ASSERT_TRUE(server.isPrepared()); + ASSERT_TRUE(server.getStarted()); + + server.stop(); + ASSERT_FALSE(server.isPrepared()); + ASSERT_FALSE(server.getStarted()); +} + +TEST_F(OpcUaServerTest, StopWithoutStartTest) +{ + OpcUaServer server = createServer(); + + server.prepare(); + + server.stop(); + ASSERT_FALSE(server.isPrepared()); + ASSERT_FALSE(server.getStarted()); +} + +TEST_F(OpcUaServerTest, NodeExists) +{ + OpcUaServer server = createServer(); + server.prepare(); + + ASSERT_TRUE(server.nodeExists(OpcUaNodeId(UA_NS0ID_OBJECTSFOLDER))); + + ASSERT_FALSE(server.nodeExists(OpcUaNodeId(1, "unknown"))); +} + +TEST_F(OpcUaServerTest, ReferenceExists) +{ + OpcUaServer server = createServer(); + server.prepare(); + + ASSERT_TRUE(server.referenceExists( + OpcUaNodeId(UA_NS0ID_ROOTFOLDER), OpcUaNodeId(UA_NS0ID_ORGANIZES), OpcUaNodeId(UA_NS0ID_OBJECTSFOLDER), true)); + ASSERT_TRUE(server.referenceExists( + OpcUaNodeId(UA_NS0ID_OBJECTSFOLDER), OpcUaNodeId(UA_NS0ID_ORGANIZES), OpcUaNodeId(UA_NS0ID_ROOTFOLDER), false)); + + ASSERT_FALSE(server.referenceExists( + OpcUaNodeId(UA_NS0ID_ROOTFOLDER), OpcUaNodeId(UA_NS0ID_ORGANIZES), OpcUaNodeId(UA_NS0ID_OBJECTSFOLDER), false)); + ASSERT_FALSE(server.referenceExists( + OpcUaNodeId(UA_NS0ID_ROOTFOLDER), OpcUaNodeId(UA_NS0ID_ORGANIZES), OpcUaNodeId(UA_NS0ID_DATATYPESFOLDER), true)); +} + +TEST_F_OPTIONAL(OpcUaServerTest, ClientConnectTest) +{ + OpcUaServer server = createServer(); + server.start(); + + UA_Client* client = CreateClient(); + ASSERT_EQ_STATUS(UA_Client_connect(client, SERVER_URL), UA_STATUSCODE_GOOD); + UA_Client_delete(client); + + server.stop(); +} + +TEST_F_OPTIONAL(OpcUaServerTest, ClientConnectTestStopBeforeClientDisconnect) +{ + OpcUaServer server = createServer(); + server.start(); + + UA_Client* client = CreateClient(); + ASSERT_EQ_STATUS(UA_Client_connect(client, SERVER_URL), UA_STATUSCODE_GOOD); + + server.stop(); + + UA_Client_delete(client); +} + +TEST_F_OPTIONAL(OpcUaServerTest, ClientConnectTestSessionContext) +{ + OpcUaServer server = createServer(); + server.createSessionContextCallback = [](const OpcUaNodeId& sessionId) { return new int; }; + server.deleteSessionContextCallback = [](void* pointer) { delete (int*) pointer; }; + server.start(); + + UA_Client* client = CreateClient(); + ASSERT_EQ_STATUS(UA_Client_connect(client, SERVER_URL), UA_STATUSCODE_GOOD); + UA_Client_delete(client); + + server.stop(); +} + +TEST_F_OPTIONAL(OpcUaServerTest, ClientConnectTestSessionContextStopBeforeClientDisconnect) +{ + OpcUaServer server = createServer(); + server.createSessionContextCallback = [](const OpcUaNodeId& sessionId) { return new int; }; + server.deleteSessionContextCallback = [](void* pointer) { delete (int*) pointer; }; + server.start(); + + UA_Client* client = CreateClient(); + ASSERT_EQ_STATUS(UA_Client_connect(client, SERVER_URL), UA_STATUSCODE_GOOD); + + server.stop(); + + UA_Client_delete(client); +} + +TEST_F(OpcUaServerTest, ReadBrowseName) +{ + OpcUaServer server = createServer(); + server.prepare(); + + auto qualifiedName = server.readBrowseName(OpcUaNodeId(UA_NS0ID_SERVER)); + ASSERT_EQ(qualifiedName->namespaceIndex, 0); + ASSERT_EQ(ToStdString(qualifiedName->name), "Server"); + + ASSERT_THROW(server.readBrowseName(OpcUaNodeId(0, "Unknown")), OpcUaException); +} + +TEST_F(OpcUaServerTest, ReadDisplayName) +{ + OpcUaServer server = createServer(); + server.prepare(); + + ASSERT_EQ(ToStdString(server.readDisplayName(OpcUaNodeId(UA_NS0ID_SERVER))->text), "Server"); + + ASSERT_THROW(server.readDisplayName(OpcUaNodeId(0, "Unknown")), OpcUaException); +} + +TEST_F(OpcUaServerTest, AddFolderTest) +{ + OpcUaServer server = createServer(); + server.prepare(); + + OpcUaNodeId nodeId(1, "FolderId"); + + AddObjectNodeParams params(nodeId, OpcUaNodeId(UA_NS0ID_SERVER)); + params.setBrowseName("Folder"); + + OpcUaNodeId outNodeId = server.addObjectNode(params); + ASSERT_EQ(OpcUaNodeId(1, "FolderId"), outNodeId); + + ASSERT_TRUE(server.nodeExists(nodeId)); + + OpcUaObject qualifiedName = server.readBrowseName(nodeId); + ASSERT_EQ(qualifiedName->namespaceIndex, 0); + ASSERT_EQ(ToStdString(qualifiedName->name), "Folder"); + + ASSERT_EQ(ToStdString(server.readDisplayName(nodeId)->text), "Folder"); + + ASSERT_THROW(server.addObjectNode(params), OpcUaException); // Duplicate +} + +TEST_F(OpcUaServerTest, AddVariableTest) +{ + OpcUaServer server = createServer(); + server.prepare(); + + OpcUaNodeId nodeId(1, "VariableId"); + + AddVariableNodeParams params(nodeId, OpcUaNodeId(UA_NS0ID_SERVER)); + params.setBrowseName("Variable"); + + OpcUaNodeId outNodeId = server.addVariableNode(params); + ASSERT_EQ(OpcUaNodeId(1, "VariableId"), outNodeId); + + ASSERT_TRUE(server.nodeExists(nodeId)); + + OpcUaObject qualifiedName = server.readBrowseName(nodeId); + ASSERT_EQ(qualifiedName->namespaceIndex, 0); + ASSERT_EQ(ToStdString(qualifiedName->name), "Variable"); + + ASSERT_EQ(ToStdString(server.readDisplayName(nodeId)->text), "Variable"); + + ASSERT_THROW(server.addVariableNode(params), OpcUaException); // Duplicate +} + +TEST_F(OpcUaServerTest, AddMethodTest) +{ + OpcUaServer server = createServer(); + server.prepare(); + + OpcUaNodeId nodeId(1, "MethodId"); + + AddMethodNodeParams params(nodeId, OpcUaNodeId(UA_NS0ID_SERVER)); + params.setBrowseName("Method"); + + OpcUaNodeId outNodeId = server.addMethodNode(params); + ASSERT_EQ(OpcUaNodeId(1, "MethodId"), outNodeId); + + ASSERT_TRUE(server.nodeExists(nodeId)); + + OpcUaObject qualifiedName = server.readBrowseName(nodeId); + ASSERT_EQ(qualifiedName->namespaceIndex, 0); + ASSERT_EQ(ToStdString(qualifiedName->name), "Method"); + + ASSERT_EQ(ToStdString(server.readDisplayName(nodeId)->text), "Method"); + + ASSERT_THROW(server.addMethodNode(params), OpcUaException); // Duplicate +} + +TEST_F(OpcUaServerTest, AddObjectType) +{ + OpcUaServer server = createServer(); + server.prepare(); + + OpcUaNodeId nodeId(1, "ObjectTypeId"); + + AddObjectTypeNodeParams params(nodeId, OpcUaNodeId(UA_NS0ID_BASEOBJECTTYPE)); + params.setBrowseName("ObjectType"); + + OpcUaNodeId outNodeId = server.addObjectTypeNode(params); + ASSERT_EQ(OpcUaNodeId(1, "ObjectTypeId"), outNodeId); + + ASSERT_TRUE(server.nodeExists(nodeId)); + + OpcUaObject qualifiedName = server.readBrowseName(nodeId); + ASSERT_EQ(qualifiedName->namespaceIndex, 0); + ASSERT_EQ(ToStdString(qualifiedName->name), "ObjectType"); + + ASSERT_EQ(ToStdString(server.readDisplayName(nodeId)->text), "ObjectType"); + + ASSERT_THROW(server.addObjectTypeNode(params), OpcUaException); // Duplicate +} + +TEST_F(OpcUaServerTest, AddVariableType) +{ + OpcUaServer server = createServer(); + server.prepare(); + + OpcUaNodeId nodeId(1, "VariableTypeId"); + + AddVariableTypeNodeParams params(nodeId, OpcUaNodeId(UA_NS0ID_BASEVARIABLETYPE)); + params.setBrowseName("VariableType"); + + OpcUaNodeId outNodeId = server.addVariableTypeNode(params); + ASSERT_EQ(OpcUaNodeId(1, "VariableTypeId"), outNodeId); + + ASSERT_TRUE(server.nodeExists(nodeId)); + + OpcUaObject qualifiedName = server.readBrowseName(nodeId); + ASSERT_EQ(qualifiedName->namespaceIndex, 0); + ASSERT_EQ(ToStdString(qualifiedName->name), "VariableType"); + + ASSERT_EQ(ToStdString(server.readDisplayName(nodeId)->text), "VariableType"); + + ASSERT_THROW(server.addVariableTypeNode(params), OpcUaException); // Duplicate +} + +TEST_F(OpcUaServerTest, AddDeleteReference) +{ + OpcUaServer server = createServer(); + server.prepare(); + + OpcUaNodeId sourceId(0, UA_NS0ID_OBJECTSFOLDER); + OpcUaNodeId refTypeId(0, UA_NS0ID_HASCOMPONENT); + OpcUaNodeId targetId(0, UA_NS0ID_SERVER_VENDORSERVERINFO); + + ASSERT_FALSE(server.referenceExists(sourceId, refTypeId, targetId, true)); + + server.addReference(sourceId, refTypeId, targetId, true); + + ASSERT_TRUE(server.referenceExists(sourceId, refTypeId, targetId, true)); + + server.deleteReference(sourceId, refTypeId, targetId, true); + + ASSERT_FALSE(server.referenceExists(sourceId, refTypeId, targetId, true)); +} + +TEST_F(OpcUaServerTest, DINodeSetTest) +{ + OpcUaServer server = createServer(); + server.prepare(); + + OpcUaNodeId uaNodeId(2, UA_DIID_TRANSFERRESULTDATADATATYPE); + + OpcUaObject qualifiedName; + ASSERT_NO_THROW(qualifiedName = server.readBrowseName(uaNodeId)); + ASSERT_EQ(ToStdString(qualifiedName->name), "TransferResultDataDataType"); +} +#ifdef NAMESPACE_TMSBT +TEST_F(OpcUaServerTest, TmsBtNodeSetTest) +{ + OpcUaServer server = createServer(); + server.prepare(); + + OpcUaNodeId uaNodeId(3, UA_TMSBTID_DAQBASEOBJECTTYPE); + + OpcUaObject qualifiedName; + ASSERT_NO_THROW(qualifiedName = server.readBrowseName(uaNodeId)); + ASSERT_EQ(ToStdString(qualifiedName->name), "DaqBaseObjectType"); +} +#endif + +#ifdef NAMESPACE_TMSBSP +TEST_F(OpcUaServerTest, TmsBspNodeSetTest) +{ + OpcUaServer server = createServer(); + server.prepare(); + + OpcUaNodeId uaNodeId(4, UA_TMSBSPID_SIGNALTYPE); + + OpcUaObject qualifiedName; + ASSERT_NO_THROW(qualifiedName = server.readBrowseName(uaNodeId)); + ASSERT_EQ(ToStdString(qualifiedName->name), "SignalType"); +} +#endif + +#ifdef NAMESPACE_TMSDEVICE +TEST_F(OpcUaServerTest, TmsDeviceNodeSetTest) +{ + OpcUaServer server = createServer(); + server.prepare(); + + OpcUaNodeId uaNodeId(5, UA_TMSDEVICEID_DAQDEVICETYPE); + + OpcUaObject qualifiedName; + ASSERT_NO_THROW(qualifiedName = server.readBrowseName(uaNodeId)); + ASSERT_EQ(ToStdString(qualifiedName->name), "DaqDeviceType"); +} +#endif + +TEST_F(OpcUaServerTest, GetServerNodes) +{ + OpcUaServer server = createServer(); + server.prepare(); + + ASSERT_NO_THROW(server.getNode(OpcUaNodeId(UA_NS0ID_SERVER))); + ASSERT_NO_THROW(server.getRootNode()); + ASSERT_NO_THROW(server.getObjectsNode()); + ASSERT_NO_THROW(server.getTypesNode()); + ASSERT_NO_THROW(server.getViewsNode()); + ASSERT_NO_THROW(server.getObjectTypesNode()); + ASSERT_NO_THROW(server.getVariableTypesNode()); + ASSERT_NO_THROW(server.getDataTypesNode()); + ASSERT_NO_THROW(server.getReferenceTypesNode()); +} + +const size_t nSelectClauses = 1; + +static UA_SimpleAttributeOperand* setupSelectClauses(void) +{ + UA_SimpleAttributeOperand* selectClauses = + (UA_SimpleAttributeOperand*) UA_Array_new(nSelectClauses, &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND]); + + selectClauses[0] = SimpleAttributeOperand::CreateMessageValue().getDetachedValue(); + + return selectClauses; +} + +TEST_F(OpcUaServerTest, TriggerEvent) +{ + OpcUaServer server = createServer(); + server.start(); + + auto client = CreateClientAndConnect(); + client->runIterate(); + + OpcUaObject request = UA_CreateSubscriptionRequest_default(); + + Subscription* subscription = client->createSubscription(request); + + /* Add a MonitoredItem */ + EventMonitoredItemCreateRequest item(UA_NODEID_NUMERIC(0, 2253)); + UA_EventFilter* filter = UA_EventFilter_new(); + UA_EventFilter_init(filter); + filter->selectClauses = setupSelectClauses(); + filter->selectClausesSize = nSelectClauses; + + item.setEventFilter(filter); + + std::promise promise; + subscription->monitoredItemsCreateEvent(UA_TIMESTAMPSTORETURN_BOTH, + *item, + [&promise](OpcUaClient* client, + Subscription* subContext, + MonitoredItem* monContext, + size_t nEventFields, + UA_Variant* eventFields) { + OpcUaVariant val(eventFields[0]); + UA_LocalizedText localizedText = val.readScalar(); + promise.set_value(ToStdString(localizedText.text)); + }); + + EventAttributes eventAttributes; + eventAttributes.setMessage("", "TestMessage"); + ASSERT_NO_THROW(server.triggerEvent(OpcUaNodeId(UA_NS0ID_BASEEVENTTYPE), OpcUaNodeId(UA_NS0ID_SERVER), eventAttributes)); + + auto future = promise.get_future(); + ASSERT_NE(future.wait_for(2s), std::future_status::timeout); + ASSERT_EQ(future.get(), "TestMessage"); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/tests/test_opcuaserverlock.cpp b/shared/libraries/opcua/opcuaserver/tests/test_opcuaserverlock.cpp new file mode 100644 index 0000000..3418fec --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/tests/test_opcuaserverlock.cpp @@ -0,0 +1,332 @@ +#include "gtest/gtest.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using OpcUaServerLockTest = testing::Test; + +TEST_F(OpcUaServerLockTest, Create) +{ + OpcUaServerLock serverLock; +} + +TEST_F(OpcUaServerLockTest, PasswordLock) +{ + OpcUaServerLock serverLock; + ASSERT_TRUE(serverLock.passwordLock("test")); +} + +TEST_F(OpcUaServerLockTest, PasswordLockTwoTimes) +{ + OpcUaServerLock serverLock; + serverLock.passwordLock("test"); + ASSERT_FALSE(serverLock.passwordLock("test1")); +} + +TEST_F(OpcUaServerLockTest, PasswordUnlock) +{ + OpcUaServerLock serverLock; + serverLock.passwordLock("test"); + ASSERT_TRUE(serverLock.passwordUnlock("test")); +} + +TEST_F(OpcUaServerLockTest, PasswordUnlockWrongPassword) +{ + OpcUaServerLock serverLock; + serverLock.passwordLock("test"); + ASSERT_FALSE(serverLock.passwordUnlock("wrong password")); +} + +TEST_F(OpcUaServerLockTest, PasswordUnlockWithoutLock) +{ + OpcUaServerLock serverLock; + ASSERT_TRUE(serverLock.passwordUnlock("test3")); +} + +TEST_F(OpcUaServerLockTest, IsPasswordLocked) +{ + OpcUaServerLock serverLock; + ASSERT_FALSE(serverLock.isPasswordLocked()); +} + +TEST_F(OpcUaServerLockTest, IsPasswordLockedAfterLock) +{ + OpcUaServerLock serverLock; + serverLock.passwordLock("test"); + ASSERT_TRUE(serverLock.isPasswordLocked()); +} + +TEST_F(OpcUaServerLockTest, IsPasswordLockedAfterUnlock) +{ + OpcUaServerLock serverLock; + serverLock.passwordLock("test"); + serverLock.passwordUnlock("test"); + ASSERT_FALSE(serverLock.isPasswordLocked()); +} + +TEST_F(OpcUaServerLockTest, IsPasswordLockedAfterWrongPasswordUnlock) +{ + OpcUaServerLock serverLock; + serverLock.passwordLock("test"); + serverLock.passwordUnlock("wrong password"); + ASSERT_TRUE(serverLock.isPasswordLocked()); +} + +TEST_F(OpcUaServerLockTest, LockConfigurationControl) +{ + OpcUaServerLock serverLock; + OpcUaNodeId sessionId(1, 1); + ASSERT_TRUE(serverLock.lockConfigurationControl(sessionId, std::chrono::seconds(10))); +} + +TEST_F(OpcUaServerLockTest, LockConfigurationControlExtendLock) +{ + OpcUaServerLock serverLock; + OpcUaNodeId sessionId(1, 1); + serverLock.lockConfigurationControl(sessionId, std::chrono::seconds(10)); + ASSERT_TRUE(serverLock.lockConfigurationControl(sessionId, std::chrono::seconds(10))); +} + +TEST_F(OpcUaServerLockTest, LockConfigurationControlRejectAccess) +{ + OpcUaServerLock serverLock; + + OpcUaNodeId sessionId1(1, 1); + serverLock.lockConfigurationControl(sessionId1, std::chrono::seconds(10)); + + OpcUaNodeId sessionId2(1, 2); + ASSERT_FALSE(serverLock.lockConfigurationControl(sessionId2, std::chrono::seconds(10))); +} + +TEST_F(OpcUaServerLockTest, LockConfigurationControlNewSessionAfterTimeout) +{ + OpcUaServerLock serverLock; + + OpcUaNodeId sessionId1(1, 1); + serverLock.lockConfigurationControl(sessionId1, std::chrono::seconds(0)); + + OpcUaNodeId sessionId2(1, 2); + ASSERT_TRUE(serverLock.lockConfigurationControl(sessionId2, std::chrono::seconds(10))); +} + +TEST_F(OpcUaServerLockTest, LockConfigurationControlAfterPasswordLock) +{ + OpcUaServerLock serverLock; + serverLock.passwordLock("test"); + + OpcUaNodeId sessionId(1, 1); + ASSERT_TRUE(serverLock.lockConfigurationControl(sessionId, std::chrono::seconds(10))); +} + +TEST_F(OpcUaServerLockTest, RefuseConfigurationControlLock) +{ + OpcUaServerLock serverLock; + serverLock.passwordLock("test"); + + OpcUaNodeId sessionId(1, 1); + serverLock.lockConfigurationControl(sessionId, std::chrono::seconds(10)); + + ASSERT_NO_THROW(serverLock.refuseConfigurationControlLock(sessionId)); +} + +TEST_F(OpcUaServerLockTest, SessionPasswordLock) +{ + OpcUaServerLock serverLock; + + OpcUaNodeId sessionId(1, 1); + ASSERT_TRUE(serverLock.passwordLock("test", sessionId)); +} + +TEST_F(OpcUaServerLockTest, SessionPasswordLockConfigurationLock) +{ + OpcUaServerLock serverLock; + + OpcUaNodeId sessionId1(1, 1); + serverLock.lockConfigurationControl(sessionId1, std::chrono::seconds(10)); + ASSERT_TRUE(serverLock.passwordLock("test", sessionId1)); +} + +TEST_F(OpcUaServerLockTest, SessionPasswordLockConfigurationLockByAnotherSession) +{ + OpcUaServerLock serverLock; + + OpcUaNodeId sessionId1(1, 1); + serverLock.lockConfigurationControl(sessionId1, std::chrono::seconds(10)); + + OpcUaNodeId sessionId2(1, 2); + ASSERT_FALSE(serverLock.passwordLock("test", sessionId2)); +} + +TEST_F(OpcUaServerLockTest, SessionPasswordUnlock) +{ + OpcUaServerLock serverLock; + + OpcUaNodeId sessionId(1, 1); + serverLock.passwordLock("test", sessionId); + ASSERT_TRUE(serverLock.passwordUnlock("test", sessionId)); +} + +TEST_F(OpcUaServerLockTest, SessionPasswordUnlockConfigurationLock) +{ + OpcUaServerLock serverLock; + + OpcUaNodeId sessionId(1, 1); + serverLock.lockConfigurationControl(sessionId, std::chrono::seconds(10)); + + serverLock.passwordLock("test", sessionId); + ASSERT_TRUE(serverLock.passwordUnlock("test", sessionId)); +} + +TEST_F(OpcUaServerLockTest, SessionPasswordUnlockConfigurationLockByAnotherSession) +{ + OpcUaServerLock serverLock; + + OpcUaNodeId sessionId1(1, 1); + serverLock.lockConfigurationControl(sessionId1, std::chrono::seconds(10)); + serverLock.passwordLock("test", sessionId1); + + OpcUaNodeId sessionId2(1, 2); + ASSERT_FALSE(serverLock.passwordUnlock("test", sessionId2)); +} + +TEST_F(OpcUaServerLockTest, RefuseConfigurationControlLockWithoutLock) +{ + OpcUaServerLock serverLock; + serverLock.passwordLock("test"); + + OpcUaNodeId sessionId(1, 1); + ASSERT_NO_THROW(serverLock.refuseConfigurationControlLock(sessionId)); +} + +TEST_F(OpcUaServerLockTest, RefuseConfigurationControlLockLockedByAnotherSession) +{ + OpcUaServerLock serverLock; + + OpcUaNodeId sessionId1(1, 1); + serverLock.lockConfigurationControl(sessionId1, std::chrono::seconds(10)); + + OpcUaNodeId sessionId2(1, 2); + ASSERT_NO_THROW(serverLock.refuseConfigurationControlLock(sessionId2)); +} + +TEST_F(OpcUaServerLockTest, HasConfigurationControlLock) +{ + OpcUaServerLock serverLock; + OpcUaNodeId sessionId(1, 1); + ASSERT_FALSE(serverLock.hasConfigurationControlLock(sessionId)); +} + +TEST_F(OpcUaServerLockTest, HasConfigurationControlLockAfterLock) +{ + OpcUaServerLock serverLock; + OpcUaNodeId sessionId(1, 1); + serverLock.lockConfigurationControl(sessionId, std::chrono::seconds(10)); + ASSERT_TRUE(serverLock.hasConfigurationControlLock(sessionId)); +} + +TEST_F(OpcUaServerLockTest, HasConfigurationControlLockAfterLockTimeout) +{ + OpcUaServerLock serverLock; + OpcUaNodeId sessionId(1, 1); + serverLock.lockConfigurationControl(sessionId, std::chrono::seconds(0)); //expires immediately + ASSERT_FALSE(serverLock.hasConfigurationControlLock(sessionId)); +} + +TEST_F(OpcUaServerLockTest, HasConfigurationControlLockAfterAnotherSessionLock) +{ + OpcUaServerLock serverLock; + OpcUaNodeId sessionId1(1, 1); + serverLock.lockConfigurationControl(sessionId1, std::chrono::seconds(10)); + + OpcUaNodeId sessionId2(1, 2); + ASSERT_FALSE(serverLock.hasConfigurationControlLock(sessionId2)); +} + +TEST_F(OpcUaServerLockTest, HasActiveConfigurationControlLock) +{ + OpcUaServerLock serverLock; + ASSERT_FALSE(serverLock.hasActiveConfigurationControlLock()); +} + +TEST_F(OpcUaServerLockTest, HasActiveConfigurationControlLockAfterLock) +{ + OpcUaServerLock serverLock; + OpcUaNodeId sessionId(1, 1); + serverLock.lockConfigurationControl(sessionId, std::chrono::seconds(10)); + + ASSERT_TRUE(serverLock.hasActiveConfigurationControlLock()); +} + +TEST_F(OpcUaServerLockTest, HasActiveConfigurationControlLockAfterTimeout) +{ + OpcUaServerLock serverLock; + OpcUaNodeId sessionId(1, 1); + serverLock.lockConfigurationControl(sessionId, std::chrono::seconds(0)); + + ASSERT_FALSE(serverLock.hasActiveConfigurationControlLock()); +} + +TEST_F(OpcUaServerLockTest, HasActiveConfigurationControlLockAfterRefuseLock) +{ + OpcUaServerLock serverLock; + OpcUaNodeId sessionId(1, 1); + serverLock.lockConfigurationControl(sessionId, std::chrono::seconds(10)); + serverLock.refuseConfigurationControlLock(sessionId); + + ASSERT_FALSE(serverLock.hasActiveConfigurationControlLock()); +} + +TEST_F(OpcUaServerLockTest, CanControlAcq) +{ + OpcUaServerLock serverLock; + OpcUaNodeId sessionId(1, 1); + ASSERT_TRUE(serverLock.canControlAcq(sessionId)); +} + +TEST_F(OpcUaServerLockTest, CanControlAcqPasswordLock) +{ + OpcUaServerLock serverLock; + serverLock.passwordLock("Test"); + OpcUaNodeId sessionId(1, 1); + ASSERT_FALSE(serverLock.canControlAcq(sessionId)); +} + +TEST_F(OpcUaServerLockTest, CanControlAcqPasswordUnlock) +{ + OpcUaServerLock serverLock; + serverLock.passwordLock("Test"); + serverLock.passwordUnlock("Test"); + OpcUaNodeId sessionId(1, 1); + ASSERT_TRUE(serverLock.canControlAcq(sessionId)); +} + +TEST_F(OpcUaServerLockTest, CanControlAcqConfigurationControlLock) +{ + OpcUaServerLock serverLock; + OpcUaNodeId sessionId(1, 1); + + serverLock.lockConfigurationControl(sessionId, std::chrono::seconds(10)); + ASSERT_TRUE(serverLock.canControlAcq(sessionId)); +} + +TEST_F(OpcUaServerLockTest, CanControlAcqConfigurationControlLockByOtherSession) +{ + OpcUaServerLock serverLock; + OpcUaNodeId sessionId1(1, 1); + serverLock.lockConfigurationControl(sessionId1, std::chrono::seconds(10)); + + OpcUaNodeId sessionId2(1, 2); + ASSERT_FALSE(serverLock.canControlAcq(sessionId2)); +} + +TEST_F(OpcUaServerLockTest, CanControlAcqConfigurationControlLockByOtherSessionAfterTimeout) +{ + OpcUaServerLock serverLock; + OpcUaNodeId sessionId1(1, 1); + serverLock.lockConfigurationControl(sessionId1, std::chrono::seconds(0)); + + OpcUaNodeId sessionId2(1, 2); + ASSERT_TRUE(serverLock.canControlAcq(sessionId2)); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/tests/test_opcuaservernode.cpp b/shared/libraries/opcua/opcuaserver/tests/test_opcuaservernode.cpp new file mode 100644 index 0000000..263a7fb --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/tests/test_opcuaservernode.cpp @@ -0,0 +1,128 @@ +#include +#include +#include +#include "common_test_functions.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using namespace utils; + +using OpcUaServerNodeTest = testing::Test; + +TEST_F(OpcUaServerNodeTest, CreateServerNode) +{ + OpcUaServer server = createServer(); + server.prepare(); + + ASSERT_NO_THROW(OpcUaServerNode(server, OpcUaNodeId(UA_NS0ID_SERVER))); +} + +TEST_F(OpcUaServerNodeTest, AddObject) +{ + OpcUaServer server = createServer(); + server.prepare(); + + OpcUaServerNode serverNode(server, OpcUaNodeId(UA_NS0ID_SERVER)); + ASSERT_NO_THROW(serverNode.addObject(OpcUaNodeId(1, "TestNode"), "TestBrowseName")); +} + +TEST_F(OpcUaServerNodeTest, GetNodeClass) +{ + OpcUaServer server = createServer(); + server.prepare(); + + OpcUaServerNode serverNode(server, OpcUaNodeId(UA_NS0ID_SERVER)); + ASSERT_EQ(serverNode.getNodeClass(), OpcUaNodeClass::Object); +} + +TEST_F(OpcUaServerNodeTest, GetBrowseName) +{ + OpcUaServer server = createServer(); + server.prepare(); + + OpcUaServerNode serverNode(server, OpcUaNodeId(UA_NS0ID_SERVER)); + auto browseName = serverNode.getBrowseName(); + ASSERT_EQ(ToStdString(browseName->name), "Server"); + ASSERT_EQ(browseName->namespaceIndex, 0); +} + +TEST_F(OpcUaServerNodeTest, GetDisplayName) +{ + OpcUaServer server = createServer(); + server.prepare(); + + OpcUaServerNode serverNode(server, OpcUaNodeId(UA_NS0ID_SERVER)); + auto displayName = serverNode.getDisplayName(); + + ASSERT_EQ(ToStdString(displayName->text), "Server"); +} + +TEST_F(OpcUaServerNodeTest, SetDisplayName) +{ + OpcUaServer server = createServer(); + server.prepare(); + + OpcUaServerNode serverNode(server, OpcUaNodeId(UA_NS0ID_SERVER)); + + ASSERT_NO_THROW(serverNode.setDisplayName("test")); + + auto displayName = serverNode.getDisplayName(); + ASSERT_EQ(ToStdString(displayName->text), "test"); +} + +TEST_F(OpcUaServerNodeTest, AddVariable) +{ + OpcUaServer server = createServer(); + server.prepare(); + + OpcUaServerNode serverNode(server, OpcUaNodeId(UA_NS0ID_SERVER)); + ASSERT_NO_THROW(serverNode.addVariable(OpcUaNodeId(1, "TestNode"), "TestBrowseName")); +} + +TEST_F(OpcUaServerNodeTest, ReadValue) +{ + OpcUaServer server = createServer(); + server.prepare(); + + AddVariableNodeParams params(OpcUaNodeId(1, "TestNode")); + params.setBrowseName("TestBrowseName"); + params.setDataType(OpcUaNodeId(UA_TYPES[UA_TYPES_INT64].typeId)); + int64_t value = 5; + UA_Variant_setScalarCopy(¶ms.attr->value, &value, &UA_TYPES[UA_TYPES_INT64]); + + auto variableNode = server.getObjectsNode().addVariable(params); + ASSERT_EQ(variableNode.read(), 5); + ASSERT_THROW(variableNode.read(), std::runtime_error); +} + +TEST_F(OpcUaServerNodeTest, SetValue) +{ + OpcUaServer server = createServer(); + server.prepare(); + + AddVariableNodeParams params(OpcUaNodeId(1, "TestNode")); + params.setBrowseName("TestBrowseName"); + params.setDataType(OpcUaNodeId(UA_TYPES[UA_TYPES_INT64].typeId)); + + auto variableNode = server.getObjectsNode().addVariable(params); + ASSERT_NO_THROW(variableNode.write(5)); + ASSERT_EQ(variableNode.read(), 5); +} + +TEST_F(OpcUaServerNodeTest, BrowseChildNodes) +{ + OpcUaServer server = createServer(); + server.prepare(); + + auto parentNode = server.getObjectsNode().addObject(OpcUaNodeId(0, "ParentNode"), "ParentNode"); + auto childNode = parentNode.addObject(OpcUaNodeId(0, "ChildNode"), "ChildNode"); + + auto result = parentNode.browseChildNodes(); + ASSERT_EQ(result.size(), 1u); + const auto& firstNode = result[0]; + ASSERT_NE(dynamic_cast(firstNode.get()), nullptr); + ASSERT_EQ(firstNode->getNodeId(), OpcUaNodeId(0, "ChildNode")); + ASSERT_EQ(ToStdString(firstNode->getBrowseName()->name), "ChildNode"); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/tests/test_opcuaservernodefactory.cpp b/shared/libraries/opcua/opcuaserver/tests/test_opcuaservernodefactory.cpp new file mode 100644 index 0000000..5c84ca9 --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/tests/test_opcuaservernodefactory.cpp @@ -0,0 +1,44 @@ +#include +#include +#include +#include "common_test_functions.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using OpcUaServerNodeFactoryTest = testing::Test; + +TEST_F(OpcUaServerNodeFactoryTest, CreateServerNodeFactory) +{ + OpcUaServer server = createServer(); + server.prepare(); + + ASSERT_NO_THROW(OpcUaServerNodeFactory nodeFactory(server)); +} + +TEST_F(OpcUaServerNodeFactoryTest, CreateObject) +{ + OpcUaServer server = createServer(); + server.prepare(); + + OpcUaServerNodeFactory nodeFactory(server); + + std::unique_ptr newNode; + ASSERT_NO_THROW(newNode = nodeFactory.createServerNode(OpcUaNodeId(UA_NS0ID_SERVER), OpcUaNodeClass::Object)); + + ASSERT_NE(dynamic_cast(newNode.get()), nullptr); +} + +TEST_F(OpcUaServerNodeFactoryTest, CreateVariable) +{ + OpcUaServer server = createServer(); + server.prepare(); + + OpcUaServerNodeFactory nodeFactory(server); + + std::unique_ptr newNode; + ASSERT_NO_THROW(newNode = nodeFactory.createServerNode(OpcUaNodeId(UA_NS0ID_SERVER_SERVERCAPABILITIES), OpcUaNodeClass::Variable)); + + ASSERT_NE(dynamic_cast(newNode.get()), nullptr); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/tests/test_opcuasession.cpp b/shared/libraries/opcua/opcuaserver/tests/test_opcuasession.cpp new file mode 100644 index 0000000..6d34565 --- /dev/null +++ b/shared/libraries/opcua/opcuaserver/tests/test_opcuasession.cpp @@ -0,0 +1,238 @@ +#include "gtest/gtest.h" +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + + +using OpcUaSessionTest = testing::Test; + +TEST_F(OpcUaSessionTest, Create) +{ + OpcUaServerLock serverLock; + OpcUaSession session(OpcUaNodeId(1, 1), &serverLock); +} + +TEST_F(OpcUaSessionTest, LockConfigurationControl) +{ + OpcUaServerLock serverLock; + OpcUaSession session(OpcUaNodeId(1, 1), &serverLock); + ASSERT_TRUE(session.lockConfigurationControl(std::chrono::seconds(10))); +} + +TEST_F(OpcUaSessionTest, LockConfigurationControlExtendLock) +{ + OpcUaServerLock serverLock; + OpcUaSession session(OpcUaNodeId(1, 1), &serverLock); + session.lockConfigurationControl(std::chrono::seconds(10)); + ASSERT_TRUE(session.lockConfigurationControl(std::chrono::seconds(10))); +} + +TEST_F(OpcUaSessionTest, LockConfigurationControlRejectAccess) +{ + OpcUaServerLock serverLock; + + OpcUaSession session1(OpcUaNodeId(1, 1), &serverLock); + session1.lockConfigurationControl(std::chrono::seconds(10)); + + OpcUaSession session2(OpcUaNodeId(1, 2), &serverLock); + ASSERT_FALSE(session2.lockConfigurationControl(std::chrono::seconds(10))); +} + +TEST_F(OpcUaSessionTest, LockConfigurationControlNewSessionAfterTimeout) +{ + OpcUaServerLock serverLock; + OpcUaSession session1(OpcUaNodeId(1, 1), &serverLock); + session1.lockConfigurationControl(std::chrono::seconds(0)); + + OpcUaSession session2(OpcUaNodeId(1, 2), &serverLock); + ASSERT_TRUE(session2.lockConfigurationControl(std::chrono::seconds(10))); +} + +TEST_F(OpcUaSessionTest, LockConfigurationControlAfterPasswordLock) +{ + OpcUaServerLock serverLock; + serverLock.passwordLock("test"); + + OpcUaSession session(OpcUaNodeId(1, 1), &serverLock); + ASSERT_TRUE(session.lockConfigurationControl(std::chrono::seconds(10))); +} + +TEST_F(OpcUaSessionTest, RefuseConfigurationControlLock) +{ + OpcUaServerLock serverLock; + serverLock.passwordLock("test"); + + OpcUaSession session(OpcUaNodeId(1, 1), &serverLock); + session.lockConfigurationControl(std::chrono::seconds(10)); + + ASSERT_NO_THROW(session.refuseConfigurationControlLock()); +} + +TEST_F(OpcUaSessionTest, PasswordLock) +{ + OpcUaServerLock serverLock; + + OpcUaSession session(OpcUaNodeId(1, 1), &serverLock); + ASSERT_TRUE(session.passwordLock("test")); +} + +TEST_F(OpcUaSessionTest, PasswordLockConfigurationLock) +{ + OpcUaServerLock serverLock; + + OpcUaSession session(OpcUaNodeId(1, 1), &serverLock); + session.lockConfigurationControl(std::chrono::seconds(10)); + ASSERT_TRUE(session.passwordLock("test")); +} + +TEST_F(OpcUaSessionTest, PasswordLockConfigurationLockByAnotherSession) +{ + OpcUaServerLock serverLock; + + OpcUaSession session1(OpcUaNodeId(1, 1), &serverLock); + session1.lockConfigurationControl(std::chrono::seconds(10)); + + OpcUaSession session2(OpcUaNodeId(1, 2), &serverLock); + ASSERT_FALSE(session2.passwordLock("test")); +} + +TEST_F(OpcUaSessionTest, PasswordUnlock) +{ + OpcUaServerLock serverLock; + + OpcUaSession session(OpcUaNodeId(1, 1), &serverLock); + session.passwordLock("test"); + ASSERT_TRUE(session.passwordUnlock("test")); +} + +TEST_F(OpcUaSessionTest, PasswordUnlockConfigurationLock) +{ + OpcUaServerLock serverLock; + + OpcUaSession session(OpcUaNodeId(1, 1), &serverLock); + session.lockConfigurationControl(std::chrono::seconds(10)); + + session.passwordLock("test"); + ASSERT_TRUE(session.passwordUnlock("test")); +} + +TEST_F(OpcUaSessionTest, PasswordUnlockConfigurationLockByAnotherSession) +{ + OpcUaServerLock serverLock; + + OpcUaSession session1(OpcUaNodeId(1, 1), &serverLock); + session1.lockConfigurationControl(std::chrono::seconds(10)); + session1.passwordLock("test"); + + OpcUaSession session2(OpcUaNodeId(1, 2), &serverLock); + ASSERT_FALSE(session2.passwordUnlock("test")); +} + +TEST_F(OpcUaSessionTest, RefuseConfigurationControlLockWithoutLock) +{ + OpcUaServerLock serverLock; + serverLock.passwordLock("test"); + + OpcUaSession session(OpcUaNodeId(1, 1), &serverLock); + ASSERT_NO_THROW(session.refuseConfigurationControlLock()); +} + +TEST_F(OpcUaSessionTest, RefuseConfigurationControlLockLockedByAnotherSession) +{ + OpcUaServerLock serverLock; + + OpcUaSession session1(OpcUaNodeId(1, 1), &serverLock); + session1.lockConfigurationControl(std::chrono::seconds(10)); + + OpcUaSession session2(OpcUaNodeId(1, 2), &serverLock); + ASSERT_NO_THROW(session2.refuseConfigurationControlLock()); +} + +TEST_F(OpcUaSessionTest, HasConfigurationControlLock) +{ + OpcUaServerLock serverLock; + OpcUaSession session(OpcUaNodeId(1, 1), &serverLock); + ASSERT_FALSE(session.hasConfigurationControlLock()); +} + +TEST_F(OpcUaSessionTest, HasConfigurationControlLockAfterLock) +{ + OpcUaServerLock serverLock; + OpcUaSession session(OpcUaNodeId(1, 1), &serverLock); + session.lockConfigurationControl(std::chrono::seconds(10)); + ASSERT_TRUE(session.hasConfigurationControlLock()); +} + +TEST_F(OpcUaSessionTest, HasConfigurationControlLockAfterLockTimeout) +{ + OpcUaServerLock serverLock; + OpcUaSession session(OpcUaNodeId(1, 1), &serverLock); + session.lockConfigurationControl(std::chrono::seconds(0)); //expires immediately + ASSERT_FALSE(session.hasConfigurationControlLock()); +} + +TEST_F(OpcUaSessionTest, HasConfigurationControlLockAfterAnotherSessionLock) +{ + OpcUaServerLock serverLock; + OpcUaSession session1(OpcUaNodeId(1, 1), &serverLock); + session1.lockConfigurationControl(std::chrono::seconds(10)); + + OpcUaSession session2(OpcUaNodeId(1, 2), &serverLock); + ASSERT_FALSE(session2.hasConfigurationControlLock()); +} + +TEST_F(OpcUaSessionTest, CanControlAcq) +{ + OpcUaServerLock serverLock; + OpcUaSession session(OpcUaNodeId(1, 1), &serverLock); + ASSERT_TRUE(session.canControlAcq()); +} + +TEST_F(OpcUaSessionTest, CanControlAcqPasswordLock) +{ + OpcUaServerLock serverLock; + serverLock.passwordLock("Test"); + OpcUaSession session(OpcUaNodeId(1, 1), &serverLock); + ASSERT_FALSE(session.canControlAcq()); +} + +TEST_F(OpcUaSessionTest, CanControlAcqPasswordUnlock) +{ + OpcUaServerLock serverLock; + serverLock.passwordLock("Test"); + serverLock.passwordUnlock("Test"); + OpcUaSession session(OpcUaNodeId(1, 1), &serverLock); + ASSERT_TRUE(session.canControlAcq()); +} + +TEST_F(OpcUaSessionTest, CanControlAcqConfigurationControlLock) +{ + OpcUaServerLock serverLock; + OpcUaSession session(OpcUaNodeId(1, 1), &serverLock); + + session.lockConfigurationControl(std::chrono::seconds(10)); + ASSERT_TRUE(session.canControlAcq()); +} + +TEST_F(OpcUaSessionTest, CanControlAcqConfigurationControlLockByOtherSession) +{ + OpcUaServerLock serverLock; + OpcUaSession session1(OpcUaNodeId(1, 1), &serverLock); + session1.lockConfigurationControl(std::chrono::seconds(10)); + + OpcUaSession session2(OpcUaNodeId(1, 2), &serverLock); + ASSERT_FALSE(session2.canControlAcq()); +} + +TEST_F(OpcUaSessionTest, CanControlAcqConfigurationControlLockByOtherSessionAfterTimeout) +{ + OpcUaServerLock serverLock; + OpcUaSession session1(OpcUaNodeId(1, 1), &serverLock); + session1.lockConfigurationControl(std::chrono::seconds(0)); + + OpcUaSession session2(OpcUaNodeId(1, 2), &serverLock); + ASSERT_TRUE(session2.canControlAcq()); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/CMakeLists.txt b/shared/libraries/opcua/opcuashared/CMakeLists.txt new file mode 100644 index 0000000..9d2586d --- /dev/null +++ b/shared/libraries/opcua/opcuashared/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.2) +set_cmake_folder_context(TARGET_FOLDER_NAME shared) +project(OpcUaShared CXX C) + +add_subdirectory(src) + +if (OPENDAQ_ENABLE_TESTS) + add_subdirectory(tests) +endif() diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/bcrypt.h b/shared/libraries/opcua/opcuashared/include/opcuashared/bcrypt.h new file mode 100644 index 0000000..759945c --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/bcrypt.h @@ -0,0 +1,121 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file bcrypt.h + * @author Jan Mikolič + * @date 23/04/2021 + * @version 1.0 + * + * @brief Wrapper class for BCrypt password hashing algorithm. + * + */ + +#pragma once +#include +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +/** + * Wrapper class for BCrypt password hashing algorithm. + */ +class BCrypt +{ +private: + static const int InfoPartSize = 7; + static const int SaltPartSize = 22; + static const int HashPartSize = 31; + static const int SaltSize = InfoPartSize + SaltPartSize; + static const int HashSize = InfoPartSize + SaltPartSize + HashPartSize; + + std::random_device randomDevice; + std::uniform_int_distribution randomDist; + + std::vector randBytes(unsigned int length); + +public: + BCrypt(); + + /** + * Compute BCrypt hash of a password using random salt. + * + * @param password The password in plain text to be hashed + * @param rounds Base-2 logarithm of the iteration count for the underlying Blowfish-based hashing algorithm + * @returns Hash string of the provided password + * @throws {BCryptException} if blowfish algorithm failed to generate the hash + */ + std::string hash(const std::string& password, unsigned int rounds = 10); + + /** + * Compute BCrypt hash of a password using static salt. Try to avoid using this method, but if you must have a static salt, then + * generate it with generateSalt(int size) method. + * + * @param password The password in plain text to be hashed + * @param salt The salt to be used for hashing the password + * @param rounds Base-2 logarithm of the iteration count for the underlying Blowfish-based hashing algorithm + * @returns Hash string of the provided password + * @throws {BCryptException} if blowfish algorithm failed to generate the hash + * @throws {BCryptSaltSizeException} if salt size is too small + */ + std::string hash(const std::string& password, std::string salt, unsigned int rounds = 10) const; + + /** + * Verifies if the password matches a hash. + * + * @param hash BCrypt hash of the password + * @param password The password in plain text + * @returns true if password matches the hash + */ + static bool Verify(const std::string& hash, const std::string& password); + + /** + * Generate a random salt string of the specified size. + * + * @param size The size of the salt to be generated + * @returns Generated salt string + * @throws {BCryptException} if blowfish algorithm failed to generate the salt + * @throws {BCryptSaltSizeException} if size is too small + */ + std::string generateSalt(unsigned int size); + + /** + * Generate a salt string from provided byte array. + * + * @param bytes Byte array from which to generate the salt + * @param size The size of the provided byte arry + * @returns Generated salt string + * @throws {BCryptException} if blowfish algorithm failed to generate the salt + * @throws {BCryptSaltSizeException} if size is too small + */ + std::string generateSalt(char* bytes, int size) const; +}; + +class BCryptException : public std::runtime_error +{ +public: + explicit BCryptException(const std::string& message); +}; + +class BCryptSaltSizeException : public BCryptException +{ +public: + explicit BCryptSaltSizeException(unsigned int minSaltSize); +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/bcrypt/crypt_blowfish.h b/shared/libraries/opcua/opcuashared/include/opcuashared/bcrypt/crypt_blowfish.h new file mode 100644 index 0000000..ec6d56d --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/bcrypt/crypt_blowfish.h @@ -0,0 +1,24 @@ +/* + * Written by Solar Designer in 2000-2011. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See crypt_blowfish.c for more information. + */ + +#ifndef _CRYPT_BLOWFISH_H +#define _CRYPT_BLOWFISH_H + +extern int _crypt_output_magic(const char *setting, char *output, int size); +extern char* _crypt_blowfish_rn(const char *key, const char *setting, char *output, int size); +extern char* _crypt_gensalt_blowfish_rn(const char *prefix, unsigned long count, const char *input, int size, char *output, int output_size); + +#endif diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuadatatype.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuadatatype.h new file mode 100644 index 0000000..2971223 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuadatatype.h @@ -0,0 +1,32 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaDataType; +using OpcUaDataTypePtr = std::shared_ptr; + +class OpcUaDataType : public OpcUaNode +{ +public: + explicit OpcUaDataType(const UA_ReferenceDescription& uaNodeDescription); + ~OpcUaDataType(); +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanode.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanode.h new file mode 100644 index 0000000..1220e6c --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanode.h @@ -0,0 +1,69 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Abstract representation of OPC UA node (can be object, variable, method ietc.) + */ + +#pragma once + +#include "opcuashared/opcua.h" +#include "opcuashared/opcuanodeid.h" +#include "opcuashared/opcuacommon.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaType; +using OpcUaTypePtr = std::shared_ptr; + +class OpcUaNode; +using OpcUaNodePtr = std::shared_ptr; + +class OpcUaNode +{ +public: + OpcUaNode(const OpcUaNodeId& uaNode, OpcUaNodeClass nodeClass); + OpcUaNode(const UA_ReferenceDescription& uaNodeDescription, OpcUaNodeClass nodeClass); + virtual ~OpcUaNode(); + + // NodeID + const OpcUaNodeId& getNodeId() const; + + // Attributes + const OpcUaNodeClass& getNodeClass() const; + void setNodeClass(const UA_NodeClass& nodeClass); + void setNodeClass(OpcUaNodeClass nodeClass); + const std::string& getBrowseName() const; + void setBrowseName(const std::string& browseName); + const std::string& getDisplayName() const; + void setDisplayName(const std::string& displayName); + + static std::string GetBrowseName(const UA_QualifiedName& browseName); + + void setType(const OpcUaTypePtr& type); + void setType(const OpcUaNodeId& objectTypeId); + const OpcUaNodeId& getTypeId() const; + +protected: + OpcUaNodeId nodeId; + std::string browseName; + std::string displayName; + OpcUaNodeClass nodeClass; + OpcUaNodeId typeId; // hasTypeDefinition (object and variable class) +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodemethod.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodemethod.h new file mode 100644 index 0000000..7b7472a --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodemethod.h @@ -0,0 +1,79 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include "opcuanode.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + + +struct OpcUaChannelMethodParameter +{ +public: + std::string getName() const + { + return name; + } + void setName(const std::string& name) + { + this->name = name; + } + + OpcUaNodeId getDataTypeId() const + { + return dataTypeId; + } + + void setDataTypeId(const OpcUaNodeId& dataTypeId) + { + this->dataTypeId = dataTypeId; + } + +private: + std::string name; + OpcUaNodeId dataTypeId; +}; + +class OpcUaNodeMethod; +using OpcUaNodeMethodPtr = std::shared_ptr; + +class OpcUaNodeMethod : public OpcUaNode +{ +public: + OpcUaNodeMethod(const OpcUaNodeId& uaNode, const OpcUaNodeId& parentNodeId); + OpcUaNodeMethod(const UA_ReferenceDescription& uaNodeDescription, const OpcUaNodeId& parentNodeId); + ~OpcUaNodeMethod(); + + std::string getTypeDescription(); + void initTypeDescription(); + + void addInputParameter(const std::string& name, const OpcUaNodeId& dataTypeId); + void addOutputParameter(const std::string& name, const OpcUaNodeId& dataTypeId); + + std::list inputParameters; + std::list outputParameters; + + const OpcUaNodeId& getParentNodeId() const; + +protected: + std::string typeDescription; + OpcUaNodeId parentNodeId; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodeobject.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodeobject.h new file mode 100644 index 0000000..98386c0 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodeobject.h @@ -0,0 +1,39 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "opcuashared/node/opcuanode.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaNodeObject; +using OpcUaNodeObjectPtr = std::shared_ptr; + +class OpcUaNodeObject : public OpcUaNode +{ +public: + explicit OpcUaNodeObject(const OpcUaNodeId& uaNode); + explicit OpcUaNodeObject(const UA_ReferenceDescription& uaNodeDescription); + ~OpcUaNodeObject(); + + static OpcUaNodeObjectPtr instantiateRoot(); + static OpcUaNodeObjectPtr instantiateObjectsFolder(); + +private: +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodevariable.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodevariable.h new file mode 100644 index 0000000..ffea435 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodevariable.h @@ -0,0 +1,50 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaNodeVariable; +using OpcUaNodeVariablePtr = std::shared_ptr; + +class OpcUaNodeVariable : public OpcUaNode +{ +public: + OpcUaNodeVariable(const OpcUaNodeId& uaNode, const UA_DataType& uaDataType, size_t dimension = 1); + OpcUaNodeVariable(const OpcUaNodeId& uaNode, const OpcUaNodeId& dataTypeNodeId, size_t dimension = 1); + OpcUaNodeVariable(const UA_ReferenceDescription& uaNodeDescription, const UA_DataType& uaDataType, size_t dimension = 1); + OpcUaNodeVariable(const UA_ReferenceDescription& uaNodeDescription, const OpcUaNodeId& dataTypeNodeId, size_t dimension = 1); + ~OpcUaNodeVariable(); + + const OpcUaNodeId getDataTypeNodeId() const; + + OpcUaVariantPtr getVariant(); + void setVariant(const UA_Variant& value); + + size_t getDimension(); + void setDimension(size_t dimension); + +protected: + OpcUaNodeId dataTypeNodeId; + OpcUaVariantPtr variant; + size_t dimension; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuaobjecttype.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuaobjecttype.h new file mode 100644 index 0000000..a4cc122 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuaobjecttype.h @@ -0,0 +1,32 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaObjectType; +using OpcUaObjectTypePtr = std::shared_ptr; + +class OpcUaObjectType : public OpcUaType +{ +public: + explicit OpcUaObjectType(const OpcUaNodeId& typeId); + ~OpcUaObjectType(); +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuatype.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuatype.h new file mode 100644 index 0000000..671156c --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuatype.h @@ -0,0 +1,31 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaType; +using OpcUaTypePtr = std::shared_ptr; + +class OpcUaType : public OpcUaNode +{ +public: + OpcUaType(const OpcUaNodeId& typeId, OpcUaNodeClass nodeClass); +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuavariabletype.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuavariabletype.h new file mode 100644 index 0000000..d628b82 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuavariabletype.h @@ -0,0 +1,32 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaVariableType; +using OpcUaVariableTypePtr = std::shared_ptr; + +class OpcUaVariableType : public OpcUaType +{ +public: + explicit OpcUaVariableType(const OpcUaNodeId& typeId); + ~OpcUaVariableType(); +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcua.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcua.h new file mode 100644 index 0000000..81efd15 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcua.h @@ -0,0 +1,121 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * OPC UA library; is included in every class across the solution. + */ +#pragma once +#define BEGIN_NAMESPACE_OPENDAQ_OPCUA \ + namespace daq::opcua \ + { + +#define END_NAMESPACE_OPENDAQ_OPCUA \ + } + +#include + +// clang compiler on macOS emits warnings when compiling code in types.h, +// so we want to silence it here +#if defined(__GNUC__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wmissing-field-initializers" + #pragma GCC diagnostic ignored "-Wmissing-braces" +#endif + +#include +#include + +#if defined(__GNUC__) + #pragma GCC diagnostic pop +#endif + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +enum class OpcUaNodeClass +{ + Object = UA_NODECLASS_OBJECT, + Variable = UA_NODECLASS_VARIABLE, + Method = UA_NODECLASS_METHOD, + ObjectType = UA_NODECLASS_OBJECTTYPE, + VariableType = UA_NODECLASS_VARIABLETYPE, + ReferenceType = UA_NODECLASS_REFERENCETYPE, + DataType = UA_NODECLASS_DATATYPE, + View = UA_NODECLASS_VIEW, + + All = Object | Variable | Method | ObjectType | VariableType | ReferenceType | DataType | View // Mask +}; + +enum class OpcUaBrowseDirection +{ + Forward = UA_BROWSEDIRECTION_FORWARD, + Inverse = UA_BROWSEDIRECTION_INVERSE, + Both = UA_BROWSEDIRECTION_BOTH +}; + +#define OPCUA_STATUSCODE_FAILED(x) ((x) &0x80000000) +#define OPCUA_STATUSCODE_SUCCEEDED(x) (!OPCUA_STATUSCODE_FAILED(x)) +#define OPCUA_STATUSCODE_IS_GOOD(x) (x == UA_STATUSCODE_GOOD) +#define OPCUA_STATUSCODE_NOT_CONNECTED(x) ((x == UA_STATUSCODE_BADDISCONNECT) || (x == UA_STATUSCODE_BADCONNECTIONCLOSED) || (x == UA_STATUSCODE_BADNOTCONNECTED)) + +#define OPCUA_STATUSCODE_LOG_MESSAGE(STATUS_CODE) \ + "StatusCode 0x" << std::hex << std::uppercase << STATUS_CODE << std::nouppercase << std::dec << "(" << UA_StatusCode_name(STATUS_CODE) \ + << ")" + +#define THROW_RUNTIME_ERROR(x) \ + { \ + std::stringstream excStream; \ + excStream << x; \ + throw std::runtime_error(excStream.str().c_str()); \ + } + +inline bool operator==(const UA_String& l, const UA_String& r) +{ + return UA_String_equal(&l, &r); +} + +inline bool operator!=(const UA_String& l, const UA_String& r) +{ + return !(l == r); +} + +inline bool operator==(const UA_String& l, const char* r) +{ + UA_String rStr{}; + if (r) + { + rStr.length = strlen(r); + rStr.data = (UA_Byte*) r; + } + + return l == rStr; +} + +inline bool operator!=(const UA_String& l, const char* r) +{ + return !(l == r); +} + +inline bool operator==(const char* l, const UA_String& r) +{ + return r == l; +} + +inline bool operator!=(const char* l, const UA_String& r) +{ + return r != l; +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacallmethodresult.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacallmethodresult.h new file mode 100644 index 0000000..526a4b2 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacallmethodresult.h @@ -0,0 +1,43 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "opcuacommon.h" +#include "opcuavariant.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaCallMethodResult +{ +public: + OpcUaCallMethodResult(const UA_CallMethodResult& callMethodResult); + virtual ~OpcUaCallMethodResult(); + + const UA_StatusCode& getStatusCode() const; + bool isStatusOK() const; + + size_t getOutputArgumentsSize() const; + OpcUaVariant getOutputArgument(size_t i) const; + + const UA_CallMethodResult& getCallMethodResult() const; + operator const UA_CallMethodResult&() const; + +protected: + const UA_CallMethodResult& callMethodResult; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacollection.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacollection.h new file mode 100644 index 0000000..150bc0a --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacollection.h @@ -0,0 +1,54 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* +Common template for collection of endpoints, clients etc. +*/ +#pragma once +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +template > +class OpcUaCollection : public OpcUaCollectionT +{ + using OpcUaCollectionT::OpcUaCollectionT; + +public: + using BaseType = T; + + void remove(size_t index); + int indexOf(const T item); +}; + +template +void OpcUaCollection::remove(size_t index) +{ + OpcUaCollection::erase(OpcUaCollection::begin() + index); +} + +template +int OpcUaCollection::indexOf(const T item) +{ + size_t pos = std::find(OpcUaCollection::begin(), OpcUaCollection::end(), item) - OpcUaCollection::begin(); + if (pos < OpcUaCollection::size()) + return int(pos); + return -1; +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacommon.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacommon.h new file mode 100644 index 0000000..6a4d607 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacommon.h @@ -0,0 +1,48 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * A bundle of static methods used in different projects accross the platform + */ + +#pragma once + +#include +#include +#include +#include + +#include "open62541/util.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +namespace utils +{ + inline std::string ToStdString(const UA_String& value) + { + return std::string((const char*) value.data, value.length); + } + + double ToSeconds(const UA_DateTime& time); + UA_StatusCode ToUaVariant(double value, const UA_NodeId& dataTypeNodeId, UA_Variant* var); + void ToUaVariant(const std::string& value, const UA_NodeId& dataTypeNodeId, UA_Variant* var); + using DurationTimeStamp = std::chrono::steady_clock::time_point; + DurationTimeStamp GetDurationTimeStamp(); + + OpcUaObject LoadFile(const std::string& path); +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatatypearraylist.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatatypearraylist.h new file mode 100644 index 0000000..9fdc7bf --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatatypearraylist.h @@ -0,0 +1,36 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaDataTypeArrayList : protected std::list +{ +public: + using std::list::list; + + OpcUaDataTypeArrayList(const OpcUaDataTypeArrayList& copy); + OpcUaDataTypeArrayList& operator=(const OpcUaDataTypeArrayList& other); + + void add(const size_t typesSize, const UA_DataType* types); + const UA_DataTypeArray* getCustomDataTypes() const; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatavalue.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatavalue.h new file mode 100644 index 0000000..9814259 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatavalue.h @@ -0,0 +1,44 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "opcuacommon.h" +#include "opcuavariant.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaDataValue +{ +public: + OpcUaDataValue(const UA_DataValue* dataValue); + virtual ~OpcUaDataValue(); + + bool hasValue() const; + const OpcUaVariant& getValue() const; + const UA_StatusCode& getStatusCode() const; + + bool isStatusOK() const; + + const UA_DataValue* getDataValue() const; + operator const UA_DataValue*() const; + +protected: + const UA_DataValue* dataValue; + const OpcUaVariant variant; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaendpoint.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaendpoint.h new file mode 100644 index 0000000..042da82 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaendpoint.h @@ -0,0 +1,69 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + +Endpoint defines the used network protocol and the necessary security +settings to be able to connect to the server. +One server can provide one or more endpoints. + +*/ + +#pragma once + +#include +#include +#include +#include "opcuacommon.h" +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaEndpoint; +using OpcUaEndpointPtr = std::shared_ptr; + +class OpcUaEndpoint +{ +public: + OpcUaEndpoint(const std::string& name, const std::string& url); + OpcUaEndpoint(); + + void setName(const std::string& name); + const std::string& getName() const; + + void setUrl(const std::string& url); + const std::string& getUrl() const; + + void setSecurityConfig(OpcUaClientSecurityConfig* securityConfig); + const OpcUaClientSecurityConfig* getSecurityConfig() const; + + void registerCustomTypes(const size_t typesSize, const UA_DataType* types); + const UA_DataTypeArray* getCustomDataTypes() const; + + void setLogLevel(const UA_LogLevel logLevel); + UA_LogLevel getLogLevel() const; + +private: + std::string name{}; + std::string url{}; + std::optional securityConfig; + OpcUaDataTypeArrayList customDataTypeList; + UA_LogLevel logLevel = UA_LOGLEVEL_WARNING; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaexception.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaexception.h new file mode 100644 index 0000000..e04e6ee --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaexception.h @@ -0,0 +1,60 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "opcua.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaException : public std::runtime_error +{ +public: + OpcUaException(UA_StatusCode statusCode, char const* const message = "") + : std::runtime_error(message) + , statusCode(statusCode) + { + } + + OpcUaException(UA_StatusCode statusCode, const std::string& message) + : OpcUaException(statusCode, message.c_str()) + { + } + + UA_StatusCode getStatusCode() const + { + return statusCode; + } + +private: + UA_StatusCode statusCode; +}; + +inline void CheckStatusCodeException(UA_StatusCode code, const char* message = "") +{ + if (code != UA_STATUSCODE_GOOD) + { + throw OpcUaException(code, message); + } +} + +inline void CheckStatusCodeException(UA_StatusCode code, const std::string& message) +{ + CheckStatusCodeException(code, message.c_str()); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcualog.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcualog.h new file mode 100644 index 0000000..82731e0 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcualog.h @@ -0,0 +1,25 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once +#include + +#define LOGD std::stringstream() +#define LOGI LOGD +#define LOGV LOGD +#define LOGW LOGD +#define LOGE LOGD + +#define LOG(...) LOGD diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodecollection.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodecollection.h new file mode 100644 index 0000000..91f0b90 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodecollection.h @@ -0,0 +1,42 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +#include "opcua.h" +#include "opcuacollection.h" +#include "node/opcuanode.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaNodeCollection : public OpcUaCollection +{ + using OpcUaCollection::OpcUaCollection; + +public: + OpcUaNodeCollection selectNodes(OpcUaNodeClass nodeClassMask); + + OpcUaNodePtr locateNode(const OpcUaNodeId& nodeId) const; +}; + + + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodeid.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodeid.h new file mode 100644 index 0000000..33b6144 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodeid.h @@ -0,0 +1,158 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using OpcUaIdentifierUniversal = std::string; + +using UA_NodeIdPtr = UA_NodeId*; + +enum class OpcUaIdentifierType +{ + Numeric = 0, + String = 3, + Guid = 4, + Undefined = -1 +}; + +static_assert(static_cast(OpcUaIdentifierType::Numeric) == UA_NODEIDTYPE_NUMERIC); +static_assert(static_cast(OpcUaIdentifierType::String) == UA_NODEIDTYPE_STRING); +static_assert(static_cast(OpcUaIdentifierType::Guid) == UA_NODEIDTYPE_GUID); + +#define OPCUANODEID_ROOTFOLDER OpcUaNodeId(0u, UA_NS0ID_ROOTFOLDER) +#define OPCUANODEID_OBJECTSFOLDER OpcUaNodeId(0u, UA_NS0ID_OBJECTSFOLDER) + +class OpcUaNodeId : public OpcUaObject +{ + using OpcUaObject::OpcUaObject; + +public: + OpcUaNodeId(); + explicit OpcUaNodeId(uint32_t identifier); + OpcUaNodeId(uint16_t namespaceIndex, const char* identifier); + OpcUaNodeId(uint16_t namespaceIndex, const std::string& identifier); + OpcUaNodeId(uint16_t namespaceIndex, uint32_t identifier); + + inline bool operator==(const OpcUaNodeId& rhs) const noexcept + { + return UA_NodeId_equal(this->getPtr(), rhs.getPtr()); + } + + inline bool operator!=(const OpcUaNodeId& rhs) const noexcept + { + return !UA_NodeId_equal(this->getPtr(), rhs.getPtr()); + } + + inline bool operator==(const UA_NodeId& rhs) const noexcept + { + return UA_NodeId_equal(this->getPtr(), &rhs); + } + + inline bool operator!=(const UA_NodeId& rhs) const noexcept + { + return !UA_NodeId_equal(this->getPtr(), &rhs); + } + + friend inline bool operator<(const OpcUaNodeId& l, const OpcUaNodeId& r) noexcept + { + const auto& lhs = l.getValue(); + const auto& rhs = r.getValue(); + if (lhs.namespaceIndex != rhs.namespaceIndex) + return lhs.namespaceIndex < rhs.namespaceIndex; + + if (lhs.identifierType != rhs.identifierType) + return lhs.identifierType < rhs.identifierType; + + switch (lhs.identifierType) + { + case UA_NODEIDTYPE_NUMERIC: + return lhs.identifier.numeric < rhs.identifier.numeric; + case UA_NODEIDTYPE_GUID: + return memcmp(&lhs.identifier.guid, &rhs.identifier.guid, sizeof(UA_Guid)) < 0; + case UA_NODEIDTYPE_BYTESTRING: + case UA_NODEIDTYPE_STRING: + if (lhs.identifier.string.length != rhs.identifier.string.length) + return lhs.identifier.string.length < rhs.identifier.string.length; + + return memcmp((char const*) lhs.identifier.string.data, + (char const*) rhs.identifier.string.data, + lhs.identifier.string.length) < 0; + } + return false; + } + + const UA_NodeId* getPtr() const noexcept; + UA_NodeId* getPtr() noexcept; + + uint16_t getNamespaceIndex() const noexcept; + OpcUaIdentifierUniversal getIdentifier() const; + OpcUaIdentifierType getIdentifierType() const; + std::string toString() const; + + bool isNull() const noexcept; + + static void SetRandomSeed(); + static OpcUaNodeId CreateWithRandomGuid(); + + static OpcUaNodeId instantiateNode(uint16_t namespaceIndex, + OpcUaIdentifierUniversal identifierUniversal, + OpcUaIdentifierType identifierType); + static OpcUaIdentifierUniversal getIdentifier(const UA_NodeId& uaNodeId); + + static OpcUaIdentifierType getIdentifierType(const UA_NodeIdType& identifierType); + + template + inline OpcUaNodeId addSuffix(Args... args) const + { + std::stringstream ss; + concat(ss, getIdentifier(), args...); + return OpcUaNodeId(getNamespaceIndex(), ss.str()); + } + +private: + + template + static void concat(std::ostream& out, const T& first) + { + out << first; + } + + template + static void concat(std::ostream& out, const T& first, const Args&... rest) + { + out << first; + concat(out, rest...); + } +}; + +END_NAMESPACE_OPENDAQ_OPCUA + +namespace std +{ + template <> + struct hash + { + size_t operator()(const daq::opcua::OpcUaNodeId& k) const noexcept + { + return static_cast(UA_NodeId_hash(k.get())); + } + }; +} diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaobject.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaobject.h new file mode 100644 index 0000000..bfd675e --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaobject.h @@ -0,0 +1,341 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +template +struct TypeToUaDataType +{ + constexpr static const UA_DataType* DataType = nullptr; +}; + +template +inline constexpr const UA_DataType* GetUaDataType() +{ + static_assert(TypeToUaDataType::DataType != nullptr, "Implement specialization of TypeToUaDataType"); + return TypeToUaDataType::DataType; +} + +#define ADD_STANDARD_TYPE_MAPPING(TYPE, TYPE_INDEX) \ + template <> \ + struct TypeToUaDataType \ + { \ + constexpr static const UA_DataType* DataType = &UA_TYPES[TYPE_INDEX]; \ + }; + +#define ADD_CUSTOM_TYPE_MAPPING(TYPE, DATA_TYPE) \ + template <> \ + struct TypeToUaDataType \ + { \ + constexpr static const UA_DataType* DataType = DATA_TYPE; \ + }; + +#define ADD_STANDARD_TYPE_ALIAS_MAPPING(MAPPING_NAME, TYPE_INDEX) \ + struct MAPPING_NAME \ + { \ + constexpr static const UA_DataType* DataType = &UA_TYPES[TYPE_INDEX]; \ + }; + +template +class OpcUaObject +{ +public: + OpcUaObject(); + OpcUaObject(const OpcUaObject& other); + OpcUaObject(const UATYPE& value, bool shallowCopy = false); + OpcUaObject(UATYPE&& value); + + virtual ~OpcUaObject(); + + inline constexpr const UA_DataType* getUaDataType() + { + return GetUaDataType(); + } + + OpcUaObject& operator=(const OpcUaObject& other); + OpcUaObject& operator=(OpcUaObject&& other); + + void setValue(UATYPE&& value); + void setValue(const UATYPE& value, bool shallowCopy = false); + + const UATYPE& getValue() const noexcept; + UATYPE& getValue() noexcept; + + const UATYPE& operator*() const noexcept; + UATYPE& operator*() noexcept; + + const UATYPE* get() const noexcept; + UATYPE* get() noexcept; + + const UATYPE* operator->() const noexcept; + UATYPE* operator->() noexcept; + + void clear() noexcept; + UATYPE getDetachedValue() noexcept; + + OpcUaObject copy() const noexcept; + UATYPE copyAndGetDetachedValue() const noexcept; + + UATYPE* newDetachedPointer(); + UATYPE* newDetachedPointerCopy() const; + + void markDetached(bool detached); + +protected: + UATYPE value; + bool shallowCopy = false; +}; + +template +OpcUaObject::OpcUaObject() + : shallowCopy(false) +{ + UA_init(&value, getUaDataType()); +} + +template +OpcUaObject::OpcUaObject(const OpcUaObject& other) + : OpcUaObject() +{ + setValue(other.getValue()); +} + +template +OpcUaObject::OpcUaObject(const UATYPE& value, bool shallowCopy) + : OpcUaObject() +{ + setValue(value, shallowCopy); +} + +template +OpcUaObject::OpcUaObject(UATYPE&& value) + : OpcUaObject() +{ + setValue(std::forward(value)); + UA_init(&value, getUaDataType()); +} + +template +OpcUaObject::~OpcUaObject() +{ + clear(); +} + +template +OpcUaObject& OpcUaObject::operator=(const OpcUaObject& other) +{ + if (&other == this) + return *this; + + setValue(other.getValue()); + return *this; +} + +template +OpcUaObject& OpcUaObject::operator=(OpcUaObject&& other) +{ + clear(); + + value = other.value; + UA_init(&other.value, getUaDataType()); + + shallowCopy = other.shallowCopy; + return *this; +} + +template +void OpcUaObject::setValue(UATYPE&& value) +{ + clear(); + this->value = value; + UA_init(&value, getUaDataType()); +} + +template +void OpcUaObject::setValue(const UATYPE& value, bool shallowCopy) +{ + clear(); + UA_init(&this->value, getUaDataType()); + if (shallowCopy) + this->value = value; + else + UA_copy(&value, &this->value, getUaDataType()); + this->shallowCopy = shallowCopy; +} + +template +const UATYPE& OpcUaObject::getValue() const noexcept +{ + return this->value; +} + +template +UATYPE& OpcUaObject::getValue() noexcept +{ + return this->value; +} + +template +const UATYPE* OpcUaObject::get() const noexcept +{ + return &this->value; +} + +template +UATYPE* OpcUaObject::get() noexcept +{ + return &this->value; +} + + +template +const UATYPE* OpcUaObject::operator->() const noexcept +{ + return &this->value; +} + +template +UATYPE* OpcUaObject::operator->() noexcept +{ + return &this->value; +} + +template +const UATYPE& OpcUaObject::operator*() const noexcept +{ + return getValue(); +} + +template +UATYPE& OpcUaObject::operator*() noexcept +{ + return getValue(); +} + +template +void OpcUaObject::clear() noexcept +{ + if (shallowCopy) + UA_init(&this->value, getUaDataType()); + else + UA_clear(&this->value, getUaDataType()); + + shallowCopy = false; +} + +template +UATYPE OpcUaObject::getDetachedValue() noexcept +{ + UATYPE val = getValue(); + shallowCopy = true; + clear(); + return val; +} + +template +OpcUaObject OpcUaObject::copy() const noexcept +{ + return OpcUaObject(value); +} + +template +UATYPE OpcUaObject::copyAndGetDetachedValue() const noexcept +{ + return copy().getDetachedValue(); +} + +template +inline UATYPE* OpcUaObject::newDetachedPointer() +{ + UATYPE* value = (UATYPE*) UA_new(TypeToUaDataType::DataType); + *value = this->getDetachedValue(); + return value; +} + +template +inline UATYPE* OpcUaObject::newDetachedPointerCopy() const +{ + UATYPE* value = (UATYPE*) UA_new(TypeToUaDataType::DataType); + *value = this->copyAndGetDetachedValue(); + return value; +} + +template +inline void OpcUaObject::markDetached(bool detached) +{ + this->shallowCopy = detached; +} + +ADD_STANDARD_TYPE_MAPPING(UA_Boolean, UA_TYPES_BOOLEAN) +ADD_STANDARD_TYPE_MAPPING(UA_SByte, UA_TYPES_SBYTE) +ADD_STANDARD_TYPE_MAPPING(UA_Byte, UA_TYPES_BYTE) +ADD_STANDARD_TYPE_MAPPING(UA_Int16, UA_TYPES_INT16) +ADD_STANDARD_TYPE_MAPPING(UA_UInt16, UA_TYPES_UINT16) +ADD_STANDARD_TYPE_MAPPING(UA_Int32, UA_TYPES_INT32) +ADD_STANDARD_TYPE_MAPPING(UA_UInt32, UA_TYPES_UINT32) +ADD_STANDARD_TYPE_MAPPING(UA_Int64, UA_TYPES_INT64) +ADD_STANDARD_TYPE_MAPPING(UA_UInt64, UA_TYPES_UINT64) +ADD_STANDARD_TYPE_MAPPING(UA_Variant, UA_TYPES_VARIANT) +ADD_STANDARD_TYPE_MAPPING(UA_String, UA_TYPES_STRING) +ADD_STANDARD_TYPE_MAPPING(UA_Double, UA_TYPES_DOUBLE) +ADD_STANDARD_TYPE_MAPPING(UA_Float, UA_TYPES_FLOAT) +ADD_STANDARD_TYPE_MAPPING(UA_BrowseRequest, UA_TYPES_BROWSEREQUEST) +ADD_STANDARD_TYPE_MAPPING(UA_BrowseResponse, UA_TYPES_BROWSERESPONSE) +ADD_STANDARD_TYPE_MAPPING(UA_BrowseNextRequest, UA_TYPES_BROWSENEXTREQUEST) +ADD_STANDARD_TYPE_MAPPING(UA_BrowseNextResponse, UA_TYPES_BROWSENEXTRESPONSE) +ADD_STANDARD_TYPE_MAPPING(UA_BrowseDescription, UA_TYPES_BROWSEDESCRIPTION) +ADD_STANDARD_TYPE_MAPPING(UA_BrowseResult, UA_TYPES_BROWSERESULT) +ADD_STANDARD_TYPE_MAPPING(UA_QualifiedName, UA_TYPES_QUALIFIEDNAME) +ADD_STANDARD_TYPE_MAPPING(UA_LocalizedText, UA_TYPES_LOCALIZEDTEXT) +ADD_STANDARD_TYPE_MAPPING(UA_ReadRequest, UA_TYPES_READREQUEST) +ADD_STANDARD_TYPE_MAPPING(UA_ReadResponse, UA_TYPES_READRESPONSE) +ADD_STANDARD_TYPE_MAPPING(UA_CallRequest, UA_TYPES_CALLREQUEST) +ADD_STANDARD_TYPE_MAPPING(UA_CallResponse, UA_TYPES_CALLRESPONSE) +ADD_STANDARD_TYPE_MAPPING(UA_NodeId, UA_TYPES_NODEID) +ADD_STANDARD_TYPE_MAPPING(UA_ReferenceDescription, UA_TYPES_REFERENCEDESCRIPTION) +ADD_STANDARD_TYPE_MAPPING(UA_ObjectAttributes, UA_TYPES_OBJECTATTRIBUTES) +ADD_STANDARD_TYPE_MAPPING(UA_MethodAttributes, UA_TYPES_METHODATTRIBUTES) +ADD_STANDARD_TYPE_MAPPING(UA_ObjectTypeAttributes, UA_TYPES_OBJECTTYPEATTRIBUTES) +ADD_STANDARD_TYPE_MAPPING(UA_VariableTypeAttributes, UA_TYPES_VARIABLETYPEATTRIBUTES) +ADD_STANDARD_TYPE_MAPPING(UA_VariableAttributes, UA_TYPES_VARIABLEATTRIBUTES) +ADD_STANDARD_TYPE_MAPPING(UA_DataTypeAttributes, UA_TYPES_DATATYPEATTRIBUTES) +ADD_STANDARD_TYPE_MAPPING(UA_ExpandedNodeId, UA_TYPES_EXPANDEDNODEID) +ADD_STANDARD_TYPE_MAPPING(UA_DataValue, UA_TYPES_DATAVALUE) +ADD_STANDARD_TYPE_MAPPING(UA_Argument, UA_TYPES_ARGUMENT) +ADD_STANDARD_TYPE_MAPPING(UA_ReadValueId, UA_TYPES_READVALUEID) +ADD_STANDARD_TYPE_MAPPING(UA_MonitoredItemCreateRequest, UA_TYPES_MONITOREDITEMCREATEREQUEST) +ADD_STANDARD_TYPE_MAPPING(UA_MonitoredItemCreateResult, UA_TYPES_MONITOREDITEMCREATERESULT) +ADD_STANDARD_TYPE_MAPPING(UA_CreateSubscriptionRequest, UA_TYPES_CREATESUBSCRIPTIONREQUEST) +ADD_STANDARD_TYPE_MAPPING(UA_CreateSubscriptionResponse, UA_TYPES_CREATESUBSCRIPTIONRESPONSE) +ADD_STANDARD_TYPE_MAPPING(UA_CallMethodRequest, UA_TYPES_CALLMETHODREQUEST) +ADD_STANDARD_TYPE_MAPPING(UA_CallMethodResult, UA_TYPES_CALLMETHODRESULT) +ADD_STANDARD_TYPE_MAPPING(UA_Range, UA_TYPES_RANGE) +ADD_STANDARD_TYPE_MAPPING(UA_KeyValuePair, UA_TYPES_KEYVALUEPAIR) +ADD_STANDARD_TYPE_MAPPING(UA_ExtensionObject, UA_TYPES_EXTENSIONOBJECT) +ADD_STANDARD_TYPE_MAPPING(UA_RationalNumber, UA_TYPES_RATIONALNUMBER) +ADD_STANDARD_TYPE_MAPPING(UA_EventFilter, UA_TYPES_EVENTFILTER) +ADD_STANDARD_TYPE_MAPPING(UA_SimpleAttributeOperand, UA_TYPES_SIMPLEATTRIBUTEOPERAND) +ADD_STANDARD_TYPE_MAPPING(UA_BrowsePathResult, UA_TYPES_BROWSEPATHRESULT) +ADD_STANDARD_TYPE_MAPPING(UA_EnumField, UA_TYPES_ENUMFIELD) +ADD_STANDARD_TYPE_MAPPING(UA_EUInformation, UA_TYPES_EUINFORMATION) + +ADD_STANDARD_TYPE_ALIAS_MAPPING(UtcTimeTypeToUaDataType, UA_TYPES_UTCTIME); + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecurity_config.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecurity_config.h new file mode 100644 index 0000000..9730d9b --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecurity_config.h @@ -0,0 +1,69 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +typedef std::function AuthenticateUserCallback; + +class OpcUaSecurityConfig +{ +public: + UA_MessageSecurityMode securityMode = UA_MESSAGESECURITYMODE_NONE; + std::optional appUri; + OpcUaObject certificate; + OpcUaObject privateKey; + OpcUaVector trustList; + OpcUaVector revocationList; + bool trustAll = false; + + void validate() const; + bool hasCertificate() const; + bool hasPrivateKey() const; + std::optional getAppUriOrParseFromCertificate() const; + +protected: + OpcUaSecurityConfig(); + OpcUaSecurityConfig(const OpcUaSecurityConfig& config); + OpcUaSecurityConfig& operator=(const OpcUaSecurityConfig& config); + +}; + +class OpcUaServerSecurityConfig : public OpcUaSecurityConfig +{ +public: + AuthenticateUserCallback authenticateUser; + + OpcUaServerSecurityConfig(); +}; + +class OpcUaClientSecurityConfig : public OpcUaSecurityConfig +{ +public: + std::optional username; + std::optional password; + + bool isAnonymous() const; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecuritycommon.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecuritycommon.h new file mode 100644 index 0000000..0afee20 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecuritycommon.h @@ -0,0 +1,31 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaSecurityCommon +{ +public: + static std::optional parseCertificateUri(const UA_ByteString& certificate); + static UA_StatusCode verifyCertificateRejectAll(void* verificationContext, const UA_ByteString* certificate); +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h new file mode 100644 index 0000000..f3c57c8 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h @@ -0,0 +1,187 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "opcuacommon.h" +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class OpcUaVariant; +using OpcUaVariantPtr = std::shared_ptr; + +namespace VariantUtils +{ + inline bool IsScalar(const UA_Variant& value) + { + return UA_Variant_isScalar(&value); + } + + inline bool IsVector(const UA_Variant& value) + { + return !IsScalar(value); + } + + template + inline bool IsType(const UA_Variant& value) + { + return value.type == GetUaDataType(); + } + + template + inline bool HasScalarType(const UA_Variant& value) + { + return IsScalar(value) && IsType(value); + } + + template + inline T ReadScalar(const UA_Variant& value) + { + if (!IsScalar(value)) + throw std::runtime_error("Variant is not a scalar"); + if (!IsType(value)) + throw std::runtime_error("Variant does not contain a scalar of specified return type"); + return *static_cast(value.data); + } + + inline std::string ToString(const UA_Variant& value) + { + return utils::ToStdString(ReadScalar(value)); + } + + inline int64_t ToNumber(const UA_Variant& value) + { + switch (value.type->typeKind) + { + case UA_TYPES_SBYTE: + return ReadScalar(value); + case UA_TYPES_BYTE: + return ReadScalar(value); + case UA_TYPES_INT16: + return ReadScalar(value); + case UA_TYPES_UINT16: + return ReadScalar(value); + case UA_TYPES_INT32: + return ReadScalar(value); + case UA_TYPES_UINT32: + return ReadScalar(value); + case UA_TYPES_INT64: + return ReadScalar(value); + case UA_TYPES_UINT64: + return ReadScalar(value); + default: + throw std::runtime_error("Type not supported!"); + } + } + + inline OpcUaNodeId ToNodeId(const UA_Variant& value) + { + UA_NodeId nodeId = ReadScalar(value); + return OpcUaNodeId(nodeId); + } + + void ToInt32Variant(OpcUaVariant& variant); + void ToInt64Variant(OpcUaVariant& variant); +} + +class OpcUaVariant : public OpcUaObject +{ +public: + using OpcUaObject::OpcUaObject; + + OpcUaVariant(); + + explicit OpcUaVariant(const uint16_t& value); + explicit OpcUaVariant(const int32_t& value); + explicit OpcUaVariant(const int64_t& value); + explicit OpcUaVariant(const char* value); + explicit OpcUaVariant(const double& value); + explicit OpcUaVariant(const bool& value); + explicit OpcUaVariant(const OpcUaNodeId& value); + OpcUaVariant(const UA_DataType* type, size_t dimension); + OpcUaVariant(const double& genericValue, const UA_DataType& originalType); + + template + inline bool isType() const + { + return VariantUtils::IsType(this->value); + } + + template + inline bool hasScalarType() + { + return VariantUtils::HasScalarType(this->value); + } + + template + T readScalar() const + { + return VariantUtils::ReadScalar(this->value); + } + + template > + void setScalar(const T& value) + { + static_assert(UATYPE::DataType != nullptr, "Implement specialization of TypeToUaDataType"); + + this->clear(); + + const auto status = UA_Variant_setScalarCopy(&this->value, &value, UATYPE::DataType); + CheckStatusCodeException(status); + } + + void setValue(UA_Variant&& value); + void setValue(const UA_Variant& value, bool shallowCopy = false); + + bool isInteger() const; + bool isString() const; + bool isDouble() const; + bool isBool() const; + bool isNodeId() const; + bool isNull() const; + bool isReal() const; + bool isNumber() const; + + std::string toString() const; + int64_t toInteger() const; + double toDouble() const; + bool toBool() const; + OpcUaNodeId toNodeId() const; + + inline bool isScalar() const + { + return VariantUtils::IsScalar(value); + } + inline bool isVector() const + { + return VariantUtils::IsVector(value); + } + + static bool IsInteger(const UA_Variant& value); +}; + +class OpcUaVariableConversionError : public OpcUaException +{ +public: + OpcUaVariableConversionError(UA_StatusCode statusCode) + : OpcUaException(statusCode, "Conversion error") + { + } +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavector.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavector.h new file mode 100644 index 0000000..f3ec30b --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavector.h @@ -0,0 +1,218 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +template +class OpcUaVectorProxy; +template +class OpcUaVector; + +template +class OpcUaVectorProxy +{ +public: + OpcUaVector& self; + size_t key; + + OpcUaVectorProxy(OpcUaVector& self, size_t key); + + OpcUaVectorProxy& operator=(UATYPE& value); + operator UATYPE() const; + UATYPE* operator->() const; +}; + +template +class OpcUaVector +{ +public: + OpcUaVector(); + explicit OpcUaVector(size_t size); + OpcUaVector(std::initializer_list items); + + OpcUaVector& operator=(const OpcUaVector& vector); + OpcUaVectorProxy const operator[](size_t i) const; + OpcUaVectorProxy operator[](size_t i); + + void push_back(const UATYPE& value); + size_t size() const; + void resize(size_t size); + void clear(); + const UATYPE* data() const; + void set(size_t i, UATYPE& value); + const UATYPE& get(size_t i) const; + + ~OpcUaVector(); + +private: + friend class OpcUaVectorProxy; + std::vector items; + + void clearItemsRange(size_t from, size_t to); + void clearItemsRange(size_t from); + void copyItems(const std::vector& src); +}; + +template +inline OpcUaVectorProxy::OpcUaVectorProxy(OpcUaVector& self, size_t key) + : self(self) + , key(key) +{ +} + +template +inline OpcUaVectorProxy& OpcUaVectorProxy::operator=(UATYPE& value) +{ + self.set(key, value); + return *this; +} + +template +inline OpcUaVectorProxy::operator UATYPE() const +{ + return self.get(key); +} + +template +inline UATYPE* OpcUaVectorProxy::operator->() const +{ + return &self.get(key); +} + +template +inline OpcUaVector::OpcUaVector() +{ +} + +template +inline OpcUaVector::OpcUaVector(size_t size) + : items(size) +{ +} + +template +inline OpcUaVector::OpcUaVector(std::initializer_list items) + : items(items) +{ +} + +template +inline OpcUaVector& OpcUaVector::operator=(const OpcUaVector& vector) +{ + if (this == &vector) + return *this; + + clear(); + resize(vector.size()); + copyItems(vector.items); + + return *this; +} + +template +inline OpcUaVectorProxy const OpcUaVector::operator[](size_t i) const +{ + return OpcUaVectorProxy(*this, i); +} + +template +inline OpcUaVectorProxy OpcUaVector::operator[](size_t i) +{ + return OpcUaVectorProxy(*this, i); +} + +template +inline OpcUaVector::~OpcUaVector() +{ + clear(); +} + +template +inline void OpcUaVector::push_back(const UATYPE& value) +{ + UATYPE tmp; + UA_copy(&value, &tmp, TypeToUaDataType::DataType); + items.push_back(tmp); +} + +template +inline size_t OpcUaVector::size() const +{ + return items.size(); +} + +template +inline void OpcUaVector::resize(size_t size) +{ + if (size < items.size()) + clearItemsRange(size); + items.resize(size); +} + +template +inline void OpcUaVector::clear() +{ + for (size_t i = 0; i < items.size(); i++) + clearItemsRange(0); + items.clear(); +} + +template +inline const UATYPE* OpcUaVector::data() const +{ + return items.data(); +} + +template +inline void OpcUaVector::set(size_t i, UATYPE& value) +{ + UA_clear(&items[i], TypeToUaDataType::DataType); + UA_copy(&value, &items[i], TypeToUaDataType::DataType); +} + +template +inline const UATYPE& OpcUaVector::get(size_t i) const +{ + return items[i]; +} + +template +inline void OpcUaVector::clearItemsRange(size_t from, size_t to) +{ + for (size_t i = from; i < to; i++) + UA_clear(&items[i], TypeToUaDataType::DataType); +} + +template +inline void OpcUaVector::clearItemsRange(size_t from) +{ + clearItemsRange(from, items.size()); +} + +template +inline void OpcUaVector::copyItems(const std::vector& src) +{ + for (size_t i = 0; i < src.size(); i++) + UA_copy(&src[i], &items[i], TypeToUaDataType::DataType); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaversion.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaversion.h new file mode 100644 index 0000000..8b221e3 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaversion.h @@ -0,0 +1,51 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "opcua.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +#pragma push_macro("major") +#pragma push_macro("minor") + +#undef major +#undef minor + +struct OpcUaVersion +{ + explicit OpcUaVersion(const char* version); + explicit constexpr OpcUaVersion(int major = 0, int minor = 0, int patch = 0) + : major(major) + , minor(minor) + , patch(patch) + { + } + + std::string toString() const; + + int major = 0; + int minor = 0; + int patch = 0; + + static bool Compatible(const OpcUaVersion& serverVersion, const OpcUaVersion& systemVersion); + static bool HasFeature(const OpcUaVersion& serverVersion, const OpcUaVersion& featureVersion); +}; + +#pragma pop_macro("minor") +#pragma pop_macro("major") + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/src/CMakeLists.txt b/shared/libraries/opcua/opcuashared/src/CMakeLists.txt new file mode 100644 index 0000000..a461d08 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/src/CMakeLists.txt @@ -0,0 +1,123 @@ +SET(MODULE_NAME opcuashared) + +set(RES_DIR_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../external/res") +set(CMAKE_GLOBALS_HEADER ${CMAKE_CURRENT_BINARY_DIR}/../include/${MODULE_NAME}/generated/cmake_globals.h) +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/cmake_globals.h.template + ${CMAKE_GLOBALS_HEADER} @ONLY +) + +set(SOURCE_CPPS opcuavariant.cpp + opcuacommon.cpp + opcuasecuritycommon.cpp + opcuaendpoint.cpp + opcuanodecollection.cpp + opcuadatavalue.cpp + opcuacallmethodresult.cpp + opcuaversion.cpp + opcuasecurity_config.cpp + opcuadatatypearraylist.cpp + opcuanodeid.cpp + cmake_globals.h.template + OpcUaTypes.natvis + bcrypt.cpp + bcrypt/crypt_blowfish.c +) + +set(SOURCE_NODE_CPPS node/opcuanode.cpp + node/opcuanodeobject.cpp + node/opcuanodemethod.cpp + node/opcuanodevariable.cpp + node/opcuatype.cpp + node/opcuaobjecttype.cpp + node/opcuavariabletype.cpp + node/opcuadatatype.cpp +) + +set(SOURCE_HEADERS opcuavariant.h + opcua.h + opcualog.h + opcuacollection.h + opcuacommon.h + opcuasecuritycommon.h + opcuaendpoint.h + opcuanodecollection.h + opcuaexception.h + opcuadatavalue.h + opcuacallmethodresult.h + opcuaversion.h + opcuaobject.h + opcuasecurity_config.h + opcuadatatypearraylist.h + opcuavector.h + opcuanodeid.h + bcrypt.h + bcrypt/crypt_blowfish.h +) + +set(SOURCE_NODE_HEADERS node/opcuanode.h + node/opcuanodeobject.h + node/opcuanodemethod.h + node/opcuanodevariable.h + node/opcuatype.h + node/opcuaobjecttype.h + node/opcuavariabletype.h + node/opcuadatatype.h +) + +set(INCLUDE_DIR ../include/${MODULE_NAME}) + +prepend_include(${INCLUDE_DIR} SOURCE_HEADERS) +prepend_include(${INCLUDE_DIR} SOURCE_NODE_HEADERS) + +set(ALL_SOURCES ${SOURCE_CPPS} + ${SOURCE_NODE_CPPS} + ${SOURCE_HEADERS} + ${SOURCE_NODE_HEADERS} + ${CMAKE_GLOBALS_HEADER} +) + +if (MSVC) + set_source_files_properties(bcrypt/crypt_blowfish.h + bcrypt/crypt_blowfish.c + PROPERTIES LANGUAGE C COMPILE_FLAGS /wd4244) +endif() + +set(SOURCE_FILES ${ALL_SOURCES}) + +add_library(${MODULE_NAME} STATIC ${ALL_SOURCES}) +add_library(${SDK_TARGET_NAMESPACE}::${MODULE_NAME} ALIAS ${MODULE_NAME}) + +if(BUILD_64Bit OR BUILD_ARM) + set_target_properties(${MODULE_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON) +else() + set_target_properties(${MODULE_NAME} PROPERTIES POSITION_INDEPENDENT_CODE OFF) +endif() + +target_include_directories(${MODULE_NAME} PUBLIC $ + $ + $ + PRIVATE ${PROJECT_SOURCE_DIR}/include/${MODULE_NAME}/generated +) + +target_link_libraries(${MODULE_NAME} PUBLIC open62541 + rapidjson + PRIVATE daq::opendaq_utils +) + +if (MSVC) + target_compile_definitions(${MODULE_NAME} PRIVATE _CRT_SECURE_NO_WARNINGS) + set_source_files_properties(opcuacommon.cpp PROPERTIES COMPILE_FLAGS /wd4100) +endif() + +set_target_properties(${MODULE_NAME} PROPERTIES PUBLIC_HEADER "${SOURCE_HEADERS}") +set_target_properties(${MODULE_NAME} PROPERTIES PUBLIC_NODE_HEADER "${SOURCE_NODE_HEADERS}") + +if(BUILD_64Bit) + set_target_properties(${MODULE_NAME} PROPERTIES OUTPUT_NAME "${MODULE_NAME}64") +endif() + +if (MSVC) + source_group("Header Files\\Node" "node/.+[.]h") + source_group("Source Files\\Node" "node/.+[.]cpp") +endif() diff --git a/shared/libraries/opcua/opcuashared/src/OpcUaTypes.natvis b/shared/libraries/opcua/opcuashared/src/OpcUaTypes.natvis new file mode 100644 index 0000000..a66da5c --- /dev/null +++ b/shared/libraries/opcua/opcuashared/src/OpcUaTypes.natvis @@ -0,0 +1,9 @@ + + + + data={data,[length]} + + data + + + \ No newline at end of file diff --git a/shared/libraries/opcua/opcuashared/src/bcrypt.cpp b/shared/libraries/opcua/opcuashared/src/bcrypt.cpp new file mode 100644 index 0000000..f519ccf --- /dev/null +++ b/shared/libraries/opcua/opcuashared/src/bcrypt.cpp @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" +{ + #include +} + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +BCrypt::BCrypt() + : randomDist(std::uniform_int_distribution(std::numeric_limits::min(), std::numeric_limits::max())) +{ +} + +std::vector BCrypt::randBytes(unsigned int length) +{ + std::vector bytes = std::vector(length); + for (unsigned int i = 0; i < length; i++) + { + bytes[i] = static_cast(randomDist(randomDevice)); + } + return bytes; +} + +std::string BCrypt::hash(const std::string& password, unsigned int rounds) +{ + std::string salt = generateSalt(SaltPartSize); + return hash(password, salt, rounds); +} + +std::string BCrypt::hash(const std::string& password, std::string salt, unsigned int rounds) const +{ + if (salt.size() < SaltPartSize) + throw BCryptSaltSizeException(SaltPartSize); + + char infoSalt[SaltSize + 1]; + infoSalt[0] = '$'; + infoSalt[1] = '2'; + infoSalt[2] = 'b'; + infoSalt[3] = '$'; + infoSalt[4] = '0' + (char) (rounds / 10); + infoSalt[5] = '0' + (char) (rounds % 10); + infoSalt[6] = '$'; + std::memcpy(&infoSalt[InfoPartSize], salt.data(), SaltPartSize); + + char hash[HashSize + 1]; + bool ok = _crypt_blowfish_rn(password.data(), infoSalt, &hash[0], HashSize + 1) != nullptr; + if (!ok) + throw BCryptException("Error while hashing the password."); + + return hash; +} + +bool BCrypt::Verify(const std::string& hash, const std::string& password) +{ + char test[HashSize + 1]; + bool ok = _crypt_blowfish_rn(password.data(), hash.data(), test, HashSize + 1); + if (!ok) + return false; + + return hash == test; +} + +std::string BCrypt::generateSalt(unsigned int size) +{ + std::vector bytes = randBytes(size); + return generateSalt(bytes.data(), (unsigned int) bytes.size()); +} + +std::string BCrypt::generateSalt(char* bytes, int size) const +{ + if (size < SaltPartSize) + throw BCryptSaltSizeException(SaltPartSize); + + char salt[SaltSize + 1]; + bool ok = _crypt_gensalt_blowfish_rn("$2b$", 8, bytes, size, &salt[0], SaltSize + 1); + if (!ok) + throw BCryptException("Error while generating bcrypt salt."); + + return std::string(&salt[InfoPartSize]); +} + +BCryptException::BCryptException(const std::string& message) + : std::runtime_error(message.c_str()) +{ +} + +BCryptSaltSizeException::BCryptSaltSizeException(unsigned int minSaltSize) + : BCryptException("Salt must be at least " + std::to_string(minSaltSize) + " characters long.") +{ +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/src/bcrypt/crypt_blowfish.c b/shared/libraries/opcua/opcuashared/src/bcrypt/crypt_blowfish.c new file mode 100644 index 0000000..797476d --- /dev/null +++ b/shared/libraries/opcua/opcuashared/src/bcrypt/crypt_blowfish.c @@ -0,0 +1,907 @@ +/* + * The crypt_blowfish homepage is: + * + * http://www.openwall.com/crypt/ + * + * This code comes from John the Ripper password cracker, with reentrant + * and crypt(3) interfaces added, but optimizations specific to password + * cracking removed. + * + * Written by Solar Designer in 1998-2014. + * No copyright is claimed, and the software is hereby placed in the public + * domain. In case this attempt to disclaim copyright and place the software + * in the public domain is deemed null and void, then the software is + * Copyright (c) 1998-2014 Solar Designer and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * It is my intent that you should be able to use this on your system, + * as part of a software package, or anywhere else to improve security, + * ensure compatibility, or for any other purpose. I would appreciate + * it if you give credit where it is due and keep your modifications in + * the public domain as well, but I don't require that in order to let + * you place this code and any modifications you make under a license + * of your choice. + * + * This implementation is fully compatible with OpenBSD's bcrypt.c for prefix + * "$2b$", originally by Niels Provos , and it uses + * some of his ideas. The password hashing algorithm was designed by David + * Mazieres . For information on the level of + * compatibility for bcrypt hash prefixes other than "$2b$", please refer to + * the comments in BF_set_key() below and to the included crypt(3) man page. + * + * There's a paper on the algorithm that explains its design decisions: + * + * http://www.usenix.org/events/usenix99/provos.html + * + * Some of the tricks in BF_ROUND might be inspired by Eric Young's + * Blowfish library (I can't be sure if I would think of something if I + * hadn't seen his code). + */ + +#include + +#include +#ifndef __set_errno +#define __set_errno(val) errno = (val) +#endif + +/* Just to make sure the prototypes match the actual definitions */ +#include + +#ifdef __i386__ +#define BF_ASM 1 +#define BF_SCALE 1 +#elif defined(__x86_64__) || defined(__alpha__) || defined(__hppa__) +#define BF_ASM 0 +#define BF_SCALE 1 +#else +#define BF_ASM 0 +#define BF_SCALE 0 +#endif + +typedef unsigned int BF_word; +typedef signed int BF_word_signed; + +/* Number of Blowfish rounds, this is also hardcoded into a few places */ +#define BF_N 16 + +typedef BF_word BF_key[BF_N + 2]; + +typedef struct { + BF_word S[4][0x100]; + BF_key P; +} BF_ctx; + +/* + * Magic IV for 64 Blowfish encryptions that we do at the end. + * The string is "OrpheanBeholderScryDoubt" on big-endian. + */ +static BF_word BF_magic_w[6] = { + 0x4F727068, 0x65616E42, 0x65686F6C, + 0x64657253, 0x63727944, 0x6F756274 +}; + +/* + * P-box and S-box tables initialized with digits of Pi. + */ +static BF_ctx BF_init_state = { + { + { + 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, + 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, + 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, + 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, + 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, + 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, + 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, + 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, + 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, + 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, + 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, + 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, + 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, + 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, + 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, + 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, + 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, + 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, + 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, + 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, + 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, + 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, + 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, + 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, + 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, + 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, + 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, + 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, + 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, + 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, + 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, + 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, + 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, + 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, + 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, + 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, + 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, + 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, + 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, + 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, + 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, + 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, + 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, + 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, + 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, + 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, + 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, + 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, + 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, + 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, + 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, + 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, + 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, + 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, + 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, + 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, + 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, + 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, + 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, + 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, + 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, + 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, + 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, + 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a + }, { + 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, + 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, + 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, + 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, + 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, + 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, + 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, + 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, + 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, + 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, + 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, + 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, + 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, + 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, + 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, + 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, + 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, + 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, + 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, + 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, + 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, + 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, + 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, + 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, + 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, + 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, + 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, + 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, + 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, + 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, + 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, + 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, + 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, + 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, + 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, + 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, + 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, + 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, + 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, + 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, + 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, + 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, + 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, + 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, + 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, + 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, + 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, + 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, + 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, + 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, + 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, + 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, + 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, + 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, + 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, + 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, + 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, + 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, + 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, + 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, + 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, + 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, + 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, + 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 + }, { + 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, + 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, + 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, + 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, + 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, + 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, + 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, + 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, + 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, + 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, + 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, + 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, + 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, + 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, + 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, + 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, + 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, + 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, + 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, + 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, + 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, + 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, + 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, + 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, + 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, + 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, + 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, + 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, + 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, + 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, + 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, + 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, + 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, + 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, + 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, + 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, + 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, + 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, + 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, + 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, + 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, + 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, + 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, + 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, + 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, + 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, + 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, + 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, + 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, + 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, + 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, + 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, + 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, + 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, + 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, + 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, + 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, + 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, + 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, + 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, + 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, + 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, + 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, + 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 + }, { + 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, + 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, + 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, + 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, + 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, + 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, + 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, + 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, + 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, + 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, + 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, + 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, + 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, + 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, + 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, + 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, + 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, + 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, + 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, + 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, + 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, + 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, + 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, + 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, + 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, + 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, + 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, + 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, + 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, + 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, + 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, + 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, + 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, + 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, + 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, + 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, + 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, + 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, + 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, + 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, + 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, + 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, + 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, + 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, + 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, + 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, + 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, + 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, + 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, + 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, + 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, + 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, + 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, + 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, + 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, + 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, + 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, + 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, + 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, + 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, + 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, + 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, + 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, + 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 + } + }, { + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, + 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, + 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, + 0x9216d5d9, 0x8979fb1b + } +}; + +static unsigned char BF_itoa64[64 + 1] = + "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + +static unsigned char BF_atoi64[0x60] = { + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 1, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 64, 64, 64, 64, 64, + 64, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 64, 64, 64, 64, 64, + 64, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 64, 64, 64, 64, 64 +}; + +#define BF_safe_atoi64(dst, src) \ +{ \ + tmp = (unsigned char)(src); \ + if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \ + tmp = BF_atoi64[tmp]; \ + if (tmp > 63) return -1; \ + (dst) = tmp; \ +} + +static int BF_decode(BF_word *dst, const char *src, int size) +{ + unsigned char *dptr = (unsigned char *)dst; + unsigned char *end = dptr + size; + const unsigned char *sptr = (const unsigned char *)src; + unsigned int tmp, c1, c2, c3, c4; + + do { + BF_safe_atoi64(c1, *sptr++); + BF_safe_atoi64(c2, *sptr++); + *dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4); + if (dptr >= end) break; + + BF_safe_atoi64(c3, *sptr++); + *dptr++ = ((c2 & 0x0F) << 4) | ((c3 & 0x3C) >> 2); + if (dptr >= end) break; + + BF_safe_atoi64(c4, *sptr++); + *dptr++ = ((c3 & 0x03) << 6) | c4; + } while (dptr < end); + + return 0; +} + +static void BF_encode(char *dst, const BF_word *src, int size) +{ + const unsigned char *sptr = (const unsigned char *)src; + const unsigned char *end = sptr + size; + unsigned char *dptr = (unsigned char *)dst; + unsigned int c1, c2; + + do { + c1 = *sptr++; + *dptr++ = BF_itoa64[c1 >> 2]; + c1 = (c1 & 0x03) << 4; + if (sptr >= end) { + *dptr++ = BF_itoa64[c1]; + break; + } + + c2 = *sptr++; + c1 |= c2 >> 4; + *dptr++ = BF_itoa64[c1]; + c1 = (c2 & 0x0f) << 2; + if (sptr >= end) { + *dptr++ = BF_itoa64[c1]; + break; + } + + c2 = *sptr++; + c1 |= c2 >> 6; + *dptr++ = BF_itoa64[c1]; + *dptr++ = BF_itoa64[c2 & 0x3f]; + } while (sptr < end); +} + +static void BF_swap(BF_word *x, int count) +{ + static int endianness_check = 1; + char *is_little_endian = (char *)&endianness_check; + BF_word tmp; + + if (*is_little_endian) + do { + tmp = *x; + tmp = (tmp << 16) | (tmp >> 16); + *x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF); + } while (--count); +} + +#if BF_SCALE +/* Architectures which can shift addresses left by 2 bits with no extra cost */ +#define BF_ROUND(L, R, N) \ + tmp1 = L & 0xFF; \ + tmp2 = L >> 8; \ + tmp2 &= 0xFF; \ + tmp3 = L >> 16; \ + tmp3 &= 0xFF; \ + tmp4 = L >> 24; \ + tmp1 = data.ctx.S[3][tmp1]; \ + tmp2 = data.ctx.S[2][tmp2]; \ + tmp3 = data.ctx.S[1][tmp3]; \ + tmp3 += data.ctx.S[0][tmp4]; \ + tmp3 ^= tmp2; \ + R ^= data.ctx.P[N + 1]; \ + tmp3 += tmp1; \ + R ^= tmp3; +#else +/* Architectures with no complicated addressing modes supported */ +#define BF_INDEX(S, i) \ + (*((BF_word *)(((unsigned char *)S) + (i)))) +#define BF_ROUND(L, R, N) \ + tmp1 = L & 0xFF; \ + tmp1 <<= 2; \ + tmp2 = L >> 6; \ + tmp2 &= 0x3FC; \ + tmp3 = L >> 14; \ + tmp3 &= 0x3FC; \ + tmp4 = L >> 22; \ + tmp4 &= 0x3FC; \ + tmp1 = BF_INDEX(data.ctx.S[3], tmp1); \ + tmp2 = BF_INDEX(data.ctx.S[2], tmp2); \ + tmp3 = BF_INDEX(data.ctx.S[1], tmp3); \ + tmp3 += BF_INDEX(data.ctx.S[0], tmp4); \ + tmp3 ^= tmp2; \ + R ^= data.ctx.P[N + 1]; \ + tmp3 += tmp1; \ + R ^= tmp3; +#endif + +/* + * Encrypt one block, BF_N is hardcoded here. + */ +#define BF_ENCRYPT \ + L ^= data.ctx.P[0]; \ + BF_ROUND(L, R, 0); \ + BF_ROUND(R, L, 1); \ + BF_ROUND(L, R, 2); \ + BF_ROUND(R, L, 3); \ + BF_ROUND(L, R, 4); \ + BF_ROUND(R, L, 5); \ + BF_ROUND(L, R, 6); \ + BF_ROUND(R, L, 7); \ + BF_ROUND(L, R, 8); \ + BF_ROUND(R, L, 9); \ + BF_ROUND(L, R, 10); \ + BF_ROUND(R, L, 11); \ + BF_ROUND(L, R, 12); \ + BF_ROUND(R, L, 13); \ + BF_ROUND(L, R, 14); \ + BF_ROUND(R, L, 15); \ + tmp4 = R; \ + R = L; \ + L = tmp4 ^ data.ctx.P[BF_N + 1]; + +#if BF_ASM +#define BF_body() \ + _BF_body_r(&data.ctx); +#else +#define BF_body() \ + L = R = 0; \ + ptr = data.ctx.P; \ + do { \ + ptr += 2; \ + BF_ENCRYPT; \ + *(ptr - 2) = L; \ + *(ptr - 1) = R; \ + } while (ptr < &data.ctx.P[BF_N + 2]); \ +\ + ptr = data.ctx.S[0]; \ + do { \ + ptr += 2; \ + BF_ENCRYPT; \ + *(ptr - 2) = L; \ + *(ptr - 1) = R; \ + } while (ptr < &data.ctx.S[3][0xFF]); +#endif + +static void BF_set_key(const char *key, BF_key expanded, BF_key initial, + unsigned char flags) +{ + const char *ptr = key; + unsigned int bug, i, j; + BF_word safety, sign, diff, tmp[2]; + +/* + * There was a sign extension bug in older revisions of this function. While + * we would have liked to simply fix the bug and move on, we have to provide + * a backwards compatibility feature (essentially the bug) for some systems and + * a safety measure for some others. The latter is needed because for certain + * multiple inputs to the buggy algorithm there exist easily found inputs to + * the correct algorithm that produce the same hash. Thus, we optionally + * deviate from the correct algorithm just enough to avoid such collisions. + * While the bug itself affected the majority of passwords containing + * characters with the 8th bit set (although only a percentage of those in a + * collision-producing way), the anti-collision safety measure affects + * only a subset of passwords containing the '\xff' character (not even all of + * those passwords, just some of them). This character is not found in valid + * UTF-8 sequences and is rarely used in popular 8-bit character encodings. + * Thus, the safety measure is unlikely to cause much annoyance, and is a + * reasonable tradeoff to use when authenticating against existing hashes that + * are not reliably known to have been computed with the correct algorithm. + * + * We use an approach that tries to minimize side-channel leaks of password + * information - that is, we mostly use fixed-cost bitwise operations instead + * of branches or table lookups. (One conditional branch based on password + * length remains. It is not part of the bug aftermath, though, and is + * difficult and possibly unreasonable to avoid given the use of C strings by + * the caller, which results in similar timing leaks anyway.) + * + * For actual implementation, we set an array index in the variable "bug" + * (0 means no bug, 1 means sign extension bug emulation) and a flag in the + * variable "safety" (bit 16 is set when the safety measure is requested). + * Valid combinations of settings are: + * + * Prefix "$2a$": bug = 0, safety = 0x10000 + * Prefix "$2b$": bug = 0, safety = 0 + * Prefix "$2x$": bug = 1, safety = 0 + * Prefix "$2y$": bug = 0, safety = 0 + */ + bug = (unsigned int)flags & 1; + safety = ((BF_word)flags & 2) << 15; + + sign = diff = 0; + + for (i = 0; i < BF_N + 2; i++) { + tmp[0] = tmp[1] = 0; + for (j = 0; j < 4; j++) { + tmp[0] <<= 8; + tmp[0] |= (unsigned char)*ptr; /* correct */ + tmp[1] <<= 8; + tmp[1] |= (BF_word_signed)(signed char)*ptr; /* bug */ +/* + * Sign extension in the first char has no effect - nothing to overwrite yet, + * and those extra 24 bits will be fully shifted out of the 32-bit word. For + * chars 2, 3, 4 in each four-char block, we set bit 7 of "sign" if sign + * extension in tmp[1] occurs. Once this flag is set, it remains set. + */ + if (j) + sign |= tmp[1] & 0x80; + if (!*ptr) + ptr = key; + else + ptr++; + } + diff |= tmp[0] ^ tmp[1]; /* Non-zero on any differences */ + + expanded[i] = tmp[bug]; + initial[i] = BF_init_state.P[i] ^ tmp[bug]; + } + +/* + * At this point, "diff" is zero iff the correct and buggy algorithms produced + * exactly the same result. If so and if "sign" is non-zero, which indicates + * that there was a non-benign sign extension, this means that we have a + * collision between the correctly computed hash for this password and a set of + * passwords that could be supplied to the buggy algorithm. Our safety measure + * is meant to protect from such many-buggy to one-correct collisions, by + * deviating from the correct algorithm in such cases. Let's check for this. + */ + diff |= diff >> 16; /* still zero iff exact match */ + diff &= 0xffff; /* ditto */ + diff += 0xffff; /* bit 16 set iff "diff" was non-zero (on non-match) */ + sign <<= 9; /* move the non-benign sign extension flag to bit 16 */ + sign &= ~diff & safety; /* action needed? */ + +/* + * If we have determined that we need to deviate from the correct algorithm, + * flip bit 16 in initial expanded key. (The choice of 16 is arbitrary, but + * let's stick to it now. It came out of the approach we used above, and it's + * not any worse than any other choice we could make.) + * + * It is crucial that we don't do the same to the expanded key used in the main + * Eksblowfish loop. By doing it to only one of these two, we deviate from a + * state that could be directly specified by a password to the buggy algorithm + * (and to the fully correct one as well, but that's a side-effect). + */ + initial[0] ^= sign; +} + +static const unsigned char flags_by_subtype[26] = + {2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0}; + +static char *BF_crypt(const char *key, const char *setting, + char *output, int size, + BF_word min) +{ +#if BF_ASM + extern void _BF_body_r(BF_ctx *ctx); +#endif + struct { + BF_ctx ctx; + BF_key expanded_key; + union { + BF_word salt[4]; + BF_word output[6]; + } binary; + } data; + BF_word L, R; + BF_word tmp1, tmp2, tmp3, tmp4; + BF_word *ptr; + BF_word count; + int i; + + if (size < 7 + 22 + 31 + 1) { + __set_errno(ERANGE); + return NULL; + } + + if (setting[0] != '$' || + setting[1] != '2' || + setting[2] < 'a' || setting[2] > 'z' || + !flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a'] || + setting[3] != '$' || + setting[4] < '0' || setting[4] > '3' || + setting[5] < '0' || setting[5] > '9' || + (setting[4] == '3' && setting[5] > '1') || + setting[6] != '$') { + __set_errno(EINVAL); + return NULL; + } + + count = (BF_word)1 << ((setting[4] - '0') * 10 + (setting[5] - '0')); + if (count < min || BF_decode(data.binary.salt, &setting[7], 16)) { + __set_errno(EINVAL); + return NULL; + } + BF_swap(data.binary.salt, 4); + + BF_set_key(key, data.expanded_key, data.ctx.P, + flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a']); + + memcpy(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S)); + + L = R = 0; + for (i = 0; i < BF_N + 2; i += 2) { + L ^= data.binary.salt[i & 2]; + R ^= data.binary.salt[(i & 2) + 1]; + BF_ENCRYPT; + data.ctx.P[i] = L; + data.ctx.P[i + 1] = R; + } + + ptr = data.ctx.S[0]; + do { + ptr += 4; + L ^= data.binary.salt[(BF_N + 2) & 3]; + R ^= data.binary.salt[(BF_N + 3) & 3]; + BF_ENCRYPT; + *(ptr - 4) = L; + *(ptr - 3) = R; + + L ^= data.binary.salt[(BF_N + 4) & 3]; + R ^= data.binary.salt[(BF_N + 5) & 3]; + BF_ENCRYPT; + *(ptr - 2) = L; + *(ptr - 1) = R; + } while (ptr < &data.ctx.S[3][0xFF]); + + do { + int done; + + for (i = 0; i < BF_N + 2; i += 2) { + data.ctx.P[i] ^= data.expanded_key[i]; + data.ctx.P[i + 1] ^= data.expanded_key[i + 1]; + } + + done = 0; + do { + BF_body(); + if (done) + break; + done = 1; + + tmp1 = data.binary.salt[0]; + tmp2 = data.binary.salt[1]; + tmp3 = data.binary.salt[2]; + tmp4 = data.binary.salt[3]; + for (i = 0; i < BF_N; i += 4) { + data.ctx.P[i] ^= tmp1; + data.ctx.P[i + 1] ^= tmp2; + data.ctx.P[i + 2] ^= tmp3; + data.ctx.P[i + 3] ^= tmp4; + } + data.ctx.P[16] ^= tmp1; + data.ctx.P[17] ^= tmp2; + } while (1); + } while (--count); + + for (i = 0; i < 6; i += 2) { + L = BF_magic_w[i]; + R = BF_magic_w[i + 1]; + + count = 64; + do { + BF_ENCRYPT; + } while (--count); + + data.binary.output[i] = L; + data.binary.output[i + 1] = R; + } + + memcpy(output, setting, 7 + 22 - 1); + output[7 + 22 - 1] = BF_itoa64[(int) + BF_atoi64[(int)setting[7 + 22 - 1] - 0x20] & 0x30]; + +/* This has to be bug-compatible with the original implementation, so + * only encode 23 of the 24 bytes. :-) */ + BF_swap(data.binary.output, 6); + BF_encode(&output[7 + 22], data.binary.output, 23); + output[7 + 22 + 31] = '\0'; + + return output; +} + +int _crypt_output_magic(const char *setting, char *output, int size) +{ + if (size < 3) + return -1; + + output[0] = '*'; + output[1] = '0'; + output[2] = '\0'; + + if (setting[0] == '*' && setting[1] == '0') + output[1] = '1'; + + return 0; +} + +/* + * Please preserve the runtime self-test. It serves two purposes at once: + * + * 1. We really can't afford the risk of producing incompatible hashes e.g. + * when there's something like gcc bug 26587 again, whereas an application or + * library integrating this code might not also integrate our external tests or + * it might not run them after every build. Even if it does, the miscompile + * might only occur on the production build, but not on a testing build (such + * as because of different optimization settings). It is painful to recover + * from incorrectly-computed hashes - merely fixing whatever broke is not + * enough. Thus, a proactive measure like this self-test is needed. + * + * 2. We don't want to leave sensitive data from our actual password hash + * computation on the stack or in registers. Previous revisions of the code + * would do explicit cleanups, but simply running the self-test after hash + * computation is more reliable. + * + * The performance cost of this quick self-test is around 0.6% at the "$2a$08" + * setting. + */ +char *_crypt_blowfish_rn(const char *key, const char *setting, + char *output, int size) +{ + const char *test_key = "8b \xd0\xc1\xd2\xcf\xcc\xd8"; + const char *test_setting = "$2a$00$abcdefghijklmnopqrstuu"; + static const char * const test_hashes[2] = + {"i1D709vfamulimlGcq0qq3UvuUasvEa\0\x55", /* 'a', 'b', 'y' */ + "VUrPmXD6q/nVSSp7pNDhCR9071IfIRe\0\x55"}; /* 'x' */ + const char *test_hash = test_hashes[0]; + char *retval; + const char *p; + int save_errno, ok; + struct { + char s[7 + 22 + 1]; + char o[7 + 22 + 31 + 1 + 1 + 1]; + } buf; + +/* Hash the supplied password */ + _crypt_output_magic(setting, output, size); + retval = BF_crypt(key, setting, output, size, 16); + save_errno = errno; + +/* + * Do a quick self-test. It is important that we make both calls to BF_crypt() + * from the same scope such that they likely use the same stack locations, + * which makes the second call overwrite the first call's sensitive data on the + * stack and makes it more likely that any alignment related issues would be + * detected by the self-test. + */ + memcpy(buf.s, test_setting, sizeof(buf.s)); + if (retval) { + unsigned int flags = flags_by_subtype[ + (unsigned int)(unsigned char)setting[2] - 'a']; + test_hash = test_hashes[flags & 1]; + buf.s[2] = setting[2]; + } + memset(buf.o, 0x55, sizeof(buf.o)); + buf.o[sizeof(buf.o) - 1] = 0; + p = BF_crypt(test_key, buf.s, buf.o, sizeof(buf.o) - (1 + 1), 1); + + ok = (p == buf.o && + !memcmp(p, buf.s, 7 + 22) && + !memcmp(p + (7 + 22), test_hash, 31 + 1 + 1 + 1)); + + { + const char *k = "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"; + BF_key ae, ai, ye, yi; + BF_set_key(k, ae, ai, 2); /* $2a$ */ + BF_set_key(k, ye, yi, 4); /* $2y$ */ + ai[0] ^= 0x10000; /* undo the safety (for comparison) */ + ok = ok && ai[0] == 0xdb9c59bc && ye[17] == 0x33343500 && + !memcmp(ae, ye, sizeof(ae)) && + !memcmp(ai, yi, sizeof(ai)); + } + + __set_errno(save_errno); + if (ok) + return retval; + +/* Should not happen */ + _crypt_output_magic(setting, output, size); + __set_errno(EINVAL); /* pretend we don't support this hash type */ + return NULL; +} + +char *_crypt_gensalt_blowfish_rn(const char *prefix, unsigned long count, + const char *input, int size, char *output, int output_size) +{ + if (size < 16 || output_size < 7 + 22 + 1 || + (count && (count < 4 || count > 31)) || + prefix[0] != '$' || prefix[1] != '2' || + (prefix[2] != 'a' && prefix[2] != 'b' && prefix[2] != 'y')) { + if (output_size > 0) output[0] = '\0'; + __set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL); + return NULL; + } + + if (!count) count = 5; + + output[0] = '$'; + output[1] = '2'; + output[2] = prefix[2]; + output[3] = '$'; + output[4] = '0' + count / 10; + output[5] = '0' + count % 10; + output[6] = '$'; + + BF_encode(&output[7], (const BF_word *)input, 16); + output[7 + 22] = '\0'; + + return output; +} diff --git a/shared/libraries/opcua/opcuashared/src/cmake_globals.h.template b/shared/libraries/opcua/opcuashared/src/cmake_globals.h.template new file mode 100644 index 0000000..9a85e6a --- /dev/null +++ b/shared/libraries/opcua/opcuashared/src/cmake_globals.h.template @@ -0,0 +1,20 @@ +#pragma once +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class CmakeGlobals +{ +public: + static const std::string ResDirPath; + + static std::string ResDirFile(std::string file) + { + return ResDirPath + "/" + file; + } +}; + +const std::string CmakeGlobals::ResDirPath = "@RES_DIR_PATH@/"; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/src/node/opcuadatatype.cpp b/shared/libraries/opcua/opcuashared/src/node/opcuadatatype.cpp new file mode 100644 index 0000000..e10462c --- /dev/null +++ b/shared/libraries/opcua/opcuashared/src/node/opcuadatatype.cpp @@ -0,0 +1,14 @@ +#include "opcuashared/node/opcuadatatype.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaDataType::OpcUaDataType(const UA_ReferenceDescription& uaNodeDescription) + : OpcUaNode(uaNodeDescription, OpcUaNodeClass::DataType) +{ +} + +OpcUaDataType::~OpcUaDataType() +{ +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/src/node/opcuanode.cpp b/shared/libraries/opcua/opcuashared/src/node/opcuanode.cpp new file mode 100644 index 0000000..6ba5c28 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/src/node/opcuanode.cpp @@ -0,0 +1,86 @@ +#include "opcuashared/node/opcuanode.h" + +#include +#include "opcuashared/node/opcuatype.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaNode::OpcUaNode(const OpcUaNodeId& nodeId, OpcUaNodeClass nodeClass) + : nodeId(std::move(nodeId)) + , nodeClass(nodeClass) +{ +} +OpcUaNode::OpcUaNode(const UA_ReferenceDescription& uaNodeDescription, OpcUaNodeClass nodeClass) + : nodeId(uaNodeDescription.nodeId.nodeId) + , browseName(OpcUaNode::GetBrowseName(uaNodeDescription.browseName)) + , displayName(utils::ToStdString(uaNodeDescription.displayName.text)) + , nodeClass(nodeClass) + , typeId(uaNodeDescription.typeDefinition.nodeId) +{ +} + +OpcUaNode::~OpcUaNode() +{ +} + +const OpcUaNodeClass& OpcUaNode::getNodeClass() const +{ + return nodeClass; +} + +void OpcUaNode::setNodeClass(const UA_NodeClass& nodeClass) +{ + setNodeClass((OpcUaNodeClass) nodeClass); +} + +void OpcUaNode::setNodeClass(OpcUaNodeClass nodeClass) +{ + this->nodeClass = nodeClass; +} + +const std::string& OpcUaNode::getBrowseName() const +{ + return browseName; +} + +void OpcUaNode::setBrowseName(const std::string& browseName) +{ + this->browseName = browseName; +} + +const std::string& OpcUaNode::getDisplayName() const +{ + return displayName; +} + +void OpcUaNode::setDisplayName(const std::string& displayName) +{ + this->displayName = displayName; +} + +const OpcUaNodeId& OpcUaNode::getNodeId() const +{ + return nodeId; +} + +std::string OpcUaNode::GetBrowseName(const UA_QualifiedName& browseName) +{ + return utils::ToStdString(browseName.name); +} + +void OpcUaNode::setType(const OpcUaTypePtr& type) +{ + this->typeId = type->getNodeId(); +} + +void OpcUaNode::setType(const OpcUaNodeId& typeId) +{ + this->typeId = typeId; +} + +const OpcUaNodeId& OpcUaNode::getTypeId() const +{ + return typeId; +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/src/node/opcuanodemethod.cpp b/shared/libraries/opcua/opcuashared/src/node/opcuanodemethod.cpp new file mode 100644 index 0000000..80106d8 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/src/node/opcuanodemethod.cpp @@ -0,0 +1,64 @@ +#include "opcuashared/node/opcuanodemethod.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaNodeMethod::OpcUaNodeMethod(const OpcUaNodeId& uaNode, const OpcUaNodeId& parentNodeId) + : OpcUaNode(uaNode, OpcUaNodeClass::Method) + , parentNodeId(parentNodeId) +{ +} + +OpcUaNodeMethod::OpcUaNodeMethod(const UA_ReferenceDescription& uaNodeDescription, const OpcUaNodeId& parentNodeId) + : OpcUaNode(uaNodeDescription, OpcUaNodeClass::Method) + , parentNodeId(parentNodeId) +{ +} + +OpcUaNodeMethod::~OpcUaNodeMethod() +{ +} + +std::string OpcUaNodeMethod::getTypeDescription() +{ + return typeDescription; +} + +void OpcUaNodeMethod::initTypeDescription() +{ + bool inputEnabled = inputParameters.size(); + bool outputEnabled = outputParameters.size(); + + std::string type; + + if (inputEnabled && outputEnabled) + type = " (in/out)"; + else if (inputEnabled && !outputEnabled) + type = " (in)"; + else if (!inputEnabled && outputEnabled) + type = " (out)"; + + typeDescription = "Method" + type; +} + +const OpcUaNodeId& OpcUaNodeMethod::getParentNodeId() const +{ + return parentNodeId; +} + +void OpcUaNodeMethod::addInputParameter(const std::string& name, const OpcUaNodeId& dataTypeId) +{ + OpcUaChannelMethodParameter param; + param.setName(name); + param.setDataTypeId(dataTypeId); + inputParameters.push_back(param); +} + +void OpcUaNodeMethod::addOutputParameter(const std::string& name, const OpcUaNodeId& dataTypeId) +{ + OpcUaChannelMethodParameter param; + param.setName(name); + param.setDataTypeId(dataTypeId); + outputParameters.push_back(param); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/src/node/opcuanodeobject.cpp b/shared/libraries/opcua/opcuashared/src/node/opcuanodeobject.cpp new file mode 100644 index 0000000..64d5e43 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/src/node/opcuanodeobject.cpp @@ -0,0 +1,30 @@ +#include "opcuashared/node/opcuanodeobject.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaNodeObject::OpcUaNodeObject(const OpcUaNodeId& uaNode) + : OpcUaNode(uaNode, OpcUaNodeClass::Object) +{ +} + +OpcUaNodeObject::OpcUaNodeObject(const UA_ReferenceDescription& uaNodeDescription) + : OpcUaNode(uaNodeDescription, OpcUaNodeClass::Object) +{ +} + +OpcUaNodeObject::~OpcUaNodeObject() +{ +} + +OpcUaNodeObjectPtr OpcUaNodeObject::instantiateRoot() +{ + return std::make_shared(OPCUANODEID_ROOTFOLDER); +} + +OpcUaNodeObjectPtr OpcUaNodeObject::instantiateObjectsFolder() +{ + return std::make_shared(OPCUANODEID_OBJECTSFOLDER); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/src/node/opcuanodevariable.cpp b/shared/libraries/opcua/opcuashared/src/node/opcuanodevariable.cpp new file mode 100644 index 0000000..60229cd --- /dev/null +++ b/shared/libraries/opcua/opcuashared/src/node/opcuanodevariable.cpp @@ -0,0 +1,61 @@ +#include "opcuashared/node/opcuanodevariable.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaNodeVariable::OpcUaNodeVariable(const OpcUaNodeId& uaNode, const UA_DataType& uaDataType, size_t dimension) + : OpcUaNodeVariable(uaNode, uaDataType.typeId, dimension) +{ +} + +OpcUaNodeVariable::OpcUaNodeVariable(const OpcUaNodeId& uaNode, const OpcUaNodeId& dataTypeNodeId, size_t dimension) + : OpcUaNode(uaNode, OpcUaNodeClass::Variable) + , dataTypeNodeId(dataTypeNodeId) + , dimension(dimension) +{ +} + +OpcUaNodeVariable::OpcUaNodeVariable(const UA_ReferenceDescription& uaNodeDescription, const UA_DataType& uaDataType, size_t dimension) + : OpcUaNodeVariable(uaNodeDescription, uaDataType.typeId, dimension) +{ +} + +OpcUaNodeVariable::OpcUaNodeVariable(const UA_ReferenceDescription& uaNodeDescription, const OpcUaNodeId& dataTypeNodeId, size_t dimension) + : OpcUaNode(uaNodeDescription, OpcUaNodeClass::Variable) + , dataTypeNodeId(dataTypeNodeId) + , dimension(dimension) +{ +} + +OpcUaNodeVariable::~OpcUaNodeVariable() +{ +} + +const OpcUaNodeId OpcUaNodeVariable::getDataTypeNodeId() const +{ + return dataTypeNodeId; +} + +OpcUaVariantPtr OpcUaNodeVariable::getVariant() +{ + return variant; +} + +void OpcUaNodeVariable::setVariant(const UA_Variant& value) +{ + if (!variant) + variant = std::make_shared(value); + else + variant->setValue(value); +} + +size_t OpcUaNodeVariable::getDimension() +{ + return dimension; +} + +void OpcUaNodeVariable::setDimension(size_t dimension) +{ + this->dimension = dimension; +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/src/node/opcuaobjecttype.cpp b/shared/libraries/opcua/opcuashared/src/node/opcuaobjecttype.cpp new file mode 100644 index 0000000..c5c15b7 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/src/node/opcuaobjecttype.cpp @@ -0,0 +1,14 @@ +#include "opcuashared/node/opcuaobjecttype.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaObjectType::OpcUaObjectType(const OpcUaNodeId& typeId) + : OpcUaType(typeId, OpcUaNodeClass::ObjectType) +{ +} + +OpcUaObjectType::~OpcUaObjectType() +{ +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/src/node/opcuatype.cpp b/shared/libraries/opcua/opcuashared/src/node/opcuatype.cpp new file mode 100644 index 0000000..cbd0d79 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/src/node/opcuatype.cpp @@ -0,0 +1,12 @@ +#include "opcuashared/node/opcuatype.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaType::OpcUaType(const OpcUaNodeId& typeId, OpcUaNodeClass nodeClass) + : OpcUaNode(typeId, nodeClass) +{ + assert(!typeId.isNull()); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/src/node/opcuavariabletype.cpp b/shared/libraries/opcua/opcuashared/src/node/opcuavariabletype.cpp new file mode 100644 index 0000000..2531718 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/src/node/opcuavariabletype.cpp @@ -0,0 +1,14 @@ +#include "opcuashared/node/opcuavariabletype.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaVariableType::OpcUaVariableType(const OpcUaNodeId& typeId) + : OpcUaType(typeId, OpcUaNodeClass::VariableType) +{ +} + +OpcUaVariableType::~OpcUaVariableType() +{ +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/src/opcuacallmethodresult.cpp b/shared/libraries/opcua/opcuashared/src/opcuacallmethodresult.cpp new file mode 100644 index 0000000..00711bd --- /dev/null +++ b/shared/libraries/opcua/opcuashared/src/opcuacallmethodresult.cpp @@ -0,0 +1,46 @@ +#include "opcuashared/opcuacallmethodresult.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaCallMethodResult::OpcUaCallMethodResult(const UA_CallMethodResult& callMethodResult) + : callMethodResult(callMethodResult) +{ +} + +OpcUaCallMethodResult::~OpcUaCallMethodResult() +{ +} + +size_t OpcUaCallMethodResult::getOutputArgumentsSize() const +{ + return callMethodResult.outputArgumentsSize; +} + +const UA_StatusCode& OpcUaCallMethodResult::getStatusCode() const +{ + return callMethodResult.statusCode; +} + +bool OpcUaCallMethodResult::isStatusOK() const +{ + return (getStatusCode() == UA_STATUSCODE_GOOD); +} + +OpcUaVariant OpcUaCallMethodResult::getOutputArgument(size_t i) const +{ + if (i < callMethodResult.outputArgumentsSize) + return OpcUaVariant(callMethodResult.outputArguments[i], true); + throw std::out_of_range("index of output argument is out of range"); +} + +const UA_CallMethodResult& OpcUaCallMethodResult::getCallMethodResult() const +{ + return callMethodResult; +} + +OpcUaCallMethodResult::operator const UA_CallMethodResult&() const +{ + return getCallMethodResult(); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/src/opcuacommon.cpp b/shared/libraries/opcua/opcuashared/src/opcuacommon.cpp new file mode 100644 index 0000000..eb67c61 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/src/opcuacommon.cpp @@ -0,0 +1,147 @@ +#include +#include +#include "opcuashared/opcuacommon.h" +#include +#include + +#include "open62541/plugin/nodestore.h" + +#ifdef OPCUA_ENABLE_ENCRYPTION +#include +#include +#include +#endif + +using namespace std::chrono; + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +namespace utils +{ + double ToSeconds(const UA_DateTime& time) + { + return (double) (time) / (double) UA_DATETIME_SEC; + } + + UA_StatusCode ToUaVariant(double value, const UA_NodeId& dataTypeNodeId, UA_Variant* var) + { + if (dataTypeNodeId.namespaceIndex == 0) + { + auto dataType = UA_findDataType(&dataTypeNodeId); + if (dataType) + { + switch (dataType->typeKind) + { + case UA_TYPES_DOUBLE: + return UA_Variant_setScalarCopy(var, &value, dataType); + case UA_TYPES_FLOAT: + { + float f = (float) value; + return UA_Variant_setScalarCopy(var, &f, dataType); + } + case UA_TYPES_BOOLEAN: + { + bool b = (value != 0); + return UA_Variant_setScalarCopy(var, &b, dataType); + } + case UA_TYPES_INT16: + { + int16_t i16 = (int16_t) std::round(value); + return UA_Variant_setScalarCopy(var, &i16, dataType); + } + case UA_TYPES_UINT16: + { + uint16_t i16 = (uint16_t) std::round(value); + return UA_Variant_setScalarCopy(var, &i16, dataType); + } + case UA_TYPES_INT32: + { + int32_t i32 = (int32_t) std::round(value); + return UA_Variant_setScalarCopy(var, &i32, dataType); + } + case UA_TYPES_UINT32: + { + int32_t i32 = (uint32_t) std::round(value); + return UA_Variant_setScalarCopy(var, &i32, dataType); + } + case UA_TYPES_INT64: + case UA_TYPES_UINT64: + { + int64_t i64 = (int64_t) std::round(value); + return UA_Variant_setScalarCopy(var, &i64, dataType); + } + } + } + } + throw std::runtime_error("C Exception: unsupported value!"); + } + + void ToUaVariant(const std::string& value, const UA_NodeId& dataTypeNodeId, UA_Variant* var) + { + if (dataTypeNodeId.namespaceIndex == 0) + { + auto dataType = UA_findDataType(&dataTypeNodeId); + if (dataType) + { + switch (dataType->typeKind) + { + case UA_TYPES_STRING: + { + UA_String str = UA_STRING((char*) value.c_str()); + UA_Variant_setScalarCopy(var, &str, dataType); + return; + } + case UA_TYPES_LOCALIZEDTEXT: + { + UA_LocalizedText str = UA_LOCALIZEDTEXT((char*) "en_US", (char*) value.c_str()); + UA_Variant_setScalarCopy(var, &str, dataType); + return; + } + default: + return; + } + } + } + throw std::runtime_error("C Exception: unsupported value!"); + } + + DurationTimeStamp GetDurationTimeStamp() + { + return std::chrono::steady_clock::now(); + } + + OpcUaObject LoadFile(const std::string& path) + { + OpcUaObject fileContentsObj = UA_BYTESTRING_NULL; + UA_ByteString& fileContents = fileContentsObj.getValue(); + + /* Open the file */ + FILE* fp = fopen(path.c_str(), "rb"); + if (!fp) + { + errno = 0; /* We read errno also from the tcp layer... */ + throw std::invalid_argument("Can not open file " + path); + } + + /* Get the file length, allocate the data and read */ + fseek(fp, 0, SEEK_END); + fileContents.length = (size_t) ftell(fp); + fileContents.data = (UA_Byte*) UA_malloc(fileContents.length * sizeof(UA_Byte)); + if (fileContents.data) + { + fseek(fp, 0, SEEK_SET); + size_t read = fread(fileContents.data, sizeof(UA_Byte), fileContents.length, fp); + if (read != fileContents.length) + UA_ByteString_clear(&fileContents); + } + else + { + fileContents.length = 0; + } + fclose(fp); + + return fileContentsObj; + } +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/src/opcuadatatypearraylist.cpp b/shared/libraries/opcua/opcuashared/src/opcuadatatypearraylist.cpp new file mode 100644 index 0000000..defc755 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/src/opcuadatatypearraylist.cpp @@ -0,0 +1,42 @@ +#include "opcuashared/opcuadatatypearraylist.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaDataTypeArrayList::OpcUaDataTypeArrayList(const OpcUaDataTypeArrayList& copy) + : std::list() +{ + operator=(copy); +} + +OpcUaDataTypeArrayList& OpcUaDataTypeArrayList::operator=(const OpcUaDataTypeArrayList& other) +{ + if (this != &other) + { + clear(); + for (const auto& cur : other) + add(cur.typesSize, cur.types); + } + return *this; +} + +void OpcUaDataTypeArrayList::add(const size_t typesSize, const UA_DataType* types) +{ + UA_DataTypeArray dataTypeArray{nullptr, typesSize, types}; + + const UA_DataTypeArray* nextElement = nullptr; + if (!empty()) + nextElement = &front(); + + UA_DataTypeArray newDataTypeArray = {nextElement, typesSize, types}; + push_front(newDataTypeArray); +} + +const UA_DataTypeArray* OpcUaDataTypeArrayList::getCustomDataTypes() const +{ + if (empty()) + return nullptr; + + return &(*begin()); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/src/opcuadatavalue.cpp b/shared/libraries/opcua/opcuashared/src/opcuadatavalue.cpp new file mode 100644 index 0000000..7665deb --- /dev/null +++ b/shared/libraries/opcua/opcuashared/src/opcuadatavalue.cpp @@ -0,0 +1,45 @@ +#include "opcuashared/opcuadatavalue.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaDataValue::OpcUaDataValue(const UA_DataValue* dataValue) + : dataValue(dataValue) + , variant(dataValue->value, true) +{ +} + +OpcUaDataValue::~OpcUaDataValue() +{ +} + +bool OpcUaDataValue::hasValue() const +{ + return dataValue->hasValue; +} + +const OpcUaVariant& OpcUaDataValue::getValue() const +{ + return variant; +} + +const UA_StatusCode& OpcUaDataValue::getStatusCode() const +{ + return dataValue->status; +} + +bool OpcUaDataValue::isStatusOK() const +{ + return (getStatusCode() == UA_STATUSCODE_GOOD); +} + +const UA_DataValue* OpcUaDataValue::getDataValue() const +{ + return dataValue; +} + +OpcUaDataValue::operator const UA_DataValue*() const +{ + return getDataValue(); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/src/opcuaendpoint.cpp b/shared/libraries/opcua/opcuashared/src/opcuaendpoint.cpp new file mode 100644 index 0000000..1ca18a6 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/src/opcuaendpoint.cpp @@ -0,0 +1,69 @@ +#include "opcuashared/opcuaendpoint.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaEndpoint::OpcUaEndpoint(const std::string& name, const std::string& url) + : name(name) + , url(url) +{ +} + +OpcUaEndpoint::OpcUaEndpoint() +{ +} + +void OpcUaEndpoint::setName(const std::string& name) +{ + this->name = name; +} + +const std::string& OpcUaEndpoint::getName() const +{ + return name; +} + +void OpcUaEndpoint::setUrl(const std::string& url) +{ + this->url = url; +} + +const std::string& OpcUaEndpoint::getUrl() const +{ + return url; +} + +void OpcUaEndpoint::setSecurityConfig(OpcUaClientSecurityConfig* securityConfig) +{ + if (securityConfig == NULL) + this->securityConfig.reset(); + else + this->securityConfig = *securityConfig; +} + +const OpcUaClientSecurityConfig* OpcUaEndpoint::getSecurityConfig() const +{ + return this->securityConfig.has_value() ? &this->securityConfig.value() : NULL; +} + +const UA_DataTypeArray* OpcUaEndpoint::getCustomDataTypes()const +{ + return customDataTypeList.getCustomDataTypes(); +} + +void OpcUaEndpoint::registerCustomTypes(const size_t typesSize, const UA_DataType* types) +{ + customDataTypeList.add(typesSize, types); + +} + +void OpcUaEndpoint::setLogLevel(const UA_LogLevel logLevel) +{ + this->logLevel = logLevel; +} + +UA_LogLevel OpcUaEndpoint::getLogLevel() const +{ + return this->logLevel; +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/src/opcuanodecollection.cpp b/shared/libraries/opcua/opcuashared/src/opcuanodecollection.cpp new file mode 100644 index 0000000..988045f --- /dev/null +++ b/shared/libraries/opcua/opcuashared/src/opcuanodecollection.cpp @@ -0,0 +1,29 @@ +#include "opcuashared/opcuanodecollection.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +/* OpcUaNodeCollection */ + +OpcUaNodeCollection OpcUaNodeCollection::selectNodes(OpcUaNodeClass nodeClassMask) +{ + OpcUaNodeCollection rtn; + + for (const auto& item : *this) + { + auto nc = static_cast(item->getNodeClass()); + if ((nc & (UA_UInt32)nodeClassMask) > 0) + rtn.push_back(item); + } + + return rtn; +} + +OpcUaNodePtr OpcUaNodeCollection::locateNode(const OpcUaNodeId& nodeId) const +{ + auto it = std::find_if(cbegin(), cend(), [&nodeId](const OpcUaNodePtr& node) { return node->getNodeId() == nodeId; }); + if (it != cend()) + return *it; + return nullptr; +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/src/opcuanodeid.cpp b/shared/libraries/opcua/opcuashared/src/opcuanodeid.cpp new file mode 100644 index 0000000..80ba803 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/src/opcuanodeid.cpp @@ -0,0 +1,130 @@ +#include "opcuashared/opcuanodeid.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaNodeId::OpcUaNodeId() + : OpcUaObject(UA_NODEID_NULL) +{ +} + +OpcUaNodeId::OpcUaNodeId(uint32_t identifier) + : OpcUaNodeId(0, identifier) +{ +} + +OpcUaNodeId::OpcUaNodeId(uint16_t namespaceIndex, const char* identifier) + : OpcUaObject(UA_NODEID_STRING_ALLOC(namespaceIndex, identifier)) +{ +} + +OpcUaNodeId::OpcUaNodeId(uint16_t namespaceIndex, const std::string& identifier) + : OpcUaNodeId(namespaceIndex, identifier.c_str()) +{ +} + +OpcUaNodeId::OpcUaNodeId(uint16_t namespaceIndex, uint32_t identifier) + : OpcUaObject(UA_NODEID_NUMERIC(namespaceIndex, identifier)) +{ +} + +const UA_NodeId* OpcUaNodeId::getPtr() const noexcept +{ + return &value; +} + +UA_NodeId* OpcUaNodeId::getPtr() noexcept +{ + return &value; +} + +uint16_t OpcUaNodeId::getNamespaceIndex() const noexcept +{ + return value.namespaceIndex; +} + +bool OpcUaNodeId::isNull() const noexcept +{ + return UA_NodeId_isNull(&value); +} + +OpcUaIdentifierUniversal OpcUaNodeId::getIdentifier() const +{ + return OpcUaNodeId::getIdentifier(value); +} + +OpcUaIdentifierType OpcUaNodeId::getIdentifierType() const +{ + return OpcUaNodeId::getIdentifierType(value.identifierType); +} + +std::string OpcUaNodeId::toString() const +{ + std::stringstream ss; + ss << "("; + ss << getNamespaceIndex(); + ss << ", "; + ss << getIdentifier(); + ss << ")"; + return ss.str(); +} + +OpcUaNodeId OpcUaNodeId::instantiateNode(uint16_t namespaceIndex, + OpcUaIdentifierUniversal identifierUniversal, + OpcUaIdentifierType identifierType) +{ + switch (identifierType) + { + case OpcUaIdentifierType::Numeric: + { + uint32_t id; + UA_readNumber((uint8_t*)identifierUniversal.c_str(), identifierUniversal.size(), &id); + return OpcUaNodeId(namespaceIndex, id); + } + case OpcUaIdentifierType::String: + return OpcUaNodeId(namespaceIndex, identifierUniversal); + default: + throw std::runtime_error("Unsupported OpcUaIdentifierType!"); + } +} + +OpcUaIdentifierUniversal OpcUaNodeId::getIdentifier(const UA_NodeId& uaNodeId) +{ + switch (getIdentifierType(uaNodeId.identifierType)) + { + case OpcUaIdentifierType::Numeric: + return std::to_string(uaNodeId.identifier.numeric); + case OpcUaIdentifierType::String: + return utils::ToStdString(uaNodeId.identifier.string); + default: + throw std::runtime_error("C Exception: unsupported identifier type!"); + }; +} + +OpcUaIdentifierType OpcUaNodeId::getIdentifierType(const UA_NodeIdType& identifierType) +{ + switch (identifierType) + { + case UA_NODEIDTYPE_NUMERIC: + return OpcUaIdentifierType::Numeric; + case UA_NODEIDTYPE_STRING: + return OpcUaIdentifierType::String; + case UA_NODEIDTYPE_GUID: + return OpcUaIdentifierType::Guid; + case UA_NODEIDTYPE_BYTESTRING: + default: + return OpcUaIdentifierType::Undefined; + }; +} + +void OpcUaNodeId::SetRandomSeed() +{ + UA_random_seed((UA_UInt64) UA_DateTime_now()); +} + +OpcUaNodeId OpcUaNodeId::CreateWithRandomGuid() +{ + return OpcUaNodeId(UA_NODEID_GUID(1, UA_Guid_random())); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/src/opcuasecurity_config.cpp b/shared/libraries/opcua/opcuashared/src/opcuasecurity_config.cpp new file mode 100644 index 0000000..1391002 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/src/opcuasecurity_config.cpp @@ -0,0 +1,84 @@ +#include "opcuashared/opcua.h" +#include "opcuashared/opcuasecurity_config.h" + +#include "opcuashared/opcuasecuritycommon.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +OpcUaSecurityConfig::OpcUaSecurityConfig() + : certificate(UA_BYTESTRING_NULL) + , privateKey(UA_BYTESTRING_NULL) +{ +} + +OpcUaSecurityConfig::OpcUaSecurityConfig(const OpcUaSecurityConfig& config) +{ + operator=(config); +} + +OpcUaSecurityConfig& OpcUaSecurityConfig::operator=(const OpcUaSecurityConfig& config) +{ + if (this == &config) + return *this; + + appUri = config.appUri; + securityMode = config.securityMode; + certificate = config.certificate; + privateKey = config.privateKey; + trustList = config.trustList; + revocationList = config.revocationList; + trustAll = config.trustAll; + + return *this; +} + +void OpcUaSecurityConfig::validate() const +{ + if (securityMode == UA_MESSAGESECURITYMODE_INVALID) + throw OpcUaException(UA_STATUSCODE_BADSECURITYCHECKSFAILED, "Invalid security mode."); + + if (securityMode == UA_MESSAGESECURITYMODE_SIGN || securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) + { + if (!hasCertificate()) + throw OpcUaException(UA_STATUSCODE_BADSECURITYCHECKSFAILED, "Certificate is not set."); + + if (!hasPrivateKey()) + throw OpcUaException(UA_STATUSCODE_BADSECURITYCHECKSFAILED, "Private key not set."); + } +} + +bool OpcUaSecurityConfig::hasCertificate() const +{ + return certificate.getValue().data != NULL; +} + +bool OpcUaSecurityConfig::hasPrivateKey() const +{ + return privateKey.getValue().data != NULL; +} + +std::optional OpcUaSecurityConfig::getAppUriOrParseFromCertificate() const +{ + std::optional appUri; + if (appUri.has_value()) + appUri = appUri.value(); + else if (this->hasCertificate()) + appUri = OpcUaSecurityCommon::parseCertificateUri(certificate.getValue()); + return appUri; +} + +OpcUaServerSecurityConfig::OpcUaServerSecurityConfig() + : OpcUaSecurityConfig() +{ + authenticateUser = [](bool isAnonymous, std::string username, std::string password) + { + return UA_STATUSCODE_GOOD; + }; +} + +bool OpcUaClientSecurityConfig::isAnonymous() const +{ + return !(username.has_value() && password.has_value()); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/src/opcuasecuritycommon.cpp b/shared/libraries/opcua/opcuashared/src/opcuasecuritycommon.cpp new file mode 100644 index 0000000..b54c1a5 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/src/opcuasecuritycommon.cpp @@ -0,0 +1,62 @@ +#include "opcuashared/opcuasecuritycommon.h" +#include "opcuashared/opcuacommon.h" + +#ifdef OPCUA_ENABLE_ENCRYPTION +#include +#include +#include +#endif + +using namespace std::chrono; + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +std::optional OpcUaSecurityCommon::parseCertificateUri(const UA_ByteString& certificate) +{ + std::optional subjectUri; + +#ifndef OPCUA_ENABLE_ENCRYPTION + throw OpcUaException(UA_STATUSCODE_BADINTERNALERROR, "Encryption was not enabled when building the project."); +#else + if (certificate.data == NULL) + return subjectUri; + + const unsigned char* pData = certificate.data; + X509* certificateX509 = d2i_X509(NULL, &pData, (long) certificate.length); + if (certificateX509 == NULL) + return subjectUri; + + GENERAL_NAMES* names = (GENERAL_NAMES*) X509_get_ext_d2i(certificateX509, NID_subject_alt_name, NULL, NULL); + if (names == NULL) + { + X509_free(certificateX509); + return subjectUri; + } + + int namesCount = sk_GENERAL_NAME_num(names); + for (int i = 0; i < namesCount; i++) + { + GENERAL_NAME* name = sk_GENERAL_NAME_value(names, i); + if (name->type == GEN_URI) + { + size_t len = name->d.ia5->length; + void* data = name->d.ia5->data; + if (data != NULL) + subjectUri = std::string((const char*) data, len); + break; + } + } + + X509_free(certificateX509); + sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); +#endif + + return subjectUri; +} + +UA_StatusCode OpcUaSecurityCommon::verifyCertificateRejectAll(void* verificationContext, const UA_ByteString* certificate) +{ + return UA_STATUSCODE_BADCERTIFICATEUNTRUSTED; +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/src/opcuavariant.cpp b/shared/libraries/opcua/opcuashared/src/opcuavariant.cpp new file mode 100644 index 0000000..97e0038 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/src/opcuavariant.cpp @@ -0,0 +1,223 @@ +#include "opcuashared/opcuavariant.h" +#include +#include +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using namespace daq::opcua::utils; + +OpcUaVariant::OpcUaVariant() + : OpcUaObject() +{ +} + +OpcUaVariant::OpcUaVariant(const uint16_t& value) +{ + UA_Variant_setScalarCopy(&this->value, &value, &UA_TYPES[UA_TYPES_UINT16]); +} + +OpcUaVariant::OpcUaVariant(const int32_t& value) + : OpcUaVariant() +{ + UA_Variant_setScalarCopy(&this->value, &value, &UA_TYPES[UA_TYPES_INT32]); +} + +OpcUaVariant::OpcUaVariant(const int64_t& value) + : OpcUaVariant() +{ + UA_Variant_setScalarCopy(&this->value, &value, &UA_TYPES[UA_TYPES_INT64]); +} + +OpcUaVariant::OpcUaVariant(const char* value) + : OpcUaVariant() +{ + UA_String* newString = UA_String_new(); + *newString = UA_STRING_ALLOC(value); + UA_Variant_setScalar(&this->value, newString, &UA_TYPES[UA_TYPES_STRING]); +} + +OpcUaVariant::OpcUaVariant(const double& value) + : OpcUaVariant() +{ + UA_Variant_setScalarCopy(&this->value, &value, &UA_TYPES[UA_TYPES_DOUBLE]); +} + +OpcUaVariant::OpcUaVariant(const bool& value) + : OpcUaVariant() +{ + UA_Variant_setScalarCopy(&this->value, &value, &UA_TYPES[UA_TYPES_BOOLEAN]); +} + +OpcUaVariant::OpcUaVariant(const OpcUaNodeId& value) + : OpcUaVariant() +{ + UA_Variant_setScalarCopy(&this->value, value.getPtr(), &UA_TYPES[UA_TYPES_NODEID]); +} + +OpcUaVariant::OpcUaVariant(const UA_DataType* type, size_t dimension) + : OpcUaVariant() +{ + value.type = type; + if (dimension > 1) + { + value.arrayLength = dimension; + value.arrayDimensions = static_cast(UA_Array_new(1, type)); + value.arrayDimensions[0] = UA_UInt32(dimension); + value.arrayDimensionsSize = 1; + } +} + +OpcUaVariant::OpcUaVariant(const double& genericValue, const UA_DataType& originalType) + : OpcUaVariant() +{ + UA_StatusCode status = ToUaVariant(genericValue, originalType.typeId, &this->value); + if (status != UA_STATUSCODE_GOOD) + throw OpcUaVariableConversionError(status); +} + + +void OpcUaVariant::setValue(UA_Variant&& value) +{ + OpcUaObject::setValue(std::move(value)); +} + +void OpcUaVariant::setValue(const UA_Variant& value, bool shallowCopy) +{ + OpcUaObject::setValue(value, shallowCopy); +} + +bool OpcUaVariant::isInteger() const +{ + return OpcUaVariant::IsInteger(this->value); +} + +bool OpcUaVariant::isString() const +{ + return VariantUtils::HasScalarType(value) || + VariantUtils::HasScalarType(value); +} + +bool OpcUaVariant::isDouble() const +{ + return VariantUtils::HasScalarType(value); +} + +bool OpcUaVariant::isBool() const +{ + return VariantUtils::HasScalarType(value); +} + +bool OpcUaVariant::isNodeId() const +{ + return VariantUtils::HasScalarType(value); +} + +bool OpcUaVariant::isNull() const +{ + return UA_Variant_isEmpty(&value); +} + +bool OpcUaVariant::isReal() const +{ + if (value.type == NULL) + return false; + + switch (value.type->typeKind) + { + case UA_TYPES_FLOAT: + case UA_TYPES_DOUBLE: + return true; + default: + return false; + } +} + +bool OpcUaVariant::isNumber() const +{ + return isInteger() || isReal(); +} + +bool OpcUaVariant::IsInteger(const UA_Variant& value) +{ + if (value.type && value.type->typeId.namespaceIndex == 0) // built-in types + { + switch (value.type->typeKind) + { + case UA_TYPES_SBYTE: + case UA_TYPES_BYTE: + case UA_TYPES_INT16: + case UA_TYPES_UINT16: + case UA_TYPES_INT32: + case UA_TYPES_UINT32: + case UA_TYPES_INT64: + case UA_TYPES_UINT64: + return true; + default: + return false; + } + } + return false; +} + +std::string OpcUaVariant::toString() const +{ + if (isType()) + { + UA_LocalizedText localizedText = readScalar(); + return ToStdString(localizedText.text); + } + + if (isType()) + { + UA_QualifiedName localizedText = readScalar(); + return ToStdString(localizedText.name); + } + + UA_String str = readScalar(); + return ToStdString(str); +} + +int64_t OpcUaVariant::toInteger() const +{ + return VariantUtils::ToNumber(this->value); +} + +double OpcUaVariant::toDouble() const +{ + return readScalar(); +} + +bool OpcUaVariant::toBool() const +{ + return readScalar(); +} + +OpcUaNodeId OpcUaVariant::toNodeId() const +{ + return VariantUtils::ToNodeId(this->value); +} + +// VariantUtils + +void VariantUtils::ToInt32Variant(OpcUaVariant& variant) +{ + if (!variant.isNumber()) + throw OpcUaException(UA_STATUSCODE_BADTYPEMISMATCH, "Variant does not contain a numeric type."); + + UA_Int32 value = (UA_Int32) variant.toInteger(); + variant.setScalar(value); +} + +void VariantUtils::ToInt64Variant(OpcUaVariant& variant) +{ + if (!variant.isNumber()) + throw OpcUaException(UA_STATUSCODE_BADTYPEMISMATCH, "Variant does not contain a numeric type."); + + UA_Int64 value = (UA_Int64) variant.toInteger(); + variant.setScalar(value); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/src/opcuaversion.cpp b/shared/libraries/opcua/opcuashared/src/opcuaversion.cpp new file mode 100644 index 0000000..e11d941 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/src/opcuaversion.cpp @@ -0,0 +1,39 @@ +#include "opcuashared/opcuaversion.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +#pragma push_macro("major") +#pragma push_macro("minor") + +#undef major +#undef minor + +OpcUaVersion::OpcUaVersion(const char* version) +{ + std::sscanf(version, "%d.%d.%d", &major, &minor, &patch); +} + +std::string OpcUaVersion::toString() const +{ + char buffer[36]; + snprintf(buffer, sizeof(buffer), "%d.%d.%d", major, minor, patch); + return buffer; +} + +bool OpcUaVersion::Compatible(const OpcUaVersion& serverVersion, const OpcUaVersion& systemVersion) +{ + return serverVersion.major == systemVersion.major && serverVersion.minor <= systemVersion.minor; +} + +bool OpcUaVersion::HasFeature(const OpcUaVersion& serverVersion, const OpcUaVersion& featureVersion) +{ + if (serverVersion.major > featureVersion.major) + return true; + + return serverVersion.major == featureVersion.major && featureVersion.minor <= serverVersion.minor; +} + +#pragma pop_macro("minor") +#pragma pop_macro("major") + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/tests/CMakeLists.txt b/shared/libraries/opcua/opcuashared/tests/CMakeLists.txt new file mode 100644 index 0000000..5e467ef --- /dev/null +++ b/shared/libraries/opcua/opcuashared/tests/CMakeLists.txt @@ -0,0 +1,37 @@ +set(MODULE_NAME opcuashared) +set(TEST_APP test_${MODULE_NAME}) + +set(TEST_SOURCES + main.cpp + test_string_utils.cpp + test_status_code.cpp + test_opcuaendpoint.cpp + test_opcuanodeid.cpp + test_opcua_variant.cpp + test_opcua_object.cpp + test_opcuadatavalue.cpp + test_opcuacallmethodresult.cpp + test_opcuaversion.cpp + test_opcua_vector.cpp + test_opcuadatatypearraylist.cpp + test_bcrypt.cpp +) + +add_executable(${TEST_APP} ${TEST_SOURCES}) + +target_link_libraries(${TEST_APP} PRIVATE ${SDK_TARGET_NAMESPACE}::${MODULE_NAME} + daq::test_utils +) + +if (MSVC) + target_compile_definitions(${TEST_APP} PRIVATE _CRT_SECURE_NO_WARNINGS) +endif() + +add_test(NAME ${TEST_APP} + COMMAND $ + WORKING_DIRECTORY bin +) + +if (OPENDAQ_ENABLE_COVERAGE) + setup_target_for_coverage(${MODULE_NAME}coverage ${TEST_APP} ${MODULE_NAME}coverage) +endif() diff --git a/shared/libraries/opcua/opcuashared/tests/main.cpp b/shared/libraries/opcua/opcuashared/tests/main.cpp new file mode 100644 index 0000000..a4ca297 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/tests/main.cpp @@ -0,0 +1,13 @@ +#include +#include + +int main(int argc, char** args) +{ + testing::InitGoogleTest(&argc, args); + + testing::TestEventListeners& listeners = testing::UnitTest::GetInstance()->listeners(); + listeners.Append(new MemCheckListener()); + + int res = RUN_ALL_TESTS(); + return res; +} diff --git a/shared/libraries/opcua/opcuashared/tests/test_bcrypt.cpp b/shared/libraries/opcua/opcuashared/tests/test_bcrypt.cpp new file mode 100644 index 0000000..8b1574f --- /dev/null +++ b/shared/libraries/opcua/opcuashared/tests/test_bcrypt.cpp @@ -0,0 +1,115 @@ +#include +#include + +using namespace daq::opcua; + +/** + * Test BCrypt class. + * + * One can generate more test cases with a help of the php script: commonlib/tests/tools/bcrypt_test_cases.php + */ + +struct BCryptTestCase +{ + std::string password; + std::string salt; + std::string hash; + int rounds; + + BCryptTestCase(std::string password, std::string salt, std::string hash, int rounds) + : password(std::move(password)) + , salt(std::move(salt)) + , hash(std::move(hash)) + , rounds(rounds) + { + } +}; + +static bool compareHashes(const std::string& a, const std::string& b) +{ + // we should ignore bcrypt version when comparing hashes + return a[0] == b[0] && a[1] == b[1] && strcmp(&a[3], &b[3]) == 0; +} + +class BCryptTest : public testing::Test, public ::testing::WithParamInterface +{ +protected: + BCrypt bcrypt; +}; + + +class BCryptTestHash : public BCryptTest +{ +}; + +class BCryptTestVerify : public BCryptTest +{ +}; + +TEST_P(BCryptTestHash, HashTest) +{ + BCryptTestCase testCase = GetParam(); + std::string hash = bcrypt.hash(testCase.password, testCase.salt, testCase.rounds); + ASSERT_TRUE(compareHashes(hash, testCase.hash)); +} + +TEST_P(BCryptTestVerify, VerifyTest) +{ + BCryptTestCase testCase = GetParam(); + ASSERT_TRUE(BCrypt::Verify(testCase.hash, testCase.password)); + ASSERT_FALSE(BCrypt::Verify(testCase.hash, testCase.password + "wrong")); +} + +INSTANTIATE_TEST_SUITE_P( + BCryptTestHashAll, + BCryptTestHash, + ::testing::Values( + BCryptTestCase("", "thisisasaltwhichis22ch", "$2y$06$thisisasaltwhichis22ceiWyJJQuCqQ6K/VMVNgl3WR2TnKke93O", 6), + BCryptTestCase("", "thisisasaltwhichis22ch", "$2y$08$thisisasaltwhichis22cetIGsXYPjot9MEiTlOQSjSqsUhO/ncum", 8), + BCryptTestCase("hello", "thisisasaltwhichis22ch", "$2y$06$thisisasaltwhichis22cenrvQa8HoAzcd4uM4IFyFZCnCW/K/Z8W", 6), + BCryptTestCase("hello", "thisisasaltwhichis22ch", "$2y$08$thisisasaltwhichis22ceGSq7Gjk/l24CRv3kIGqHqO1FkjVJqfa", 8), + BCryptTestCase("MpxzNrkTT)0OTBlU5TTY", "thisisasaltwhichis22ch", "$2y$06$thisisasaltwhichis22cewx9N0qHf5lH1qhen4ZSkh9G.9vF7bpC", 6), + BCryptTestCase("MpxzNrkTT)0OTBlU5TTY", "thisisasaltwhichis22ch", "$2y$08$thisisasaltwhichis22cehPvOT6ZlqH0g2TnuEL4wXbzDyVzqtJK", 8), + BCryptTestCase("2xNRPxj8EJfcN.Yxghkyt54Z39}Ylz0X4LwanXJB3i2mk<2Qs<9gWivWhpUe", "thisisasaltwhichis22ch", "$2y$06$thisisasaltwhichis22ceeL2tbWfYYl6VVS.6kwSgf4Afnv5UVWu", 6), + BCryptTestCase("2xNRPxj8EJfcN.Yxghkyt54Z39}Ylz0X4LwanXJB3i2mk<2Qs<9gWivWhpUe", "thisisasaltwhichis22ch", "$2y$08$thisisasaltwhichis22cejWbLJJzXmMWFyRkQhHGqvFWPPnh1era", 8), + BCryptTestCase("", "thisisasaltwhichis22chHello", "$2y$06$thisisasaltwhichis22ceiWyJJQuCqQ6K/VMVNgl3WR2TnKke93O", 6), + BCryptTestCase("", "thisisasaltwhichis22chHello", "$2y$08$thisisasaltwhichis22cetIGsXYPjot9MEiTlOQSjSqsUhO/ncum", 8), + BCryptTestCase("hello", "thisisasaltwhichis22chHello", "$2y$06$thisisasaltwhichis22cenrvQa8HoAzcd4uM4IFyFZCnCW/K/Z8W", 6), + BCryptTestCase("hello", "thisisasaltwhichis22chHello", "$2y$08$thisisasaltwhichis22ceGSq7Gjk/l24CRv3kIGqHqO1FkjVJqfa", 8), + BCryptTestCase("MpxzNrkTT)0OTBlU5TTY", "thisisasaltwhichis22chHello", "$2y$06$thisisasaltwhichis22cewx9N0qHf5lH1qhen4ZSkh9G.9vF7bpC", 6), + BCryptTestCase("MpxzNrkTT)0OTBlU5TTY", "thisisasaltwhichis22chHello", "$2y$08$thisisasaltwhichis22cehPvOT6ZlqH0g2TnuEL4wXbzDyVzqtJK", 8), + BCryptTestCase("2xNRPxj8EJfcN.Yxghkyt54Z39}Ylz0X4LwanXJB3i2mk<2Qs<9gWivWhpUe", "thisisasaltwhichis22chHello", "$2y$06$thisisasaltwhichis22ceeL2tbWfYYl6VVS.6kwSgf4Afnv5UVWu", 6), + BCryptTestCase("2xNRPxj8EJfcN.Yxghkyt54Z39}Ylz0X4LwanXJB3i2mk<2Qs<9gWivWhpUe", "thisisasaltwhichis22chHello", "$2y$08$thisisasaltwhichis22cejWbLJJzXmMWFyRkQhHGqvFWPPnh1era", 8), + BCryptTestCase("", "MkjCFcpnaHo.ngQW8hDv1Y", "$2y$06$MkjCFcpnaHo.ngQW8hDv1OE5e7EEsNBkPqjKjbeiAAGDZ32tMeoxi", 6), + BCryptTestCase("", "MkjCFcpnaHo.ngQW8hDv1Y", "$2y$08$MkjCFcpnaHo.ngQW8hDv1Oq3XwM.TU1ux4xZH9SWTvEeO6PaRKJhq", 8), + BCryptTestCase("hello", "MkjCFcpnaHo.ngQW8hDv1Y", "$2y$06$MkjCFcpnaHo.ngQW8hDv1OKSXItY4YgdUhR1XnCCIdVTG6/Z9Q8lq", 6), + BCryptTestCase("hello", "MkjCFcpnaHo.ngQW8hDv1Y", "$2y$08$MkjCFcpnaHo.ngQW8hDv1OI06YNkstj1fnz7Hb7hMALmyKde/b6XC", 8), + BCryptTestCase("MpxzNrkTT)0OTBlU5TTY", "MkjCFcpnaHo.ngQW8hDv1Y", "$2y$06$MkjCFcpnaHo.ngQW8hDv1OWBmePzneCphnun8DXjkg0xSyFELeGQK", 6), + BCryptTestCase("MpxzNrkTT)0OTBlU5TTY", "MkjCFcpnaHo.ngQW8hDv1Y", "$2y$08$MkjCFcpnaHo.ngQW8hDv1Opd3VPU7yrnM2bcYLxKXnz5GseN./Ihe", 8), + BCryptTestCase("2xNRPxj8EJfcN.Yxghkyt54Z39}Ylz0X4LwanXJB3i2mk<2Qs<9gWivWhpUe", "MkjCFcpnaHo.ngQW8hDv1Y", "$2y$06$MkjCFcpnaHo.ngQW8hDv1O2bkSBvdwGDuLKRRKAKDrJjDaEHkvbbS", 6), + BCryptTestCase("2xNRPxj8EJfcN.Yxghkyt54Z39}Ylz0X4LwanXJB3i2mk<2Qs<9gWivWhpUe", "MkjCFcpnaHo.ngQW8hDv1Y", "$2y$08$MkjCFcpnaHo.ngQW8hDv1Ow2pDUKWKd3hQQKpiPMMzJY12zfFs1OG", 8), + BCryptTestCase("", "V0bNN/hb14yIaLqiGzRq8HBnUg/f7Ord6Q2ENsN.X3RmPgQR8wCfFDwKXJ3E", "$2y$06$V0bNN/hb14yIaLqiGzRq8.0q2LbRd5Bky7G/FobYdfIDZDt.3GfuS", 6), + BCryptTestCase("", "V0bNN/hb14yIaLqiGzRq8HBnUg/f7Ord6Q2ENsN.X3RmPgQR8wCfFDwKXJ3E", "$2y$08$V0bNN/hb14yIaLqiGzRq8.F9Eco7RM.M4t2WJoqcHpbKg9GmpD0BK", 8), + BCryptTestCase("hello", "V0bNN/hb14yIaLqiGzRq8HBnUg/f7Ord6Q2ENsN.X3RmPgQR8wCfFDwKXJ3E", "$2y$06$V0bNN/hb14yIaLqiGzRq8.h96biwYKLx4XkUR6uIq4MvxrGmMBo9q", 6), + BCryptTestCase("hello", "V0bNN/hb14yIaLqiGzRq8HBnUg/f7Ord6Q2ENsN.X3RmPgQR8wCfFDwKXJ3E", "$2y$08$V0bNN/hb14yIaLqiGzRq8./LDV//ottPlTJbrHPKM9GPrnc9VvHky", 8), + BCryptTestCase("MpxzNrkTT)0OTBlU5TTY", "V0bNN/hb14yIaLqiGzRq8HBnUg/f7Ord6Q2ENsN.X3RmPgQR8wCfFDwKXJ3E", "$2y$06$V0bNN/hb14yIaLqiGzRq8.Rvv5BWMw9VGPlDfCkMY9CgANdtm.cki", 6), + BCryptTestCase("MpxzNrkTT)0OTBlU5TTY", "V0bNN/hb14yIaLqiGzRq8HBnUg/f7Ord6Q2ENsN.X3RmPgQR8wCfFDwKXJ3E", "$2y$08$V0bNN/hb14yIaLqiGzRq8.SiqvUcvyIVUuPmBOyv/h8iCzGwuzG2G", 8), + BCryptTestCase("2xNRPxj8EJfcN.Yxghkyt54Z39}Ylz0X4LwanXJB3i2mk<2Qs<9gWivWhpUe", "V0bNN/hb14yIaLqiGzRq8HBnUg/f7Ord6Q2ENsN.X3RmPgQR8wCfFDwKXJ3E", "$2y$06$V0bNN/hb14yIaLqiGzRq8.hRrCzpywIiN0DtynMdE4yrXf3cOwCJS", 6), + BCryptTestCase("2xNRPxj8EJfcN.Yxghkyt54Z39}Ylz0X4LwanXJB3i2mk<2Qs<9gWivWhpUe", "V0bNN/hb14yIaLqiGzRq8HBnUg/f7Ord6Q2ENsN.X3RmPgQR8wCfFDwKXJ3E", "$2y$08$V0bNN/hb14yIaLqiGzRq8.fKNrgl454jT6cqUTmCNI67wil/qB.Ya", 8) +)); + +INSTANTIATE_TEST_SUITE_P( + BCryptTestVerifyAll, + BCryptTestVerify, + ::testing::Values( + BCryptTestCase("", "", "$2y$06$vHGBnsrghALFuir57FW6g.eelIYPnAvZCqMcixaPD0ge7dxFg6Ldy", 6), + BCryptTestCase("", "", "$2y$08$RkQxUBJv0fMV32wHx1MWeu/79CQCvxNZbP.a2KkZG5D5PHsxguaM6", 8), + BCryptTestCase("hello", "", "$2y$06$kM1HuyiWFB0RUnI5e2tlCuhNeO.NxUE/QIyBpWoC0Av7xSJ0CNgci", 6), + BCryptTestCase("hello", "", "$2y$08$Q7KWcZNJfhG92UyuKj9aNesCozbY2nPde7vnNUrYbwW8cyISekTQu", 8), + BCryptTestCase("QOzQ-xgq(4gF(aw1", "", "$2y$06$JOoIFeD2H6uLtcfZ7y1Nv.7086L6d.QFRL90e7tx4x7/dy0q4oNJ2", 6), + BCryptTestCase("QOzQ-xgq(4gF(aw1", "", "$2y$08$bIbtUgz8hhye4Iw.gX2fc.yYQOik10qMMmue6i6ld6fJrr8VLMZn6", 8), + BCryptTestCase("8dK>paPE26/9{Zb29VyU", "", "$2y$06$znnkg1eVKFniEnL0QacK6OMi60p67ynDrLmi7vTOcSu0pFiD8MUbm", 6), + BCryptTestCase("8dK>paPE26/9{Zb29VyU", "", "$2y$08$nqwBRmGip.fSASDshXNKcOkHqa7BLndfZMjPAJT3CuKjxYUonTjbi", 8), + BCryptTestCase("LYb>ycmZvhM.(u{U76HVMoXW)Sf7gycmZvhM.(u{U76HVMoXW)Sf7g +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using OpcUaObjectTest = testing::Test; + +TEST_F(OpcUaObjectTest, CreateSimpleType) +{ + OpcUaObject simpleVal; + + UA_Int16 value; + UA_Int16_init(&value); + + ASSERT_EQ(simpleVal.getValue(), value); +} + +TEST_F(OpcUaObjectTest, CreateComplexType) +{ + OpcUaObject complexVal; + + ASSERT_TRUE(UA_Variant_isEmpty(complexVal.get())); +} + +TEST_F(OpcUaObjectTest, SimpleTypeCopyConstructor) +{ + UA_Int32 ua_val = 5; + + OpcUaObject variant(ua_val); + + const UA_Int32& val = variant.getValue(); + + ASSERT_EQ(val, 5); +} + +TEST_F(OpcUaObjectTest, ComplexTypeCopyConstructor) +{ + UA_Variant ua_variant; + UA_Variant_init(&ua_variant); + + double value = 5; + UA_Variant_setScalarCopy(&ua_variant, &value, &UA_TYPES[UA_TYPES_DOUBLE]); + + OpcUaObject object(ua_variant); + + const UA_Variant& var = object.getValue(); + + UA_Variant_hasScalarType(&var, &UA_TYPES[UA_TYPES_DOUBLE]); + ASSERT_EQ(*static_cast(var.data), value); + + UA_Variant_clear(&ua_variant); +} + +TEST_F(OpcUaObjectTest, SimpleTypeMoveConstructor) +{ + UA_Int32 ua_val = 5; + + OpcUaObject variant(std::move(ua_val)); + + ASSERT_EQ(ua_val, 0); + + const UA_Int32& val = variant.getValue(); + + ASSERT_EQ(val, 5); +} + +TEST_F(OpcUaObjectTest, ComplexTypeMoveConstructor) +{ + UA_Variant ua_variant; + double value = 5; + UA_Variant_setScalarCopy(&ua_variant, &value, &UA_TYPES[UA_TYPES_DOUBLE]); + + OpcUaObject variant(std::move(ua_variant)); + ASSERT_TRUE(UA_Variant_isEmpty(&ua_variant)); + + const UA_Variant& var = variant.getValue(); + + UA_Variant_hasScalarType(&var, &UA_TYPES[UA_TYPES_DOUBLE]); + ASSERT_EQ(*static_cast(var.data), value); +} + +TEST_F(OpcUaObjectTest, SimpleTypeMoveAssignment) +{ + OpcUaObject object(5); + object = OpcUaObject(6); + + ASSERT_EQ(object.getValue(), 6); +} + +TEST_F(OpcUaObjectTest, ComplexTypeMoveAssignment) +{ + OpcUaObject object(UA_STRING_ALLOC("Test")); + object = OpcUaObject(UA_STRING_ALLOC("New val")); + + UA_String result = UA_STRING_ALLOC("New val"); + + ASSERT_TRUE(*object == result); + + UA_String_clear(&result); +} + +TEST_F(OpcUaObjectTest, SimpleTypeSetValueCopy) +{ + UA_Int16 ua_int = 14; + + OpcUaObject object; + object.setValue(ua_int); + + ASSERT_EQ(object.getValue(), 14); +} + +TEST_F(OpcUaObjectTest, ComplexTypeSetValueCopy) +{ + UA_String ua_str = UA_STRING_ALLOC("Test"); + + OpcUaObject object; + object.setValue(ua_str); + + UA_String_clear(&ua_str); + + ASSERT_TRUE(*object == "Test"); +} + +TEST_F(OpcUaObjectTest, SimpleTypeSetValueMove) +{ + OpcUaObject object; + object.setValue(14); + + ASSERT_EQ(object.getValue(), 14); +} + +TEST_F(OpcUaObjectTest, ComplexTypeSetValueMove) +{ + UA_String str = UA_STRING_ALLOC("Test"); + + OpcUaObject object; + object.setValue(std::move(str)); + + ASSERT_EQ(str.data, nullptr); + ASSERT_EQ(str.length, 0u); + + ASSERT_TRUE(*object == "Test"); +} + +TEST_F(OpcUaObjectTest, SimpleTypeCopyConstructOperator) +{ + OpcUaObject variant(5); + OpcUaObject variant1 = variant; + + ASSERT_EQ(variant.getValue(), 5); + ASSERT_EQ(variant1.getValue(), 5); +} + +TEST_F(OpcUaObjectTest, ComplexTypeCopyConstructOperator) +{ + OpcUaObject variant(UA_STRING_ALLOC("Test")); + OpcUaObject variant1 = variant; + + ASSERT_TRUE(variant.getValue() == "Test"); + ASSERT_TRUE(variant1.getValue() == "Test"); +} + +TEST_F(OpcUaObjectTest, SimpleTypeAssignmentOperator) +{ + OpcUaObject variant(5); + OpcUaObject variant1; + variant1 = variant; + + ASSERT_EQ(variant.getValue(), 5); + ASSERT_EQ(variant1.getValue(), 5); +} + +TEST_F(OpcUaObjectTest, ComplexTypeAssignmentOperator) +{ + OpcUaObject variant(UA_STRING_ALLOC("Test")); + OpcUaObject variant1; + + variant1 = variant; + + ASSERT_TRUE(variant.getValue() == "Test"); + ASSERT_TRUE(variant1.getValue() == "Test"); +} + +TEST_F(OpcUaObjectTest, ArrowOperator) +{ + OpcUaObject object(UA_STRING_ALLOC("Test")); + + const OpcUaObject& objectConst = object; + ASSERT_EQ(objectConst->length, 4u); + ASSERT_EQ(object->length, 4u); +} + +TEST_F(OpcUaObjectTest, SimpleTypeClear) +{ + OpcUaObject object(4); + + ASSERT_EQ(object.getValue(), 4); + + object.clear(); + + ASSERT_EQ(object.getValue(), 0); +} + +TEST_F(OpcUaObjectTest, ComplexTypeClear) +{ + OpcUaObject object(UA_STRING_ALLOC("Test")); + + ASSERT_TRUE(object.getValue() == "Test"); + + object.clear(); + + ASSERT_TRUE(object.getValue() == UA_STRING_NULL); +} + +TEST_F(OpcUaObjectTest, SimpleTypeGetDetachedValue) +{ + OpcUaObject object(4); + + ASSERT_EQ(object.getValue(), 4); + + object.getDetachedValue(); + + ASSERT_EQ(object.getValue(), 0); +} + +TEST_F(OpcUaObjectTest, ComplexTypeGetDetachedValue) +{ + UA_String text = UA_STRING_ALLOC("Test"); + + OpcUaObject object(text); + + UA_String value = object.getDetachedValue(); + + ASSERT_TRUE(value == text); + ASSERT_TRUE(object.getValue() == UA_STRING_NULL); + + UA_String_clear(&value); + UA_String_clear(&text); +} + +TEST_F(OpcUaObjectTest, SelfAssign) +{ + auto targetNodeId = OpcUaNodeId(1, 1000); + auto nodeId = OpcUaNodeId(1, 1000); + OpcUaNodeId* pNodeId = &nodeId; + nodeId = nodeId; + ASSERT_EQ(pNodeId, &nodeId); + ASSERT_EQ(targetNodeId, nodeId); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/tests/test_opcua_security.cpp b/shared/libraries/opcua/opcuashared/tests/test_opcua_security.cpp new file mode 100644 index 0000000..f7ed10c --- /dev/null +++ b/shared/libraries/opcua/opcuashared/tests/test_opcua_security.cpp @@ -0,0 +1,458 @@ +#include "gtest/gtest.h" +#include "testutils/testutils.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using Dewesoft::Utils::Crypto::BCrypt; + +BEGIN_NAMESPACE_OPCUA + +class OpcUaSecurityTest : public MemCheckTest +{ + bool EnableMemoryLeakDump() + { + return false; + } +}; + +static std::string TestFile(std::string name) +{ + return CmakeGlobals::ResDirFile("testKeys/keys/" + name); +} + +class TestServer +{ +public: + TestServer() + { + server = std::make_shared(); + server->setPort(4840); + } + + ~TestServer() + { + if (isStarted()) + server->stop(); + nodes.clear(); + } + + void setSecurityConfig(OpcUaServerSecurityConfig* config) + { + server->setSecurityConfig(config); + } + + void defineStringVar(std::string name, std::string value) + { + UA_NodeId nodeId = UA_NODEID_STRING_ALLOC(1, name.c_str()); + UA_String valueStr = UA_STRING_ALLOC(value.c_str()); + + OpcUaNodeValueServerStringPtr node = std::make_shared(nodeId); + node->setBrowseName(name.c_str()); + node->setValue(valueStr, UA_DateTime_now()); + server->createServerNode(node, OpcUaNodeId(0, UA_NS0ID_SERVER)); + nodes.push_back(node); + + UA_String_clear(&valueStr); + UA_NodeId_clear(&nodeId); + } + + void start() + { + server->start(); + } + + void stop() + { + server->stop(); + } + + bool isStarted() + { + return server->getStarted(); + } + + std::shared_ptr getServer() + { + return server; + } + + static OpcUaServerSecurityConfig CreateSecurityConfig() + { + OpcUaServerSecurityConfig config; + config.certificate = OpcUaCommon::loadFile(TestFile("server-cert.der")); + config.privateKey = OpcUaCommon::loadFile(TestFile("server-private.der")); + config.trustList.push_back(OpcUaCommon::loadFile(TestFile("client-cert.der")).getValue()); + config.appUri = "urn:dewesoft.com"; + config.securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT; + return config; + } + + static std::unordered_map CreateUsers() + { + BCrypt bcrypt; + unsigned int rounds = 8; + std::unordered_map users; + users["newton"] = bcrypt.hash("newton123", rounds); + users["galileo"] = bcrypt.hash("galileo123", rounds); + users["tesla"] = bcrypt.hash("tesla123", rounds); + users["pascal"] = bcrypt.hash("pascal123", rounds); + return users; + } + +private: + std::shared_ptr server; + std::vector nodes; +}; + +class TestClient +{ +public: + TestClient() + { + client = std::make_shared(OpcUaDataFetchStrategy::Buffered); + securityConfig = NULL; + } + + void setSecurityConfig(OpcUaClientSecurityConfig* config) + { + securityConfig = config; + } + + void connect() + { + OpcUaEndpoint endpoint("test", "opc.tcp://localhost:4840/", OpcUaServerType::General, ""); + endpoint.setSecurityConfig(securityConfig); + + OpcUaCollection endpoints; + endpoints.push_back(endpoint); + client->assignEndpoints(endpoints); + + client->connect(); + } + + void disconnect() + { + client->disconnect(); + } + + bool isConnected() + { + return client->size() > 0 && client->at(0)->isConnected(); + } + + std::string readStringVar(std::string name) + { + UA_NodeId nodeId = UA_NODEID_STRING_ALLOC(1, name.c_str()); + ReadResult r = client->at(0)->readValue(&nodeId); + + UA_Variant variant = r.value->getValue(); + UA_String* uaStr = (UA_String*) variant.data; + std::string value = std::string((char*) uaStr->data, uaStr->length); + + UA_NodeId_clear(&nodeId); + return value; + } + + std::shared_ptr getClient() + { + return client; + } + + static OpcUaClientSecurityConfig CreateSecurityConfig() + { + OpcUaClientSecurityConfig config; + config.certificate = OpcUaCommon::loadFile(TestFile("client-cert.der")); + config.privateKey = OpcUaCommon::loadFile(TestFile("client-private.der")); + config.trustList.push_back(OpcUaCommon::loadFile(TestFile("server-cert.der")).getValue()); + config.appUri = "urn:testclient.com"; + config.securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT; + return config; + } + +private: + std::shared_ptr client; + OpcUaClientSecurityConfig* securityConfig; +}; + +TEST_F(OpcUaSecurityTest, LoadCertificateTest) +{ + OpcUaObject cert; + + ASSERT_NO_THROW(cert = OpcUaCommon::loadFile(TestFile("client-cert.der"))); + ASSERT_GT(cert.getValue().length, 0); + + ASSERT_ANY_THROW(cert = OpcUaCommon::loadFile(TestFile("client-cert-missing.der"))); + + ASSERT_NO_THROW(cert = OpcUaCommon::loadFile(TestFile("garbage-cert.der"))); + ASSERT_GT(cert.getValue().length, 0); +} + +TEST_F(OpcUaSecurityTest, SecurityConfigMemoryTest) +{ + OpcUaClientSecurityConfig a; + a.certificate = OpcUaCommon::loadFile(TestFile("client-cert.der")).getValue(); + + a.trustList.push_back(OpcUaCommon::loadFile(TestFile("server-cert.der")).getValue()); + a.trustList[0] = OpcUaCommon::loadFile(TestFile("client-cert.der")).getValue(); + + a.appUri = "urn:testclient.com"; + a.securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT; + + OpcUaClientSecurityConfig b = a; +} + +TEST_F(OpcUaSecurityTest, PlainTextTest) +{ + std::string message = "Hello world, plain text communication works."; + + TestServer testServer; + testServer.setSecurityConfig(NULL); + testServer.start(); + ASSERT_TRUE(testServer.isStarted()); + + testServer.defineStringVar("testVar", message); + + TestClient testClient; + testClient.setSecurityConfig(NULL); + testClient.connect(); + ASSERT_TRUE(testClient.isConnected()); + + std::string received = testClient.readStringVar("testVar"); + ASSERT_EQ(received, message); + + testClient.disconnect(); + ASSERT_FALSE(testClient.isConnected()); + + testServer.stop(); + ASSERT_FALSE(testServer.isStarted()); +} + +TEST_F(OpcUaSecurityTest, SecurityModeNoneTest) +{ + std::string message = "Hello world, security mode UA_MESSAGESECURITYMODE_NONE works."; + + OpcUaServerSecurityConfig serverSecurity; + serverSecurity.securityMode = UA_MESSAGESECURITYMODE_NONE; + + OpcUaClientSecurityConfig clientSecurity; + clientSecurity.securityMode = UA_MESSAGESECURITYMODE_NONE; + + TestServer testServer; + testServer.setSecurityConfig(&serverSecurity); + testServer.start(); + ASSERT_TRUE(testServer.isStarted()); + + testServer.defineStringVar("testVar", message); + + TestClient testClient; + testClient.setSecurityConfig(&clientSecurity); + testClient.connect(); + ASSERT_TRUE(testClient.isConnected()); + + std::string received = testClient.readStringVar("testVar"); + ASSERT_EQ(received, message); + + testClient.disconnect(); + ASSERT_FALSE(testClient.isConnected()); + + testServer.stop(); + ASSERT_FALSE(testServer.isStarted()); +} + +TEST_F(OpcUaSecurityTest, SecurityModeSignEncryptTest) +{ + std::string message = "Hello world, security mode UA_MESSAGESECURITYMODE_SIGNANDENCRYPT works."; + + OpcUaServerSecurityConfig serverSecurity = TestServer::CreateSecurityConfig(); + OpcUaClientSecurityConfig clientSecurity = TestClient::CreateSecurityConfig(); + + TestServer testServer; + testServer.setSecurityConfig(&serverSecurity); + testServer.start(); + ASSERT_TRUE(testServer.isStarted()); + + testServer.defineStringVar("testVar", message); + + TestClient testClient; + testClient.setSecurityConfig(&clientSecurity); + testClient.connect(); + ASSERT_TRUE(testClient.isConnected()); + + std::string received = testClient.readStringVar("testVar"); + ASSERT_EQ(received, message); + + testClient.disconnect(); + ASSERT_FALSE(testClient.isConnected()); + + testServer.stop(); + ASSERT_FALSE(testServer.isStarted()); +} + +TEST_F(OpcUaSecurityTest, WrongSecurityModeTest) +{ + OpcUaServerSecurityConfig serverSecurity = TestServer::CreateSecurityConfig(); + serverSecurity.securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT; + + OpcUaClientSecurityConfig clientSecurity = TestClient::CreateSecurityConfig(); + clientSecurity.securityMode = UA_MESSAGESECURITYMODE_NONE; + + TestServer testServer; + testServer.setSecurityConfig(&serverSecurity); + testServer.start(); + ASSERT_TRUE(testServer.isStarted()); + + TestClient testClient; + testClient.setSecurityConfig(&clientSecurity); + testClient.connect(); + ASSERT_FALSE(testClient.isConnected()); + + testServer.stop(); + ASSERT_FALSE(testServer.isStarted()); +} + +TEST_F(OpcUaSecurityTest, ExpiredCertificateTest) +{ + OpcUaServerSecurityConfig serverSecurity = TestServer::CreateSecurityConfig(); + serverSecurity.trustList.push_back(OpcUaCommon::loadFile(TestFile("client-cert-expired.der")).getValue()); + + OpcUaClientSecurityConfig clientSecurity; + clientSecurity.trustList.push_back(OpcUaCommon::loadFile(TestFile("server-cert.der")).getValue()); + clientSecurity.certificate = OpcUaCommon::loadFile(TestFile("client-cert-expired.der")); + clientSecurity.privateKey = OpcUaCommon::loadFile(TestFile("client-private-expired.der")); + clientSecurity.securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT; + clientSecurity.appUri = "urn:testclient.com"; + + TestServer testServer; + testServer.setSecurityConfig(&serverSecurity); + testServer.start(); + ASSERT_TRUE(testServer.isStarted()); + + TestClient testClient; + testClient.setSecurityConfig(&clientSecurity); + testClient.connect(); + ASSERT_FALSE(testClient.isConnected()); + + testServer.stop(); + ASSERT_FALSE(testServer.isStarted()); +} + +TEST_F(OpcUaSecurityTest, GarbageCertificateTest) +{ + OpcUaServerSecurityConfig serverSecurity = TestServer::CreateSecurityConfig(); + + OpcUaClientSecurityConfig clientSecurity; + clientSecurity.trustList.push_back(OpcUaCommon::loadFile(TestFile("server-cert.der")).getValue()); + clientSecurity.certificate = OpcUaCommon::loadFile(TestFile("garbage-cert.der")).getValue(); + clientSecurity.privateKey = OpcUaCommon::loadFile(TestFile("client-private.der")).getValue(); + clientSecurity.securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT; + clientSecurity.appUri = "urn:testclient.com"; + + TestServer testServer; + testServer.setSecurityConfig(&serverSecurity); + testServer.start(); + ASSERT_TRUE(testServer.isStarted()); + + TestClient testClient; + testClient.setSecurityConfig(&clientSecurity); + testClient.connect(); + ASSERT_FALSE(testClient.isConnected()); + + testServer.stop(); + serverSecurity.trustList.push_back(OpcUaCommon::loadFile(TestFile("garbage-cert.der")).getValue()); + ASSERT_THROW(testServer.start(), OpcUaException); + ASSERT_FALSE(testServer.isStarted()); +} + +TEST_F(OpcUaSecurityTest, UntrustedCertificateTest) +{ + OpcUaServerSecurityConfig serverSecurity = TestServer::CreateSecurityConfig(); + + OpcUaClientSecurityConfig clientSecurity; + clientSecurity.trustList.push_back(OpcUaCommon::loadFile(TestFile("server-cert.der")).getValue()); + clientSecurity.certificate = OpcUaCommon::loadFile(TestFile("tesla-cert.der")); + clientSecurity.privateKey = OpcUaCommon::loadFile(TestFile("tesla-private.der")); + clientSecurity.securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT; + clientSecurity.appUri = "urn:nikolatesla.com"; + + TestServer testServer; + testServer.setSecurityConfig(&serverSecurity); + testServer.start(); + ASSERT_TRUE(testServer.isStarted()); + + TestClient testClient; + testClient.setSecurityConfig(&clientSecurity); + testClient.connect(); + ASSERT_FALSE(testClient.isConnected()); + + testServer.stop(); + serverSecurity.trustList.push_back(OpcUaCommon::loadFile(TestFile("tesla-cert.der")).getValue()); + testServer.start(); + ASSERT_TRUE(testServer.isStarted()); + testClient.connect(); + + testServer.stop(); + ASSERT_FALSE(testServer.isStarted()); +} + +TEST_F(OpcUaSecurityTest, AuthenticationTest) +{ + std::unordered_map users = TestServer::CreateUsers(); + + OpcUaServerSecurityConfig serverSecurity = TestServer::CreateSecurityConfig(); + serverSecurity.authenticateUser = [&users](bool isAnonymous, std::string username, std::string password) -> UA_StatusCode { + if (!isAnonymous && users.count(username)) + { + std::string hash = users[username]; + if (BCrypt::Verify(hash, password)) + return UA_STATUSCODE_GOOD; + } + + return UA_STATUSCODE_BADUSERACCESSDENIED; + }; + + OpcUaClientSecurityConfig clientSecurity = TestClient::CreateSecurityConfig(); + + TestServer testServer; + testServer.setSecurityConfig(&serverSecurity); + testServer.start(); + ASSERT_TRUE(testServer.isStarted()); + + TestClient testClient; + testClient.setSecurityConfig(&clientSecurity); + + // annonymous login + testClient.connect(); + ASSERT_FALSE(testClient.isConnected()); + + // wrong password + clientSecurity.username = "tesla"; + clientSecurity.password = "wrongPassword"; + testClient.connect(); + ASSERT_FALSE(testClient.isConnected()); + + // wrong user + clientSecurity.username = "wrongUser"; + clientSecurity.password = "tesla123"; + testClient.connect(); + ASSERT_FALSE(testClient.isConnected()); + + // crrect login + clientSecurity.username = "tesla"; + clientSecurity.password = "tesla123"; + testClient.connect(); + ASSERT_TRUE(testClient.isConnected()); + + testClient.disconnect(); + ASSERT_FALSE(testClient.isConnected()); + testServer.stop(); + ASSERT_FALSE(testServer.isStarted()); +} + +END_NAMESPACE_OPCUA diff --git a/shared/libraries/opcua/opcuashared/tests/test_opcua_variant.cpp b/shared/libraries/opcua/opcuashared/tests/test_opcua_variant.cpp new file mode 100644 index 0000000..9c75c0e --- /dev/null +++ b/shared/libraries/opcua/opcuashared/tests/test_opcua_variant.cpp @@ -0,0 +1,205 @@ +#include "gtest/gtest.h" +#include "opcuashared/opcuavariant.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using OpcUaVariantTest = testing::Test; + +TEST_F(OpcUaVariantTest, CreateNull) +{ + OpcUaVariant variant; + ASSERT_FALSE(variant.isBool()); + ASSERT_FALSE(variant.isDouble()); + ASSERT_FALSE(variant.isInteger()); + ASSERT_FALSE(variant.isString()); + ASSERT_FALSE(variant.isNodeId()); +} + +TEST_F(OpcUaVariantTest, CreateBool) +{ + OpcUaVariant variant(true); + ASSERT_TRUE(variant.isBool()); + ASSERT_FALSE(variant.isDouble()); + ASSERT_FALSE(variant.isInteger()); + ASSERT_FALSE(variant.isString()); + ASSERT_FALSE(variant.isNodeId()); + ASSERT_EQ(variant.toBool(), true); +} + +TEST_F(OpcUaVariantTest, CreateDouble) +{ + OpcUaVariant variant(5.5); + ASSERT_FALSE(variant.isBool()); + ASSERT_TRUE(variant.isDouble()); + ASSERT_FALSE(variant.isInteger()); + ASSERT_FALSE(variant.isString()); + ASSERT_FALSE(variant.isNodeId()); + ASSERT_EQ(variant.toDouble(), 5.5); +} + +TEST_F(OpcUaVariantTest, CreateInt) +{ + OpcUaVariant variant(int64_t(5)); + ASSERT_FALSE(variant.isBool()); + ASSERT_FALSE(variant.isDouble()); + ASSERT_TRUE(variant.isInteger()); + ASSERT_FALSE(variant.isString()); + ASSERT_FALSE(variant.isNodeId()); + ASSERT_EQ(variant.toInteger(), 5); +} + +TEST_F(OpcUaVariantTest, CreateString) +{ + OpcUaVariant variant("Hi"); + ASSERT_FALSE(variant.isBool()); + ASSERT_FALSE(variant.isDouble()); + ASSERT_FALSE(variant.isInteger()); + ASSERT_TRUE(variant.isString()); + ASSERT_FALSE(variant.isNodeId()); + ASSERT_STREQ(variant.toString().c_str(), "Hi"); +} + +TEST_F(OpcUaVariantTest, CreateString1) +{ + OpcUaVariant variant = OpcUaVariant("Test"); + ASSERT_FALSE(variant.isBool()); + ASSERT_FALSE(variant.isDouble()); + ASSERT_FALSE(variant.isInteger()); + ASSERT_TRUE(variant.isString()); + ASSERT_FALSE(variant.isNodeId()); + ASSERT_STREQ(variant.toString().c_str(), "Test"); +} + +TEST_F(OpcUaVariantTest, CreateNodeId) +{ + OpcUaVariant variant(OpcUaNodeId(1, "Test")); + + ASSERT_FALSE(variant.isBool()); + ASSERT_FALSE(variant.isDouble()); + ASSERT_FALSE(variant.isInteger()); + ASSERT_FALSE(variant.isString()); + ASSERT_TRUE(variant.isNodeId()); + + ASSERT_EQ(variant.toNodeId(), OpcUaNodeId(1, "Test")); +} + +TEST_F(OpcUaVariantTest, CopyConstructor) +{ + UA_Variant* ua_variant = UA_Variant_new(); + double value = 5; + UA_Variant_setScalarCopy(ua_variant, &value, &UA_TYPES[UA_TYPES_DOUBLE]); + + OpcUaVariant variant(*ua_variant); + variant.setValue(*ua_variant); + + ASSERT_FALSE(variant.isBool()); + ASSERT_TRUE(variant.isDouble()); + ASSERT_FALSE(variant.isInteger()); + ASSERT_FALSE(variant.isString()); + ASSERT_EQ(variant.toDouble(), 5); + UA_Variant_delete(ua_variant); +} + +TEST_F(OpcUaVariantTest, MoveConstructor) +{ + UA_Variant ua_variant; + double value = 5; + UA_Variant_setScalarCopy(&ua_variant, &value, &UA_TYPES[UA_TYPES_DOUBLE]); + + OpcUaVariant variant(std::move(ua_variant)); + ASSERT_FALSE(variant.isBool()); + ASSERT_TRUE(variant.isDouble()); + ASSERT_FALSE(variant.isInteger()); + ASSERT_FALSE(variant.isString()); + ASSERT_EQ(variant.toDouble(), 5); + + ASSERT_TRUE(UA_Variant_isEmpty(&ua_variant)); +} + +TEST_F(OpcUaVariantTest, MoveAssignment) +{ + OpcUaVariant variant("Hi"); + variant = OpcUaVariant("Test"); + ASSERT_TRUE(variant.isString()); + ASSERT_STREQ(variant.toString().c_str(), "Test"); +} + +TEST_F(OpcUaVariantTest, SetValueCopy) +{ + UA_Variant ua_variant; + double value = 5; + UA_Variant_setScalarCopy(&ua_variant, &value, &UA_TYPES[UA_TYPES_DOUBLE]); + + OpcUaVariant variant; + variant.setValue(ua_variant); + ASSERT_FALSE(variant.isBool()); + ASSERT_TRUE(variant.isDouble()); + ASSERT_FALSE(variant.isInteger()); + ASSERT_FALSE(variant.isString()); + ASSERT_EQ(variant.toDouble(), 5); + + UA_Variant_clear(&ua_variant); +} + +TEST_F(OpcUaVariantTest, SetValueMove) +{ + UA_Variant ua_variant; + double value = 5; + UA_Variant_setScalarCopy(&ua_variant, &value, &UA_TYPES[UA_TYPES_DOUBLE]); + + OpcUaVariant variant; + variant.setValue(std::move(ua_variant)); + ASSERT_FALSE(variant.isBool()); + ASSERT_TRUE(variant.isDouble()); + ASSERT_FALSE(variant.isInteger()); + ASSERT_FALSE(variant.isString()); + ASSERT_EQ(variant.toDouble(), 5); + + ASSERT_TRUE(UA_Variant_isEmpty(&ua_variant)); +} + +TEST_F(OpcUaVariantTest, CopyConstructOperator) +{ + OpcUaVariant variant(int64_t(5)); + OpcUaVariant variant1 = variant; + + ASSERT_TRUE(variant.isInteger()); + ASSERT_EQ(variant.toInteger(), 5); + + ASSERT_TRUE(variant1.isInteger()); + ASSERT_EQ(variant1.toInteger(), 5); +} + +TEST_F(OpcUaVariantTest, AssignmentOperator) +{ + OpcUaVariant variant(int64_t(5)); + OpcUaVariant variant1; + variant1 = variant; + + ASSERT_TRUE(variant.isInteger()); + ASSERT_EQ(variant.toInteger(), 5); + + ASSERT_TRUE(variant1.isInteger()); + ASSERT_EQ(variant1.toInteger(), 5); +} + +TEST_F(OpcUaVariantTest, ReadScalar) +{ + OpcUaVariant variant(static_cast(5)); + + ASSERT_EQ(variant.readScalar(), 5); + + ASSERT_THROW(variant.readScalar(), std::runtime_error); +} + +TEST_F(OpcUaVariantTest, SetScalar) +{ + OpcUaVariant variant; + + ASSERT_NO_THROW(variant.setScalar(5)); + + ASSERT_EQ(variant.readScalar(), 5); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/tests/test_opcua_vector.cpp b/shared/libraries/opcua/opcuashared/tests/test_opcua_vector.cpp new file mode 100644 index 0000000..18b2552 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/tests/test_opcua_vector.cpp @@ -0,0 +1,107 @@ +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using OpcUaVectorTest = testing::Test; + +TEST_F(OpcUaVectorTest, ScopeTest) +{ + OpcUaObject a = OpcUaObject(UA_STRING_ALLOC("Hello One")); + OpcUaObject b = OpcUaObject(UA_STRING_ALLOC("Hello Two")); + + { + OpcUaVector vect; + vect.push_back(a.getValue()); + vect.push_back(a.getValue()); + ASSERT_EQ(utils::ToStdString(vect[1]), utils::ToStdString(a.getValue())); + vect[1] = b.getValue(); + ASSERT_EQ(utils::ToStdString(vect[1]), utils::ToStdString(b.getValue())); + } +} + +TEST_F(OpcUaVectorTest, CopyTest) +{ + OpcUaVector a = {1, 2, 3, 4, 5}; + OpcUaVector b = {10, 20, 30}; + + a = b; + ASSERT_EQ(a.size(), b.size()); + ASSERT_EQ(a[0], b[0]); + ASSERT_EQ(a[1], b[1]); + ASSERT_EQ(a[2], b[2]); + + UA_Int32 b0 = 10; + UA_Int32 a0 = 99; + a[0] = a0; + ASSERT_EQ(a[0], a0); + ASSERT_EQ(b[0], b0); +} + +TEST_F(OpcUaVectorTest, ResizeTest) +{ + const size_t sizeA = 5; + OpcUaVector a = {1, 2, 3, 4, 5}; + const size_t sizeB = 3; + OpcUaVector b = {10, 20, 30}; + + size_t newSizeA = 3; + ASSERT_EQ(a.size(), sizeA); + a.resize(newSizeA); + ASSERT_EQ(a.size(), newSizeA); + + size_t newSizeB = 10; + ASSERT_EQ(b.size(), sizeB); + b.resize(newSizeB); + ASSERT_EQ(b.size(), newSizeB); + + OpcUaVector c; + c.resize(10); +} + +TEST_F(OpcUaVectorTest, AppendTest) +{ + std::vector a = {1, 2, 3, 4, 5}; + OpcUaVector b; + for (size_t i = 0; i < a.size(); i++) + b.push_back(a[i]); + + ASSERT_EQ(a.size(), b.size()); + bool areEqual = memcmp(a.data(), b.data(), sizeof(UA_Int32) * a.size()) == 0; + ASSERT_TRUE(areEqual); + + UA_Int32 last = 99; + b[b.size() - 1] = last; + areEqual = memcmp(a.data(), b.data(), sizeof(UA_Int32) * a.size()) == 0; + ASSERT_FALSE(areEqual); +} + +TEST_F(OpcUaVectorTest, SetGetTest) +{ + UA_Int32 a = 1; + UA_Int32 b = 2; + UA_Int32 c = 3; + + OpcUaVector vectA; + vectA.resize(10); + + vectA[0] = a; + ASSERT_EQ(vectA[0], a); + vectA[1] = b; + ASSERT_EQ(vectA[1], b); + vectA[1] = c; + ASSERT_EQ(vectA[1], c); + + OpcUaVector vectB; + vectB.resize(10); + + vectB.set(0, a); + ASSERT_EQ(vectB.get(0), a); + vectB.set(1, b); + ASSERT_EQ(vectB.get(1), b); + vectB.set(1, c); + ASSERT_EQ(vectB.get(1), c); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/tests/test_opcuacallmethodresult.cpp b/shared/libraries/opcua/opcuashared/tests/test_opcuacallmethodresult.cpp new file mode 100644 index 0000000..43b5d8f --- /dev/null +++ b/shared/libraries/opcua/opcuashared/tests/test_opcuacallmethodresult.cpp @@ -0,0 +1,44 @@ +#include "gtest/gtest.h" +#include "opcuashared/opcuacallmethodresult.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using OpcUaCallMethodResultTest = testing::Test; + +TEST_F(OpcUaCallMethodResultTest, Create) +{ + UA_CallMethodResult callMethodResult; + UA_CallMethodResult_init(&callMethodResult); + + callMethodResult.statusCode = UA_STATUSCODE_BADAGGREGATELISTMISMATCH; + + callMethodResult.outputArgumentsSize = 2; + callMethodResult.outputArguments = (UA_Variant*) UA_Array_new(callMethodResult.outputArgumentsSize, &UA_TYPES[UA_TYPES_VARIANT]); + + UA_Int64 intVal = 0; + UA_Variant_setScalarCopy(&callMethodResult.outputArguments[0], &intVal, &UA_TYPES[UA_TYPES_INT64]); + + UA_String strVal = UA_STRING_ALLOC("Test"); + UA_Variant_setScalarCopy(&callMethodResult.outputArguments[1], &strVal, &UA_TYPES[UA_TYPES_STRING]); + UA_String_clear(&strVal); + + OpcUaCallMethodResult value(callMethodResult); + + ASSERT_EQ(value.getOutputArgumentsSize(), 2u); + ASSERT_EQ(value.getStatusCode(), UA_STATUSCODE_BADAGGREGATELISTMISMATCH); + + OpcUaVariant val1 = value.getOutputArgument(0); + ASSERT_TRUE(val1.isInteger()); + ASSERT_EQ(val1.toInteger(), 0); + + OpcUaVariant val2 = value.getOutputArgument(1); + ASSERT_TRUE(val2.isString()); + ASSERT_STREQ(val2.toString().c_str(), "Test"); + + ASSERT_THROW(value.getOutputArgument(2), std::out_of_range); + + UA_CallMethodResult_clear(&callMethodResult); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/tests/test_opcuadatatypearraylist.cpp b/shared/libraries/opcua/opcuashared/tests/test_opcuadatatypearraylist.cpp new file mode 100644 index 0000000..3676f59 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/tests/test_opcuadatatypearraylist.cpp @@ -0,0 +1,140 @@ +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +typedef struct { + UA_Float x; + UA_Float y; +} Struct1; +static UA_DataTypeMember struct1_members[2] = { + /* a */ + { + UA_TYPENAME("a") // .typeName + &UA_TYPES[UA_TYPES_FLOAT], // .memberType + 0, // .padding + false, // .isArray + false // .isOptional + }, + /* b */ + { + UA_TYPENAME("b") // .typeName + &UA_TYPES[UA_TYPES_FLOAT], // .memberType + 0, // .padding + false, // .isArray + false // .isOptional + } +}; +static const UA_DataType struct1Type = { + UA_TYPENAME("Struct1") // .typeName + {1, UA_NODEIDTYPE_NUMERIC, {4242}}, // .typeId + {1, UA_NODEIDTYPE_NUMERIC, {1}}, // .binaryEncodingId + sizeof(Struct1), // .memSize + UA_DATATYPEKIND_STRUCTURE, // .typeKind + true, // .pointerFree + false, // .overlayable + 2, // .membersize + struct1_members // .members +}; + +typedef struct { + UA_Float x; + UA_Float y; + UA_Float z; +} Struct2; +static UA_DataTypeMember struct2_members[3] = { + /* x */ + { + UA_TYPENAME("x") // .typeName + &UA_TYPES[UA_TYPES_FLOAT], // .memberType + 0, // .padding + false, // .isArray + false // .isOptional + }, + /* y */ + { + UA_TYPENAME("y") // .typeName + &UA_TYPES[UA_TYPES_FLOAT], // .memberType + 0, // .padding + false, // .isArray + false // .isOptional + }, + /* z */ + { + UA_TYPENAME("z") // .typeName + &UA_TYPES[UA_TYPES_FLOAT], // .memberType + 0, // .padding + false, // .isArray + false // .isOptional + }, +}; +static const UA_DataType struct2Type = { + UA_TYPENAME("Struct2") // .typeName + {1, UA_NODEIDTYPE_NUMERIC, {4243}}, // .typeId + {1, UA_NODEIDTYPE_NUMERIC, {2}}, // .binaryEncodingId + sizeof(Struct2), // .memSize + UA_DATATYPEKIND_STRUCTURE, // .typeKind + true, // .pointerFree + false, // .overlayable + 3, // .membersize + struct2_members // .members +}; + +TEST(OpcUaDataTypeArrayListTest, EmptyList) +{ + OpcUaDataTypeArrayList arrList; + ASSERT_EQ(arrList.getCustomDataTypes(), nullptr); +} + +TEST(OpcUaDataTypeArrayListTest, SingleListElement) +{ + UA_DataType types[1]; + types[0] = struct1Type; + + OpcUaDataTypeArrayList arrList; + + arrList.add(1, types); + const UA_DataTypeArray* dataType = arrList.getCustomDataTypes(); + + ASSERT_EQ(dataType->next, nullptr); + ASSERT_EQ(dataType->typesSize, 1u); +} + +TEST(OpcUaDataTypeArrayListTest, MultipleListElements) +{ + UA_DataType types1[1]; + types1[0] = struct1Type; + UA_DataType types2[1]; + types2[0] = struct2Type; + + OpcUaDataTypeArrayList arrList; + arrList.add(1, types1); + arrList.add(1, types2); + + const UA_DataTypeArray* dataType = arrList.getCustomDataTypes(); + int count = 0; + while (dataType != NULL) + { + ++count; + dataType = dataType->next; + } + + ASSERT_EQ(count, 2); +} + +TEST(OpcUaDataTypeArrayListTest, LargerTypeCount) +{ + UA_DataType types[2]; + types[0] = struct1Type; + types[1] = struct2Type; + + OpcUaDataTypeArrayList arrList; + arrList.add(2, types); + + const UA_DataTypeArray* dataType = arrList.getCustomDataTypes(); + + ASSERT_EQ(dataType->typesSize, 2u); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/tests/test_opcuadatavalue.cpp b/shared/libraries/opcua/opcuashared/tests/test_opcuadatavalue.cpp new file mode 100644 index 0000000..6c4f6e4 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/tests/test_opcuadatavalue.cpp @@ -0,0 +1,69 @@ +#include "gtest/gtest.h" +#include "opcuashared/opcuadatavalue.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using OpcUaDataValueTest = testing::Test; + +TEST_F(OpcUaDataValueTest, CreateWithInt) +{ + UA_DataValue dataValue; + UA_DataValue_init(&dataValue); + + dataValue.status = UA_STATUSCODE_BADAGGREGATELISTMISMATCH; + UA_Int64 val = 0; + + UA_Variant_setScalarCopy(&dataValue.value, &val, &UA_TYPES[UA_TYPES_INT64]); + + OpcUaDataValue value(&dataValue); + + ASSERT_TRUE(value.getValue().isInteger()); + ASSERT_EQ(value.getStatusCode(), UA_STATUSCODE_BADAGGREGATELISTMISMATCH); + + UA_DataValue_clear(&dataValue); +} + +TEST_F(OpcUaDataValueTest, CreateWithIntRawDataValue) +{ + UA_DataValue dataValue; + UA_DataValue_init(&dataValue); + + dataValue.status = UA_STATUSCODE_BADAGGREGATELISTMISMATCH; + UA_Int64 val = 0; + + UA_Variant_setScalarCopy(&dataValue.value, &val, &UA_TYPES[UA_TYPES_INT64]); + + OpcUaDataValue value(&dataValue); + + const UA_DataValue* rawDataValue = value.getDataValue(); + ASSERT_EQ(rawDataValue, &dataValue); + + rawDataValue = value; + ASSERT_EQ(rawDataValue, &dataValue); + + UA_DataValue_clear(&dataValue); +} + +TEST_F(OpcUaDataValueTest, TestNoCopyBehaviour) +{ + UA_DataValue dataValue; + UA_DataValue_init(&dataValue); + + dataValue.status = UA_STATUSCODE_BADAGGREGATELISTMISMATCH; + UA_Int64* val = UA_Int64_new(); + *val = 1; + + UA_Variant_setScalar(&dataValue.value, val, &UA_TYPES[UA_TYPES_INT64]); + + OpcUaDataValue value(&dataValue); + ASSERT_EQ(value.getValue().toInteger(), 1); + *val = 2; + ASSERT_EQ(value.getValue().toInteger(), 2); + + ASSERT_EQ(value.getValue().getValue().data, dataValue.value.data); + + UA_DataValue_clear(&dataValue); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/tests/test_opcuaendpoint.cpp b/shared/libraries/opcua/opcuashared/tests/test_opcuaendpoint.cpp new file mode 100644 index 0000000..b5dd702 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/tests/test_opcuaendpoint.cpp @@ -0,0 +1,20 @@ +#include +#include "opcuashared/opcuaendpoint.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using OpcUaEndpointTest = testing::Test; + +TEST_F(OpcUaEndpointTest, CreateEmptyEndpoint) +{ + ASSERT_NO_THROW(OpcUaEndpoint ep{}); +} + +TEST_F(OpcUaEndpointTest, CreateEndpoint) +{ + OpcUaEndpoint ep{"name", "opc.tcp://localhost:4840"}; + ASSERT_EQ(ep.getName(), "name"); + ASSERT_EQ(ep.getUrl(), "opc.tcp://localhost:4840"); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/tests/test_opcuanodeid.cpp b/shared/libraries/opcua/opcuashared/tests/test_opcuanodeid.cpp new file mode 100644 index 0000000..71402e7 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/tests/test_opcuanodeid.cpp @@ -0,0 +1,239 @@ +#include "gtest/gtest.h" +#include "opcuashared/opcuanodeid.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using OpcUaNodeIdTest = testing::Test; + +TEST_F(OpcUaNodeIdTest, CreateNull) +{ + OpcUaNodeId nodeId; + ASSERT_TRUE(nodeId.isNull()); +} + +TEST_F(OpcUaNodeIdTest, CreateInt) +{ + OpcUaNodeId nodeId(1, 2); + + ASSERT_EQ(nodeId.getNamespaceIndex(), 1); + ASSERT_EQ(nodeId.getIdentifierType(), OpcUaIdentifierType::Numeric); + ASSERT_EQ(nodeId.getIdentifier(), "2"); +} + +TEST_F(OpcUaNodeIdTest, CreateString) +{ + OpcUaNodeId nodeId(1, "TestIden"); + + ASSERT_EQ(nodeId.getNamespaceIndex(), 1); + ASSERT_EQ(nodeId.getIdentifierType(), OpcUaIdentifierType::String); + ASSERT_EQ(nodeId.getIdentifier(), "TestIden"); +} + +TEST_F(OpcUaNodeIdTest, CreateFromOpcUaNodeInt) +{ + UA_NodeId uaNode = UA_NODEID_NUMERIC(1, 2); + OpcUaNodeId nodeId(uaNode); + UA_NodeId_clear(&uaNode); + + ASSERT_EQ(nodeId.getNamespaceIndex(), 1); + ASSERT_EQ(nodeId.getIdentifierType(), OpcUaIdentifierType::Numeric); + ASSERT_EQ(nodeId.getIdentifier(), "2"); +} + +TEST_F(OpcUaNodeIdTest, CreateFromOpcUaNodeString) +{ + UA_NodeId uaNode = UA_NODEID_STRING_ALLOC(1, "TestIden"); + OpcUaNodeId nodeId(uaNode); + UA_NodeId_clear(&uaNode); + + ASSERT_EQ(nodeId.getNamespaceIndex(), 1); + ASSERT_EQ(nodeId.getIdentifierType(), OpcUaIdentifierType::String); + ASSERT_EQ(nodeId.getIdentifier(), "TestIden"); +} + +TEST_F(OpcUaNodeIdTest, CreateFromOpcUaNodeInt1) +{ + UA_NodeId uaNode = UA_NODEID_NUMERIC(1, 2); + OpcUaNodeId nodeId = uaNode; + UA_NodeId_clear(&uaNode); + + ASSERT_EQ(nodeId.getNamespaceIndex(), 1); + ASSERT_EQ(nodeId.getIdentifierType(), OpcUaIdentifierType::Numeric); + ASSERT_EQ(nodeId.getIdentifier(), "2"); +} + +TEST_F(OpcUaNodeIdTest, CreateFromOpcUaNodeString1) +{ + UA_NodeId uaNode = UA_NODEID_STRING_ALLOC(1, "TestIden"); + OpcUaNodeId nodeId = uaNode; + UA_NodeId_clear(&uaNode); + + ASSERT_EQ(nodeId.getNamespaceIndex(), 1); + ASSERT_EQ(nodeId.getIdentifierType(), OpcUaIdentifierType::String); + ASSERT_EQ(nodeId.getIdentifier(), "TestIden"); +} + +TEST_F(OpcUaNodeIdTest, AppendStringToInt) +{ + OpcUaNodeId nodeId(1, 2); + OpcUaNodeId newNode = nodeId.addSuffix("!!!"); + ASSERT_EQ(newNode.getNamespaceIndex(), 1); + ASSERT_EQ(newNode.getIdentifierType(), OpcUaIdentifierType::String); + ASSERT_EQ(newNode.getIdentifier(), "2!!!"); + + newNode = nodeId.addSuffix("_", "!!!"); + ASSERT_EQ(newNode.getNamespaceIndex(), 1); + ASSERT_EQ(newNode.getIdentifierType(), OpcUaIdentifierType::String); + ASSERT_EQ(newNode.getIdentifier(), "2_!!!"); +} + +TEST_F(OpcUaNodeIdTest, AppendStringToString) +{ + OpcUaNodeId nodeId(1, "2"); + OpcUaNodeId newNode = nodeId.addSuffix("!!!"); + ASSERT_EQ(newNode.getNamespaceIndex(), 1); + ASSERT_EQ(newNode.getIdentifierType(), OpcUaIdentifierType::String); + ASSERT_EQ(newNode.getIdentifier(), "2!!!"); + + newNode = nodeId.addSuffix("_", "!!!"); + ASSERT_EQ(newNode.getNamespaceIndex(), 1); + ASSERT_EQ(newNode.getIdentifierType(), OpcUaIdentifierType::String); + ASSERT_EQ(newNode.getIdentifier(), "2_!!!"); +} + +TEST_F(OpcUaNodeIdTest, TestEqual) +{ + OpcUaNodeId nodeIdStr1(1, "2"); + OpcUaNodeId nodeIdStr2(1, "2"); + OpcUaNodeId nodeIdStr3(1, "2222"); + OpcUaNodeId nodeIdStr4(2, "2"); + + OpcUaNodeId nodeIdInt1(1, 2); + OpcUaNodeId nodeIdInt2(1, 2); + OpcUaNodeId nodeIdInt3(1, 3); + OpcUaNodeId nodeIdInt4(2, 2); + + ASSERT_TRUE(nodeIdStr1 == nodeIdStr2); + ASSERT_FALSE(nodeIdStr1 != nodeIdStr2); + ASSERT_FALSE(nodeIdStr1 == nodeIdStr3); + ASSERT_TRUE(nodeIdStr1 != nodeIdStr3); + ASSERT_FALSE(nodeIdStr1 == nodeIdStr4); + ASSERT_TRUE(nodeIdStr1 != nodeIdStr4); + + ASSERT_TRUE(nodeIdInt1 == nodeIdInt2); + ASSERT_FALSE(nodeIdInt1 != nodeIdInt2); + ASSERT_FALSE(nodeIdInt1 == nodeIdInt3); + ASSERT_TRUE(nodeIdInt1 != nodeIdInt3); + ASSERT_FALSE(nodeIdInt1 == nodeIdInt4); + ASSERT_TRUE(nodeIdInt1 != nodeIdInt4); +} + +TEST_F(OpcUaNodeIdTest, TestEqualUAType) +{ + OpcUaNodeId nodeIdStr1(1, "2"); + OpcUaNodeId nodeIdStr2(1, "2222"); + + UA_NodeId uaNodeIdStr = UA_NODEID_STRING_ALLOC(1, "2222"); + + ASSERT_TRUE(nodeIdStr1 != uaNodeIdStr); + ASSERT_FALSE(nodeIdStr1 == uaNodeIdStr); + + ASSERT_FALSE(nodeIdStr2 != uaNodeIdStr); + ASSERT_TRUE(nodeIdStr2 == uaNodeIdStr); + + UA_NodeId_clear(&uaNodeIdStr); +} + +TEST_F(OpcUaNodeIdTest, TestLessOperator) +{ + OpcUaNodeId nodeIdStr1(1, "2"); + OpcUaNodeId nodeIdStr2(1, "2"); + OpcUaNodeId nodeIdStr3(1, "2222"); + OpcUaNodeId nodeIdStr4(2, "2"); + + OpcUaNodeId nodeIdInt1(1, 2); + OpcUaNodeId nodeIdInt2(1, 2); + OpcUaNodeId nodeIdInt3(1, 3); + OpcUaNodeId nodeIdInt4(2, 2); + + ASSERT_NE(nodeIdStr1 < nodeIdStr3, nodeIdStr3 < nodeIdStr1); + ASSERT_NE(nodeIdStr1 < nodeIdStr4, nodeIdStr4 < nodeIdStr1); + + ASSERT_NE(nodeIdInt1 < nodeIdInt3, nodeIdInt3 < nodeIdInt1); + ASSERT_NE(nodeIdInt1 < nodeIdInt4, nodeIdInt4 < nodeIdInt1); + + ASSERT_NE(nodeIdInt1 < nodeIdStr1, nodeIdStr1 < nodeIdInt1); + + ASSERT_FALSE(nodeIdInt1 < nodeIdInt1); + ASSERT_FALSE(nodeIdInt1 < nodeIdInt2); + ASSERT_FALSE(nodeIdInt2 < nodeIdInt1); + + ASSERT_FALSE(nodeIdStr1 < nodeIdStr1); + ASSERT_FALSE(nodeIdStr1 < nodeIdStr2); + ASSERT_FALSE(nodeIdStr2 < nodeIdStr1); +} + +TEST_F(OpcUaNodeIdTest, TestToString) +{ + OpcUaNodeId nodeIdStr(1, "2"); + OpcUaNodeId nodeIdInt(1, 2); + + ASSERT_EQ(nodeIdStr.toString(), "(1, 2)"); + ASSERT_EQ(nodeIdInt.toString(), "(1, 2)"); +} + +TEST_F(OpcUaNodeIdTest, TestInstantiateNode) +{ + OpcUaNodeId nodeIdInt = OpcUaNodeId::instantiateNode(2, "4", OpcUaIdentifierType::Numeric); + OpcUaNodeId nodeIdStr = OpcUaNodeId::instantiateNode(2, "4", OpcUaIdentifierType::String); + + ASSERT_EQ(nodeIdInt, OpcUaNodeId(2, 4)); + ASSERT_EQ(nodeIdStr, OpcUaNodeId(2, "4")); +} + +TEST_F(OpcUaNodeIdTest, TestShallowCopy) +{ + OpcUaNodeId nodeid = OpcUaNodeId(UA_TYPES[UA_TYPES_INT64].typeId, true); +} + +TEST_F(OpcUaNodeIdTest, HashTest) +{ + OpcUaNodeId nodeIdStr1(1, "str1"); + OpcUaNodeId nodeIdStr2(1, "str2"); + OpcUaNodeId nodeIdStr3(1, "str2"); + + OpcUaNodeId nodeIdInt1(1, 2); + OpcUaNodeId nodeIdInt2(1, 2); + + ASSERT_NE(std::hash{}(nodeIdStr1), std::hash{}(nodeIdStr2)); + ASSERT_EQ(std::hash{}(nodeIdStr2), std::hash{}(nodeIdStr3)); + ASSERT_NE(std::hash{}(nodeIdStr1), std::hash{}(nodeIdInt1)); + ASSERT_EQ(std::hash{}(nodeIdInt1), std::hash{}(nodeIdInt2)); +} + +TEST_F(OpcUaNodeIdTest, CreateWithRandomGuid) +{ + OpcUaNodeId nodeId = OpcUaNodeId::CreateWithRandomGuid(); + ASSERT_EQ(nodeId.getIdentifierType(), OpcUaIdentifierType::Guid); +} + +TEST_F(OpcUaNodeIdTest, TestIdentifierNumeric) +{ + auto node1 = OpcUaNodeId::instantiateNode(1, "-999", OpcUaIdentifierType::Numeric); + ASSERT_EQ(node1.getIdentifier(), "0"); + + auto node2 = OpcUaNodeId::instantiateNode(1, "4259502693", OpcUaIdentifierType::Numeric); + ASSERT_EQ(node2.getIdentifier(), "4259502693"); + + auto node3 = OpcUaNodeId::instantiateNode(1, " 756", OpcUaIdentifierType::Numeric); + ASSERT_EQ(node3.getIdentifier(), "0"); + + auto node4 = OpcUaNodeId::instantiateNode(1, "ab 756 t 89", OpcUaIdentifierType::Numeric); + ASSERT_EQ(node4.getIdentifier(), "0"); + + auto node6 = OpcUaNodeId::instantiateNode(1, " 3", OpcUaIdentifierType::Numeric); + ASSERT_EQ(node6.getIdentifier(), "0"); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/tests/test_opcuaversion.cpp b/shared/libraries/opcua/opcuashared/tests/test_opcuaversion.cpp new file mode 100644 index 0000000..86d5ab1 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/tests/test_opcuaversion.cpp @@ -0,0 +1,99 @@ +#include "gtest/gtest.h" +#include "opcuashared/opcuaversion.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using OpcUaVersionTest = testing::Test; + +TEST_F(OpcUaVersionTest, CreateDefault) +{ + OpcUaVersion version; + ASSERT_EQ(version.major, 0); + ASSERT_EQ(version.minor, 0); + ASSERT_EQ(version.patch, 0); + + ASSERT_EQ(version.toString(), "0.0.0"); +} + +TEST_F(OpcUaVersionTest, Create) +{ + OpcUaVersion version(10, 20, 30); + ASSERT_EQ(version.major, 10); + ASSERT_EQ(version.minor, 20); + ASSERT_EQ(version.patch, 30); + + ASSERT_EQ(version.toString(), "10.20.30"); +} + +TEST_F(OpcUaVersionTest, CreateByMembers) +{ + OpcUaVersion version{10, 20}; + ASSERT_EQ(version.major, 10); + ASSERT_EQ(version.minor, 20); + ASSERT_EQ(version.patch, 0); + + ASSERT_EQ(version.toString(), "10.20.0"); +} + +TEST_F(OpcUaVersionTest, CreateFromString) +{ + OpcUaVersion version("10.20.30"); + ASSERT_EQ(version.major, 10); + ASSERT_EQ(version.minor, 20); + ASSERT_EQ(version.patch, 30); + + ASSERT_EQ(version.toString(), "10.20.30"); +} + +TEST_F(OpcUaVersionTest, CreateFromErrString) +{ + OpcUaVersion version("dummy"); + ASSERT_EQ(version.major, 0); + ASSERT_EQ(version.minor, 0); + ASSERT_EQ(version.patch, 0); + + ASSERT_EQ(version.toString(), "0.0.0"); +} + +TEST_F(OpcUaVersionTest, LongestToString) +{ + OpcUaVersion version((std::numeric_limits::min)(), (std::numeric_limits::min)(), (std::numeric_limits::min)()); + + ASSERT_EQ(version.toString(), "-2147483648.-2147483648.-2147483648"); +} + +TEST_F(OpcUaVersionTest, Compatible) +{ + OpcUaVersion v1(1, 1, 1); + OpcUaVersion v2(1, 1, 2); + OpcUaVersion v3(1, 2, 1); + OpcUaVersion v4(3, 2, 1); + + ASSERT_TRUE(OpcUaVersion::Compatible(v1, v2)); + ASSERT_TRUE(OpcUaVersion::Compatible(v2, v1)); + + ASSERT_TRUE(OpcUaVersion::Compatible(v1, v3)); + ASSERT_FALSE(OpcUaVersion::Compatible(v3, v1)); + + ASSERT_FALSE(OpcUaVersion::Compatible(v1, v4)); + ASSERT_FALSE(OpcUaVersion::Compatible(v4, v1)); +} + +TEST_F(OpcUaVersionTest, HasFeature) +{ + OpcUaVersion featureVersion(2, 4, 0); + + OpcUaVersion serverVersion1(1, 6, 1); + OpcUaVersion serverVersion2(2, 2, 2); + OpcUaVersion serverVersion3(2, 4, 5); + OpcUaVersion serverVersion4(2, 6, 1); + OpcUaVersion serverVersion5(3, 6, 1); + + ASSERT_FALSE(OpcUaVersion::HasFeature(serverVersion1, featureVersion)); + ASSERT_FALSE(OpcUaVersion::HasFeature(serverVersion2, featureVersion)); + ASSERT_TRUE(OpcUaVersion::HasFeature(serverVersion3, featureVersion)); + ASSERT_TRUE(OpcUaVersion::HasFeature(serverVersion4, featureVersion)); + ASSERT_TRUE(OpcUaVersion::HasFeature(serverVersion5, featureVersion)); // it has feature, but u can remove backword compatibility code +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/tests/test_status_code.cpp b/shared/libraries/opcua/opcuashared/tests/test_status_code.cpp new file mode 100644 index 0000000..11306c5 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/tests/test_status_code.cpp @@ -0,0 +1,38 @@ +#include "gtest/gtest.h" +#include "opcuashared/opcua.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using StatusCodeTest = testing::Test; + +TEST_F(StatusCodeTest, Succeeded) +{ + ASSERT_TRUE(OPCUA_STATUSCODE_SUCCEEDED(UA_STATUSCODE_GOOD)); + ASSERT_TRUE(OPCUA_STATUSCODE_SUCCEEDED(UA_STATUSCODE_GOODNODATA)); + ASSERT_FALSE(OPCUA_STATUSCODE_SUCCEEDED(UA_STATUSCODE_BADALREADYEXISTS)); +} + +TEST_F(StatusCodeTest, Failed) +{ + ASSERT_FALSE(OPCUA_STATUSCODE_FAILED(UA_STATUSCODE_GOOD)); + ASSERT_FALSE(OPCUA_STATUSCODE_FAILED(UA_STATUSCODE_GOODNODATA)); + ASSERT_TRUE(OPCUA_STATUSCODE_FAILED(UA_STATUSCODE_BADALREADYEXISTS)); +} + +TEST_F(StatusCodeTest, IsGood) +{ + ASSERT_TRUE(OPCUA_STATUSCODE_IS_GOOD(UA_STATUSCODE_GOOD)); + ASSERT_FALSE(OPCUA_STATUSCODE_IS_GOOD(UA_STATUSCODE_GOODNODATA)); + ASSERT_FALSE(OPCUA_STATUSCODE_IS_GOOD(UA_STATUSCODE_BADALREADYEXISTS)); +} + +TEST_F(StatusCodeTest, NotConnected) +{ + ASSERT_FALSE(OPCUA_STATUSCODE_NOT_CONNECTED(UA_STATUSCODE_GOOD)); + ASSERT_FALSE(OPCUA_STATUSCODE_NOT_CONNECTED(UA_STATUSCODE_GOODNODATA)); + ASSERT_FALSE(OPCUA_STATUSCODE_NOT_CONNECTED(UA_STATUSCODE_BADALREADYEXISTS)); + ASSERT_TRUE(OPCUA_STATUSCODE_NOT_CONNECTED(UA_STATUSCODE_BADDISCONNECT)); + ASSERT_TRUE(OPCUA_STATUSCODE_NOT_CONNECTED(UA_STATUSCODE_BADCONNECTIONCLOSED)); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/tests/test_string_utils.cpp b/shared/libraries/opcua/opcuashared/tests/test_string_utils.cpp new file mode 100644 index 0000000..166d234 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/tests/test_string_utils.cpp @@ -0,0 +1,50 @@ +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using OpcUaStringTest = testing::Test; + +TEST_F(OpcUaStringTest, Compare) +{ + UA_String first = UA_STRING_STATIC("a"); + UA_String second = UA_STRING_STATIC("b"); + UA_String third = UA_STRING_STATIC("a"); + + ASSERT_TRUE(first == third); + ASSERT_FALSE(first == second); + + ASSERT_FALSE(first != third); + ASSERT_TRUE(first != second); +} + +TEST_F(OpcUaStringTest, CompareConstChar) +{ + UA_String first = UA_STRING_STATIC("a"); + ASSERT_TRUE(first == "a"); + ASSERT_FALSE(first != "a"); + ASSERT_FALSE(first == "b"); + ASSERT_TRUE(first != "b"); + + ASSERT_TRUE("a" == first); + ASSERT_FALSE("a" != first); + ASSERT_FALSE("b" == first); + ASSERT_TRUE("b" != first); +} + +TEST_F(OpcUaStringTest, ToStdString) +{ + UA_String test = UA_STRING_STATIC("test"); + std::string testStr = utils::ToStdString(test); + ASSERT_EQ(testStr, "test"); +} + +TEST_F(OpcUaStringTest, ToStdStringNull) +{ + UA_String test{}; + std::string testStr = utils::ToStdString(test); + ASSERT_EQ(testStr, ""); +} + + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/tools/generate_datatypes.sh b/shared/libraries/opcua/opcuashared/tools/generate_datatypes.sh new file mode 100644 index 0000000..bb58a5e --- /dev/null +++ b/shared/libraries/opcua/opcuashared/tools/generate_datatypes.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +OPEN62541_ROOT="C:/DXEProjects/Apps/Blueberry/build/x64/msvc-19/full/external/bbopen62541/build/open62541-src" + +python $OPEN62541_ROOT/tools/generate_datatypes.py \ + --namespace="1:https://blueberrydaq.com/ua" \ + --type-csv=schema/BB.NodeIds.csv \ + --type-bsd=schema/BB.Opc.Ua.Types.bsd \ + --no-builtin \ + bb diff --git a/shared/libraries/opcua/opcuashared/tools/schema/BB.NodeIds.csv b/shared/libraries/opcua/opcuashared/tools/schema/BB.NodeIds.csv new file mode 100644 index 0000000..35317ab --- /dev/null +++ b/shared/libraries/opcua/opcuashared/tools/schema/BB.NodeIds.csv @@ -0,0 +1,4 @@ +BufferValue,1,DataType +BufferValue_Encoding_DefaultBinary,1,Object +PropertyInfoDataType,2,DataType +PropertyInfoDataType_Encoding_DefaultBinary,2,Object \ No newline at end of file diff --git a/shared/libraries/opcua/opcuashared/tools/schema/BB.Opc.Ua.Types.bsd b/shared/libraries/opcua/opcuashared/tools/schema/BB.Opc.Ua.Types.bsd new file mode 100644 index 0000000..3409033 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/tools/schema/BB.Opc.Ua.Types.bsd @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/shared/libraries/opcua/tests/CMakeLists.txt b/shared/libraries/opcua/tests/CMakeLists.txt new file mode 100644 index 0000000..7cb4330 --- /dev/null +++ b/shared/libraries/opcua/tests/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.2) +set_cmake_folder_context(TARGET_FOLDER_NAME) +project(OpcUaTests CXX) + +add_subdirectory(testopcua) diff --git a/shared/libraries/opcua/tests/testopcua/CMakeLists.txt b/shared/libraries/opcua/tests/testopcua/CMakeLists.txt new file mode 100644 index 0000000..a842d5c --- /dev/null +++ b/shared/libraries/opcua/tests/testopcua/CMakeLists.txt @@ -0,0 +1,28 @@ +set(MODULE_NAME opcua) +set(TEST_APP test_${MODULE_NAME}) + +set(TEST_SOURCES + main.cpp + test_opcua_security.cpp +) + +add_executable(${TEST_APP} ${TEST_SOURCES}) + +target_link_libraries(${TEST_APP} PRIVATE opcuashared + opcuaserver + opcuaclient + daq::test_utils +) + +if (MSVC) + target_compile_definitions(${TEST_APP} PRIVATE _CRT_SECURE_NO_WARNINGS) +endif() + +add_test(NAME ${TEST_APP} + COMMAND $ + WORKING_DIRECTORY bin +) + +if (OPENDAQ_ENABLE_COVERAGE) + setup_target_for_coverage(${MODULE_NAME}testcoverage ${TEST_APP} ${MODULE_NAME}testcoverage) +endif() diff --git a/shared/libraries/opcua/tests/testopcua/main.cpp b/shared/libraries/opcua/tests/testopcua/main.cpp new file mode 100644 index 0000000..a4ca297 --- /dev/null +++ b/shared/libraries/opcua/tests/testopcua/main.cpp @@ -0,0 +1,13 @@ +#include +#include + +int main(int argc, char** args) +{ + testing::InitGoogleTest(&argc, args); + + testing::TestEventListeners& listeners = testing::UnitTest::GetInstance()->listeners(); + listeners.Append(new MemCheckListener()); + + int res = RUN_ALL_TESTS(); + return res; +} diff --git a/shared/libraries/opcua/tests/testopcua/test_opcua_security.cpp b/shared/libraries/opcua/tests/testopcua/test_opcua_security.cpp new file mode 100644 index 0000000..ef33ad3 --- /dev/null +++ b/shared/libraries/opcua/tests/testopcua/test_opcua_security.cpp @@ -0,0 +1,566 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "opcuashared/opcuasecuritycommon.h" +#include + +using namespace daq::utils; + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using OpcUaSecurityTest = testing::Test; + +static std::string TestFile(std::string name) +{ + return CmakeGlobals::ResDirFile("testKeys/keys/" + name); +} + +class TestServer +{ +public: + TestServer() + { + server = std::make_shared(); + server->setPort(4840); + } + + ~TestServer() + { + if (isStarted()) + server->stop(); + nodes.clear(); + } + + void setSecurityConfig(OpcUaServerSecurityConfig* config) + { + server->setSecurityConfig(config); + } + + void start() + { + server->start(); + } + + void stop() + { + server->stop(); + } + + bool isStarted() + { + return server->getStarted(); + } + + std::shared_ptr getServer() + { + return server; + } + + static OpcUaServerSecurityConfig CreateSecurityConfig() + { + OpcUaServerSecurityConfig config; + config.certificate = utils::LoadFile(TestFile("server-cert.der")); + config.privateKey = utils::LoadFile(TestFile("server-private.der")); + config.trustList.push_back(utils::LoadFile(TestFile("client-cert.der")).getValue()); + config.appUri = "urn:dewesoft.com"; + config.securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT; + config.trustAll = false; + return config; + } + + static std::unordered_map CreateUsers() + { + BCrypt bcrypt; + unsigned int rounds = 8; + std::unordered_map users; + users["newton"] = bcrypt.hash("newton123", rounds); + users["galileo"] = bcrypt.hash("galileo123", rounds); + users["tesla"] = bcrypt.hash("tesla123", rounds); + users["pascal"] = bcrypt.hash("pascal123", rounds); + return users; + } + +private: + std::shared_ptr server; + std::vector nodes; +}; + +class TestClient +{ +public: + TestClient() + { + securityConfig = NULL; + } + + void setSecurityConfig(OpcUaClientSecurityConfig* config) + { + securityConfig = config; + } + + void connect() + { + OpcUaEndpoint endpoint("test", "opc.tcp://localhost:4840/"); + endpoint.setSecurityConfig(securityConfig); + + client = std::make_shared(endpoint); + + if (timeout > 0) + client->setTimeout(timeout); + + client->connect(); + } + + void disconnect() + { + client->disconnect(); + client = nullptr; + } + + void setTimeout(int timeoutMs) + { + this->timeout = timeoutMs; + } + + bool isConnected() + { + return client && client->isConnected(); + } + + bool nodeExist(const OpcUaNodeId& nodeId) + { + auto result = client->nodeExists(nodeId); + return result; + } + + OpcUaClientPtr getClient() + { + return client; + } + + static OpcUaClientSecurityConfig CreateSecurityConfig() + { + OpcUaClientSecurityConfig config; + config.certificate = utils::LoadFile(TestFile("client-cert.der")); + config.privateKey = utils::LoadFile(TestFile("client-private.der")); + config.trustList.push_back(utils::LoadFile(TestFile("server-cert.der")).getValue()); + config.appUri = "urn:testclient.com"; + config.securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT; + config.trustAll = false; + return config; + } + +private: + OpcUaClientPtr client; + OpcUaClientSecurityConfig* securityConfig; + int timeout = -1; +}; + +TEST_F_OPTIONAL(OpcUaSecurityTest, LoadCertificateTest) +{ + OpcUaObject cert; + + ASSERT_NO_THROW(cert = utils::LoadFile(TestFile("client-cert.der"))); + ASSERT_GT(cert.getValue().length, (size_t) 0); + + ASSERT_ANY_THROW(cert = utils::LoadFile(TestFile("client-cert-missing.der"))); + + ASSERT_NO_THROW(cert = utils::LoadFile(TestFile("garbage-cert.der"))); + ASSERT_GT(cert.getValue().length, (size_t) 0); +} + +TEST_F_OPTIONAL(OpcUaSecurityTest, SecurityConfigMemoryTest) +{ + OpcUaClientSecurityConfig a; + a.certificate = utils::LoadFile(TestFile("client-cert.der")).getValue(); + + a.trustList.push_back(utils::LoadFile(TestFile("server-cert.der")).getValue()); + a.trustList[0] = utils::LoadFile(TestFile("client-cert.der")).getValue(); + + a.appUri = "urn:testclient.com"; + a.securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT; + + OpcUaClientSecurityConfig b = a; +} + +TEST_F_OPTIONAL(OpcUaSecurityTest, SecurityModeNoneTest) +{ + OpcUaServerSecurityConfig serverSecurity; + serverSecurity.securityMode = UA_MESSAGESECURITYMODE_NONE; + + OpcUaClientSecurityConfig clientSecurity; + clientSecurity.securityMode = UA_MESSAGESECURITYMODE_NONE; + + TestServer testServer; + testServer.setSecurityConfig(&serverSecurity); + testServer.start(); + ASSERT_TRUE(testServer.isStarted()); + + TestClient testClient; + testClient.setSecurityConfig(&clientSecurity); + testClient.connect(); + ASSERT_TRUE(testClient.isConnected()); + + ASSERT_NO_THROW(testClient.nodeExist(OpcUaNodeId(UA_NS0ID_SERVER))); + + testClient.disconnect(); + ASSERT_FALSE(testClient.isConnected()); + + testServer.stop(); + ASSERT_FALSE(testServer.isStarted()); +} + +TEST_F_OPTIONAL(OpcUaSecurityTest, AuthenticationTest) +{ + OpcUaServerSecurityConfig serverSecurity = TestServer::CreateSecurityConfig(); + OpcUaClientSecurityConfig clientSecurity = TestClient::CreateSecurityConfig(); + +#ifndef OPCUA_ENABLE_ENCRYPTION + serverSecurity.certificate = UA_BYTESTRING_NULL; + serverSecurity.securityMode = UA_MESSAGESECURITYMODE_NONE; + clientSecurity.certificate = UA_BYTESTRING_NULL; + clientSecurity.securityMode = UA_MESSAGESECURITYMODE_NONE; +#endif + + std::unordered_map users = TestServer::CreateUsers(); + serverSecurity.authenticateUser = [&users](bool isAnonymous, std::string username, std::string password) -> UA_StatusCode { + if (!isAnonymous && users.count(username)) + { + std::string hash = users[username]; + if (BCrypt::Verify(hash, password)) + return UA_STATUSCODE_GOOD; + } + + return UA_STATUSCODE_BADUSERACCESSDENIED; + }; + + TestServer testServer; + testServer.setSecurityConfig(&serverSecurity); + testServer.start(); + ASSERT_TRUE(testServer.isStarted()); + + TestClient testClient; + testClient.setSecurityConfig(&clientSecurity); + + testClient.connect(); + ASSERT_FALSE(testClient.isConnected()); + + clientSecurity.username = "tesla"; + clientSecurity.password = "wrongPassword"; + testClient.connect(); + ASSERT_FALSE(testClient.isConnected()); + + clientSecurity.username = "wrongUser"; + clientSecurity.password = "tesla123"; + testClient.connect(); + ASSERT_FALSE(testClient.isConnected()); + + clientSecurity.username.reset(); + clientSecurity.password = "tesla123"; + testClient.connect(); + ASSERT_FALSE(testClient.isConnected()); + + clientSecurity.username = ""; + clientSecurity.password = "tesla123"; + testClient.connect(); + ASSERT_FALSE(testClient.isConnected()); + + clientSecurity.username = "tesla"; + clientSecurity.password = ""; + testClient.connect(); + ASSERT_FALSE(testClient.isConnected()); + + clientSecurity.username = "tesla"; + clientSecurity.password.reset(); + testClient.connect(); + ASSERT_FALSE(testClient.isConnected()); + + clientSecurity.username = "tesla"; + clientSecurity.password = "tesla123"; + testClient.connect(); + ASSERT_TRUE(testClient.isConnected()); + + testClient.disconnect(); + ASSERT_FALSE(testClient.isConnected()); + testServer.stop(); + ASSERT_FALSE(testServer.isStarted()); +} + +#ifdef OPCUA_ENABLE_ENCRYPTION + +TEST_F_OPTIONAL(OpcUaSecurityTest, SecurityModeSignEncryptTest) +{ + OpcUaServerSecurityConfig serverSecurity = TestServer::CreateSecurityConfig(); + OpcUaClientSecurityConfig clientSecurity = TestClient::CreateSecurityConfig(); + + TestServer testServer; + testServer.setSecurityConfig(&serverSecurity); + testServer.start(); + ASSERT_TRUE(testServer.isStarted()); + + TestClient testClient; + testClient.setSecurityConfig(&clientSecurity); + testClient.connect(); + ASSERT_TRUE(testClient.isConnected()); + + ASSERT_NO_THROW(testClient.nodeExist(UA_NS0ID_SERVER)); + + testClient.disconnect(); + ASSERT_FALSE(testClient.isConnected()); + + testServer.stop(); + ASSERT_FALSE(testServer.isStarted()); +} + +TEST_F_OPTIONAL(OpcUaSecurityTest, WrongSecurityModeTest) +{ + OpcUaServerSecurityConfig serverSecurity = TestServer::CreateSecurityConfig(); + serverSecurity.securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT; + + OpcUaClientSecurityConfig clientSecurity = TestClient::CreateSecurityConfig(); + clientSecurity.securityMode = UA_MESSAGESECURITYMODE_NONE; + + TestServer testServer; + testServer.setSecurityConfig(&serverSecurity); + testServer.start(); + ASSERT_TRUE(testServer.isStarted()); + + TestClient testClient; + testClient.setSecurityConfig(&clientSecurity); + testClient.connect(); + ASSERT_FALSE(testClient.isConnected()); + + testServer.stop(); + ASSERT_FALSE(testServer.isStarted()); +} + +TEST_F_OPTIONAL(OpcUaSecurityTest, ExpiredCertificateTest) +{ + OpcUaServerSecurityConfig serverSecurity = TestServer::CreateSecurityConfig(); + serverSecurity.trustList.push_back(LoadFile(TestFile("client-cert-expired.der")).getValue()); + + OpcUaClientSecurityConfig clientSecurity; + clientSecurity.trustList.push_back(LoadFile(TestFile("server-cert.der")).getValue()); + clientSecurity.certificate = LoadFile(TestFile("client-cert-expired.der")); + clientSecurity.privateKey = LoadFile(TestFile("client-private-expired.der")); + clientSecurity.securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT; + clientSecurity.appUri = "urn:testclient.com"; + + TestServer testServer; + testServer.setSecurityConfig(&serverSecurity); + testServer.start(); + ASSERT_TRUE(testServer.isStarted()); + + TestClient testClient; + testClient.setSecurityConfig(&clientSecurity); + testClient.connect(); + ASSERT_FALSE(testClient.isConnected()); + + testServer.stop(); + ASSERT_FALSE(testServer.isStarted()); +} + +TEST_F_OPTIONAL(OpcUaSecurityTest, GarbageCertificateTest) +{ + OpcUaServerSecurityConfig serverSecurity = TestServer::CreateSecurityConfig(); + + OpcUaClientSecurityConfig clientSecurity; + clientSecurity.trustList.push_back(LoadFile(TestFile("server-cert.der")).getValue()); + clientSecurity.certificate = LoadFile(TestFile("garbage-cert.der")).getValue(); + clientSecurity.privateKey = LoadFile(TestFile("client-private.der")).getValue(); + clientSecurity.securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT; + clientSecurity.appUri = "urn:testclient.com"; + + TestServer testServer; + testServer.setSecurityConfig(&serverSecurity); + testServer.start(); + ASSERT_TRUE(testServer.isStarted()); + + TestClient testClient; + testClient.setSecurityConfig(&clientSecurity); + testClient.connect(); + ASSERT_FALSE(testClient.isConnected()); + + testServer.stop(); + serverSecurity.trustList.push_back(LoadFile(TestFile("garbage-cert.der")).getValue()); + testServer.setSecurityConfig(&serverSecurity); + ASSERT_THROW(testServer.start(), OpcUaException); + ASSERT_FALSE(testServer.isStarted()); +} + +TEST_F_OPTIONAL(OpcUaSecurityTest, UntrustedCertificateTest) +{ + OpcUaServerSecurityConfig serverSecurity = TestServer::CreateSecurityConfig(); + + OpcUaClientSecurityConfig clientSecurity; + clientSecurity.trustList.push_back(LoadFile(TestFile("server-cert.der")).getValue()); + clientSecurity.certificate = LoadFile(TestFile("tesla-cert.der")); + clientSecurity.privateKey = LoadFile(TestFile("tesla-private.der")); + clientSecurity.securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT; + clientSecurity.appUri = "urn:nikolatesla.com"; + + TestServer testServer; + testServer.setSecurityConfig(&serverSecurity); + testServer.start(); + ASSERT_TRUE(testServer.isStarted()); + + TestClient testClient; + testClient.setSecurityConfig(&clientSecurity); + testClient.connect(); + ASSERT_FALSE(testClient.isConnected()); + + testServer.stop(); + serverSecurity.trustList.push_back(LoadFile(TestFile("tesla-cert.der")).getValue()); + testServer.start(); + ASSERT_TRUE(testServer.isStarted()); + testClient.connect(); + + testServer.stop(); + ASSERT_FALSE(testServer.isStarted()); +} + +TEST_F_OPTIONAL(OpcUaSecurityTest, RevokedCertificateTest) +{ + OpcUaServerSecurityConfig serverSecurity = TestServer::CreateSecurityConfig(); + serverSecurity.trustList.clear(); + serverSecurity.trustList.push_back(LoadFile(TestFile("client-cert.der")).getValue()); + serverSecurity.trustList.push_back(LoadFile(TestFile("tesla-cert.der")).getValue()); + serverSecurity.revocationList.clear(); + serverSecurity.revocationList.push_back(LoadFile(TestFile("../ca/root.crl")).getValue()); + + auto tryConnectClient = [](std::string prefix) { + OpcUaClientSecurityConfig clientSecurity = TestClient::CreateSecurityConfig(); + clientSecurity.certificate = LoadFile(TestFile(prefix + "-cert.der")); + clientSecurity.privateKey = LoadFile(TestFile(prefix + "-private.der")); + + TestClient client; + client.setSecurityConfig(&clientSecurity); + client.connect(); + bool connected = client.isConnected(); + client.disconnect(); + return connected; + }; + + TestServer testServer; + testServer.setSecurityConfig(&serverSecurity); + testServer.start(); + ASSERT_TRUE(testServer.isStarted()); + + ASSERT_TRUE(tryConnectClient("client")); + ASSERT_FALSE(tryConnectClient("tesla")); // todo: fix revocation list issue + + testServer.stop(); + ASSERT_FALSE(testServer.isStarted()); +} + +TEST_F_OPTIONAL(OpcUaSecurityTest, AppUriFromCertificate) +{ + OpcUaServerSecurityConfig serverSecurity = TestServer::CreateSecurityConfig(); + serverSecurity.appUri.reset(); + + TestServer testServer; + testServer.setSecurityConfig(&serverSecurity); + testServer.start(); + ASSERT_TRUE(testServer.isStarted()); + testServer.stop(); + ASSERT_FALSE(testServer.isStarted()); +} + +TEST_F_OPTIONAL(OpcUaSecurityTest, ParseCertificateUri) +{ + OpcUaObject serverCert = LoadFile(TestFile("server-cert.der")); + OpcUaObject clientCert = LoadFile(TestFile("client-cert.der")); + OpcUaObject garbageCert = LoadFile(TestFile("garbage-cert.der")); + + std::optional urn; + urn = OpcUaSecurityCommon::parseCertificateUri(serverCert.getValue()); + ASSERT_EQ(urn.value_or(""), "urn:dewesoft.com"); + urn = OpcUaSecurityCommon::parseCertificateUri(clientCert.getValue()); + ASSERT_EQ(urn.value_or(""), "urn:testclient.com"); + urn = OpcUaSecurityCommon::parseCertificateUri(garbageCert.getValue()); + ASSERT_EQ(urn.value_or(""), ""); +} + +TEST_F_OPTIONAL(OpcUaSecurityTest, TrustAllTest) +{ + OpcUaObject clientCert = LoadFile(TestFile("client-cert.der")); + OpcUaObject serverCert = LoadFile(TestFile("server-cert.der")); + + auto tryConnect = [](bool serverTrustAll, + std::vector serverTrustList, + bool clientTrustAll, + std::vector clientTrustList) { + OpcUaServerSecurityConfig serverSecurity = TestServer::CreateSecurityConfig(); + serverSecurity.trustAll = serverTrustAll; + serverSecurity.trustList.clear(); + for (size_t i = 0; i < serverTrustList.size(); i++) + serverSecurity.trustList.push_back(serverTrustList[i]); + + OpcUaClientSecurityConfig clientSecurity = TestClient::CreateSecurityConfig(); + clientSecurity.trustAll = clientTrustAll; + clientSecurity.trustList.clear(); + for (size_t i = 0; i < clientTrustList.size(); i++) + clientSecurity.trustList.push_back(clientTrustList[i]); + + TestServer testServer; + testServer.setSecurityConfig(&serverSecurity); + testServer.start(); + + TestClient testClient; + testClient.setTimeout(1000); + testClient.setSecurityConfig(&clientSecurity); + testClient.connect(); + bool connected = testClient.isConnected(); + testClient.disconnect(); + testServer.stop(); + + return connected; + }; + + bool connected; + + connected = tryConnect(false, {}, false, {}); + ASSERT_FALSE(connected); + connected = tryConnect(false, {clientCert.getValue()}, false, {}); + ASSERT_FALSE(connected); + connected = tryConnect(false, {}, false, {serverCert.getValue()}); + ASSERT_FALSE(connected); + connected = tryConnect(false, {clientCert.getValue()}, false, {serverCert.getValue()}); + ASSERT_TRUE(connected); + + connected = tryConnect(true, {}, false, {}); + ASSERT_FALSE(connected); + connected = tryConnect(true, {clientCert.getValue()}, false, {}); + ASSERT_FALSE(connected); + connected = tryConnect(true, {}, false, {serverCert.getValue()}); + ASSERT_TRUE(connected); + connected = tryConnect(true, {clientCert.getValue()}, false, {serverCert.getValue()}); + ASSERT_TRUE(connected); + + connected = tryConnect(false, {}, true, {}); + ASSERT_FALSE(connected); + connected = tryConnect(false, {clientCert.getValue()}, true, {}); + ASSERT_TRUE(connected); + connected = tryConnect(false, {}, true, {serverCert.getValue()}); + ASSERT_FALSE(connected); + connected = tryConnect(false, {clientCert.getValue()}, true, {serverCert.getValue()}); + ASSERT_TRUE(connected); + + connected = tryConnect(true, {}, true, {}); + ASSERT_TRUE(connected); + connected = tryConnect(true, {clientCert.getValue()}, true, {}); + ASSERT_TRUE(connected); + connected = tryConnect(true, {}, true, {serverCert.getValue()}); + ASSERT_TRUE(connected); + connected = tryConnect(true, {clientCert.getValue()}, true, {serverCert.getValue()}); + ASSERT_TRUE(connected); +} + +#endif // OPCUA_ENABLE_ENCRYPTION + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcuatms/CMakeLists.txt b/shared/libraries/opcuatms/CMakeLists.txt new file mode 100644 index 0000000..4300b51 --- /dev/null +++ b/shared/libraries/opcuatms/CMakeLists.txt @@ -0,0 +1,9 @@ +set_cmake_folder_context(TARGET_FOLDER_NAME) + +add_subdirectory(opcuatms) +add_subdirectory(opcuatms_server) +add_subdirectory(opcuatms_client) + +if (OPENDAQ_ENABLE_TESTS) + add_subdirectory(tests) +endif() diff --git a/shared/libraries/opcuatms/opcuatms/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms/CMakeLists.txt new file mode 100644 index 0000000..031df0e --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.2) +set_cmake_folder_context(TARGET_FOLDER_NAME) +project(opcuatms VERSION 2.0.0 LANGUAGES CXX) + +add_subdirectory(src) + +if (OPENDAQ_ENABLE_TESTS) + add_subdirectory(tests) +endif() diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h new file mode 100644 index 0000000..be60e3e --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h @@ -0,0 +1,301 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "opcuatms/converters/variant_converter.h" +#include "opcuatms/converters/selection_converter.h" +#include "opendaq/data_descriptor_ptr.h" +#include "open62541/tmsbt_nodeids.h" +#include "open62541/tmsbsp_nodeids.h" +#include "open62541/nodeids.h" +#include "opendaq/function_block_type_ptr.h" + +namespace daq::opcua::tms { + +namespace converters +{ + static OpcUaVariant convertToVariant(IntfID interfaceId, + const BaseObjectPtr& object, + const UA_DataType* targetType, + const ContextPtr& context); + static OpcUaVariant convertToArrayVariant(IntfID elementId, + const ListPtr& list, + const UA_DataType* targetType, + const ContextPtr& context); + static BaseObjectPtr convertToDaqObject(const OpcUaVariant& variant, const ContextPtr& context); + static BaseObjectPtr convertToDaqList(const OpcUaVariant& variant, const ContextPtr& context); + + static std::unordered_map> + idToVariantMap{{INumber::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToVariant(object, targetType); }}, + {IString::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToVariant(object, targetType, ctx); }}, + {IUnit::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToVariant(object, targetType, ctx); }}, + {IRatio::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToVariant(object, targetType, ctx); }}, + {IBoolean::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToVariant(object, targetType, ctx); }}, + {IInteger::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToVariant(object, targetType, ctx); }}, + {IFloat::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToVariant(object, targetType, ctx); }}, + {IDict::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToVariant(object, targetType, ctx); }}, + {IDataDescriptor::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToVariant(object, targetType, ctx); }}, + {IDimension::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToVariant(object, targetType, ctx); }}, + {IDimensionRule::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToVariant(object, targetType, ctx); }}, + {IDataRule::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToVariant(object, targetType, ctx); }}, + {IFunctionBlockType::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToVariant(object, targetType, ctx); }}, + {IScaling::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToVariant(object, targetType, ctx); }}, + {IArgumentInfo::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToVariant(object, targetType, ctx); }}, + {IRange::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToVariant(object, targetType, ctx); }}, + {IStruct::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToVariant(object, targetType, ctx); }}, + {IList::Id, [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) { + return VariantConverter::ToArrayVariant(object, targetType, ctx); + }}}; + + static std::unordered_map&, const UA_DataType*, const ContextPtr&)>> + idToArrayVariantMap{{INumber::Id, + [](const ListPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToArrayVariant(object, targetType, ctx); }}, + {IString::Id, + [](const ListPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToArrayVariant(object, targetType, ctx); }}, + {IUnit::Id, + [](const ListPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToArrayVariant(object, targetType, ctx); }}, + {IRatio::Id, + [](const ListPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToArrayVariant(object, targetType, ctx); }}, + {IBoolean::Id, + [](const ListPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToArrayVariant(object, targetType, ctx); }}, + {IInteger::Id, + [](const ListPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToArrayVariant(object, targetType, ctx); }}, + {IFloat::Id, + [](const ListPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToArrayVariant(object, targetType, ctx); }}, + {IDataDescriptor::Id, + [](const ListPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToArrayVariant(object, targetType, ctx); }}, + {IDimension::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToArrayVariant(object, targetType, ctx); }}, + {IDimensionRule::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToArrayVariant(object, targetType, ctx); }}, + {IDataRule::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToArrayVariant(object, targetType, ctx); }}, + {IFunctionBlockType::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToArrayVariant(object, targetType, ctx); }}, + {IScaling::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToArrayVariant(object, targetType, ctx); }}, + {IRange::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToArrayVariant(object, targetType, ctx); }}, + {IStruct::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToArrayVariant(object, targetType, ctx); }}, + {IArgumentInfo::Id, [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) { + return VariantConverter::ToArrayVariant(object, targetType, ctx); + }}}; + + // Does not include DataRule and DimensionRule due to ambiguity issues. + // Does not include generic struct converter. + static std::unordered_map> uaTypeToDaqObject{ + {OpcUaNodeId(0, UA_NS0ID_BOOLEAN), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_FLOAT), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_DOUBLE), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_SBYTE), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_BYTE), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_INT16), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_UINT16), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_INT32), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_UINT32), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_INT64), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_UINT64), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_STRING), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_LOCALIZEDTEXT), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_QUALIFIEDNAME), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_EUINFORMATIONWITHQUANTITY), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_EUINFORMATION), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_RATIONALNUMBER), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_RATIONALNUMBER64), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_DATADESCRIPTORSTRUCTURE), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_STRUCTDESCRIPTORSTRUCTURE), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_DIMENSIONDESCRIPTORSTRUCTURE), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_FUNCTIONBLOCKINFOSTRUCTURE), + [](const OpcUaVariant& var, const ContextPtr& context) + { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_POSTSCALINGSTRUCTURE), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_LINEARSCALINGDESCRIPTIONSTRUCTURE), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_ARGUMENT), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_RANGE), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}}; + + static std::unordered_map(const OpcUaVariant&, const ContextPtr& context)>> + uaTypeToDaqList{ + {OpcUaNodeId(0, UA_NS0ID_BOOLEAN), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_FLOAT), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_DOUBLE), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_SBYTE), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_BYTE), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_INT16), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_UINT16), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_INT32), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_UINT32), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_INT64), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_UINT64), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_STRING), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_LOCALIZEDTEXT), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_QUALIFIEDNAME), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(NAMESPACE_TMSBT, UA_TYPES_TMSBT_EUINFORMATIONWITHQUANTITY), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(0, UA_TYPES_EUINFORMATION), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_RATIONALNUMBER), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_RATIONALNUMBER64), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_DATADESCRIPTORSTRUCTURE), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_STRUCTDESCRIPTORSTRUCTURE), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_DIMENSIONDESCRIPTORSTRUCTURE), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_FUNCTIONBLOCKINFOSTRUCTURE), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_POSTSCALINGSTRUCTURE), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_LINEARSCALINGDESCRIPTIONSTRUCTURE), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_ARGUMENT), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_RANGE), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}}; + + static OpcUaVariant convertToVariant(IntfID interfaceId, + const BaseObjectPtr& object, + const UA_DataType* targetType, + const ContextPtr& context) + { + if (const auto it = idToVariantMap.find(interfaceId); it != idToVariantMap.cend()) + return it->second(object, targetType, context); + + return {}; + } + + static OpcUaVariant convertToArrayVariant(IntfID elementId, + const ListPtr& list, + const UA_DataType* targetType, + const ContextPtr& context) + { + if (const auto it = idToArrayVariantMap.find(elementId); it != idToArrayVariantMap.cend()) + return it->second(list, targetType, context); + + return {}; + } + + static BaseObjectPtr convertToDaqObject(const OpcUaVariant& variant, const ContextPtr& context) + { + const auto typeId = variant.getValue().type->typeId; + if (const auto it = uaTypeToDaqObject.find(OpcUaNodeId(typeId)); it != uaTypeToDaqObject.cend()) + return it->second(variant, context); + + return nullptr; + } + + static BaseObjectPtr convertToDaqList(const OpcUaVariant& variant, const ContextPtr& context) + { + const auto typeId = variant.getValue().type->typeId; + if (const auto it = uaTypeToDaqList.find(OpcUaNodeId(typeId)); it != uaTypeToDaqList.cend()) + return it->second(variant, context); + + return nullptr; + } +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/list_conversion_utils.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/list_conversion_utils.h new file mode 100644 index 0000000..247f290 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/list_conversion_utils.h @@ -0,0 +1,173 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "opcuashared/opcuavariant.h" +#include "opcuatms/opcuatms.h" +#include "opcuatms/extension_object.h" +#include "opcuatms/converters/variant_converter.h" +#include "opcuatms/converters/struct_converter.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +template <> +OpcUaVariant VariantConverter::ToVariant(const BaseObjectPtr& object, + const UA_DataType* targetType, + const ContextPtr& context); + +class ListConversionUtils +{ +public: + template + static OpcUaVariant ToArrayVariant(const ListPtr& list, const ContextPtr& context = nullptr); + template + static ListPtr VariantToList(const OpcUaVariant& variant, const ContextPtr& context = nullptr); + + template + static OpcUaVariant ToExtensionObjectArrayVariant(const ListPtr& list, const ContextPtr& context = nullptr); + template + static ListPtr ExtensionObjectVariantToList(const OpcUaVariant& variant, const ContextPtr& context = nullptr); + + static OpcUaVariant ToVariantTypeArrayVariant(const ListPtr& list, const ContextPtr& context = nullptr); + static ListPtr VariantTypeArrayToList(const OpcUaVariant& variant, const ContextPtr& context = nullptr); +}; + +inline OpcUaVariant ListConversionUtils::ToVariantTypeArrayVariant(const ListPtr& list, const ContextPtr& context) +{ + constexpr auto type = GetUaDataType(); + const auto arr = static_cast(UA_Array_new(list.getCount(), type)); + + for (SizeT i = 0; i < list.getCount(); i++) + { + auto tmsStruct = VariantConverter::ToVariant(list.getItemAt(i), nullptr, context); + arr[i] = tmsStruct.getDetachedValue(); + } + + auto variant = OpcUaVariant(); + UA_Variant_setArray(variant.get(), arr, list.getCount(), type); + return variant; +} + +inline ListPtr ListConversionUtils::VariantTypeArrayToList(const OpcUaVariant& variant, const ContextPtr& context) +{ + if (!variant.isType()) + throw ConversionFailedException{}; + + auto list = List(); + const auto data = static_cast(variant->data); + + for (size_t i = 0; i < variant->arrayLength; i++) + { + OpcUaVariant arrayField = OpcUaVariant(data[i]); + const auto obj = VariantConverter::ToDaqObject(arrayField, context); + list.pushBack(obj); + } + + return list; +} + +template +OpcUaVariant ListConversionUtils::ToArrayVariant(const ListPtr& list, const ContextPtr& context) +{ + constexpr auto type = GetUaDataType(); + auto arr = static_cast(UA_Array_new(list.getCount(), type)); + try + { + for (SizeT i = 0; i < list.getCount(); i++) + { + auto tmsStruct = StructConverter::ToTmsType(list.getItemAt(i), context); + arr[i] = tmsStruct.getDetachedValue(); + } + } + catch (...) + { + UA_Array_delete(arr, list.getCount(), type); + throw; + } + + auto variant = OpcUaVariant(); + UA_Variant_setArray(variant.get(), arr, list.getCount(), type); + return variant; +} + +template +ListPtr ListConversionUtils::VariantToList(const OpcUaVariant& variant, const ContextPtr& context) +{ + if (!variant.isType()) + throw ConversionFailedException(); + + auto data = static_cast(variant->data); + auto list = List(); + + for (size_t i = 0; i < variant->arrayLength; i++) + { + const auto obj = StructConverter::ToDaqObject(data[i], context); + list.pushBack(obj); + } + + return list; +} + +template +OpcUaVariant ListConversionUtils::ToExtensionObjectArrayVariant(const ListPtr& list, const ContextPtr& context) +{ + constexpr auto type = GetUaDataType(); + const auto arr = static_cast(UA_Array_new(list.getCount(), type)); + + try + { + for (SizeT i = 0; i < list.getCount(); i++) + { + auto variant = VariantConverter::ToVariant(list.getItemAt(i), nullptr, context); + auto extensionObject = ExtensionObject(variant); + arr[i] = extensionObject.getDetachedValue(); + } + } + catch(...) + { + UA_Array_delete(arr, list.getCount(), type); + throw; + } + + auto variant = OpcUaVariant(); + UA_Variant_setArray(variant.get(), static_cast(arr), list.getCount(), type); + return variant; +} + +template +ListPtr ListConversionUtils::ExtensionObjectVariantToList(const OpcUaVariant& variant, const ContextPtr& context) +{ + if (!variant.isType()) + throw ConversionFailedException(); + + const auto data = static_cast(variant->data); + auto list = List(); + + for (size_t i = 0; i < variant->arrayLength; i++) + { + auto extensionObject = ExtensionObject(data[i]); + BaseObjectPtr object = nullptr; + if (extensionObject.isDecoded()) + object = VariantConverter::ToDaqObject(extensionObject.getAsVariant(), context); + + list.pushBack(object); + } + + return list; +} + + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/selection_converter.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/selection_converter.h new file mode 100644 index 0000000..23d7e53 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/selection_converter.h @@ -0,0 +1,40 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include "opcuashared/opcuavariant.h" +#include "opcuatms/opcuatms.h" +#include "opendaq/context_ptr.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +// New implementations of converters should always be specializations of VariantConverter and StructConverter. +// Selections are temporary exceptions. + +class SelectionVariantConverter +{ +public: + static BaseObjectPtr ToDaqObject(const OpcUaVariant& variant, const ContextPtr& context = nullptr); + static OpcUaVariant ToVariant(const BaseObjectPtr& selectionValues, const ContextPtr& context = nullptr); + +private: + static OpcUaObject ToKeyValuePair(const IntegerPtr& key, const BaseObjectPtr& value, const ContextPtr& context); + static OpcUaVariant ListToVariant(const ListPtr& selectionValues, const ContextPtr& context); + static OpcUaVariant DictToVariant(const DictPtr& selectionValues, const ContextPtr& context); +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/struct_converter.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/struct_converter.h new file mode 100644 index 0000000..852783b --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/struct_converter.h @@ -0,0 +1,33 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "opcuatms/opcuatms.h" +#include "opcuashared/opcuavariant.h" +#include "opcuashared/opcuaobject.h" +#include "opendaq/context_ptr.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +template ::SmartPtr> +class StructConverter +{ +public: + static BlueberryTypePtr ToDaqObject(const TmsType& tmsStruct, const ContextPtr& context = nullptr); + static OpcUaObject ToTmsType(const BlueberryTypePtr& object, const ContextPtr& context = nullptr); +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/variant_converter.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/variant_converter.h new file mode 100644 index 0000000..cc969b0 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/variant_converter.h @@ -0,0 +1,42 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include "opcuashared/opcuavariant.h" +#include "opcuatms/opcuatms.h" +#include "opcuatms/type_mappings.h" +#include "opcuashared/opcuaobject.h" +#include "opendaq/context_ptr.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +template ::SmartPtr> +class VariantConverter +{ +public: + static BlueberryTypePtr ToDaqObject(const OpcUaVariant& variant, const ContextPtr& context = nullptr); + static OpcUaVariant ToVariant(const BlueberryTypePtr& object, + const UA_DataType* targetType = nullptr, + const ContextPtr& context = nullptr); + + static ListPtr ToDaqList(const OpcUaVariant& variant, const ContextPtr& context = nullptr); + static OpcUaVariant ToArrayVariant(const ListPtr& list, + const UA_DataType* targetType = nullptr, + const ContextPtr& context = nullptr); +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h new file mode 100644 index 0000000..b3b5f97 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h @@ -0,0 +1,41 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include "opcuashared/opcuavariant.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +StringPtr ConvertToDaqCoreString(const UA_String& uaString); +OpcUaObject ConvertToOpcUaString(const StringPtr& str); +BinaryDataPtr CreateCoreBinaryDataFromUaByteString(const UA_ByteString& uaByteString); +OpcUaObject CreateUaByteStringFromCoreBinaryData(const BinaryDataPtr& binaryData); +SampleType SampleTypeFromTmsEnum(UA_SampleTypeEnumeration tmsEnum); +UA_SampleTypeEnumeration SampleTypeToTmsEnum(SampleType daqEnum); +ScaledSampleType ScaledSampleTypeFromTmsEnum(UA_SampleTypeEnumeration tmsEnum); +UA_SampleTypeEnumeration ScaledSampleTypeToTmsEnum(ScaledSampleType daqEnum); +OpcUaNodeId CoreTypeToUANodeID(CoreType type); +CoreType UANodeIdToCoreType(OpcUaNodeId nodeId); +OpcUaVariant DecodeIfExtensionObject(const OpcUaVariant& variant); +OpcUaVariant UnwrapIfVariant(const OpcUaVariant& variant); +const UA_DataType* GetUAStructureDataTypeByName(const std::string& structName); + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/errors.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/errors.h new file mode 100644 index 0000000..ea6d0b1 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/errors.h @@ -0,0 +1,24 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include + +#define OPENDAQ_ERRTYPE_OPCUA 0x09 + +#define OPENDAQ_ERR_OPCUA_GENERAL OPENDAQ_ERROR_CODE(OPENDAQ_ERRTYPE_OPCUA, 0x001) +#define OPENDAQ_ERR_OPCUA_OBJECT_NOT_DECODED OPENDAQ_ERROR_CODE(OPENDAQ_ERRTYPE_OPCUA, 0x002) +#define OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE OPENDAQ_ERROR_CODE(OPENDAQ_ERRTYPE_OPCUA, 0x003) diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/exceptions.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/exceptions.h new file mode 100644 index 0000000..24e0065 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/exceptions.h @@ -0,0 +1,28 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +DEFINE_EXCEPTION(OpcUaGeneral, OPENDAQ_ERR_OPCUA_GENERAL, "General OpcUa error") +DEFINE_EXCEPTION(OpcUaObjectNotDecoded, OPENDAQ_ERR_OPCUA_OBJECT_NOT_DECODED, "Extension object is not decoded.") +DEFINE_EXCEPTION(OpcUaClientCallNotAvailable, OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE, "This function call is not available/implemented for usage on connected-to OpcUa servers.") + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/extension_object.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/extension_object.h new file mode 100644 index 0000000..f6bfa41 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/extension_object.h @@ -0,0 +1,50 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "opcuatms/opcuatms.h" +#include "opcuashared/opcuavariant.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class ExtensionObject : public OpcUaObject +{ +public: + using Super = OpcUaObject; + using Super::Super; + + ExtensionObject(); + ExtensionObject(const OpcUaObject& extensionObject); + ExtensionObject(const OpcUaVariant& variant); + + void setFromVariant(const OpcUaVariant& variant); + OpcUaVariant getAsVariant(); + bool isDecoded() const; + + template + inline bool isType() const + { + return this->value.content.decoded.type == GetUaDataType(); + } + + template + T* asType() + { + return (T*) this->value.content.decoded.data; + } +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h new file mode 100644 index 0000000..ba49dc3 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h @@ -0,0 +1,28 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#define BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS \ + namespace daq::opcua::tms \ + { +#define END_NAMESPACE_OPENDAQ_OPCUA_TMS } diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h new file mode 100644 index 0000000..88f9853 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h @@ -0,0 +1,39 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "opcuatms/opcuatms.h" + +namespace daq::opcua +{ + ADD_CUSTOM_TYPE_MAPPING(UA_BaseRuleDescriptionStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_BASERULEDESCRIPTIONSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_CustomRuleDescriptionStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_CUSTOMRULEDESCRIPTIONSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_ConstantRuleDescriptionStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_CONSTANTRULEDESCRIPTIONSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_LinearRuleDescriptionStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LINEARRULEDESCRIPTIONSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_ListRuleDescriptionStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LISTRULEDESCRIPTIONSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_LogRuleDescriptionStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LOGRULEDESCRIPTIONSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_EUInformationWithQuantity, &UA_TYPES_TMSBT[UA_TYPES_TMSBT_EUINFORMATIONWITHQUANTITY]) + ADD_CUSTOM_TYPE_MAPPING(UA_DataDescriptorStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_DATADESCRIPTORSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_StructDescriptorStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_STRUCTDESCRIPTORSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_DimensionDescriptorStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_DIMENSIONDESCRIPTORSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_RationalNumber64, &UA_TYPES_TMSBT[UA_TYPES_TMSBT_RATIONALNUMBER64]) + ADD_CUSTOM_TYPE_MAPPING(UA_PostScalingStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_POSTSCALINGSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_LinearScalingDescriptionStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LINEARSCALINGDESCRIPTIONSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_FunctionBlockInfoStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_FUNCTIONBLOCKINFOSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_DaqKeyValuePair, &UA_TYPES_TMSBT[UA_TYPES_TMSBT_DAQKEYVALUEPAIR]) + ADD_CUSTOM_TYPE_MAPPING(UA_SelectionEntryStructure, &UA_TYPES_TMSBT[UA_TYPES_TMSBT_SELECTIONENTRYSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_DeviceDomainStructure, &UA_TYPES_TMSDEVICE[UA_TYPES_TMSDEVICE_DEVICEDOMAINSTRUCTURE]) +} diff --git a/shared/libraries/opcuatms/opcuatms/src/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms/src/CMakeLists.txt new file mode 100644 index 0000000..9b99bc7 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/src/CMakeLists.txt @@ -0,0 +1,74 @@ +set(MODULE_NAME opcuatms) + +set(SRC_PublicHeaders errors.h + opcuatms.h + core_types_utils.h + type_mappings.h + extension_object.h + converter_maps.h +) + +set(SRC_PrivateHeaders exceptions.h +) + +set(SRC_Cpp core_types_utils.cpp + extension_object.cpp +) + +# converters + +set(CONVERTERS_SRC_DIR "converters") + +set(SRC_Converters_Headers ${CONVERTERS_SRC_DIR}/struct_converter.h + ${CONVERTERS_SRC_DIR}/variant_converter.h + ${CONVERTERS_SRC_DIR}/list_conversion_utils.h + ${CONVERTERS_SRC_DIR}/selection_converter.h +) + +set(SRC_Converters ${CONVERTERS_SRC_DIR}/range_converter.cpp + ${CONVERTERS_SRC_DIR}/unit_converter.cpp + ${CONVERTERS_SRC_DIR}/number_converter.cpp + ${CONVERTERS_SRC_DIR}/data_rule_converter.cpp + ${CONVERTERS_SRC_DIR}/dimension_rule_converter.cpp + ${CONVERTERS_SRC_DIR}/ratio_converter.cpp + ${CONVERTERS_SRC_DIR}/data_descriptor_converter.cpp + ${CONVERTERS_SRC_DIR}/scaling_converter.cpp + ${CONVERTERS_SRC_DIR}/dimension_converter.cpp + ${CONVERTERS_SRC_DIR}/function_block_type_converter.cpp + ${CONVERTERS_SRC_DIR}/core_types_converter.cpp + ${CONVERTERS_SRC_DIR}/base_object_converter.cpp + ${CONVERTERS_SRC_DIR}/dict_converter.cpp + ${CONVERTERS_SRC_DIR}/selection_converter.cpp + ${CONVERTERS_SRC_DIR}/argument_converter.cpp + ${CONVERTERS_SRC_DIR}/generic_struct_converter.cpp +) + +set(SRC_PublicHeaders ${SRC_PublicHeaders} ${SRC_Converters_Headers}) +set(SRC_Cpp ${SRC_Cpp} ${SRC_Converters}) + +source_group("converters" "${CONVERTERS_SRC_DIR}/*") + +# /structs + +prepend_include(${MODULE_NAME} SRC_PublicHeaders) +prepend_include(${MODULE_NAME} SRC_PrivateHeaders) + +add_library(${MODULE_NAME} STATIC ${SRC_PublicHeaders} + ${SRC_PrivateHeaders} + ${SRC_Cpp} +) + +add_library(${SDK_TARGET_NAMESPACE}::${MODULE_NAME} ALIAS ${MODULE_NAME}) + +target_include_directories(${MODULE_NAME} PUBLIC $ + $ + $ +) + +target_link_libraries(${MODULE_NAME} PUBLIC daq::opendaq + daq::opcuashared + daq::opcua_tms_types +) + +set_target_properties(${MODULE_NAME} PROPERTIES PUBLIC_HEADER "${SRC_PublicHeaders}") +opendaq_set_output_lib_name(${MODULE_NAME} ${PROJECT_VERSION_MAJOR}) \ No newline at end of file diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/argument_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/argument_converter.cpp new file mode 100644 index 0000000..2bf50c9 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/src/converters/argument_converter.cpp @@ -0,0 +1,88 @@ +#include +#include +#include "opcuatms/converters/list_conversion_utils.h" +#include "opcuatms/converters/struct_converter.h" +#include "opcuatms/converters/variant_converter.h" +#include "open62541/types_tmsbsp_generated.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +// Template specializations + +template class StructConverter; +template class VariantConverter; + +// UA_Argument + +template <> +ArgumentInfoPtr StructConverter::ToDaqObject(const UA_Argument& tmsStruct, const ContextPtr& /*context*/) +{ + return ArgumentInfo(ConvertToDaqCoreString(tmsStruct.name), UANodeIdToCoreType(OpcUaNodeId(tmsStruct.dataType))); +} + +template <> +OpcUaObject StructConverter::ToTmsType(const ArgumentInfoPtr& object, + const ContextPtr& /*context*/) +{ + if (!object.assigned()) + return {}; + + OpcUaObject uaArg; + uaArg->description = UA_LOCALIZEDTEXT_ALLOC("", ""); + uaArg->name = UA_STRING_ALLOC(object.getName().getCharPtr()); + uaArg->dataType = CoreTypeToUANodeID(object.getType()).getDetachedValue(); + + // TODO: handle list and dict + // https://www.open62541.org/doc/0.2/tutorial_server_method.html + uaArg->valueRank = -1; + + return uaArg; +} + +// Variant converter + +template <> +ArgumentInfoPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + const auto decodedVariant = DecodeIfExtensionObject(variant); + + if (!decodedVariant.isType()) + throw ConversionFailedException(); + + return StructConverter::ToDaqObject(*static_cast(decodedVariant->data)); +} + +template <> +OpcUaVariant VariantConverter::ToVariant(const ArgumentInfoPtr& object, + const UA_DataType* targetType, + const ContextPtr& /*context*/) +{ + auto variant = OpcUaVariant(); + + if (targetType == nullptr || targetType == &UA_TYPES[UA_TYPES_ARGUMENT]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else + throw ConversionFailedException{}; + + return variant; +} + +template <> +ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + if (variant.isType()) + return ListConversionUtils::ExtensionObjectVariantToList(variant); + return ListConversionUtils::VariantToList(variant); +} + +template <> +OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& list, + const UA_DataType* targetType, + const ContextPtr& /*context*/) +{ + if (targetType == nullptr || targetType == &UA_TYPES[UA_TYPES_ARGUMENT]) + return ListConversionUtils::ToArrayVariant(list); + throw ConversionFailedException{}; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp new file mode 100644 index 0000000..906afae --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp @@ -0,0 +1,170 @@ +#include "opcuatms/converters/variant_converter.h" +#include "opcuatms/core_types_utils.h" +#include "opendaq/data_descriptor_ptr.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +// Definitions + +template class VariantConverter; + +template <> +BaseObjectPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& context); + +template <> +ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, const ContextPtr& context); + +template <> +OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& list, + const UA_DataType* targetType, + const ContextPtr& context); +template <> +OpcUaVariant VariantConverter::ToVariant(const BaseObjectPtr& object, + const UA_DataType* targetType, + const ContextPtr& context); + +END_NAMESPACE_OPENDAQ_OPCUA_TMS + +#include "opcuatms/converters/selection_converter.h" +#include "opcuatms/converter_maps.h" +#include "opcuatms/converters/list_conversion_utils.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +// Variant converter + +template <> +ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, const ContextPtr& context) +{ + if (variant.isNull()) + return nullptr; + + if (variant.isType()) + return ListConversionUtils::ExtensionObjectVariantToList(variant, context); + if (variant.isType()) + return ListConversionUtils::VariantTypeArrayToList(variant, context); + + const auto list = converters::convertToDaqList(variant, context); + if (list.assigned()) + return list; + + const auto typeKind = variant.getValue().type->typeKind; + if (typeKind == UA_DATATYPEKIND_STRUCTURE || typeKind == UA_DATATYPEKIND_OPTSTRUCT) + return VariantConverter::ToDaqList(variant, context); + + throw ConversionFailedException(); +} + +template <> +BaseObjectPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& context) +{ + if (variant.isNull()) + return nullptr; + + if (!variant.isScalar()) + { + if (variant.isType()) + { + const auto extensionObject = ExtensionObject(*static_cast(variant->data)); + if (extensionObject.isType()) + return VariantConverter::ToDaqObject(variant, context); + if (extensionObject.isType()) + return SelectionVariantConverter::ToDaqObject(variant, context); + } + else + { + if (variant.isType()) + return VariantConverter::ToDaqObject(variant, context); + if (variant.isType()) + return SelectionVariantConverter::ToDaqObject(variant, context); + } + + return ToDaqList(variant, context); + } + + auto decoded = DecodeIfExtensionObject(variant); + auto unwrapped = UnwrapIfVariant(decoded); + + const auto obj = converters::convertToDaqObject(unwrapped, context); + if (obj.assigned()) + return obj; + + const auto typeKind = unwrapped.getValue().type->typeKind; + if (typeKind == UA_DATATYPEKIND_STRUCTURE || typeKind == UA_DATATYPEKIND_OPTSTRUCT) + return VariantConverter::ToDaqObject(unwrapped, context); + + throw ConversionFailedException(); +} + +template <> +OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& list, + const UA_DataType* targetType, + const ContextPtr& context) +{ + if (targetType == &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]) + return ListConversionUtils::ToExtensionObjectArrayVariant(list, context); + if (targetType == &UA_TYPES[UA_TYPES_VARIANT]) + return ListConversionUtils::ToVariantTypeArrayVariant(list, context); + + const auto elementType = list.asPtrOrNull(); + IntfID elementId; + elementType->getElementInterfaceId(&elementId); + + if (IntfID::Compare(elementId, IUnknown::Id) && list.getCount() > 0) + elementId = list[0].asPtr().getInterfaceIds()[0]; + + auto var = converters::convertToArrayVariant(elementId, list, targetType, context); + if (!var.isNull()) + return var; + + return ListConversionUtils::ToExtensionObjectArrayVariant(list, context); +} + +template <> +OpcUaVariant VariantConverter::ToVariant(const BaseObjectPtr& object, + const UA_DataType* targetType, + const ContextPtr& context) +{ + if (!object.assigned()) + return {}; + + const auto ids = object.asPtr().getInterfaceIds(); + auto wrapConvertedValue = targetType == &UA_TYPES[UA_TYPES_EXTENSIONOBJECT] || targetType == &UA_TYPES[UA_TYPES_VARIANT]; + wrapConvertedValue = wrapConvertedValue && !object.asPtrOrNull().assigned(); + + if (wrapConvertedValue) + { + for (auto id : ids) + { + OpcUaVariant converted = converters::convertToVariant(id, object, nullptr, context); + if (converted.isNull()) + continue; + + OpcUaVariant wrapped; + if (targetType == &UA_TYPES[UA_TYPES_VARIANT]) + { + UA_Variant_setScalar(&wrapped.getValue(), converted.newDetachedPointer(), targetType); + } + else + { + auto extensionObject = ExtensionObject(converted); + UA_Variant_setScalar(&wrapped.getValue(), extensionObject.newDetachedPointer(), targetType); + } + + return wrapped; + } + } + else + { + for (auto id : ids) + { + OpcUaVariant converted = converters::convertToVariant(id, object, targetType, context); + if (!converted.isNull()) + return converted; + } + } + + throw ConversionFailedException(); +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/core_types_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/core_types_converter.cpp new file mode 100644 index 0000000..39b4af9 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/src/converters/core_types_converter.cpp @@ -0,0 +1,398 @@ +#include "opcuatms/converters/variant_converter.h" +#include "opcuatms/converters/struct_converter.h" +#include "opcuatms/converters/list_conversion_utils.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +// Bool + +template <> +BoolPtr StructConverter::ToDaqObject(const UA_Boolean& value, const ContextPtr& /*context*/) +{ + return value; +} + +template <> +OpcUaObject StructConverter::ToTmsType(const BoolPtr& object, const ContextPtr& /*context*/) +{ + return OpcUaObject(static_cast(object)); +} + +template <> +BoolPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + if (variant.isNull()) + return {}; + return variant.toBool(); +} + +template <> +OpcUaVariant VariantConverter::ToVariant(const BoolPtr& object, const UA_DataType* targetType, const ContextPtr& /*context*/) +{ + if (targetType == nullptr || targetType == &UA_TYPES[UA_TYPES_BOOLEAN]) + return OpcUaVariant(static_cast(object)); + + throw ConversionFailedException{}; +} + +template <> +ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + return ListConversionUtils::VariantToList(variant); +} + +template <> +OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& list, + const UA_DataType* targetType, + const ContextPtr& /*context*/) +{ + if (targetType == nullptr || targetType == &UA_TYPES[UA_TYPES_BOOLEAN]) + return ListConversionUtils::ToArrayVariant(list); + + throw ConversionFailedException{}; +} + +// Int + +template <> +IntegerPtr StructConverter::ToDaqObject(const UA_Int64& value, const ContextPtr& /*context*/) +{ + return value; +} + +template <> +OpcUaObject StructConverter::ToTmsType(const IntegerPtr& object, const ContextPtr& /*context*/) +{ + return {static_cast(object)}; +} + +template <> +IntegerPtr StructConverter::ToDaqObject(const UA_UInt64& value, const ContextPtr& /*context*/) +{ + return value; +} + +template <> +OpcUaObject StructConverter::ToTmsType(const IntegerPtr& object, const ContextPtr& /*context*/) +{ + return {static_cast(object)}; +} + +template <> +IntegerPtr StructConverter::ToDaqObject(const UA_Int32& value, const ContextPtr& /*context*/) +{ + return value; +} + +template <> +OpcUaObject StructConverter::ToTmsType(const IntegerPtr& object, const ContextPtr& /*context*/) +{ + return {static_cast(object)}; +} + +template <> +IntegerPtr StructConverter::ToDaqObject(const UA_UInt32& value, const ContextPtr& /*context*/) +{ + return value; +} + +template <> +OpcUaObject StructConverter::ToTmsType(const IntegerPtr& object, const ContextPtr& /*context*/) +{ + return {static_cast(object)}; +} + +template <> +IntegerPtr StructConverter::ToDaqObject(const UA_UInt16& value, const ContextPtr& /*context*/) +{ + return value; +} + +template <> +OpcUaObject StructConverter::ToTmsType(const IntegerPtr& object, const ContextPtr& /*context*/) +{ + return {static_cast(object)}; +} + +template <> +IntegerPtr StructConverter::ToDaqObject(const UA_Int16& value, const ContextPtr& /*context*/) +{ + return value; +} + +template <> +OpcUaObject StructConverter::ToTmsType(const IntegerPtr& object, const ContextPtr& /*context*/) +{ + return {static_cast(object)}; +} + +template <> +IntegerPtr StructConverter::ToDaqObject(const UA_Byte& value, const ContextPtr& /*context*/) +{ + return value; +} + +template <> +OpcUaObject StructConverter::ToTmsType(const IntegerPtr& object, const ContextPtr& /*context*/) +{ + return {static_cast(object)}; +} + +template <> +IntegerPtr StructConverter::ToDaqObject(const UA_SByte& value, const ContextPtr& /*context*/) +{ + return value; +} + +template <> +OpcUaObject StructConverter::ToTmsType(const IntegerPtr& object, const ContextPtr& /*context*/) +{ + return {static_cast(object)}; +} + +template <> +IntegerPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + if (variant.isNull()) + return {}; + return variant.toInteger(); +} + +template <> +OpcUaVariant VariantConverter::ToVariant(const IntegerPtr& object, const UA_DataType* targetType, const ContextPtr& /*context*/) +{ + auto variant = OpcUaVariant(); + + if (targetType == nullptr || targetType == &UA_TYPES[UA_TYPES_INT64]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else if (targetType == &UA_TYPES[UA_TYPES_UINT64]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else if (targetType == &UA_TYPES[UA_TYPES_INT32]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else if (targetType == &UA_TYPES[UA_TYPES_UINT32]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else if (targetType == &UA_TYPES[UA_TYPES_INT16]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else if (targetType == &UA_TYPES[UA_TYPES_UINT16]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else if (targetType == &UA_TYPES[UA_TYPES_BYTE]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else if (targetType == &UA_TYPES[UA_TYPES_SBYTE]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else + throw ConversionFailedException{}; + + return variant; +} + +template <> +ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + + throw ConversionFailedException{}; +} + +template <> +OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& list, + const UA_DataType* targetType, + const ContextPtr& /*context*/) +{ + if (targetType == nullptr || targetType == &UA_TYPES[UA_TYPES_INT64]) + return ListConversionUtils::ToArrayVariant(list); + if (targetType == &UA_TYPES[UA_TYPES_UINT64]) + return ListConversionUtils::ToArrayVariant(list); + if (targetType == &UA_TYPES[UA_TYPES_INT32]) + return ListConversionUtils::ToArrayVariant(list); + if (targetType == &UA_TYPES[UA_TYPES_UINT32]) + return ListConversionUtils::ToArrayVariant(list); + if (targetType == &UA_TYPES[UA_TYPES_INT16]) + return ListConversionUtils::ToArrayVariant(list); + if (targetType == &UA_TYPES[UA_TYPES_UINT16]) + return ListConversionUtils::ToArrayVariant(list); + if (targetType == &UA_TYPES[UA_TYPES_BYTE]) + return ListConversionUtils::ToArrayVariant(list); + if (targetType == &UA_TYPES[UA_TYPES_SBYTE]) + return ListConversionUtils::ToArrayVariant(list); + + throw ConversionFailedException{}; +} + +// Float + +template <> +FloatPtr StructConverter::ToDaqObject(const UA_Double& value, const ContextPtr& /*context*/) +{ + return value; +} + +template <> +OpcUaObject StructConverter::ToTmsType(const FloatPtr& object, const ContextPtr& /*context*/) +{ + return {static_cast(object)}; +} + +template <> +FloatPtr StructConverter::ToDaqObject(const UA_Float& value, const ContextPtr& /*context*/) +{ + return value; +} + +template <> +OpcUaObject StructConverter::ToTmsType(const FloatPtr& object, const ContextPtr& /*context*/) +{ + return {static_cast(object)}; +} + + +template <> +FloatPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + return variant.toDouble(); +} + +template <> +OpcUaVariant VariantConverter::ToVariant(const FloatPtr& object, const UA_DataType* targetType, const ContextPtr& /*context*/) +{ + auto variant = OpcUaVariant(); + + if (targetType == nullptr || targetType == &UA_TYPES[UA_TYPES_DOUBLE]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else if (targetType == &UA_TYPES[UA_TYPES_FLOAT]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else + throw ConversionFailedException{}; + + return variant; +} + +template <> +ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + + throw ConversionFailedException{}; +} + +template <> +OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& list, + const UA_DataType* targetType, + const ContextPtr& /*context*/) +{ + if (targetType == nullptr || targetType == &UA_TYPES[UA_TYPES_DOUBLE]) + return ListConversionUtils::ToArrayVariant(list); + if (targetType == &UA_TYPES[UA_TYPES_FLOAT]) + return ListConversionUtils::ToArrayVariant(list); + + throw ConversionFailedException{}; +} + +// String + +template <> +StringPtr StructConverter::ToDaqObject(const UA_String& value, const ContextPtr& /*context*/) +{ + return utils::ToStdString(value); +} + +template <> +OpcUaObject StructConverter::ToTmsType(const StringPtr& object, const ContextPtr& /*context*/) +{ + return {UA_STRING_ALLOC(object.getCharPtr())}; +} + +template <> +StringPtr StructConverter::ToDaqObject(const UA_LocalizedText& value, const ContextPtr& /*context*/) +{ + return utils::ToStdString(value.text); +} + +template <> +OpcUaObject StructConverter::ToTmsType(const StringPtr& object, const ContextPtr& /*context*/) +{ + return {UA_LOCALIZEDTEXT_ALLOC("", object.getCharPtr())}; +} + +template <> +StringPtr StructConverter::ToDaqObject(const UA_QualifiedName& value, const ContextPtr& /*context*/) +{ + return utils::ToStdString(value.name); +} + +template <> +OpcUaObject StructConverter::ToTmsType(const StringPtr& object, const ContextPtr& /*context*/) +{ + return {UA_QUALIFIEDNAME_ALLOC(0, object.getCharPtr())}; +} + +template <> +StringPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + if (variant.isNull()) + return {}; + return variant.toString(); +} + +template <> +OpcUaVariant VariantConverter::ToVariant(const StringPtr& object, const UA_DataType* targetType, const ContextPtr& /*context*/) +{ + auto variant = OpcUaVariant(); + + if (targetType == nullptr || targetType == &UA_TYPES[UA_TYPES_STRING]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else if (targetType == &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else if (targetType == &UA_TYPES[UA_TYPES_QUALIFIEDNAME]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else + throw ConversionFailedException{}; + + return variant; +} + +template <> +ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + + throw ConversionFailedException{}; +} + +template <> +OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& list, + const UA_DataType* targetType, + const ContextPtr& /*context*/) +{ + if (targetType == nullptr || targetType == &UA_TYPES[UA_TYPES_STRING]) + return ListConversionUtils::ToArrayVariant(list); + if (targetType == &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]) + return ListConversionUtils::ToArrayVariant(list); + + throw ConversionFailedException{}; +} + + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/data_descriptor_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/data_descriptor_converter.cpp new file mode 100644 index 0000000..5046a31 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/src/converters/data_descriptor_converter.cpp @@ -0,0 +1,320 @@ +#include +#include +#include "opcuatms/converters/struct_converter.h" +#include "opcuatms/converters/variant_converter.h" +#include "opcuatms/core_types_utils.h" +#include "opcuatms/extension_object.h" +#include "opcuatms/converters/list_conversion_utils.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +// Definitions + +template class StructConverter; +template class StructConverter; +template class VariantConverter; + +template <> +DataDescriptorPtr StructConverter::ToDaqObject(const UA_StructDescriptorStructure& tmsStruct, + const ContextPtr& /*context*/); + +template <> +OpcUaObject StructConverter::ToTmsType( + const DataDescriptorPtr& object, const ContextPtr& /*context*/); + +template <> +DataDescriptorPtr StructConverter::ToDaqObject(const UA_DataDescriptorStructure& tmsStruct, + const ContextPtr& /*context*/); + +template <> +DataDescriptorPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& /*context*/); + +template <> +OpcUaVariant VariantConverter::ToVariant(const DataDescriptorPtr& object, + const UA_DataType* targetType, + const ContextPtr& /*context*/); + +template <> +ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, const ContextPtr& /*context*/); + +template <> +OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& list, + const UA_DataType* targetType, + const ContextPtr& /*context*/); + +template <> +DataDescriptorPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& /*context*/); + +template <> +OpcUaVariant VariantConverter::ToVariant(const DataDescriptorPtr& object, + const UA_DataType* targetType, + const ContextPtr& /*context*/); + +template <> +DataDescriptorPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& /*context*/); + +template <> +OpcUaVariant VariantConverter::ToVariant(const DataDescriptorPtr& object, + const UA_DataType* targetType, + const ContextPtr& /*context*/); + +// Helper methods + +static void WriteDimensions(const ListPtr& dimensions, + UA_DimensionDescriptorStructure*& dimensionsOut, + size_t& dimensionsSizeOut) +{ + if (!dimensions.assigned() || dimensions.getCount() == 0) + return; + + dimensionsSizeOut = dimensions.getCount(); + dimensionsOut = static_cast(UA_Array_new(dimensions.getCount(), GetUaDataType())); + + for (SizeT i = 0; i < dimensions.getCount(); i++) + { + auto tmsDimension = StructConverter::ToTmsType(dimensions[i]); + dimensionsOut[i] = tmsDimension.getDetachedValue(); + } +} + +static ListPtr ReadDimensions(const UA_DimensionDescriptorStructure* dimensions, size_t dimensionsSize) +{ + auto list = List(); + for (size_t i = 0; i < dimensionsSize; i++) + { + auto dimension = StructConverter::ToDaqObject(dimensions[i]); + list.pushBack(dimension); + } + return list; +} + +static void WriteMetadata(const DictPtr& metadata, + UA_KeyValuePair*& metadataOut, + size_t& dimensionsSizeOut) +{ + metadataOut = static_cast(UA_Array_new(metadata.getCount(), &UA_TYPES[UA_TYPES_KEYVALUEPAIR])); + dimensionsSizeOut = metadata.getCount(); + size_t index = 0; + + for (const auto& [name, value] : metadata) + { + OpcUaObject pair; + pair->key = UA_QUALIFIEDNAME_ALLOC(1, name.getCharPtr()); + pair->value = VariantConverter::ToVariant(value).getDetachedValue(); + metadataOut[index] = pair.getDetachedValue(); + + index++; + } +} + +static DictPtr ReadMetadata(const UA_KeyValuePair* metadata, size_t metadataSize) +{ + auto dict = Dict(); + if (!metadata) + return dict; + + for (size_t i = 0; i < metadataSize; i++) + { + const auto pair = &metadata[i]; + if (const auto variant = OpcUaVariant(pair->value); variant.isString()) + dict.set(ConvertToDaqCoreString(pair->key.name), variant.toString()); + } + return dict; +} + +// UA_StructDescriptorStructure + +template <> +DataDescriptorPtr StructConverter::ToDaqObject(const UA_StructDescriptorStructure& tmsStruct, + const ContextPtr& /*context*/) +{ + auto members = List(); + for (size_t i = 0; i < tmsStruct.fieldsSize; i++) + { + auto memberObject = ExtensionObject(tmsStruct.fields[i]); + auto memberVariant = memberObject.getAsVariant(); + auto member = VariantConverter::ToDaqObject(memberVariant); + members.pushBack(member); + } + + const auto descriptor = DataDescriptorBuilder() + .setSampleType(SampleType::Undefined) + .setName(ConvertToDaqCoreString(tmsStruct.name)) + .setDimensions(ReadDimensions(tmsStruct.dimensions, tmsStruct.dimensionsSize)) + .setMetadata(ReadMetadata(tmsStruct.metadata, tmsStruct.metadataSize)) + .setStructFields(members); + + return descriptor.build(); +} + +template <> +OpcUaObject StructConverter::ToTmsType( + const DataDescriptorPtr& object, const ContextPtr& /*context*/) +{ + OpcUaObject tmsStruct; + tmsStruct->name = ConvertToOpcUaString(object.getName()).getDetachedValue(); + + WriteDimensions(object.getDimensions(), tmsStruct->dimensions, tmsStruct->dimensionsSize); + WriteMetadata(object.getMetadata(), tmsStruct->metadata, tmsStruct->metadataSize); + + auto members = object.getStructFields(); + tmsStruct->fieldsSize = members.getCount(); + tmsStruct->fields = static_cast(UA_Array_new(members.getCount(), GetUaDataType())); + + for (SizeT i = 0; i < members.getCount(); i++) + { + auto member = members[i]; + auto variant = VariantConverter::ToVariant(member); + auto memberObject = ExtensionObject(variant); + tmsStruct->fields[i] = memberObject.getDetachedValue(); + } + + return tmsStruct; +} + +// UA_DataDescriptorStructure + +template <> +DataDescriptorPtr StructConverter::ToDaqObject(const UA_DataDescriptorStructure& tmsStruct, + const ContextPtr& /*context*/) +{ + const auto descriptor = DataDescriptorBuilder() + .setSampleType(SampleTypeFromTmsEnum(tmsStruct.sampleType)) + .setName(ConvertToDaqCoreString(tmsStruct.name)) + .setDimensions(ReadDimensions(tmsStruct.dimensions, tmsStruct.dimensionsSize)) + .setMetadata(ReadMetadata(tmsStruct.metadata, tmsStruct.metadataSize)); + + if (tmsStruct.unit) + descriptor.setUnit(StructConverter::ToDaqObject(*tmsStruct.unit)); + + if (tmsStruct.valueRange) + descriptor.setValueRange(StructConverter::ToDaqObject(*tmsStruct.valueRange)); + + auto ruleObject = ExtensionObject(tmsStruct.rule); + if (ruleObject.isDecoded()) + descriptor.setRule(VariantConverter::ToDaqObject(ruleObject.getAsVariant())); + + if (tmsStruct.origin) + descriptor.setOrigin(ConvertToDaqCoreString(*tmsStruct.origin)); + + if (tmsStruct.tickResolution) + descriptor.setTickResolution(StructConverter::ToDaqObject(*tmsStruct.tickResolution)); + + if (tmsStruct.postScaling) + descriptor.setPostScaling(StructConverter::ToDaqObject(*tmsStruct.postScaling)); + + return descriptor.build(); +} + +template <> +OpcUaObject StructConverter::ToTmsType( + const DataDescriptorPtr& object, const ContextPtr& /*context*/) +{ + OpcUaObject tmsStruct; + tmsStruct->sampleType = SampleTypeToTmsEnum(object.getSampleType()); + + WriteDimensions(object.getDimensions(), tmsStruct->dimensions, tmsStruct->dimensionsSize); + WriteMetadata(object.getMetadata(), tmsStruct->metadata, tmsStruct->metadataSize); + + tmsStruct->name = ConvertToOpcUaString(object.getName()).getDetachedValue(); + + if (object.getUnit().assigned()) + tmsStruct->unit = StructConverter::ToTmsType(object.getUnit()).newDetachedPointer(); + + if (object.getValueRange().assigned()) + tmsStruct->valueRange = StructConverter::ToTmsType(object.getValueRange()).newDetachedPointer(); + + if (object.getRule().assigned()) + { + auto ruleObject = ExtensionObject(VariantConverter::ToVariant(object.getRule())); + tmsStruct->rule = ruleObject.getDetachedValue(); + } + + if (object.getOrigin().assigned()) + tmsStruct->origin = ConvertToOpcUaString(object.getOrigin()).newDetachedPointer(); + + if (object.getTickResolution().assigned()) + tmsStruct->tickResolution = StructConverter::ToTmsType(object.getTickResolution()).newDetachedPointer(); + + if (object.getPostScaling().assigned()) + tmsStruct->postScaling = StructConverter::ToTmsType(object.getPostScaling()).newDetachedPointer(); + + return tmsStruct; +} + +// Variant DataDescriptorPtr + +template <> +DataDescriptorPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + const auto decodedVariant = DecodeIfExtensionObject(variant); + + if (decodedVariant.isType()) + { + const auto tmsStruct = static_cast(variant->data); + return StructConverter::ToDaqObject(*tmsStruct); + } + + if (decodedVariant.isType()) + { + const auto tmsStruct = static_cast(variant->data); + return StructConverter::ToDaqObject(*tmsStruct); + } + + throw ConversionFailedException(); +} + +template <> +OpcUaVariant VariantConverter::ToVariant(const DataDescriptorPtr& object, + const UA_DataType* targetType, + const ContextPtr& /*context*/) +{ + auto variant = OpcUaVariant(); + + if (targetType ==nullptr || targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_BASEDATADESCRIPTORSTRUCTURE]) + { + if (object.isStructDescriptor()) + variant.setScalar(*StructConverter::ToTmsType(object)); + else + variant.setScalar(*StructConverter::ToTmsType(object)); + } + else if (targetType ==&UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_DATADESCRIPTORSTRUCTURE]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else if (targetType ==&UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_STRUCTDESCRIPTORSTRUCTURE]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else + throw ConversionFailedException{}; + + return variant; +} + +template <> +ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + if (variant.isType()) + return ListConversionUtils::ExtensionObjectVariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + + throw ConversionFailedException{}; +} + +template <> +OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& list, + const UA_DataType* targetType, + const ContextPtr& /*context*/) +{ + if (targetType == nullptr || targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_BASEDATADESCRIPTORSTRUCTURE]) + return ListConversionUtils::ToExtensionObjectArrayVariant(list); + if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_DATADESCRIPTORSTRUCTURE]) + return ListConversionUtils::ToArrayVariant(list); + if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_STRUCTDESCRIPTORSTRUCTURE]) + return ListConversionUtils::ToArrayVariant(list); + + throw ConversionFailedException{}; +} + + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/data_rule_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/data_rule_converter.cpp new file mode 100644 index 0000000..6d9ce81 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/src/converters/data_rule_converter.cpp @@ -0,0 +1,261 @@ +#include +#include "opcuatms/converters/struct_converter.h" +#include "opcuatms/converters/variant_converter.h" +#include "open62541/types_tmsbsp_generated_handling.h" +#include "opcuatms/converters/list_conversion_utils.h" +#include "opcuatms/core_types_utils.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +// Template specializations + +template class VariantConverter; + +// UA_LinearRuleDescription + +template <> +DataRulePtr StructConverter::ToDaqObject(const UA_LinearRuleDescriptionStructure& tmsStruct, + const ContextPtr& /*context*/) +{ + if (tmsStruct.type != "linear") + throw ConversionFailedException(); + + const NumberPtr delta = VariantConverter::ToDaqObject(OpcUaVariant(tmsStruct.delta)); + const NumberPtr start = VariantConverter::ToDaqObject(OpcUaVariant(tmsStruct.start)); + + return LinearDataRule(delta, start); +} + +template <> +OpcUaObject StructConverter::ToTmsType( + const DataRulePtr& object, const ContextPtr& /*context*/) +{ + const NumberPtr delta = object.getParameters().get("delta"); + const NumberPtr start = object.getParameters().get("start"); + + OpcUaObject uaRuleDescription; + + uaRuleDescription->type = UA_STRING_ALLOC("linear"); + uaRuleDescription->delta = VariantConverter::ToVariant(delta).getDetachedValue(); + uaRuleDescription->start = VariantConverter::ToVariant(start).getDetachedValue(); + + return uaRuleDescription; +} + +// UA_ConstantRuleDescription + +template <> +DataRulePtr StructConverter::ToDaqObject( + const UA_ConstantRuleDescriptionStructure& tmsStruct, const ContextPtr& /*context*/) +{ + if (tmsStruct.type != "constant") + throw ConversionFailedException(); + + const NumberPtr value = VariantConverter::ToDaqObject(tmsStruct.value); + return ConstantDataRule(value); +} + +template <> +OpcUaObject StructConverter::ToTmsType( + const DataRulePtr& object, const ContextPtr& /*context*/) +{ + const NumberPtr value = object.getParameters().get("constant"); + OpcUaObject uaRuleDescription; + + uaRuleDescription->type = UA_STRING_ALLOC("constant"); + uaRuleDescription->value = VariantConverter::ToVariant(value).getDetachedValue(); + + return uaRuleDescription; +} + +// UA_BaseRuleDescription + +template <> +DataRulePtr StructConverter::ToDaqObject(const UA_BaseRuleDescriptionStructure& tmsStruct, + const ContextPtr& /*context*/) +{ + if (tmsStruct.type != "explicit") + throw ConversionFailedException(); + + return ExplicitDataRule(); +} + +template <> +OpcUaObject StructConverter::ToTmsType( + const DataRulePtr& object, const ContextPtr& /*context*/) +{ + OpcUaObject uaRuleDescription; + uaRuleDescription->type = UA_STRING_ALLOC("explicit"); + return uaRuleDescription; +} + +// UA_CustomRuleDescription + +template <> +DataRulePtr StructConverter::ToDaqObject(const UA_CustomRuleDescriptionStructure& tmsStruct, + const ContextPtr& context) +{ + if (tmsStruct.type != "custom") + throw ConversionFailedException(); + + auto params = Dict(); + for (size_t i = 0; i < tmsStruct.parametersSize; i++) + { + auto value = OpcUaVariant(tmsStruct.parameters[i].value); + auto key = OpcUaVariant(tmsStruct.parameters[i].key); + if (key.isString()) + { + try + { + params.set(key.toString(), VariantConverter::ToDaqObject(value, context)); + } + catch (...) + { + } + } + } + + return DataRuleBuilder().setType(DataRuleType::Other).setParameters(params).build(); +} + +template <> +OpcUaObject StructConverter::ToTmsType( + const DataRulePtr& object, const ContextPtr& context) +{ + OpcUaObject uaRuleDescription; + uaRuleDescription->type = UA_STRING_ALLOC("custom"); + auto params = object.getParameters(); + + const auto type = GetUaDataType(); + uaRuleDescription->parameters = static_cast(UA_Array_new(params.getCount(), type)); + uaRuleDescription->parametersSize = params.getCount(); + size_t index = 0; + + for (const auto& [name, value] : params) + { + OpcUaObject pair; + pair->key = VariantConverter::ToVariant(name).getDetachedValue(); + pair->value = VariantConverter::ToVariant(value, nullptr, context).getDetachedValue(); + uaRuleDescription->parameters[index] = pair.getDetachedValue(); + + index++; + } + + return uaRuleDescription; +} + +// Variant converters + +template <> +DataRulePtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + const auto decodedVariant = DecodeIfExtensionObject(variant); + + if (decodedVariant.isType()) + { + const auto tmsStruct = static_cast(decodedVariant->data); + return StructConverter::ToDaqObject(*tmsStruct); + } + + if (decodedVariant.isType()) + { + const auto tmsStruct = static_cast(decodedVariant->data); + return StructConverter::ToDaqObject(*tmsStruct); + } + + if (decodedVariant.isType()) + { + const auto tmsStruct = static_cast(decodedVariant->data); + return StructConverter::ToDaqObject(*tmsStruct); + } + + if (decodedVariant.isType()) + { + const auto tmsStruct = static_cast(decodedVariant->data); + return StructConverter::ToDaqObject(*tmsStruct); + } + + throw ConversionFailedException(); +} + +template <> +OpcUaVariant VariantConverter::ToVariant(const DataRulePtr& object, const UA_DataType* targetType, const ContextPtr& /*context*/) +{ + auto variant = OpcUaVariant(); + + if (targetType == nullptr) + { + switch (object.getType()) + { + case DataRuleType::Linear: + { + variant.setScalar(*StructConverter::ToTmsType(object)); + break; + } + case DataRuleType::Constant: + { + variant.setScalar(*StructConverter::ToTmsType(object)); + break; + } + case DataRuleType::Explicit: + { + variant.setScalar(*StructConverter::ToTmsType(object)); + break; + } + case DataRuleType::Other: + { + variant.setScalar(*StructConverter::ToTmsType(object)); + break; + } + } + } + else if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LINEARRULEDESCRIPTIONSTRUCTURE]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_CONSTANTRULEDESCRIPTIONSTRUCTURE]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_BASERULEDESCRIPTIONSTRUCTURE]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_CUSTOMRULEDESCRIPTIONSTRUCTURE]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else + throw ConversionFailedException{}; + + return variant; +} + +template <> +ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + if (variant.isType()) + return ListConversionUtils::ExtensionObjectVariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + + throw ConversionFailedException{}; +} + +template <> +OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& list, + const UA_DataType* targetType, + const ContextPtr& /*context*/) +{ + if (targetType == nullptr) + return ListConversionUtils::ToExtensionObjectArrayVariant(list); + if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LINEARRULEDESCRIPTIONSTRUCTURE]) + return ListConversionUtils::ToArrayVariant(list); + if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_CONSTANTRULEDESCRIPTIONSTRUCTURE]) + return ListConversionUtils::ToArrayVariant(list); + if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_BASERULEDESCRIPTIONSTRUCTURE]) + return ListConversionUtils::ToArrayVariant(list); + if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_CUSTOMRULEDESCRIPTIONSTRUCTURE]) + return ListConversionUtils::ToArrayVariant(list); + throw ConversionFailedException{}; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/dict_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/dict_converter.cpp new file mode 100644 index 0000000..9eb8e79 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/src/converters/dict_converter.cpp @@ -0,0 +1,130 @@ +#include "opcuatms/core_types_utils.h" +#include "opcuatms/converters/list_conversion_utils.h" +#include "opcuatms/converters/variant_converter.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +namespace dict_converter +{ + static OpcUaObject ToKeyValuePair(const BaseObjectPtr& key, const BaseObjectPtr& value, const ContextPtr& context) + { + OpcUaObject pair; + pair->key = VariantConverter::ToVariant(key, nullptr, context).getDetachedValue(); + pair->value = VariantConverter::ToVariant(value, nullptr, context).getDetachedValue(); + return pair; + } + + static DictPtr ExtensionObjectToDict(const OpcUaVariant& variant, const ContextPtr& context) + { + const auto data = static_cast(variant->data); + auto dict = Dict(); + + OpcUaVariant decodedVariant; + OpcUaVariant valueVariant; + OpcUaVariant keyVariant; + + for (size_t i = 0; i < variant->arrayLength; i++) + { + auto extensionObject = ExtensionObject(data[i]); + if (extensionObject.isDecoded()) + decodedVariant = extensionObject.getAsVariant(); + else + throw ConversionFailedException{}; + + if (!decodedVariant.isType()) + throw ConversionFailedException{}; + + const auto decodedData = static_cast(decodedVariant->data); + + keyVariant.setValue(decodedData->key); + const auto key = VariantConverter::ToDaqObject(keyVariant, context); + + valueVariant.setValue(decodedData->value); + const auto value = VariantConverter::ToDaqObject(valueVariant, context); + + dict.set(key, value); + } + + return dict; + } + + static DictPtr DaqKeyValuePairToDict(const OpcUaVariant& variant, const ContextPtr& context) + { + auto dict = Dict(); + OpcUaVariant valueVariant; + OpcUaVariant keyVariant; + const auto data = static_cast(variant->data); + + for (size_t i = 0; i < variant->arrayLength; i++) + { + const UA_DaqKeyValuePair keyValuePairData = data[i]; + + keyVariant.setValue(keyValuePairData.key); + const auto key = VariantConverter::ToDaqObject(keyVariant, context); + + valueVariant.setValue(keyValuePairData.value); + const auto value = VariantConverter::ToDaqObject(valueVariant, context); + + dict.set(key, value); + } + + return dict; + } +} + +template <> +DictPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& context) +{ + if (variant.isScalar()) + throw ConversionFailedException(); + if (variant.isType()) + return dict_converter::ExtensionObjectToDict(variant, context); + if (variant.isType()) + return dict_converter::DaqKeyValuePairToDict(variant, context); + + throw ConversionFailedException(); +} + +template <> +OpcUaVariant VariantConverter::ToVariant(const DictPtr& object, + const UA_DataType* targetType, + const ContextPtr& context) +{ + if (targetType != nullptr && targetType != &UA_TYPES_TMSBT[UA_TYPES_TMSBT_DAQKEYVALUEPAIR]) + throw ConversionFailedException{}; + + auto variant = OpcUaVariant(); + if (object.getCount() == 0) + return variant; + + const auto type = GetUaDataType(); + const auto arr = static_cast(UA_Array_new(object.getCount(), type)); + + int i = 0; + for (auto [key, value] : object) + { + auto tmsStruct = dict_converter::ToKeyValuePair(key, value, context); + arr[i] = tmsStruct.getDetachedValue(); + ++i; + } + + UA_Variant_setArray(variant.get(), arr, object.getCount(), type); + return variant; +} + +template <> +ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + throw ConversionFailedException{}; +} + +template <> +OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& /*list*/, + const UA_DataType* /*targetType*/, + const ContextPtr& /*context*/) +{ + throw ConversionFailedException{}; +} + + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/dimension_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/dimension_converter.cpp new file mode 100644 index 0000000..fea69be --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/src/converters/dimension_converter.cpp @@ -0,0 +1,105 @@ +#include +#include "opcuatms/converters/list_conversion_utils.h" +#include "opcuatms/converters/struct_converter.h" +#include "opcuatms/converters/variant_converter.h" +#include "opcuatms/core_types_utils.h" +#include "opcuatms/extension_object.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +// Template specializations + +template class StructConverter; +template class VariantConverter; + +// UA_DimensionDescriptorStructure + +template <> +DimensionPtr StructConverter::ToDaqObject(const UA_DimensionDescriptorStructure& tmsStruct, + const ContextPtr& /*context*/) +{ + const auto dimension = DimensionBuilder(); + + if (tmsStruct.name) + dimension->setName(ConvertToDaqCoreString(*tmsStruct.name)); + + if (tmsStruct.unit) + dimension->setUnit(StructConverter::ToDaqObject(*tmsStruct.unit)); + + auto ruleObject = ExtensionObject(tmsStruct.dimensionRule); + if (ruleObject.isDecoded()) + dimension->setRule(VariantConverter::ToDaqObject(ruleObject.getAsVariant())); + + return dimension.build(); +} + +template <> +OpcUaObject StructConverter::ToTmsType( + const DimensionPtr& object, const ContextPtr& /*context*/) +{ + OpcUaObject dimension; + + if (object.getName().assigned()) + dimension->name = ConvertToOpcUaString(object.getName()).newDetachedPointer(); + + if (object.getUnit().assigned()) + dimension->unit = StructConverter::ToTmsType(object.getUnit()).newDetachedPointer(); + + if (object.getRule().assigned()) + { + auto ruleObject = ExtensionObject(VariantConverter::ToVariant(object.getRule())); + dimension->dimensionRule = ruleObject.getDetachedValue(); + } + + return dimension; +} + +// Variant converters + +template <> +DimensionPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + const auto decodedVariant = DecodeIfExtensionObject(variant); + + if (!decodedVariant.isType()) + throw ConversionFailedException(); + + const auto tmsStruct = static_cast(decodedVariant->data); + return StructConverter::ToDaqObject(*tmsStruct); +} + +template <> +OpcUaVariant VariantConverter::ToVariant(const DimensionPtr& object, + const UA_DataType* targetType, + const ContextPtr& /*context*/) +{ + auto variant = OpcUaVariant(); + if (targetType == nullptr || targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_DIMENSIONDESCRIPTORSTRUCTURE]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else + throw ConversionFailedException{}; + + return variant; +} + +template <> +ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + if (variant.isType()) + return ListConversionUtils::ExtensionObjectVariantToList(variant); + + return ListConversionUtils::VariantToList(variant); +} + +template <> +OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& list, + const UA_DataType* targetType, + const ContextPtr& /*context*/) +{ + if (targetType == nullptr || targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_DIMENSIONDESCRIPTORSTRUCTURE]) + return ListConversionUtils::ToArrayVariant(list); + + throw ConversionFailedException{}; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/dimension_rule_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/dimension_rule_converter.cpp new file mode 100644 index 0000000..26ab7b8 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/src/converters/dimension_rule_converter.cpp @@ -0,0 +1,298 @@ +#include +#include "opcuatms/core_types_utils.h" +#include "opcuatms/converters/list_conversion_utils.h" +#include "opcuatms/converters/struct_converter.h" +#include "opcuatms/converters/variant_converter.h" +#include "open62541/types_tmsbsp_generated_handling.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +// Template specializations + +template class StructConverter; +template class StructConverter; +template class StructConverter; +template class VariantConverter; + +// UA_LinearRuleDescription + +template <> +DimensionRulePtr StructConverter::ToDaqObject( + const UA_LinearRuleDescriptionStructure& tmsStruct, const ContextPtr& /*context*/) +{ + if (tmsStruct.type != "linear") + throw ConversionFailedException(); + + if (tmsStruct.size == nullptr) + throw ConversionFailedException(); + + const SizeT size = *tmsStruct.size; + const NumberPtr delta = VariantConverter::ToDaqObject(tmsStruct.delta); + const NumberPtr start = VariantConverter::ToDaqObject(tmsStruct.start); + return LinearDimensionRule(delta, start, size); +} + +template <> +OpcUaObject StructConverter::ToTmsType( + const DimensionRulePtr& object, const ContextPtr& /*context*/) +{ + const SizeT size = object.getParameters().get("size"); + const NumberPtr delta = object.getParameters().get("delta"); + const NumberPtr start = object.getParameters().get("start"); + + OpcUaObject uaRuleDescription; + + uaRuleDescription->type = UA_STRING_ALLOC("linear"); + uaRuleDescription->delta = VariantConverter::ToVariant(delta).getDetachedValue(); + uaRuleDescription->start = VariantConverter::ToVariant(start).getDetachedValue(); + uaRuleDescription->size = UA_UInt32_new(); + *uaRuleDescription->size = size; + + return uaRuleDescription; +} + +// UA_LogRuleDescriptionStructure + +template <> +DimensionRulePtr StructConverter::ToDaqObject( + const UA_LogRuleDescriptionStructure& tmsStruct, const ContextPtr& /*context*/) +{ + if (tmsStruct.type != "log") + throw ConversionFailedException(); + + const NumberPtr delta = VariantConverter::ToDaqObject(tmsStruct.delta); + const NumberPtr start = VariantConverter::ToDaqObject(tmsStruct.start); + return LogarithmicDimensionRule(delta, start, tmsStruct.base, tmsStruct.size); +} + +template <> +OpcUaObject StructConverter::ToTmsType( + const DimensionRulePtr& object, const ContextPtr& /*context*/) +{ + const SizeT size = object.getParameters().get("size"); + const NumberPtr delta = object.getParameters().get("delta"); + const NumberPtr start = object.getParameters().get("start"); + const Int base = object.getParameters().get("base"); + + OpcUaObject uaRuleDescription; + + uaRuleDescription->type = UA_STRING_ALLOC("log"); + uaRuleDescription->size = size; + uaRuleDescription->delta = VariantConverter::ToVariant(delta).getDetachedValue(); + uaRuleDescription->start = VariantConverter::ToVariant(start).getDetachedValue(); + uaRuleDescription->base = base; + + return uaRuleDescription; +} + +// UA_ListRuleDescription + +template <> +DimensionRulePtr StructConverter::ToDaqObject( + const UA_ListRuleDescriptionStructure& tmsStruct, const ContextPtr& /*context*/) +{ + if (tmsStruct.type != "list") + throw ConversionFailedException(); + + const SizeT elementsSize = tmsStruct.elementsSize; + if (elementsSize == 0) + throw ConversionFailedException(); + + ListPtr list = List(); + for (SizeT i = 0; i < elementsSize; i++) + { + NumberPtr value = VariantConverter::ToDaqObject(tmsStruct.elements[i]); + list.pushBack(value); + } + + return ListDimensionRule(list); +} + +template <> +OpcUaObject StructConverter::ToTmsType( + const DimensionRulePtr& object, const ContextPtr& /*context*/) +{ + ListPtr daqList = object.getParameters().get("list"); + + OpcUaObject uaRuleDescription; + uaRuleDescription->elementsSize = daqList.getCount(); + uaRuleDescription->elements = static_cast(UA_Array_new(uaRuleDescription->elementsSize, GetUaDataType())); + uaRuleDescription->type = UA_STRING_ALLOC("list"); + + for (SizeT i = 0; i < daqList.getCount(); i++) + uaRuleDescription->elements[i] = VariantConverter::ToVariant(daqList[i]).getDetachedValue(); + + return uaRuleDescription; +} + +template <> +DimensionRulePtr StructConverter::ToDaqObject( + const UA_CustomRuleDescriptionStructure& tmsStruct, const ContextPtr& context) +{ + if (tmsStruct.type != "custom") + throw ConversionFailedException(); + + auto params = Dict(); + for (size_t i = 0; i < tmsStruct.parametersSize; i++) + { + auto value = OpcUaVariant(tmsStruct.parameters[i].value); + auto key = OpcUaVariant(tmsStruct.parameters[i].key); + if (key.isString()) + { + try + { + params.set(key.toString(), VariantConverter::ToDaqObject(value, context)); + } + catch (...) + { + } + } + } + + return DimensionRuleBuilder().setType(DimensionRuleType::Other).setParameters(params).build(); +} + +template <> +OpcUaObject StructConverter::ToTmsType( + const DimensionRulePtr& object, const ContextPtr& context) +{ + OpcUaObject uaRuleDescription; + uaRuleDescription->type = UA_STRING_ALLOC("custom"); + const auto params = object.getParameters(); + + const auto type = GetUaDataType(); + uaRuleDescription->parameters = static_cast(UA_Array_new(params.getCount(), type)); + uaRuleDescription->parametersSize = params.getCount(); + size_t index = 0; + + for (const auto& [name, value] : params) + { + OpcUaObject pair; + pair->key = VariantConverter::ToVariant(name).getDetachedValue(); + pair->value = VariantConverter::ToVariant(value, nullptr, context).getDetachedValue(); + uaRuleDescription->parameters[index] = pair.getDetachedValue(); + + index++; + } + + return uaRuleDescription; +} + +// Variant converter + +template <> +DimensionRulePtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + const auto decodedVariant = DecodeIfExtensionObject(variant); + + if (decodedVariant.isType()) + { + const auto tmsRuleDescription = static_cast(decodedVariant->data); + return StructConverter::ToDaqObject(*tmsRuleDescription); + } + + if (decodedVariant.isType()) + { + const auto tmsRuleDescription = static_cast(decodedVariant->data); + return StructConverter::ToDaqObject(*tmsRuleDescription); + } + + if (decodedVariant.isType()) + { + const auto tmsRuleDescription = static_cast(decodedVariant->data); + return StructConverter::ToDaqObject(*tmsRuleDescription); + } + + if (decodedVariant.isType()) + { + const auto tmsRuleDescription = static_cast(decodedVariant->data); + return StructConverter::ToDaqObject(*tmsRuleDescription); + } + + throw ConversionFailedException(); +} + +template <> +OpcUaVariant VariantConverter::ToVariant(const DimensionRulePtr& object, + const UA_DataType* targetType, + const ContextPtr& /*context*/) +{ + auto variant = OpcUaVariant(); + + if (targetType == nullptr) + { + switch (object.getType()) + { + case DimensionRuleType::Linear: + { + variant.setScalar(*StructConverter::ToTmsType(object)); + break; + } + case DimensionRuleType::Logarithmic: + { + variant.setScalar(*StructConverter::ToTmsType(object)); + break; + } + case DimensionRuleType::List: + { + variant.setScalar(*StructConverter::ToTmsType(object)); + break; + } + case DimensionRuleType::Other: + { + variant.setScalar(*StructConverter::ToTmsType(object)); + break; + } + } + } + else if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LINEARRULEDESCRIPTIONSTRUCTURE]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LOGRULEDESCRIPTIONSTRUCTURE]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LISTRULEDESCRIPTIONSTRUCTURE]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_CUSTOMRULEDESCRIPTIONSTRUCTURE]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else + throw ConversionFailedException{}; + + return variant; +} + +template <> +ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + if (variant.isType()) + return ListConversionUtils::ExtensionObjectVariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + + throw ConversionFailedException{}; +} + +template <> +OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& list, + const UA_DataType* targetType, + const ContextPtr& /*context*/) +{ + if (targetType == nullptr) + return ListConversionUtils::ToExtensionObjectArrayVariant(list); + if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LINEARRULEDESCRIPTIONSTRUCTURE]) + return ListConversionUtils::ToArrayVariant(list); + if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LOGRULEDESCRIPTIONSTRUCTURE]) + return ListConversionUtils::ToArrayVariant(list); + if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LISTRULEDESCRIPTIONSTRUCTURE]) + return ListConversionUtils::ToArrayVariant(list); + if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_CUSTOMRULEDESCRIPTIONSTRUCTURE]) + return ListConversionUtils::ToArrayVariant(list); + + throw ConversionFailedException{}; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/function_block_type_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/function_block_type_converter.cpp new file mode 100644 index 0000000..4324da5 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/src/converters/function_block_type_converter.cpp @@ -0,0 +1,90 @@ +#include +#include +#include "opcuatms/converters/list_conversion_utils.h" +#include "opcuatms/converters/struct_converter.h" +#include "opcuatms/converters/variant_converter.h" +#include "open62541/types_tmsbsp_generated.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +// Template specializations + +template class StructConverter; +template class VariantConverter; + +// UA_FunctionBlockTypeStructure + +template <> +FunctionBlockTypePtr StructConverter::ToDaqObject( + const UA_FunctionBlockInfoStructure& tmsStruct, const ContextPtr& /*context*/) +{ + const StringPtr id(ConvertToDaqCoreString(tmsStruct.id)); + const StringPtr name(ConvertToDaqCoreString(tmsStruct.name)); + const StringPtr description(ConvertToDaqCoreString(tmsStruct.description)); + + return FunctionBlockType(id, name, description); +} + +template <> +OpcUaObject StructConverter::ToTmsType( + const FunctionBlockTypePtr& object, const ContextPtr& /*context*/) +{ + OpcUaObject type; + + type->id = ConvertToOpcUaString(object.getId()).getDetachedValue(); + type->name = ConvertToOpcUaString(object.getName()).getDetachedValue(); + type->description = ConvertToOpcUaString(object.getDescription()).getDetachedValue(); + + return type; +} + +// Variant converter + +template <> +FunctionBlockTypePtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + const auto decodedVariant = DecodeIfExtensionObject(variant); + + if (!decodedVariant.isType()) + throw ConversionFailedException(); + + const auto tmsStruct = static_cast(decodedVariant->data); + return StructConverter::ToDaqObject(*tmsStruct); +} + +template <> +OpcUaVariant VariantConverter::ToVariant(const FunctionBlockTypePtr& object, + const UA_DataType* targetType, + const ContextPtr& /*context*/) +{ + auto variant = OpcUaVariant(); + + if (targetType == nullptr || targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_FUNCTIONBLOCKINFOSTRUCTURE]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else + throw ConversionFailedException{}; + + return variant; +} + +template <> +ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + if (variant.isType()) + return ListConversionUtils::ExtensionObjectVariantToList(variant); + + return ListConversionUtils::VariantToList(variant); +} + +template <> +OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& list, + const UA_DataType* targetType, + const ContextPtr& /*context*/) +{ + if (targetType == nullptr || targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_FUNCTIONBLOCKINFOSTRUCTURE]) + return ListConversionUtils::ToArrayVariant(list); + + throw ConversionFailedException{}; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/generic_struct_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/generic_struct_converter.cpp new file mode 100644 index 0000000..4c0829f --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/src/converters/generic_struct_converter.cpp @@ -0,0 +1,262 @@ +#include "opcuatms/core_types_utils.h" +#include "opcuatms/extension_object.h" +#include "opcuatms/converters/struct_converter.h" +#include "opcuatms/converters/variant_converter.h" +#include "coretypes/struct_factory.h" +#include "coretypes/struct_type_factory.h" +#include "coretypes/simple_type_factory.h" +#include "opcuatms/converters/list_conversion_utils.h" +#include "iostream" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +namespace detail +{ + static TypePtr createType(const BaseObjectPtr& obj) + { + const auto ct = obj.getCoreType(); + if (ct == ctStruct) + return obj.asPtr().getStructType(); + + return SimpleType(ct); + } +} + +template <> +StructPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& context) +{ + if (variant.isNull()) + return nullptr; + + if (!context.assigned() || !context.getTypeManager().assigned()) + throw ConversionFailedException{"Generic struct conversion requires the TypeManager."}; + + const auto typeManager = context.getTypeManager(); + + const auto type = variant->type; + + const UA_DataTypeMember* members = type->members; + const UA_UInt32 membersSize = type->membersSize; + auto src = reinterpret_cast(variant->data); + + DictPtr daqMembers = Dict(); + ListPtr memberTypes = List(); + + for (SizeT i = 0; i < membersSize; ++i) + { + const UA_DataTypeMember* member = &members[i]; + const UA_DataType* memberType = member->memberType; + src += member->padding; + + // TODO: Refactor this + if (!member->isOptional) + { + if (!member->isArray) + { + OpcUaVariant memberVariant{}; + UA_Variant_setScalarCopy(&memberVariant.getValue(), reinterpret_cast(src), memberType); + const auto obj = VariantConverter::ToDaqObject(memberVariant, context); + daqMembers.set(member->memberName, obj); + src += memberType->memSize; + memberTypes.pushBack(detail::createType(obj)); + } + else + { + const size_t size = *reinterpret_cast(src); + src += sizeof(size_t); + OpcUaVariant memberVariant{}; + UA_Variant_setArrayCopy(&memberVariant.getValue(), *reinterpret_cast(src), size, memberType); + + const auto obj = VariantConverter::ToDaqObject(memberVariant, context); + daqMembers.set(member->memberName, obj); + memberTypes.pushBack(detail::createType(obj)); + src += sizeof(void*); + } + } + else + { + if (!member->isArray) + { + if(*reinterpret_cast(src) != nullptr) + { + OpcUaVariant memberVariant{}; + UA_Variant_setScalarCopy(&memberVariant.getValue(), *reinterpret_cast(src), memberType); + + const auto obj = VariantConverter::ToDaqObject(memberVariant, context); + daqMembers.set(member->memberName, obj); + memberTypes.pushBack(detail::createType(obj)); + } + else + { + daqMembers.set(member->memberName, nullptr); + // TODO: Set appropriate type + memberTypes.pushBack(SimpleType(ctUndefined)); + } + } + else + { + if(*reinterpret_cast(src + sizeof(size_t)) != nullptr) + { + const size_t size = *reinterpret_cast(src); + src += sizeof(size_t); + OpcUaVariant memberVariant{}; + UA_Variant_setArrayCopy(&memberVariant.getValue(), reinterpret_cast(src), size, memberType); + + const auto obj = VariantConverter::ToDaqObject(memberVariant, context); + daqMembers.set(member->memberName, obj); + memberTypes.pushBack(detail::createType(obj)); + } + else + { + daqMembers.set(member->memberName, nullptr); + src += sizeof(size_t*); + memberTypes.pushBack(SimpleType(ctUndefined)); + } + } + src += sizeof(void*); + } + } + + if (!typeManager.hasType(type->typeName)) + typeManager.addType(StructType(type->typeName, daqMembers.getKeyList(), memberTypes)); + + return Struct(type->typeName, daqMembers, typeManager); +} + +template <> +OpcUaVariant VariantConverter::ToVariant(const StructPtr& object, const UA_DataType* /*targetType*/, const ContextPtr& context) +{ + const auto type = GetUAStructureDataTypeByName(object.getStructType().getName()); + if (type == nullptr) + throw ConversionFailedException{}; + + const UA_DataTypeMember* members = type->members; + const UA_UInt32 membersSize = type->membersSize; + + void* data = UA_new(type); + const auto daqMembers = object.getAsDictionary(); + + if (membersSize != daqMembers.getCount()) + throw ConversionFailedException{}; + + auto dst = reinterpret_cast(data); + for (SizeT i = 0; i < membersSize; ++i) + { + const UA_DataTypeMember* member = &members[i]; + const UA_DataType* memberType = member->memberType; + + if (!daqMembers.hasKey(member->memberName)) + throw ConversionFailedException{}; + + auto daqMember = daqMembers.get(member->memberName); + dst += member->padding; + + if (!daqMember.assigned()) + { + if (member->isOptional) + { + if (member->isArray) + dst += sizeof(size_t*); + dst += sizeof(void*); + continue; + } + + throw ConversionFailedException{}; + } + + OpcUaVariant variant = VariantConverter::ToVariant(daqMember, memberType, context); + if (variant->type != memberType && !(variant->data == UA_EMPTY_ARRAY_SENTINEL && variant->arrayLength == 0)) + throw ConversionFailedException{}; + + void* src = variant->data; + + if (!member->isArray) + { + if (!member->isOptional) + { + UA_copy(src, reinterpret_cast(dst), memberType); + dst += memberType->memSize; + } + else + { + [[maybe_unused]] + const UA_StatusCode retval = UA_Array_copy(src, 1, reinterpret_cast(dst), memberType); + dst += sizeof(void*); + } + } + else + { + auto *dst_size = reinterpret_cast(dst); + const size_t size = variant->arrayLength; + dst += sizeof(size_t); + const UA_StatusCode retval = UA_Array_copy(src, size, reinterpret_cast(dst), memberType); + if(retval == UA_STATUSCODE_GOOD) + *dst_size = size; + else + *dst_size = 0; + dst += sizeof(void*); + } + } + + OpcUaVariant variant{}; + UA_Variant_setScalar(&variant.getValue(), data, type); + + return variant; +} + +template <> +ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, const ContextPtr& context) +{ + auto list = List(); + auto src = reinterpret_cast(variant->data); + + for (size_t i = 0; i < variant->arrayLength; i++) + { + OpcUaVariant varObj; + UA_Variant_setScalarCopy(&varObj.getValue(), reinterpret_cast(src), variant->type); + + const auto obj = ToDaqObject(varObj, context); + list.pushBack(obj); + src += variant->type->memSize; + } + + return list; +} + +template <> +OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& list, + const UA_DataType* /*targetType*/, + const ContextPtr& context) +{ + if (list.empty()) + { + auto varObj = OpcUaVariant(); + varObj->data = UA_EMPTY_ARRAY_SENTINEL; + return varObj; + } + + auto firstConvertedStruct = ToVariant(list[0], nullptr, context); + auto type = firstConvertedStruct->type; + + auto arr = UA_Array_new(list.getCount(), type); + auto dst = reinterpret_cast(arr); + + UA_copy(firstConvertedStruct->data, reinterpret_cast(dst), firstConvertedStruct->type); + dst += firstConvertedStruct->type->memSize; + + for (SizeT i = 1; i < list.getCount(); i++) + { + auto convertedStruct = ToVariant(list[i], nullptr, context); + if (convertedStruct->type != type) + throw ConversionFailedException{}; + + UA_copy(convertedStruct->data, reinterpret_cast(dst), convertedStruct->type); + dst += convertedStruct->type->memSize; + } + + auto variant = OpcUaVariant(); + UA_Variant_setArray(variant.get(), arr, list.getCount(), type); + return variant; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/number_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/number_converter.cpp new file mode 100644 index 0000000..20be340 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/src/converters/number_converter.cpp @@ -0,0 +1,67 @@ +#include "opcuatms/core_types_utils.h" +#include "opcuatms/converters/struct_converter.h" +#include "opcuatms/converters/variant_converter.h" +#include "opcuatms/converters/list_conversion_utils.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +// Template specializations + +template class VariantConverter; + +// Variant converter + +template <> +NumberPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + const auto decodedVariant = DecodeIfExtensionObject(variant); + + if (decodedVariant.isInteger()) + return VariantConverter::ToDaqObject(decodedVariant); + + if (decodedVariant.isDouble()) + return VariantConverter::ToDaqObject(decodedVariant); + + throw ConversionFailedException(); +} + +template <> +OpcUaVariant VariantConverter::ToVariant(const NumberPtr& object, const UA_DataType* targetType, const ContextPtr& /*context*/) +{ + if (targetType == nullptr) + { + if (object.getCoreType() == ctInt) + return VariantConverter::ToVariant(object.getIntValue()); + + if (object.getCoreType() == ctFloat) + return VariantConverter::ToVariant(object.getFloatValue()); + + throw ConversionFailedException(); + } + + //TODO: Add if statements for target types of int and float + + + throw ConversionFailedException(); +} + +template <> +ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + return ListConversionUtils::ExtensionObjectVariantToList(variant); +} + +template <> +OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& list, + const UA_DataType* targetType, + const ContextPtr& /*context*/) +{ + if (targetType == nullptr) + return ListConversionUtils::ToExtensionObjectArrayVariant(list); + + //TODO: Add if statements for target types of int and float + + throw ConversionFailedException(); +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/range_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/range_converter.cpp new file mode 100644 index 0000000..5176e8b --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/src/converters/range_converter.cpp @@ -0,0 +1,75 @@ +#include + +#include "opcuatms/core_types_utils.h" +#include "opcuatms/converters/list_conversion_utils.h" +#include "opcuatms/converters/struct_converter.h" +#include "opcuatms/converters/variant_converter.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +// Template specializations + +template class StructConverter; +template class VariantConverter; + +// UA_Range + +template <> +RangePtr StructConverter::ToDaqObject(const UA_Range& tmsStruct, const ContextPtr& /*context*/) +{ + return Range(tmsStruct.low, tmsStruct.high); +} + +template <> +OpcUaObject StructConverter::ToTmsType(const RangePtr& object, const ContextPtr& /*context*/) +{ + OpcUaObject range; + range->low = object.getLowValue(); + range->high = object.getHighValue(); + return range; +} + +// Variant converter + +template <> +RangePtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + const auto decodedVariant = DecodeIfExtensionObject(variant); + + if (!decodedVariant.isType()) + throw ConversionFailedException(); + + return StructConverter::ToDaqObject(*static_cast(decodedVariant->data)); +} + +template <> +OpcUaVariant VariantConverter::ToVariant(const RangePtr& object, const UA_DataType* targetType, const ContextPtr& /*context*/) +{ + auto variant = OpcUaVariant(); + + if (targetType == nullptr || targetType == &UA_TYPES[UA_TYPES_RANGE]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else + throw ConversionFailedException{}; + + return variant; +} + +template <> +ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + return ListConversionUtils::VariantToList(variant); +} + +template <> +OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& list, + const UA_DataType* targetType, + const ContextPtr& /*context*/) +{ + if (targetType == nullptr || targetType == &UA_TYPES[UA_TYPES_RANGE]) + return ListConversionUtils::ToArrayVariant(list); + + throw ConversionFailedException{}; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/ratio_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/ratio_converter.cpp new file mode 100644 index 0000000..84255fa --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/src/converters/ratio_converter.cpp @@ -0,0 +1,116 @@ +#include + +#include "opcuatms/core_types_utils.h" +#include "opcuatms/converters/struct_converter.h" +#include "opcuatms/converters/variant_converter.h" +#include "opcuatms/converters/list_conversion_utils.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +// Template specializations + +template class StructConverter; +template class StructConverter; +template class VariantConverter; + + +// UA_RationalNumber + +template <> +RatioPtr StructConverter::ToDaqObject(const UA_RationalNumber& tmsStruct, const ContextPtr& /*context*/) +{ + return Ratio(tmsStruct.numerator, tmsStruct.denominator); +} + +template <> +OpcUaObject StructConverter::ToTmsType(const RatioPtr& object, const ContextPtr& /*context*/) +{ + OpcUaObject ratio; + ratio->numerator = object.getNumerator(); + ratio->denominator = object.getDenominator(); + return ratio; +} + +// UA_RationalNumber64 + +template <> +RatioPtr StructConverter::ToDaqObject(const UA_RationalNumber64& tmsStruct, const ContextPtr& /*context*/) +{ + return Ratio(tmsStruct.numerator, tmsStruct.denominator); +} + +template <> +OpcUaObject StructConverter::ToTmsType(const RatioPtr& object, + const ContextPtr& /*context*/) +{ + OpcUaObject ratio; + ratio->numerator = object.getNumerator(); + ratio->denominator = object.getDenominator(); + return ratio; +} + +// Variant converter + +template <> +RatioPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + const auto decodedVariant = DecodeIfExtensionObject(variant); + + if (decodedVariant.isType()) + { + const auto tmsStruct = static_cast(decodedVariant->data); + return StructConverter::ToDaqObject(*tmsStruct); + } + + + if (decodedVariant.isType()) + { + const auto tmsStruct = static_cast(decodedVariant->data); + return StructConverter::ToDaqObject(*tmsStruct); + } + + throw ConversionFailedException(); +} + +template <> +OpcUaVariant VariantConverter::ToVariant(const RatioPtr& object, const UA_DataType* targetType, const ContextPtr& /*context*/) +{ + auto variant = OpcUaVariant(); + + if (targetType == nullptr || targetType == &UA_TYPES_TMSBT[UA_TYPES_TMSBT_RATIONALNUMBER64]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else if (targetType == &UA_TYPES[UA_TYPES_RATIONALNUMBER]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else + throw ConversionFailedException{}; + + return variant; +} + +template <> +ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + if (variant.isType()) + return ListConversionUtils::ExtensionObjectVariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + + throw ConversionFailedException{}; +} + +template <> +OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& list, + const UA_DataType* targetType, + const ContextPtr& /*context*/) +{ + if (targetType == nullptr || targetType == &UA_TYPES_TMSBT[UA_TYPES_TMSBT_RATIONALNUMBER64]) + return ListConversionUtils::ToArrayVariant(list); + if (targetType == &UA_TYPES[UA_TYPES_RATIONALNUMBER]) + return ListConversionUtils::ToArrayVariant(list); + + throw ConversionFailedException{}; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/scaling_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/scaling_converter.cpp new file mode 100644 index 0000000..69115e4 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/src/converters/scaling_converter.cpp @@ -0,0 +1,170 @@ +#include +#include "opcuatms/converters/struct_converter.h" +#include "opcuatms/converters/variant_converter.h" +#include "open62541/types_tmsbsp_generated_handling.h" +#include "opcuatms/core_types_utils.h" +#include "opcuatms/extension_object.h" +#include "opcuatms/converters/list_conversion_utils.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +// Definitions + +template class StructConverter; +template class StructConverter; +template class VariantConverter; + +template <> +ScalingPtr StructConverter::ToDaqObject( + const UA_LinearScalingDescriptionStructure& tmsStruct, const ContextPtr& /*context*/); +template <> +OpcUaObject StructConverter::ToTmsType( + const ScalingPtr& object, const ContextPtr& /*context*/); +template <> +ScalingPtr StructConverter::ToDaqObject(const UA_PostScalingStructure& tmsStruct, + const ContextPtr& /*context*/); +template <> +OpcUaObject StructConverter::ToTmsType(const ScalingPtr& object, + const ContextPtr& /*context*/); +template <> +ScalingPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& /*context*/); +template <> +OpcUaVariant VariantConverter::ToVariant(const ScalingPtr& object, const UA_DataType* targetType, const ContextPtr& /*context*/); + +// UA_LinearScalingDescription + +template <> +ScalingPtr StructConverter::ToDaqObject( + const UA_LinearScalingDescriptionStructure& tmsStruct, const ContextPtr& /*context*/) +{ + auto scale = VariantConverter::ToDaqObject(tmsStruct.scale); + auto offset = VariantConverter::ToDaqObject(tmsStruct.offset); + return LinearScaling(scale, offset); +} + +template <> +OpcUaObject StructConverter::ToTmsType( + const ScalingPtr& object, const ContextPtr& /*context*/) +{ + if (object.getType() != ScalingType::Linear) + throw ConversionFailedException(); + + OpcUaObject scaling; + scaling->type = UA_STRING_ALLOC("linear"); + + auto scale = object.getParameters().get("scale"); + scaling->scale = VariantConverter::ToVariant(scale).getDetachedValue(); + + auto offset = object.getParameters().get("offset"); + scaling->offset = VariantConverter::ToVariant(offset).getDetachedValue(); + + return scaling; +} + +// UA_PostScalingStructure + +template <> +ScalingPtr StructConverter::ToDaqObject(const UA_PostScalingStructure& tmsStruct, + const ContextPtr& /*context*/) +{ + auto scalingObject = ExtensionObject(tmsStruct.scalingDescription); + const auto scalingVariant = scalingObject.getAsVariant(); + const auto scaling = VariantConverter::ToDaqObject(scalingVariant); + + auto postScaling = ScalingBuilderCopy(scaling) + .setInputDataType(SampleTypeFromTmsEnum(tmsStruct.inputSampleType)) + .setOutputDataType(ScaledSampleTypeFromTmsEnum(tmsStruct.outputSampleType)) + .build(); + return postScaling; +} + +template <> +OpcUaObject StructConverter::ToTmsType(const ScalingPtr& object, + const ContextPtr& /*context*/) +{ + OpcUaObject uaPostScaling; + uaPostScaling->inputSampleType = SampleTypeToTmsEnum(object.getInputSampleType()); + uaPostScaling->outputSampleType = ScaledSampleTypeToTmsEnum(object.getOutputSampleType()); + + OpcUaObject uaLinearScalingDescription; + const NumberPtr scale = object.getParameters().get("scale"); + const NumberPtr offset = object.getParameters().get("offset"); + + uaLinearScalingDescription->type = UA_STRING_ALLOC("linear"); + uaLinearScalingDescription->scale = VariantConverter::ToVariant(scale).getDetachedValue(); + uaLinearScalingDescription->offset = VariantConverter::ToVariant(offset).getDetachedValue(); + + uaPostScaling->scalingDescription.encoding = UA_EXTENSIONOBJECT_DECODED; + uaPostScaling->scalingDescription.content.decoded.type = &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LINEARSCALINGDESCRIPTIONSTRUCTURE]; + + const auto uaLinearScalingDescriptionPtr = UA_LinearScalingDescriptionStructure_new(); + *uaLinearScalingDescriptionPtr = uaLinearScalingDescription.getDetachedValue(); + uaPostScaling->scalingDescription.content.decoded.data = uaLinearScalingDescriptionPtr; + + return uaPostScaling; +} + +// Variant converters + +template <> +ScalingPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + const auto decodedVariant = DecodeIfExtensionObject(variant); + + if (decodedVariant.isType()) + { + const auto tmsStruct = static_cast(decodedVariant->data); + return StructConverter::ToDaqObject(*tmsStruct); + } + + if (decodedVariant.isType()) + { + const auto tmsStruct = static_cast(decodedVariant->data); + return StructConverter::ToDaqObject(*tmsStruct); + } + + throw ConversionFailedException(); +} + +template <> +OpcUaVariant VariantConverter::ToVariant(const ScalingPtr& object, const UA_DataType* targetType, const ContextPtr& /*context*/) +{ + auto variant = OpcUaVariant(); + + if (targetType == nullptr || targetType ==&UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_POSTSCALINGSTRUCTURE]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LINEARSCALINGDESCRIPTIONSTRUCTURE]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else + throw ConversionFailedException{}; + + return variant; +} + +template <> +ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + if (variant.isType()) + return ListConversionUtils::ExtensionObjectVariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + + throw ConversionFailedException{}; +} + +template <> +OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& list, + const UA_DataType* targetType, + const ContextPtr& /*context*/) +{ + if (targetType == nullptr || targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_POSTSCALINGSTRUCTURE]) + return ListConversionUtils::ToArrayVariant(list); + if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LINEARSCALINGDESCRIPTIONSTRUCTURE]) + return ListConversionUtils::ToArrayVariant(list); + + throw ConversionFailedException{}; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/selection_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/selection_converter.cpp new file mode 100644 index 0000000..382d149 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/src/converters/selection_converter.cpp @@ -0,0 +1,112 @@ +#include "opcuatms/converters/selection_converter.h" +#include "opcuatms/extension_object.h" +#include "opcuatms/converters/variant_converter.h" +#include "opcuatms/converters/struct_converter.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +BaseObjectPtr SelectionVariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& context) +{ + if (!variant.isType()) + throw ConversionFailedException(); + + auto data = static_cast(variant->data); + auto dict = Dict(); + + OpcUaVariant decodedVariant; + OpcUaVariant valueVariant; + bool isDictionary = false; + + for (size_t i = 0; i < variant->arrayLength; i++) + { + auto extensionObject = ExtensionObject(data[i]); + if (extensionObject.isDecoded()) + decodedVariant = extensionObject.getAsVariant(); + else + throw ConversionFailedException{}; + + if (!decodedVariant.isType()) + throw ConversionFailedException{}; + + const auto decodedData = static_cast(decodedVariant->data); + + const auto key = StructConverter::ToDaqObject(decodedData->key); + valueVariant.setValue(decodedData->value); + const auto value = VariantConverter::ToDaqObject(valueVariant, context); + + isDictionary = isDictionary || !(static_cast(i) == key); + dict.set(key, value); + } + + if (isDictionary) + return dict; + return dict.getValueList(); +} + +OpcUaVariant SelectionVariantConverter::ToVariant(const BaseObjectPtr& selectionValues, const ContextPtr& context) +{ + if (!selectionValues.assigned()) + throw ConversionFailedException{}; + + const auto list = selectionValues.asPtrOrNull(); + if (list.assigned()) + return ListToVariant(list, context); + + const auto dict = selectionValues.asPtrOrNull(); + if (dict.assigned()) + return DictToVariant(dict, context); + + throw ConversionFailedException{}; +} + +OpcUaObject SelectionVariantConverter::ToKeyValuePair(const IntegerPtr& key, + const BaseObjectPtr& value, + const ContextPtr& context) +{ + OpcUaObject pair; + pair->key = key; + pair->value = VariantConverter::ToVariant(value, nullptr, context).getDetachedValue(); + return pair; +} + +OpcUaVariant SelectionVariantConverter::ListToVariant(const ListPtr& selectionValues, const ContextPtr& context) +{ + auto variant = OpcUaVariant(); + if (selectionValues.getCount() == 0) + return variant; + + const auto type = GetUaDataType(); + const auto arr = static_cast(UA_Array_new(selectionValues.getCount(), type)); + + for (SizeT i = 0; i < selectionValues.getCount(); ++i) + { + auto tmsStruct = ToKeyValuePair(i, selectionValues[i], context); + arr[i] = tmsStruct.getDetachedValue(); + } + + UA_Variant_setArray(variant.get(), arr, selectionValues.getCount(), type); + return variant; +} + +OpcUaVariant SelectionVariantConverter::DictToVariant(const DictPtr& selectionValues, const ContextPtr& context) +{ + auto variant = OpcUaVariant(); + if (selectionValues.getCount() == 0) + return variant; + + const auto type = GetUaDataType(); + const auto arr = static_cast(UA_Array_new(selectionValues.getCount(), type)); + + int i = 0; + for (auto [key, value] : selectionValues) + { + auto tmsStruct = ToKeyValuePair(key, value, context); + arr[i] = tmsStruct.getDetachedValue(); + ++i; + } + + UA_Variant_setArray(variant.get(), arr, selectionValues.getCount(), type); + return variant; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/unit_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/unit_converter.cpp new file mode 100644 index 0000000..f730768 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/src/converters/unit_converter.cpp @@ -0,0 +1,123 @@ +#include +#include +#include "opcuatms/converters/list_conversion_utils.h" +#include "opcuatms/converters/struct_converter.h" +#include "opcuatms/converters/variant_converter.h" +#include "open62541/types_tmsbsp_generated.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +// Template specializations + +template class StructConverter; +template class StructConverter; +template class VariantConverter; + +// UA_EUInformationWithQuantity + +template <> +UnitPtr StructConverter::ToDaqObject(const UA_EUInformationWithQuantity& tmsStruct, + const ContextPtr& /*context*/) +{ + const StringPtr displayName(ConvertToDaqCoreString(tmsStruct.displayName.text)); + const StringPtr description(ConvertToDaqCoreString(tmsStruct.description.text)); + const StringPtr quantity(ConvertToDaqCoreString(tmsStruct.quantity)); + + return Unit(displayName, tmsStruct.unitId, description, quantity); +} + +template <> +OpcUaObject StructConverter::ToTmsType(const UnitPtr& object, + const ContextPtr& /*context*/) +{ + OpcUaObject tmsUnit; + + tmsUnit->unitId = object.getId(); + tmsUnit->description = UA_LOCALIZEDTEXT_ALLOC("en-US", object.getName().getCharPtr()); + tmsUnit->displayName = UA_LOCALIZEDTEXT_ALLOC("en-US", object.getSymbol().getCharPtr()); + tmsUnit->quantity = ConvertToOpcUaString(object.getQuantity()).getDetachedValue(); + + return tmsUnit; +} + +// UA_EUInformation + +template <> +UnitPtr StructConverter::ToDaqObject(const UA_EUInformation& tmsStruct, const ContextPtr& /*context*/) +{ + const StringPtr displayName(ConvertToDaqCoreString(tmsStruct.displayName.text)); + const StringPtr description(ConvertToDaqCoreString(tmsStruct.description.text)); + + return Unit(displayName, tmsStruct.unitId, description, ""); +} + +template <> +OpcUaObject StructConverter::ToTmsType(const UnitPtr& object, const ContextPtr& /*context*/) +{ + OpcUaObject tmsUnit; + + tmsUnit->unitId = object.getId(); + tmsUnit->description = UA_LOCALIZEDTEXT_ALLOC("en-US", object.getName().getCharPtr()); + tmsUnit->displayName = UA_LOCALIZEDTEXT_ALLOC("en-US", object.getSymbol().getCharPtr()); + + return tmsUnit; +} + +// Variant converter + +template <> +UnitPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + const auto decodedVariant = DecodeIfExtensionObject(variant); + + if (decodedVariant.isType()) + return StructConverter::ToDaqObject(*static_cast(decodedVariant->data)); + + if (decodedVariant.isType()) + return StructConverter::ToDaqObject(*static_cast(decodedVariant->data)); + + throw ConversionFailedException(); +} + +template <> +OpcUaVariant VariantConverter::ToVariant(const UnitPtr& object, const UA_DataType* targetType, const ContextPtr& /*context*/) +{ + auto variant = OpcUaVariant(); + + if (targetType == nullptr || targetType == &UA_TYPES_TMSBT[UA_TYPES_TMSBT_EUINFORMATIONWITHQUANTITY]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else if (targetType == &UA_TYPES[UA_TYPES_EUINFORMATION]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else + throw ConversionFailedException{}; + + return variant; +} + +template <> +ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + if (variant.isType()) + return ListConversionUtils::ExtensionObjectVariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + + throw ConversionFailedException{}; +} + +template <> +OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& list, + const UA_DataType* targetType, + const ContextPtr& /*context*/) +{ + if (targetType == nullptr || targetType == &UA_TYPES_TMSBT[UA_TYPES_TMSBT_EUINFORMATIONWITHQUANTITY]) + return ListConversionUtils::ToArrayVariant(list); + if (targetType == &UA_TYPES[UA_TYPES_EUINFORMATION]) + return ListConversionUtils::ToArrayVariant(list); + + throw ConversionFailedException{}; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp b/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp new file mode 100644 index 0000000..3ccf818 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp @@ -0,0 +1,265 @@ +#include + +#include "opcuashared/opcuadatatypearraylist.h" +#include "opcuatms/extension_object.h" +#include "open62541/nodeids.h" +#include "open62541/tmsbt_nodeids.h" +#include "open62541/types_di_generated.h" +#include "open62541/types_tmsesp_generated.h" + +using namespace daq::opcua; +using namespace daq; +using namespace daq::opcua; + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +namespace details +{ + static std::unordered_map nodeIdToCoreTypeMap = { + {OpcUaNodeId(0, UA_NS0ID_BOOLEAN), ctBool}, + {OpcUaNodeId(0, UA_NS0ID_FLOAT), ctFloat}, + {OpcUaNodeId(0, UA_NS0ID_DOUBLE), ctFloat}, + {OpcUaNodeId(0, UA_NS0ID_SBYTE), ctInt}, + {OpcUaNodeId(0, UA_NS0ID_BYTE), ctInt}, + {OpcUaNodeId(0, UA_NS0ID_INT16), ctInt}, + {OpcUaNodeId(0, UA_NS0ID_UINT16), ctInt}, + {OpcUaNodeId(0, UA_NS0ID_INT32), ctInt}, + {OpcUaNodeId(0, UA_NS0ID_UINT32), ctInt}, + {OpcUaNodeId(0, UA_NS0ID_INT64), ctInt}, + {OpcUaNodeId(0, UA_NS0ID_UINT64), ctInt}, + {OpcUaNodeId(0, UA_NS0ID_STRING), ctString}, + {OpcUaNodeId(0, UA_NS0ID_RATIONALNUMBER), ctRatio}, + {OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_RATIONALNUMBER64), ctRatio}, + {OpcUaNodeId(0, UA_TMSBTID_RATIONALNUMBER64), ctRatio} + }; +} + +StringPtr ConvertToDaqCoreString(const UA_String& uaString) +{ + if (uaString.length == 0 && uaString.data == nullptr) + return nullptr; + return String(reinterpret_cast(uaString.data), uaString.length); +} + +OpcUaObject ConvertToOpcUaString(const StringPtr& str) +{ + if (str.assigned()) + return OpcUaObject(UA_STRING_ALLOC(str.getCharPtr())); + return {}; +} + +BinaryDataPtr CreateCoreBinaryDataFromUaByteString(const UA_ByteString& uaByteString) +{ + if (uaByteString.length == 0 && uaByteString.data == nullptr) + return nullptr; + return BinaryData(reinterpret_cast(uaByteString.data), uaByteString.length); +} + +OpcUaObject CreateUaByteStringFromCoreBinaryData(const BinaryDataPtr& binaryData) +{ + OpcUaObject byteString; + byteString->data = (uint8_t*) UA_malloc(binaryData.getSize()); + byteString->length = binaryData.getSize(); + memcpy(byteString->data, binaryData.getAddress(), binaryData.getSize()); + return OpcUaObject(byteString); +} + +SampleType SampleTypeFromTmsEnum(UA_SampleTypeEnumeration tmsEnum) +{ + switch (tmsEnum) + { + case UA_SAMPLETYPEENUMERATION_INVALID: + return SampleType::Invalid; + case UA_SAMPLETYPEENUMERATION_FLOAT32: + return SampleType::Float32; + case UA_SAMPLETYPEENUMERATION_FLOAT64: + return SampleType::Float64; + case UA_SAMPLETYPEENUMERATION_UINT8: + return SampleType::UInt8; + case UA_SAMPLETYPEENUMERATION_INT8: + return SampleType::Int8; + case UA_SAMPLETYPEENUMERATION_UINT16: + return SampleType::UInt16; + case UA_SAMPLETYPEENUMERATION_INT16: + return SampleType::Int16; + case UA_SAMPLETYPEENUMERATION_UINT32: + return SampleType::UInt32; + case UA_SAMPLETYPEENUMERATION_INT32: + return SampleType::Int32; + case UA_SAMPLETYPEENUMERATION_UINT64: + return SampleType::UInt64; + case UA_SAMPLETYPEENUMERATION_INT64: + return SampleType::Int64; + case UA_SAMPLETYPEENUMERATION_COMPLEXFLOAT32: + return SampleType::ComplexFloat32; + case UA_SAMPLETYPEENUMERATION_COMPLEXFLOAT64: + return SampleType::ComplexFloat64; + case UA_SAMPLETYPEENUMERATION_BINARY: + return SampleType::Binary; + case UA_SAMPLETYPEENUMERATION_STRING: + return SampleType::String; + case UA_SAMPLETYPEENUMERATION_RANGEINT64: + return SampleType::RangeInt64; + default: + throw ConversionFailedException(); + } +} + +UA_SampleTypeEnumeration SampleTypeToTmsEnum(SampleType daqEnum) +{ + switch (daqEnum) + { + case SampleType::Invalid: + return UA_SAMPLETYPEENUMERATION_INVALID; + case SampleType::Float32: + return UA_SAMPLETYPEENUMERATION_FLOAT32; + case SampleType::Float64: + return UA_SAMPLETYPEENUMERATION_FLOAT64; + case SampleType::UInt8: + return UA_SAMPLETYPEENUMERATION_UINT8; + case SampleType::Int8: + return UA_SAMPLETYPEENUMERATION_INT8; + case SampleType::UInt16: + return UA_SAMPLETYPEENUMERATION_UINT16; + case SampleType::Int16: + return UA_SAMPLETYPEENUMERATION_INT16; + case SampleType::UInt32: + return UA_SAMPLETYPEENUMERATION_UINT32; + case SampleType::Int32: + return UA_SAMPLETYPEENUMERATION_INT32; + case SampleType::UInt64: + return UA_SAMPLETYPEENUMERATION_UINT64; + case SampleType::Int64: + return UA_SAMPLETYPEENUMERATION_INT64; + case SampleType::ComplexFloat32: + return UA_SAMPLETYPEENUMERATION_COMPLEXFLOAT32; + case SampleType::ComplexFloat64: + return UA_SAMPLETYPEENUMERATION_COMPLEXFLOAT64; + case SampleType::Binary: + return UA_SAMPLETYPEENUMERATION_BINARY; + case SampleType::String: + return UA_SAMPLETYPEENUMERATION_STRING; + case SampleType::RangeInt64: + return UA_SAMPLETYPEENUMERATION_RANGEINT64; + default: + throw ConversionFailedException(); + } +} + + +ScaledSampleType ScaledSampleTypeFromTmsEnum(UA_SampleTypeEnumeration tmsEnum) +{ + switch (tmsEnum) + { + case UA_SAMPLETYPEENUMERATION_FLOAT32: + return ScaledSampleType::Float32; + case UA_SAMPLETYPEENUMERATION_FLOAT64: + return ScaledSampleType::Float64; + default: + throw ConversionFailedException(); + } +} + +UA_SampleTypeEnumeration ScaledSampleTypeToTmsEnum(ScaledSampleType daqEnum) +{ + switch (daqEnum) + { + case ScaledSampleType::Float32: + return UA_SAMPLETYPEENUMERATION_FLOAT32; + case ScaledSampleType::Float64: + return UA_SAMPLETYPEENUMERATION_FLOAT64; + default: + throw ConversionFailedException(); + } +} + +OpcUaNodeId CoreTypeToUANodeID(CoreType type) +{ + switch(type) + { + case ctBool: + return OpcUaNodeId(0, UA_NS0ID_BOOLEAN); + case ctInt: + return OpcUaNodeId(0, UA_NS0ID_INT64); + case ctFloat: + return OpcUaNodeId(0, UA_NS0ID_DOUBLE); + case ctString: + return OpcUaNodeId(0, UA_NS0ID_STRING); + case ctRatio: + return OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_RATIONALNUMBER64); + case ctProc: + case ctList: + case ctDict: + case ctObject: + case ctBinaryData: + case ctFunc: + case ctComplexNumber: + case ctUndefined: + default: + throw ConversionFailedException{"Mapping between core type and node id is not available"}; + } +} + +CoreType UANodeIdToCoreType(OpcUaNodeId nodeId) +{ + if (const auto it = details::nodeIdToCoreTypeMap.find(nodeId); it != details::nodeIdToCoreTypeMap.cend()) + return it->second; + throw ConversionFailedException{"Mapping between node id and core type is not available."}; +} + +OpcUaVariant DecodeIfExtensionObject(const OpcUaVariant& variant) +{ + if (variant.isType()) + { + const auto data = (UA_ExtensionObject*) variant->data; + auto extensionObject = tms::ExtensionObject(data[0]); + if (extensionObject.isDecoded()) + return extensionObject.getAsVariant(); + + throw ConversionFailedException(); + } + + return variant; +} + +OpcUaVariant UnwrapIfVariant(const OpcUaVariant& variant) +{ + if (variant.isType()) + { + const auto data = (UA_Variant*) variant->data; + return OpcUaVariant(data[0]); + } + + return variant; +} + +const UA_DataType* GetUAStructureDataTypeByName(const std::string& structName) +{ + // TODO: Create static list, add any custom types added automatically. + OpcUaDataTypeArrayList typeArr; + typeArr.add(UA_TYPES_COUNT, UA_TYPES); + typeArr.add(UA_TYPES_DI_COUNT, UA_TYPES_DI); + typeArr.add(UA_TYPES_TMSBT_COUNT, UA_TYPES_TMSBT); + typeArr.add(UA_TYPES_TMSBSP_COUNT, UA_TYPES_TMSBSP); + typeArr.add(UA_TYPES_TMSDEVICE_COUNT, UA_TYPES_TMSDEVICE); + typeArr.add(UA_TYPES_TMSESP_COUNT, UA_TYPES_TMSESP); + + const UA_DataTypeArray* dataType = typeArr.getCustomDataTypes(); + while(dataType) + { + for(size_t i = 0; i < dataType->typesSize; ++i) + { + if (dataType->types[i].typeName == structName) + { + const auto typeKind = dataType->types[i].typeKind; + if (typeKind == UA_DATATYPEKIND_STRUCTURE || typeKind == UA_DATATYPEKIND_OPTSTRUCT) + return &dataType->types[i]; + } + } + dataType = dataType->next; + } + + return nullptr; +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcuatms/opcuatms/src/extension_object.cpp b/shared/libraries/opcuatms/opcuatms/src/extension_object.cpp new file mode 100644 index 0000000..df072ec --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/src/extension_object.cpp @@ -0,0 +1,55 @@ +#include "opcuatms/extension_object.h" +#include "opcuatms/converters/variant_converter.h" +#include +#include "opcuatms/exceptions.h" +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace daq::opcua; + +ExtensionObject::ExtensionObject() + : Super() +{ +} + +ExtensionObject::ExtensionObject(const OpcUaObject& extensionObject) + : Super(extensionObject) +{ +} + +ExtensionObject::ExtensionObject(const daq::opcua::OpcUaVariant& variant) + : Super() +{ + this->setFromVariant(variant); +} + +void ExtensionObject::setFromVariant(const daq::opcua::OpcUaVariant& variant) +{ + + if (variant.isNull()) + UA_ExtensionObject_clear(&value); + else + UA_ExtensionObject_setValueCopy(&value, variant->data, variant->type); +} + +daq::opcua::OpcUaVariant ExtensionObject::getAsVariant() +{ + if (!isDecoded()) + throw OpcUaObjectNotDecodedException(); + + this->markDetached(true); + auto variant = OpcUaVariant(); + variant->data = this->value.content.decoded.data; + variant->type = this->value.content.decoded.type; + return variant; +} + +bool ExtensionObject::isDecoded() const +{ + return this->value.encoding == UA_EXTENSIONOBJECT_DECODED || this->value.encoding == UA_EXTENSIONOBJECT_DECODED_NODELETE; +} + + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/tests/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms/tests/CMakeLists.txt new file mode 100644 index 0000000..4c941d8 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/tests/CMakeLists.txt @@ -0,0 +1,29 @@ +set(MODULE_NAME opcuatms) +set(TEST_APP test_${MODULE_NAME}) + +set(TEST_SOURCES test_core_types_utils.cpp + test_exception.cpp + test_variant_converter.cpp + test_variant_list_converter.cpp + test_extension_object.cpp + test_generic_struct_converter.cpp +) + +add_executable(${TEST_APP} testapp.cpp + ${TEST_SOURCES} +) + +set_target_properties(${TEST_APP} PROPERTIES DEBUG_POSTFIX _debug) + +target_link_libraries(${TEST_APP} PRIVATE ${SDK_TARGET_NAMESPACE}::${MODULE_NAME} + daq::test_utils +) + +add_test(NAME ${TEST_APP} + COMMAND $ + WORKING_DIRECTORY bin +) + +if (OPENDAQ_ENABLE_COVERAGE) + setup_target_for_coverage(${MODULE_NAME}coverage ${TEST_APP} ${MODULE_NAME}coverage) +endif() diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_core_types_utils.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_core_types_utils.cpp new file mode 100644 index 0000000..5848583 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/tests/test_core_types_utils.cpp @@ -0,0 +1,63 @@ +#include +#include +#include + +using CoreTypesUtilsTest = testing::Test; + +using namespace daq; +using namespace daq::opcua; +using namespace daq::opcua; + +TEST_F(CoreTypesUtilsTest, ConvertToDaqCoreString) +{ + UA_String testString = UA_String_fromChars("test"); + StringPtr rtString = ConvertToDaqCoreString(testString); + ASSERT_EQ(rtString.toStdString(), "test"); + + UA_String_clear(&testString); +} + +TEST_F(CoreTypesUtilsTest, ConvertToDaqCoreStringNull) +{ + UA_String testString = UA_STRING_NULL; + StringPtr rtString = ConvertToDaqCoreString(testString); + ASSERT_FALSE(rtString.assigned()); + + UA_String_clear(&testString); +} + +TEST_F(CoreTypesUtilsTest, ConvertToDaqCoreStringEmpty) +{ + UA_String testString = UA_String_fromChars(""); + StringPtr rtString = ConvertToDaqCoreString(testString); + ASSERT_EQ(rtString.toStdString(), ""); + + UA_String_clear(&testString); +} + +TEST_F(CoreTypesUtilsTest, ConvertToOpcUaString) +{ + StringPtr rtString = "test"; + + OpcUaObject str = ConvertToOpcUaString(rtString); + rtString.release(); + + ASSERT_TRUE(*str == "test"); +} + +TEST_F(CoreTypesUtilsTest, ConvertToOpcUaStringNull) +{ + StringPtr rtString; + + OpcUaObject str = ConvertToOpcUaString(rtString); + rtString.release(); + + ASSERT_TRUE(*str == UA_STRING_NULL); +} + +TEST_F(CoreTypesUtilsTest, SampleTypeConverter) +{ + ASSERT_EQ(SampleTypeFromTmsEnum(SampleTypeToTmsEnum(SampleType::Int32)), SampleType::Int32); + ASSERT_EQ(SampleTypeFromTmsEnum(SampleTypeToTmsEnum(SampleType::Int64)), SampleType::Int64); + ASSERT_EQ(SampleTypeFromTmsEnum(SampleTypeToTmsEnum(SampleType::UInt64)), SampleType::UInt64); +} diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_exception.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_exception.cpp new file mode 100644 index 0000000..215bc9a --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/tests/test_exception.cpp @@ -0,0 +1,13 @@ +#include +#include + +using ExceptionTest = testing::Test; + +using namespace daq; +using namespace daq::opcua; + +TEST_F(ExceptionTest, ThrowException) +{ + EXPECT_THROW(throw OpcUaGeneralException(), OpcUaGeneralException); + EXPECT_THROW(throwExceptionFromErrorCode(OPENDAQ_ERR_OPCUA_GENERAL), OpcUaGeneralException); +} diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_extension_object.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_extension_object.cpp new file mode 100644 index 0000000..33e1678 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/tests/test_extension_object.cpp @@ -0,0 +1,63 @@ +#include "gtest/gtest.h" +#include "opcuatms/extension_object.h" +#include +#include "opcuashared/opcuaobject.h" +#include "opcuatms/converters/variant_converter.h" + +using ExtensionObjectTest = testing::Test; + +using namespace daq; +using namespace daq::opcua; +using namespace daq::opcua::tms; +using namespace daq::opcua; + +TEST_F(ExtensionObjectTest, IsDecoded) +{ + const RangePtr range = Range(0, 10); + const auto variant = VariantConverter::ToVariant(range); + + ExtensionObject eo(variant); + ASSERT_TRUE(eo.isDecoded()); +} + +TEST_F(ExtensionObjectTest, IsType) +{ + const RangePtr range = Range(0, 10); + auto variant = VariantConverter::ToVariant(range); + + ExtensionObject eo(variant); + ASSERT_TRUE(eo.isType()); + ASSERT_FALSE(eo.isType()); +} + +TEST_F(ExtensionObjectTest, VariantConversion) +{ + const RangePtr range = Range(0, 10); + const RangePtr rangeWrong = Range(10, 20); + const auto variant = VariantConverter::ToVariant(range); + + auto eo = ExtensionObject(); + eo.setFromVariant(variant); + const auto variantOut = eo.getAsVariant(); + const RangePtr rangeOut = VariantConverter::ToDaqObject(variantOut); + + ASSERT_TRUE(rangeOut.equals(range)); + ASSERT_FALSE(rangeOut.equals(rangeWrong)); +} + +TEST_F(ExtensionObjectTest, ExtensionObjectConstructor) +{ + UA_Range tmsRangeSrc = {0, 10}; + RangePtr rangeSrc = Range(0, 10); + RangePtr rangeWrong = Range(10, 20); + + OpcUaObject eoSrc; + UA_ExtensionObject_setValueCopy(eoSrc.get(), &tmsRangeSrc, &UA_TYPES[UA_TYPES_RANGE]); + + ExtensionObject eo(eoSrc); + const auto variantOut = eo.getAsVariant(); + const auto rangeOut = VariantConverter::ToDaqObject(variantOut); + + ASSERT_TRUE(rangeOut.equals(rangeSrc)); + ASSERT_FALSE(rangeOut.equals(rangeWrong)); +} diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_generic_struct_converter.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_generic_struct_converter.cpp new file mode 100644 index 0000000..405ae03 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/tests/test_generic_struct_converter.cpp @@ -0,0 +1,251 @@ +#include "gtest/gtest.h" +#include "opcuatms/converters/variant_converter.h" +#include "coretypes/struct_factory.h" +#include "coretypes/struct_type_factory.h" +#include "coretypes/type_manager_factory.h" +#include "coreobjects/unit_factory.h" +#include "opcuatms/extension_object.h" +#include "opendaq/context_factory.h" +#include "opendaq/data_rule_factory.h" +#include "coretypes/simple_type_factory.h" +#include "opendaq/data_descriptor_factory.h" + +using GenericStructConverterTest = testing::Test; + +using namespace daq; +using namespace opcua; +using namespace tms; +using namespace opcua; + +namespace test_helpers +{ + static ContextPtr setupContext() + { + auto typeManager = TypeManager(); + typeManager.addType(StructType("RationalNumber64", + List("Numerator", "Denominator"), + List(SimpleType(ctInt), SimpleType(ctInt)))); + + typeManager.addType(StructType("DeviceDomainStructure", + List("Resolution", "TicksSinceOrigin", "Origin", "Unit"), + List(SimpleType(ctRatio), SimpleType(ctInt), SimpleType(ctString), UnitStructType()))); + + typeManager.addType(StructType("DimensionDescriptorStructure", + List("Name", "DimensionRule", "Unit"), + List(SimpleType(ctString), SimpleType(ctStruct), UnitStructType()))); + + typeManager.addType(StructType("ListRuleDescriptionStructure", + List("Type", "Elements"), + List(SimpleType(ctString), SimpleType(ctList)))); + + typeManager.addType(StructType("CustomRuleDescriptionStructure", + List("Type", "Parameters"), + List(SimpleType(ctString), SimpleType(ctDict)))); + + typeManager.addType(StructType("AdditionalParametersType", + List("Parameters"), + List(SimpleType(ctList)))); + + typeManager.addType(StructType("KeyValuePair", + List("Key", "Value"), + List(SimpleType(ctString), SimpleType(ctUndefined)))); + + return Context(nullptr, Logger(), typeManager, nullptr); + } +} + +TEST_F(GenericStructConverterTest, TestSimpleStruct) +{ + auto context = test_helpers::setupContext(); + DictPtr members = Dict(); + members.set("Numerator", 10); + members.set("Denominator", 50); + + const auto structure = Struct("RationalNumber64", members, context.getTypeManager()); + + auto var = VariantConverter::ToVariant(structure, nullptr, context); + + const auto rational = static_cast(var->data); + ASSERT_EQ(rational->numerator, 10); + ASSERT_EQ(rational->denominator, 50); + + const auto convertedStructure = VariantConverter::ToDaqObject(var, context); + ASSERT_EQ(structure.getStructType().getName(), convertedStructure.getStructType().getName()); + ASSERT_EQ(structure.getAsDictionary(), convertedStructure.getAsDictionary()); +} + +TEST_F(GenericStructConverterTest, TestStructWithOtherStructs) +{ + auto context = test_helpers::setupContext(); + DictPtr members = Dict({{"Resolution", Ratio(10, 20)}, + {"TicksSinceOrigin", 1000}, + {"Origin", "origin"}, + {"Unit", Unit("symbol", -1, "name", "quantity")}}); + const auto structure = Struct("DeviceDomainStructure", members, context.getTypeManager()); + + auto var = VariantConverter::ToVariant(structure, nullptr, context); + const auto deviceDomain = static_cast(var->data); + ASSERT_EQ(utils::ToStdString(deviceDomain->origin), "origin"); + ASSERT_EQ(utils::ToStdString(deviceDomain->unit.quantity), "quantity"); + ASSERT_EQ(deviceDomain->unit.unitId, -1); + ASSERT_EQ(deviceDomain->ticksSinceOrigin, 1000); + ASSERT_EQ(deviceDomain->resolution.numerator, 10); + + const auto convertedStructure = VariantConverter::ToDaqObject(var, context); + ASSERT_EQ(structure.getAsDictionary(), convertedStructure.getAsDictionary()); +} + +TEST_F(GenericStructConverterTest, TestDataDescriptorStruct) +{ + const auto context = test_helpers::setupContext(); + const auto dataDescriptor = DataDescriptorBuilder().build(); + const auto var = VariantConverter::ToVariant(dataDescriptor, nullptr, context); + const StructPtr dataDescriptorStruct = VariantConverter::ToDaqObject(var, context); + + ASSERT_EQ(dataDescriptor.asPtr().getStructType(), dataDescriptorStruct.getStructType()); + ASSERT_EQ(dataDescriptor.asPtr().getAsDictionary(), dataDescriptorStruct.getAsDictionary()); +} + +TEST_F(GenericStructConverterTest, TestStructWithOptionalsAssigned) +{ + auto context = test_helpers::setupContext(); + DictPtr members = Dict({{"Name", "name"}, + {"DimensionRule", + Struct("LinearRuleDescriptionStructure", + Dict( + {{"Type", "linear"}, {"Start", 10}, {"Delta", 10}, + {"Size", 10}}), + context.getTypeManager())}, + {"Unit", Unit("symbol", -1, "name", "quantity")}}); + const auto structure = Struct("DimensionDescriptorStructure", members, context.getTypeManager()); + + + auto var = VariantConverter::ToVariant(structure, nullptr, context); + + const auto dimension = static_cast(var->data); + ASSERT_EQ(utils::ToStdString(*dimension->name), "name"); + ASSERT_EQ(utils::ToStdString(dimension->unit->quantity), "quantity"); + + const StructPtr convertedStructure = VariantConverter::ToDaqObject(var, context); + ASSERT_EQ(structure, convertedStructure); +} + +TEST_F(GenericStructConverterTest, TestStructWithOptionalsUnassigned1) +{ + auto context = test_helpers::setupContext(); + context.getTypeManager().addType(StructType("LinearRuleDescriptionStructure", + List("Type", "Start", "Delta", "Size"), + List(SimpleType(ctString), + SimpleType(ctInt), + SimpleType(ctInt), + SimpleType(ctInt)))); + DictPtr members = Dict({{"Name", "name"}, + {"DimensionRule", + Struct("LinearRuleDescriptionStructure", + Dict( + {{"Type", "linear"}, {"Start", 10}, {"Delta", 10}, + {"Size", nullptr}}), + context.getTypeManager())}, + {"Unit", nullptr}}); + const auto structure = Struct("DimensionDescriptorStructure", members, context.getTypeManager()); + + auto var = VariantConverter::ToVariant(structure, nullptr, context); + + const auto dimension = static_cast(var->data); + ASSERT_EQ(utils::ToStdString(*dimension->name), "name"); + ASSERT_EQ(dimension->unit, nullptr); + + const StructPtr convertedStructure = VariantConverter::ToDaqObject(var, context); + ASSERT_EQ(structure, convertedStructure); +} + +TEST_F(GenericStructConverterTest, TestStructWithOptionalsUnassigned2) +{ + auto context = test_helpers::setupContext(); + DictPtr members = Dict({{"Name", "name"}, + {"DimensionRule", + Struct("LinearRuleDescriptionStructure", + Dict( + {{"Type", "linear"}, {"Start", 10}, {"Delta", 10}, + {"Size", nullptr}}), + context.getTypeManager())}, + {"Unit", nullptr}}); + const auto structure = Struct("DimensionDescriptorStructure", members, context.getTypeManager()); + + auto var = VariantConverter::ToVariant(structure, nullptr, context); + + const auto dimension = static_cast(var->data); + ASSERT_EQ(utils::ToStdString(*dimension->name), "name"); + ASSERT_EQ(dimension->unit, nullptr); + + const StructPtr convertedStructure = VariantConverter::ToDaqObject(var, context); + ASSERT_EQ(structure, convertedStructure); +} + +TEST_F(GenericStructConverterTest, TestStructWithArrays1) +{ + auto context = test_helpers::setupContext(); + const auto structure = Struct("ListRuleDescriptionStructure", + Dict({{"Type", "list"}, {"Elements", List("foo", "bar")}}), + context.getTypeManager()); + + auto var = VariantConverter::ToVariant(structure, nullptr, context); + + const auto rule = static_cast(var->data); + ASSERT_EQ(utils::ToStdString(rule->type), "list"); + ASSERT_EQ(rule->elementsSize, 2); + + const StructPtr convertedStructure = VariantConverter::ToDaqObject(var, context); + ASSERT_EQ(structure, convertedStructure); +} + +TEST_F(GenericStructConverterTest, TestStructWithArrays2) +{ + auto context = test_helpers::setupContext(); + const auto structure = Struct("CustomRuleDescriptionStructure", + Dict({{"Type", "list"}, {"Parameters", Dict({{"foo", "bar"}, {"foo1", "bar1"}})}}), + context.getTypeManager()); + + + auto var = VariantConverter::ToVariant(structure, nullptr, context); + + const auto rule = static_cast(var->data); + ASSERT_EQ(utils::ToStdString(rule->type), "list"); + ASSERT_EQ(rule->parametersSize, 2); + + auto keyVariant = OpcUaVariant(rule->parameters[0].key); + ASSERT_EQ(VariantConverter::ToDaqObject(keyVariant, context), "foo"); + + const StructPtr convertedStructure = VariantConverter::ToDaqObject(var, context); + ASSERT_EQ(structure, convertedStructure); +} + +TEST_F(GenericStructConverterTest, TestStructWithArrays3) +{ + auto context = test_helpers::setupContext(); + const auto keyValuePairList = List( + Struct("KeyValuePair", Dict({{"Key", "key1"}, {"Value", "value1"}}), context.getTypeManager()), + Struct("KeyValuePair", Dict({{"Key", "key1"}, {"Value", "value1"}}), context.getTypeManager())); + + const auto structure = Struct("AdditionalParametersType", + Dict({{"Parameters", keyValuePairList}}), + context.getTypeManager()); + + auto var = VariantConverter::ToVariant(structure, nullptr, context); + const StructPtr convertedStructure = VariantConverter::ToDaqObject(var, context); + ASSERT_EQ(structure, convertedStructure); +} + +TEST_F(GenericStructConverterTest, TestStructWithArraysEmptyList) +{ + auto context = test_helpers::setupContext(); + const auto keyValuePairList = List(); + + const auto structure = Struct("AdditionalParametersType", + Dict({{"Parameters", keyValuePairList}}), + context.getTypeManager()); + + auto var = VariantConverter::ToVariant(structure, nullptr, context); + const StructPtr convertedStructure = VariantConverter::ToDaqObject(var, context); + ASSERT_EQ(structure, convertedStructure); +} diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_variant_converter.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_variant_converter.cpp new file mode 100644 index 0000000..4ff1bf8 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/tests/test_variant_converter.cpp @@ -0,0 +1,428 @@ +#include "gtest/gtest.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "coretypes/ratio_factory.h" +#include "opcuatms/converters/variant_converter.h" +#include "opcuatms/converters/struct_converter.h" +#include "opcuashared/opcuavariant.h" + +using VariantConverterTest = testing::Test; + +using namespace daq; +using namespace daq::opcua; +using namespace daq::opcua::tms; +using namespace opcua; + +static ListPtr CreateTestDimensions() +{ + auto list = List(); + + const auto rule1 = LinearDimensionRule(2.0, 3.0, 4); + const auto unit1 = Unit("V", 1, "voltage", "1"); + auto dimension1 = Dimension(rule1, unit1, "x"); + list.pushBack(dimension1); + + const auto rule2 = LogarithmicDimensionRule(1.0, 4.0, 2, 9); + auto dimension2 = Dimension(rule2); + list.pushBack(dimension2); + + return list; +} + +static DataDescriptorBuilderPtr CreateTestStructDescriptorBuilder() +{ + // struct Meta { + // string description; + // } + // + // struct CanMessage { + // int id; + // byte data; + // Meta meta; + // }; + + auto id = DataDescriptorBuilder().setSampleType(SampleType::Int32).setName("id").build(); + auto data = DataDescriptorBuilder().setSampleType(SampleType::UInt8).setName("data").build(); + + auto desc = DataDescriptorBuilder() + .setSampleType(SampleType::String) + .setName("description") + .setUnit(Unit("V", 1, "voltage", "quantity")) + .setValueRange(Range(1, 10)) + .setRule(ExplicitDataRule()) + .setOrigin("2022-11-30T10:53:06") + .build(); + + auto meta = DataDescriptorBuilder() + .setSampleType(SampleType::Undefined) + .setName("meta") + .setDimensions(CreateTestDimensions()) + .setStructFields(List(desc)) + .build(); + + auto can = DataDescriptorBuilder() + .setSampleType(SampleType::Undefined) + .setName("CAN message") + .setStructFields(List(id, data, meta)); + + return can; +} + +static DataDescriptorPtr CreateTestStructDescriptor() +{ + return CreateTestStructDescriptorBuilder().build(); +} + +TEST_F(VariantConverterTest, Range) +{ + const RangePtr daqRange2 = Range(2, 20); + const RangePtr daqRange3 = Range(3, 30); + + const auto variant = VariantConverter::ToVariant(daqRange2); + const auto daqRangeOut = VariantConverter::ToDaqObject(variant); + + ASSERT_TRUE(daqRangeOut.equals(daqRange2)); + ASSERT_FALSE(daqRangeOut.equals(daqRange3)); +} + +TEST_F(VariantConverterTest, Unit) +{ + const UnitPtr daqUnit2 = Unit("V", 2, "measured voltage", "voltage"); + const UnitPtr daqUnit3 = Unit("m", 3, "height of defender", "lenght"); + + const auto variant = VariantConverter::ToVariant(daqUnit2); + const auto daqUnitOut = VariantConverter::ToDaqObject(variant); + + ASSERT_TRUE(daqUnitOut.equals(daqUnit2)); + ASSERT_FALSE(daqUnitOut.equals(daqUnit3)); +} + +TEST_F(VariantConverterTest, UnitMissingFields) +{ + auto daqUnit = UnitBuilder().setSymbol("s").build(); + const auto variant = VariantConverter::ToVariant(daqUnit); + const auto daqUnitOut = VariantConverter::ToDaqObject(variant); + ASSERT_TRUE(daqUnitOut.equals(daqUnit)); +} + +TEST_F(VariantConverterTest, Bool) +{ + auto variant = VariantConverter::ToVariant(True); + auto daqBoolOut = VariantConverter::ToDaqObject(variant); + ASSERT_EQ(daqBoolOut, True); + + variant = VariantConverter::ToVariant(true); + daqBoolOut = VariantConverter::ToDaqObject(variant); + ASSERT_EQ(daqBoolOut, true); + + variant = VariantConverter::ToVariant(False); + daqBoolOut = VariantConverter::ToDaqObject(variant); + ASSERT_EQ(daqBoolOut, False); + + variant = VariantConverter::ToVariant(false); + daqBoolOut = VariantConverter::ToDaqObject(variant); + ASSERT_EQ(daqBoolOut, false); +} + +TEST_F(VariantConverterTest, Int) +{ + auto variant = VariantConverter::ToVariant(55); + auto daqIntOut = VariantConverter::ToDaqObject(variant); + ASSERT_EQ(daqIntOut, 55); +} + +TEST_F(VariantConverterTest, Float) +{ + auto variant = VariantConverter::ToVariant(55.55); + auto daqFloatOut = VariantConverter::ToDaqObject(variant); + ASSERT_EQ(daqFloatOut, 55.55); +} + +TEST_F(VariantConverterTest, Number) +{ + const NumberPtr number1 = 10; + const NumberPtr number2 = 33.3; + const NumberPtr number3 = -27; + + NumberPtr numberOut; + OpcUaVariant variant; + + variant = VariantConverter::ToVariant(number1); + numberOut = VariantConverter::ToDaqObject(variant); + ASSERT_TRUE(numberOut.equals(number1)); + + variant = VariantConverter::ToVariant(number2); + numberOut = VariantConverter::ToDaqObject(variant); + ASSERT_TRUE(numberOut.equals(number2)); + + variant = VariantConverter::ToVariant(number3); + numberOut = VariantConverter::ToDaqObject(variant); + ASSERT_TRUE(numberOut.equals(number3)); + ASSERT_FALSE(numberOut.equals(number2)); +} + +TEST_F(VariantConverterTest, String) +{ + StringPtr hello = "Hello World!"; + + auto variant = VariantConverter::ToVariant(hello); + auto stringOut = VariantConverter::ToDaqObject(variant); + ASSERT_EQ(stringOut, hello); +} + +TEST_F(VariantConverterTest, BaseObject) +{ + BaseObjectPtr object; + BaseObjectPtr objectOut; + OpcUaVariant variant; + + object = nullptr; + variant = VariantConverter::ToVariant(object); + objectOut = VariantConverter::ToDaqObject(variant); + ASSERT_EQ(objectOut, object); + + object = true; + variant = VariantConverter::ToVariant(object); + objectOut = VariantConverter::ToDaqObject(variant); + ASSERT_EQ(objectOut, object); + + object = -3; + variant = VariantConverter::ToVariant(object); + objectOut = VariantConverter::ToDaqObject(variant); + ASSERT_EQ(objectOut, object); + + object = 12.5; + variant = VariantConverter::ToVariant(object); + objectOut = VariantConverter::ToDaqObject(variant); + ASSERT_EQ(objectOut, object); + + object = "Hello World!"; + variant = VariantConverter::ToVariant(object); + objectOut = VariantConverter::ToDaqObject(variant); + ASSERT_EQ(objectOut, object); +} + +TEST_F(VariantConverterTest, LinearDataRule) +{ + const DataRulePtr daqDataRule = LinearDataRule(2.0, 3.0); + const DataRulePtr daqDataRuleWrong = LinearDataRule(1.0, 4.0); + + const auto variant = VariantConverter::ToVariant(daqDataRule); + const auto daqDataRuleOut = VariantConverter::ToDaqObject(variant); + + ASSERT_TRUE(daqDataRuleOut.equals(daqDataRule)); + ASSERT_FALSE(daqDataRuleOut.equals(daqDataRuleWrong)); +} + +TEST_F(VariantConverterTest, ConstantDataRule) +{ + const DataRulePtr daqDataRule = ConstantDataRule(2.0); + const DataRulePtr daqDataRuleWrong = ConstantDataRule(1.0); + + const auto variant = VariantConverter::ToVariant(daqDataRule); + const auto daqDataRuleOut = VariantConverter::ToDaqObject(variant); + + ASSERT_TRUE(daqDataRuleOut.equals(daqDataRule)); + ASSERT_FALSE(daqDataRuleOut.equals(daqDataRuleWrong)); +} + +TEST_F(VariantConverterTest, ExplicitDataRule) +{ + const DataRulePtr daqDataRule = ExplicitDataRule(); + + const auto variant = VariantConverter::ToVariant(daqDataRule); + const auto daqDataRuleOut = VariantConverter::ToDaqObject(variant); + + ASSERT_TRUE(daqDataRuleOut.equals(daqDataRule)); +} + +TEST_F(VariantConverterTest, CustomDataRule) +{ + auto params = Dict(); + params.set("count", 1); + params.set("type", "apple"); + params.set("type1", "gala"); + params.set("type2", "fuji"); + params.set("weight", 1.123); + + auto daqDataRule = DataRuleBuilder().setType(DataRuleType::Other).setParameters(params).build(); + + const auto variant = VariantConverter::ToVariant(daqDataRule); + const auto daqDataRuleOut = VariantConverter::ToDaqObject(variant); + + ASSERT_TRUE(daqDataRuleOut.equals(daqDataRule)); +} + +TEST_F(VariantConverterTest, DataDescriptor) +{ + auto descriptor = DataDescriptorBuilder() + .setSampleType(SampleType::Float64) + .setName("Value 1") + .setUnit(Unit("V", 1, "voltage", "quantity")) + .setValueRange(Range(1, 10)) + .setRule(ExplicitDataRule()) + .setDimensions(CreateTestDimensions()) + .setPostScaling(LinearScaling(10, 2)) + .build(); + + auto variant = VariantConverter::ToVariant(descriptor); + auto descriptorOut = VariantConverter::ToDaqObject(variant); + + ASSERT_TRUE(descriptorOut.equals(descriptor)); +} + +TEST_F(VariantConverterTest, DataDescriptorEmpty) +{ + auto daqDescriptor = DataDescriptorBuilder().setSampleType(SampleType::Float64).build(); + auto variant = VariantConverter::ToVariant(daqDescriptor); + auto descriptorOut = VariantConverter::ToDaqObject(variant); + ASSERT_TRUE(descriptorOut.equals(daqDescriptor)); +} + +TEST_F(VariantConverterTest, StructDataDescriptor) +{ + auto descriptor = CreateTestStructDescriptor(); + auto descriptorWrong = DataDescriptorBuilder().setSampleType(SampleType::Float64).setName("Descriptor wrong").build(); + + auto variant = VariantConverter::ToVariant(descriptor); + auto descriptorOut = VariantConverter::ToDaqObject(variant); + + ASSERT_TRUE(descriptorOut.equals(descriptor)); + ASSERT_FALSE(descriptorOut.equals(descriptorWrong)); +} + +TEST_F(VariantConverterTest, StructDescriptorEmpty) +{ + auto descriptor = DataDescriptorBuilder().setSampleType(SampleType::Float64).build(); + auto variant = VariantConverter::ToVariant(descriptor); + auto descriptorOut = VariantConverter::ToDaqObject(variant); + ASSERT_TRUE(descriptorOut.equals(descriptor)); +} + +TEST_F(VariantConverterTest, DataDescriptorMetadata) +{ + auto metadata = Dict(); + metadata.set("name", "sine1"); + metadata.set("frequency", "50"); + + auto descriptor = CreateTestStructDescriptorBuilder().setName("Sine1").setMetadata(metadata).build(); + auto descriptorWrong = DataDescriptorBuilder().setSampleType(SampleType::Float64).setName("Wrong descriptor").build(); + + auto variant = VariantConverter::ToVariant(descriptor); + auto descriptorOut = VariantConverter::ToDaqObject(variant); + + ASSERT_TRUE(descriptorOut.equals(descriptor)); + ASSERT_FALSE(descriptorOut.equals(descriptorWrong)); +} + +TEST_F(VariantConverterTest, LinearDimensionRule) +{ + const DimensionRulePtr daqRule = LinearDimensionRule(2.0, 3.0, 4); + const DimensionRulePtr daqRuleWrong = LinearDimensionRule(1.0, 4.0, 9); + + const auto variant = VariantConverter::ToVariant(daqRule); + const auto daqRuleOut = VariantConverter::ToDaqObject(variant); + + ASSERT_TRUE(daqRuleOut.equals(daqRule)); + ASSERT_FALSE(daqRuleOut.equals(daqRuleWrong)); +} + +TEST_F(VariantConverterTest, LogDimensionRule) +{ + const DimensionRulePtr daqRule = LogarithmicDimensionRule(2.0, 3.0, 10, 4); + const DimensionRulePtr daqRuleWrong = LogarithmicDimensionRule(1.0, 4.0, 2, 9); + + const auto variant = VariantConverter::ToVariant(daqRule); + const auto daqRuleOut = VariantConverter::ToDaqObject(variant); + + ASSERT_TRUE(daqRuleOut.equals(daqRule)); + ASSERT_FALSE(daqRuleOut.equals(daqRuleWrong)); +} + +TEST_F(VariantConverterTest, ListDimensionRule) +{ + ListPtr list{10, 20, 30}; + ListPtr listWrong{1, 2, 3}; + const DimensionRulePtr daqRule = ListDimensionRule(list); + const DimensionRulePtr daqRuleWrong = ListDimensionRule(listWrong); + + const auto variant = VariantConverter::ToVariant(daqRule); + const auto daqRuleOut = VariantConverter::ToDaqObject(variant); + + ASSERT_TRUE(daqRuleOut.equals(daqRule)); + ASSERT_FALSE(daqRuleOut.equals(daqRuleWrong)); +} + +TEST_F(VariantConverterTest, CustomDimensionRule) +{ + auto params = Dict(); + params.set("count", 1); + params.set("type", "apple"); + params.set("type1", "gala"); + params.set("type2", "fuji"); + params.set("weight", 1.123); + + auto daqDimensionRule = DimensionRuleBuilder().setType(DimensionRuleType::Other).setParameters(params).build(); + + const auto variant = VariantConverter::ToVariant(daqDimensionRule); + const auto daqDimensionRuleOut = VariantConverter::ToDaqObject(variant); + + ASSERT_TRUE(daqDimensionRuleOut.equals(daqDimensionRule)); +} + +TEST_F(VariantConverterTest, LinearScaling) +{ + const ScalingPtr daqScaling = LinearScaling(2.0, 3.0, SampleType::UInt8, ScaledSampleType::Float32); + const ScalingPtr daqScalingWrong = LinearScaling(1.0, 4.0, SampleType::Int16, ScaledSampleType::Float64); + + const auto variant = VariantConverter::ToVariant(daqScaling); + auto daqScalingOut = VariantConverter::ToDaqObject(variant); + + ASSERT_TRUE(daqScalingOut.equals(daqScaling)); + ASSERT_FALSE(daqScalingOut.equals(daqScalingWrong)); +} + +TEST_F(VariantConverterTest, Dimension) +{ + const auto rule = LinearDimensionRule(2.0, 3.0, 4); + const auto unit = Unit("V", 1, "voltage", "1"); + auto dimension = Dimension(rule, unit, "x"); + + auto dimensionWrong = Dimension(rule, unit, "wrong"); + + const auto variant = VariantConverter::ToVariant(dimension); + auto dimensionOut = VariantConverter::ToDaqObject(variant); + + ASSERT_TRUE(dimensionOut.equals(dimension)); + ASSERT_FALSE(dimensionOut.equals(dimensionWrong)); +} + +TEST_F(VariantConverterTest, Ratio) +{ + auto ratio = Ratio(1, 2); + auto ratioWrong = Ratio(1, 10); + + const auto variant = VariantConverter::ToVariant(ratio); + auto ratioOut = VariantConverter::ToDaqObject(variant); + + ASSERT_TRUE(ratioOut.equals(ratio)); + ASSERT_FALSE(ratioOut.equals(ratioWrong)); +} + +TEST_F(VariantConverterTest, FunctionBlockType) +{ + const FunctionBlockTypePtr fbType = FunctionBlockType("UNIQUE ID", "NAME", "DESCRIPTION"); + + const auto variant = VariantConverter::ToVariant(fbType); + const auto fbTypeOut = VariantConverter::ToDaqObject(variant); + + ASSERT_EQ(fbTypeOut.getId(), fbType.getId()); + ASSERT_EQ(fbTypeOut.getName(), fbType.getName()); + ASSERT_EQ(fbTypeOut.getDescription(), fbType.getDescription()); +} diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_variant_list_converter.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_variant_list_converter.cpp new file mode 100644 index 0000000..dbedf28 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/tests/test_variant_list_converter.cpp @@ -0,0 +1,289 @@ +#include "gtest/gtest.h" +#include +#include +#include +#include +#include +#include +#include +#include "coretypes/ratio_factory.h" +#include "opcuatms/converters/variant_converter.h" +#include "opcuatms/converters/struct_converter.h" +#include "opcuashared/opcuavariant.h" +#include "opcuatms/converters/list_conversion_utils.h" + +using VariantListConverterTest = testing::Test; + +using namespace daq; +using namespace daq::opcua; +using namespace daq::opcua::tms; +using namespace opcua; + +TEST_F(VariantListConverterTest, Empty) +{ + auto list = List(); + + const auto variant = VariantConverter::ToArrayVariant(list); + const auto listOut = VariantConverter::ToDaqList(variant); + + Bool eq{false}; + listOut->equals(list, &eq); + ASSERT_TRUE(eq); +} + +TEST_F(VariantListConverterTest, Number) +{ + auto list = List(); + list.pushBack(10); + list.pushBack(-2); + list.pushBack(1.5); + + const auto variant = VariantConverter::ToArrayVariant(list); + const auto listOut = VariantConverter::ToDaqList(variant); + + Bool eq{false}; + listOut->equals(list, &eq); + ASSERT_TRUE(eq); +} + +TEST_F(VariantListConverterTest, Range) +{ + auto list = List(); + list.pushBack(Range(1, 10)); + list.pushBack(Range(2, 20)); + + const auto variant = VariantConverter::ToArrayVariant(list); + const auto listOut = VariantConverter::ToDaqList(variant); + + Bool eq{false}; + listOut->equals(list, &eq); + ASSERT_TRUE(eq); +} + +TEST_F(VariantListConverterTest, Ratio) +{ + auto list = List(); + list.pushBack(Ratio(10, 2)); + list.pushBack(Ratio(-2, 5)); + + const auto variant = VariantConverter::ToArrayVariant(list); + const auto listOut = VariantConverter::ToDaqList(variant); + + Bool eq{false}; + listOut->equals(list, &eq); + ASSERT_TRUE(eq); +} + +TEST_F(VariantListConverterTest, Unit) +{ + auto list = List(); + list.pushBack(Unit("symbol", 1, "name", "q")); + list.pushBack(Unit("V", 2)); + + const auto variant = VariantConverter::ToArrayVariant(list); + const auto listOut = VariantConverter::ToDaqList(variant); + + Bool eq{false}; + listOut->equals(list, &eq); + ASSERT_TRUE(eq); +} + +TEST_F(VariantListConverterTest, Boolean) +{ + auto list = List(); + list.pushBack(true); + list.pushBack(false); + list.pushBack(true); + + const auto variant = VariantConverter::ToArrayVariant(list); + const auto listOut = VariantConverter::ToDaqList(variant); + + Bool eq{false}; + listOut->equals(list, &eq); + ASSERT_TRUE(eq); +} + +TEST_F(VariantListConverterTest, Integer) +{ + auto list = List(); + list.pushBack(1000); + list.pushBack(-15); + list.pushBack(-22); + + const auto variant = VariantConverter::ToArrayVariant(list); + const auto listOut = VariantConverter::ToDaqList(variant); + + Bool eq{false}; + listOut->equals(list, &eq); + ASSERT_TRUE(eq); +} + +TEST_F(VariantListConverterTest, Float) +{ + auto list = List(); + list.pushBack(1000); + list.pushBack(3.14); + list.pushBack(-1.5); + + const auto variant = VariantConverter::ToArrayVariant(list); + const auto listOut = VariantConverter::ToDaqList(variant); + + Bool eq{false}; + listOut->equals(list, &eq); + ASSERT_TRUE(eq); +} + +TEST_F(VariantListConverterTest, String) +{ + auto list = List(); + list.pushBack("Hello World!"); + list.pushBack(""); + list.pushBack("hakuna matata"); + + const auto variant = VariantConverter::ToArrayVariant(list); + const auto listOut = VariantConverter::ToDaqList(variant); + + Bool eq{false}; + listOut->equals(list, &eq); + ASSERT_TRUE(eq); +} + +TEST_F(VariantListConverterTest, BaseObject) +{ + auto list = List(); + list.pushBack(nullptr); + list.pushBack(true); + list.pushBack(3); + list.pushBack(12.5); + list.pushBack("hakuna matata"); + + const auto variant = VariantConverter::ToArrayVariant(list); + const auto listOut = VariantConverter::ToDaqList(variant); + + Bool eq{false}; + listOut->equals(list, &eq); + ASSERT_TRUE(eq); +} + +TEST_F(VariantListConverterTest, DataDescriptor) +{ + auto id = DataDescriptorBuilder().setSampleType(SampleType::Int32).setName("id").build(); + auto data = DataDescriptorBuilder().setSampleType(SampleType::UInt8).setName("data").build(); + auto can = DataDescriptorBuilder() + .setSampleType(SampleType::Undefined) + .setName("CAN message") + .setStructFields(List(id, data)) + .build(); + + auto meta = DataDescriptorBuilder().setSampleType(SampleType::Float64).setName("meta").build(); + + auto list = List(); + list.pushBack(can); + list.pushBack(meta); + + const auto variant = VariantConverter::ToArrayVariant(list); + const auto listOut = VariantConverter::ToDaqList(variant); + + Bool eq{false}; + listOut->equals(list, &eq); + ASSERT_TRUE(eq); +} + +TEST_F(VariantListConverterTest, ListDataDescriptor) +{ + auto list = List(); + list.pushBack(DataDescriptorBuilder().setSampleType(SampleType::Float64).build()); + + ASSERT_NO_THROW(VariantConverter::ToArrayVariant(list)); + EXPECT_THROW(VariantConverter::ToDaqList(OpcUaVariant()), ConversionFailedException); +} + +TEST_F(VariantListConverterTest, DataDescriptorMetadata) +{ + auto metadata = Dict(); + metadata.set("name", "sine1"); + metadata.set("frequency", "50"); + auto descriptor1 = DataDescriptorBuilder().setSampleType(SampleType::Float64).setName("Sine1").setMetadata(metadata).build(); + + auto descriptor2 = DataDescriptorBuilder().setSampleType(SampleType::Float64).setName("Sine2").build(); + + auto list = List(); + list.pushBack(descriptor1); + list.pushBack(descriptor2); + + const auto variant = VariantConverter::ToArrayVariant(list); + const auto listOut = VariantConverter::ToDaqList(variant); + + Bool eq{false}; + listOut->equals(list, &eq); + ASSERT_TRUE(eq); +} + +TEST_F(VariantListConverterTest, DataRule) +{ + auto list = List(); + list.pushBack(LinearDataRule(2.0, 3.0)); + list.pushBack(ConstantDataRule(100.0)); + list.pushBack(ExplicitDataRule()); + + const auto variant = VariantConverter::ToArrayVariant(list); + const auto listOut = VariantConverter::ToDaqList(variant); + + Bool eq{false}; + listOut->equals(list, &eq); + ASSERT_TRUE(eq); +} + +TEST_F(VariantListConverterTest, Dimension) +{ + const auto rule = LinearDimensionRule(2.0, 3.0, 4); + const auto unit = Unit("V", 1, "voltage", "1"); + auto dx = Dimension(rule, unit, "x"); + auto dy = Dimension(rule, unit, "y"); + + auto list = List(); + list.pushBack(dx); + list.pushBack(dy); + + const auto variant = VariantConverter::ToArrayVariant(list); + const auto listOut = VariantConverter::ToDaqList(variant); + + Bool eq{false}; + listOut->equals(list, &eq); + ASSERT_TRUE(eq); +} + +TEST_F(VariantListConverterTest, Scaling) +{ + auto list = List(); + list.pushBack(LinearScaling(2.0, 3.0, SampleType::UInt8, ScaledSampleType::Float32)); + list.pushBack(LinearScaling(10.0, 2.0, SampleType::Float64, ScaledSampleType::Float64)); + + const auto variant = VariantConverter::ToArrayVariant(list); + const auto listOut = VariantConverter::ToDaqList(variant); + + Bool eq{false}; + listOut->equals(list, &eq); + ASSERT_TRUE(eq); +} + +TEST_F(VariantListConverterTest, NonExtensionObjectTest) +{ + constexpr size_t listSize = 3; + + auto list = List(); + list.pushBack(Integer(10)); + list.pushBack(String("foo")); + list.pushBack(Floating(123.23)); + + const auto type = GetUaDataType(); + auto arr = (UA_Variant*) UA_Array_new(listSize, type); + + for (SizeT i = 0; i < listSize; ++i) + { + arr[i] = VariantConverter::ToArrayVariant(list).getDetachedValue(); + arr[i].arrayLength = list.getCount(); + } + + UA_Array_delete(arr, 3, type); +} diff --git a/shared/libraries/opcuatms/opcuatms/tests/testapp.cpp b/shared/libraries/opcuatms/opcuatms/tests/testapp.cpp new file mode 100644 index 0000000..06b4198 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/tests/testapp.cpp @@ -0,0 +1,13 @@ +#include +#include +#include + +int main(int argc, char** args) +{ + testing::InitGoogleTest(&argc, args); + + testing::TestEventListeners& listeners = testing::UnitTest::GetInstance()->listeners(); + listeners.Append(new DaqMemCheckListener()); + + return RUN_ALL_TESTS(); +} diff --git a/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt new file mode 100644 index 0000000..96dcd6c --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.2) +set_cmake_folder_context(TARGET_FOLDER_NAME) +project(opcuatms_client VERSION 2.0.0 LANGUAGES CXX) + +add_subdirectory(src) + +if (OPENDAQ_ENABLE_TESTS) + add_subdirectory(tests) +endif() diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_factory.h new file mode 100644 index 0000000..e51da29 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_factory.h @@ -0,0 +1,35 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "opcuaclient/opcuaclient.h" +#include "opcuatms_client/objects/tms_client_channel_impl.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +inline ChannelPtr TmsClientChannel( + const ContextPtr& ctx, + const ComponentPtr& parent, + const StringPtr& localId, + const daq::opcua::tms::TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId) +{ + ChannelPtr obj(createWithImplementation(ctx, parent, localId, clientContext, nodeId)); + return obj; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_impl.h new file mode 100644 index 0000000..9cd9113 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_impl.h @@ -0,0 +1,33 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "opcuatms_client/objects/tms_client_function_block_impl.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class TmsClientChannelImpl : public TmsClientFunctionBlockBaseImpl +{ + public: + explicit TmsClientChannelImpl( + const ContextPtr& context, + const ComponentPtr& parent, + const StringPtr& localId, + const daq::opcua::tms::TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId); +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_factory.h new file mode 100644 index 0000000..7d04d7f --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_factory.h @@ -0,0 +1,32 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once +#include "opcuatms_client/objects/tms_client_context.h" +#include "opcuatms_client/objects/tms_client_component_impl.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +inline ComponentPtr TmsClientComponent(const ContextPtr& context, + const ComponentPtr& parent, + const StringPtr& localId, + const daq::opcua::tms::TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId) +{ + ComponentPtr obj(createWithImplementation(context, parent, localId, clientContext, nodeId)); + return obj; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h new file mode 100644 index 0000000..b923ee6 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h @@ -0,0 +1,60 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "opcuatms_client/objects/tms_client_property_object_impl.h" +#include "opendaq/channel_impl.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +template +class TmsClientComponentBaseImpl; + +using TmsClientComponentImpl = TmsClientComponentBaseImpl>; + +template +class TmsClientComponentBaseImpl : public TmsClientPropertyObjectBaseImpl +{ +public: + + template = 0> + TmsClientComponentBaseImpl(const ContextPtr& ctx, + const ComponentPtr& parent, + const StringPtr& localId, + const TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId) + : TmsClientPropertyObjectBaseImpl(ctx, parent, localId, clientContext, nodeId) + { + } + + template = 0> + TmsClientComponentBaseImpl(const ContextPtr& ctx, + const ComponentPtr& parent, + const StringPtr& localId, + const TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId, + const FunctionBlockTypePtr& type) + : TmsClientPropertyObjectBaseImpl(ctx, parent, localId, clientContext, nodeId, type) + { + } + + // Component overrides + ErrCode INTERFACE_FUNC getActive(Bool* active) override; + ErrCode INTERFACE_FUNC setActive(Bool active) override; + ErrCode INTERFACE_FUNC getTags(ITagsConfig** tags) override; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h new file mode 100644 index 0000000..5cbc0ed --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h @@ -0,0 +1,62 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "opcuatms/opcuatms.h" +#include "opcuaclient/opcuaclient.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class TmsClientContext; +using TmsClientContextPtr = std::shared_ptr; + +class TmsClientContext +{ +public: + explicit TmsClientContext(const opcua::OpcUaClientPtr& client); + + const opcua::OpcUaClientPtr& getClient() const; + + void registerObject(const opcua::OpcUaNodeId& nodeId, const BaseObjectPtr& object); + void unregisterObject(const opcua::OpcUaNodeId& nodeId); + BaseObjectPtr getObject(const opcua::OpcUaNodeId& nodeId) const; + opcua::OpcUaNodeId getNodeId(const BaseObjectPtr object) const; + + template ::SmartPtr> + Ptr getObject(const opcua::OpcUaNodeId& nodeId) + { + auto obj = this->getObject(nodeId); + if (obj.assigned()) + return obj.asPtrOrNull(); + return Ptr(); + } + + template ::SmartPtr> + opcua::OpcUaNodeId getNodeId(const Ptr object) const + { + return this->getNodeId(object); + } + +protected: + opcua::OpcUaClientPtr client; + mutable std::mutex mutex; + + // Context should not hold objects because of cycling reference + std::unordered_map objects; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_factory.h new file mode 100644 index 0000000..5749904 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_factory.h @@ -0,0 +1,45 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once +#include "opcuatms_client/objects/tms_client_context.h" +#include "opcuatms_client/objects/tms_client_device_impl.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +inline DevicePtr TmsClientDevice(const ContextPtr& context, + const ComponentPtr& parent, + const StringPtr& localId, + const daq::opcua::tms::TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId, + const FunctionPtr& createStreamingCallback) +{ + DevicePtr obj(createWithImplementation(context, parent, localId, clientContext, nodeId, createStreamingCallback, false)); + return obj; +} + +inline DevicePtr TmsClientRootDevice(const ContextPtr& context, + const ComponentPtr& parent, + const StringPtr& localId, + const daq::opcua::tms::TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId, + const FunctionPtr& createStreamingCallback) +{ + DevicePtr obj(createWithImplementation(context, parent, localId, clientContext, nodeId, createStreamingCallback, true)); + return obj; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h new file mode 100644 index 0000000..9a804ab --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h @@ -0,0 +1,77 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "opcuatms_client/objects/tms_client_component_impl.h" +#include "opendaq/device_impl.h" +#include "opendaq/device_ptr.h" +#include "opendaq/streaming_ptr.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class TmsClientDeviceImpl : public TmsClientComponentBaseImpl +{ +public: + explicit TmsClientDeviceImpl(const ContextPtr& ctx, + const ComponentPtr& parent, + const StringPtr& localId, + const TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId, + const FunctionPtr& createStreamingCallback, + bool isRootDevice); + +protected: + void findAndCreateSubdevices(); + DevicePtr onAddDevice(const StringPtr& connectionString, const PropertyObjectPtr& config) override; + void onRemoveDevice(const DevicePtr& device) override; + DeviceInfoPtr onGetInfo() override; + RatioPtr onGetResolution() override; + uint64_t onGetTicksSinceOrigin() override; + std::string onGetOrigin() override; + UnitPtr onGetDomainUnit() override; + void findAndCreateFunctionBlocks(); + void findAndCreateSignals(); + void findAndCreateInputsOutputs(); + void findAndCreateCustomComponents(); + FunctionBlockPtr onAddFunctionBlock(const StringPtr& typeId, const PropertyObjectPtr& config) override; + void onRemoveFunctionBlock(const FunctionBlockPtr& functionBlock) override; + + // Streaming related methods + void findAndCreateStreamingOptions(); + void setUpStreamings(); + void connectToStreamings(); + + DeviceInfoConfigPtr deviceInfo; + + // Streaming related members + std::vector streamings; + FunctionPtr createStreamingCallback; + bool isRootDevice; + +private: + void fetchTimeDomain(); + void fetchTicksSinceOrigin(); + + bool timeDomainFetched = false; + RatioPtr resolution; + SizeT ticksSinceOrigin; + StringPtr origin; + UnitPtr domainUnit; + LoggerPtr logger; + LoggerComponentPtr loggerComponent; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_factory.h new file mode 100644 index 0000000..c982037 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_factory.h @@ -0,0 +1,34 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once +#include "opcuatms_client/objects/tms_client_context.h" +#include "opcuatms_client/objects/tms_client_folder_impl.h" +#include + +#include "open62541/tmsdevice_nodeids.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + inline FolderPtr TmsClientFolder(const ContextPtr& context, + const ComponentPtr& parent, + const StringPtr& localId, + const daq::opcua::tms::TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId) +{ + FolderPtr obj(createWithImplementation>(context, parent, localId, clientContext, nodeId, false)); + return obj; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h new file mode 100644 index 0000000..bd73ccd --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h @@ -0,0 +1,37 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "opcuatms_client/objects/tms_client_component_impl.h" +#include "opendaq/folder_impl.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +template > +class TmsClientFolderImpl : public TmsClientComponentBaseImpl +{ +public: + explicit TmsClientFolderImpl(const ContextPtr& ctx, + const ComponentPtr& parent, + const StringPtr& localId, + const TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId, + bool customFolderType); +private: + void findAndCreateFolders(); +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_factory.h new file mode 100644 index 0000000..05204f6 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_factory.h @@ -0,0 +1,34 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once +#include +#include "opcuatms_client/objects/tms_client_context.h" +#include "opcuatms_client/objects/tms_client_function_block_impl.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +inline FunctionBlockPtr TmsClientFunctionBlock( + const ContextPtr& ctx, + const ComponentPtr& parent, + const StringPtr& localId, + const daq::opcua::tms::TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId) +{ + FunctionBlockPtr obj(createWithImplementation(ctx, parent, localId, clientContext, nodeId)); + return obj; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h new file mode 100644 index 0000000..d3df713 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h @@ -0,0 +1,50 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "opcuatms_client/objects/tms_client_component_impl.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +template +class TmsClientFunctionBlockBaseImpl; + +using TmsClientFunctionBlockImpl = TmsClientFunctionBlockBaseImpl; + +template +class TmsClientFunctionBlockBaseImpl : public TmsClientComponentBaseImpl +{ +public: + explicit TmsClientFunctionBlockBaseImpl( + const ContextPtr& context, + const ComponentPtr& parent, + const StringPtr& localId, + const TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId); + + SignalPtr onGetStatusSignal() override; + +protected: + void findAndCreateFunctionBlocks(); + void findAndCreateSignals(); + void findAndCreateInputPorts(); + void readFbType(); + tsl::ordered_set getFunctionBlockNodeIds(); + tsl::ordered_set getOutputSignalNodeIds(); + tsl::ordered_set getInputPortNodeIds(); +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_factory.h new file mode 100644 index 0000000..e2c88a0 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_factory.h @@ -0,0 +1,32 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once +#include "opcuatms_client/objects/tms_client_context.h" +#include "opcuatms_client/objects/tms_client_function_impl.h" +#include "coretypes/function_ptr.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +inline FunctionPtr TmsClientFunction(const daq::opcua::tms::TmsClientContextPtr& ctx, + const ContextPtr& daqContext, + const opcua::OpcUaNodeId& parentId, + const opcua::OpcUaNodeId& methodId) +{ + FunctionPtr obj(createWithImplementation(ctx, daqContext, parentId, methodId)); + return obj; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_impl.h new file mode 100644 index 0000000..93ca4bd --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_impl.h @@ -0,0 +1,47 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "tms_client_context.h" +#include "coretypes/function.h" +#include "coretypes/coretype.h" +#include "opcuashared/opcuanodeid.h" +#include "opendaq/context_ptr.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + + +class TmsClientFunctionImpl : public ImplementationOf +{ +public: + + TmsClientFunctionImpl(const TmsClientContextPtr& ctx, + const ContextPtr& daqContext, + const opcua::OpcUaNodeId& parentId, + const opcua::OpcUaNodeId& methodId); + + ErrCode INTERFACE_FUNC call(IBaseObject* args, IBaseObject** result) override; + ErrCode INTERFACE_FUNC getCoreType(CoreType* coreType) override; + +private: + TmsClientContextPtr ctx; + ContextPtr daqContext; + opcua::OpcUaNodeId parentId; + opcua::OpcUaNodeId methodId; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_factory.h new file mode 100644 index 0000000..a67af90 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_factory.h @@ -0,0 +1,33 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once +#include +#include "opcuatms_client/objects/tms_client_context.h" +#include "opcuatms_client/objects/tms_client_input_port_impl.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +inline InputPortPtr TmsClientInputPort(const ContextPtr& context, + const ComponentPtr& parent, + const StringPtr& localId, + const TmsClientContextPtr& ctx, + const opcua::OpcUaNodeId& nodeId) +{ + InputPortPtr obj = createWithImplementation(context, parent, localId, ctx, nodeId); + return obj; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h new file mode 100644 index 0000000..8932dac --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h @@ -0,0 +1,44 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "opcuatms_client/objects/tms_client_component_impl.h" +#include "opendaq/input_port_impl.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class TmsClientInputPortImpl : public TmsClientComponentBaseImpl +{ +public: + explicit TmsClientInputPortImpl(const ContextPtr& ctx, + const ComponentPtr& parent, + const StringPtr& localId, + const TmsClientContextPtr& tmsCtx, + const opcua::OpcUaNodeId& nodeId); + + ErrCode INTERFACE_FUNC acceptsSignal(ISignal* signal, Bool* accepts) override; + ErrCode INTERFACE_FUNC connect(ISignal* signal) override; + ErrCode INTERFACE_FUNC disconnect() override; + ErrCode INTERFACE_FUNC getSignal(ISignal** signal) override; + ErrCode INTERFACE_FUNC getConnection(IConnection** connection) override; + ErrCode INTERFACE_FUNC getRequiresSignal(Bool* value) override; + ErrCode INTERFACE_FUNC setRequiresSignal(Bool value) override; + +protected: + SignalPtr onGetSignal(); +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_factory.h new file mode 100644 index 0000000..e06f398 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_factory.h @@ -0,0 +1,33 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once +#include "opcuatms_client/objects/tms_client_context.h" +#include "opcuatms_client/objects/tms_client_io_folder_impl.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +inline FolderPtr TmsClientIoFolder(const ContextPtr& context, + const ComponentPtr& parent, + const StringPtr& localId, + const daq::opcua::tms::TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId) +{ + FolderPtr obj(createWithImplementation(context, parent, localId, clientContext, nodeId)); + return obj; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h new file mode 100644 index 0000000..d7230e0 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h @@ -0,0 +1,37 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include "opcuatms_client/objects/tms_client_folder_impl.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class TmsClientIoFolderImpl : public TmsClientFolderImpl +{ +public: + explicit TmsClientIoFolderImpl(const ContextPtr& ctx, + const ComponentPtr& parent, + const StringPtr& localId, + const TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId); + +protected: + void findAndCreateChannels(); + void findAndCreateIoFolders(); +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h new file mode 100644 index 0000000..3ffb95b --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h @@ -0,0 +1,98 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "opcuaclient/monitored_item_create_request.h" +#include "opcuaclient/opcuaclient.h" +#include "opcuatms/converters/variant_converter.h" +#include "opcuatms/opcuatms.h" +#include "opcuaclient/reference_utils.h" +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class TmsClientObjectImpl +{ +public: + using ReferenceMap = std::unordered_map>; + +protected: + explicit TmsClientObjectImpl(const ContextPtr& daqContext, const TmsClientContextPtr& ctx, const opcua::OpcUaNodeId& nodeId); + virtual ~TmsClientObjectImpl(); + + void registerObject(const BaseObjectPtr& obj); + SignalPtr findSignal(const opcua::OpcUaNodeId& nodeId) const; + bool hasReference(const std::string& name); + opcua::OpcUaNodeId getNodeId(const std::string& nodeName); + void writeValue(const std::string& nodeName, const opcua::OpcUaVariant& value); + opcua::OpcUaVariant readValue(const std::string& nodeName); + virtual void subscriptionStatusChangeCallback(UA_StatusChangeNotification* notification); + + /*! + * @brief Returns child nodes of a specific type. By default it returns also the nodes which are a + * a subtype of the specific type. It can be disabled. + * @param client The opc-ua client + * @param nodeId The root nodeId + * @param typeId The type of child nodes to return + * @param subTypeEnabled Allows also that nodes of the sub types of the request type are returned. + */ + std::vector getChildNodes(const opcua::OpcUaClientPtr& client, + const opcua::OpcUaNodeId& nodeId, + const opcua::OpcUaNodeId& typeId, + const bool subTypeEnabled = true); + + opcua::MonitoredItem* monitoredItemsCreateEvent( + const opcua::EventMonitoredItemCreateRequest& item, + const opcua::EventNotificationCallbackType& eventNotificationCallback); + + opcua::MonitoredItem* monitoredItemsCreateDataChange( + const UA_MonitoredItemCreateRequest& item, + const opcua::DataChangeNotificationCallbackType& dataChangeNotificationCallback); + + template ::SmartPtr> + void writeValue(const std::string& nodeName, const CoreTypePtr& value) + { + writeValue(nodeName, VariantConverter::ToVariant(value)); + } + + template ::SmartPtr> + CoreTypePtr readValue(const std::string& nodeName) + { + const auto variant = readValue(nodeName); + return VariantConverter::ToDaqObject(variant); + } + + template ::SmartPtr> + ListPtr readList(const std::string& nodeName) + { + const auto variant = readValue(nodeName); + return VariantConverter::ToDaqList(variant); + } + + TmsClientContextPtr clientContext; + + opcua::OpcUaClientPtr client; + opcua::OpcUaNodeId nodeId; + opcua::ReferenceUtils referenceUtils; + ContextPtr daqContext; + +private: + opcua::Subscription* getSubscription(); + opcua::Subscription* subscription = nullptr; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_factory.h new file mode 100644 index 0000000..0869534 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_factory.h @@ -0,0 +1,32 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once +#include "coretypes/procedure_ptr.h" +#include "opcuatms_client/objects/tms_client_context.h" +#include "opcuatms_client/objects/tms_client_procedure_impl.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +inline ProcedurePtr TmsClientProcedure(const daq::opcua::tms::TmsClientContextPtr& ctx, + const ContextPtr& daqContext, + const opcua::OpcUaNodeId& parentId, + const opcua::OpcUaNodeId& methodId) +{ + ProcedurePtr obj(createWithImplementation(ctx, daqContext, parentId, methodId)); + return obj; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_impl.h new file mode 100644 index 0000000..c7a5f7c --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_impl.h @@ -0,0 +1,45 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "coretypes/coretype.h" +#include "coretypes/procedure.h" +#include "opcuashared/opcuanodeid.h" +#include "tms_client_context.h" +#include "opendaq/context_ptr.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class TmsClientProcedureImpl : public ImplementationOf +{ +public: + TmsClientProcedureImpl(const TmsClientContextPtr& ctx, + const ContextPtr& daqContexts, + const opcua::OpcUaNodeId& parentId, + const opcua::OpcUaNodeId& methodId); + + ErrCode INTERFACE_FUNC dispatch(IBaseObject* args) override; + ErrCode INTERFACE_FUNC getCoreType(CoreType* coreType) override; + +private: + TmsClientContextPtr ctx; + ContextPtr daqContext; + opcua::OpcUaNodeId parentId; + opcua::OpcUaNodeId methodId; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_factory.h new file mode 100644 index 0000000..8933455 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_factory.h @@ -0,0 +1,48 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once +#include "opcuatms_client/objects/tms_client_context.h" +#include "opcuatms_client/objects/tms_client_property_impl.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +OPENDAQ_DECLARE_CLASS_FACTORY_WITH_INTERFACE(INLINE_FACTORY, + TmsClientProperty, + IProperty, + const daq::ContextPtr&, + daqContext, + const daq::opcua::tms::TmsClientContextPtr&, + ctx, + const opcua::OpcUaNodeId&, + nodeId) + +OPENDAQ_DEFINE_CLASS_FACTORY_WITH_INTERFACE(INLINE_FACTORY, + TmsClientProperty, + IProperty, + const daq::ContextPtr&, + daqContext, + const daq::opcua::tms::TmsClientContextPtr&, + client, + const opcua::OpcUaNodeId&, + nodeId) + +inline PropertyPtr TmsClientProperty(const ContextPtr& daqContext, const TmsClientContextPtr& ctx, const OpcUaNodeId& nodeId) +{ + PropertyPtr obj(TmsClientProperty_Create(daqContext, ctx, nodeId)); + return obj; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h new file mode 100644 index 0000000..d200262 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h @@ -0,0 +1,34 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "coreobjects/property_impl.h" +#include "opcuatms/opcuatms.h" +#include "opcuatms_client/objects/tms_client_object_impl.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class TmsClientPropertyImpl : public TmsClientObjectImpl, public PropertyImpl +{ +public: + explicit TmsClientPropertyImpl(const ContextPtr& daqContext, const TmsClientContextPtr& ctx, const opcua::OpcUaNodeId& nodeId); + +protected: + void readBasicInfo(); + void configurePropertyFields(); +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_factory.h new file mode 100644 index 0000000..db3600f --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_factory.h @@ -0,0 +1,50 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once +#include "opcuatms/opcuatms.h" +#include "opcuatms_client/objects/tms_client_context.h" +#include "opcuatms_client/objects/tms_client_property_object_impl.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +OPENDAQ_DECLARE_CLASS_FACTORY_WITH_INTERFACE(INLINE_FACTORY, + TmsClientPropertyObject, + IPropertyObject, + const daq::ContextPtr&, + daqContext, + const daq::opcua::tms::TmsClientContextPtr&, + clientContext, + const opcua::OpcUaNodeId&, + nodeId) + +OPENDAQ_DEFINE_CLASS_FACTORY_WITH_INTERFACE(INLINE_FACTORY, + TmsClientPropertyObject, + IPropertyObject, + const daq::ContextPtr&, + daqContext, + const daq::opcua::tms::TmsClientContextPtr&, + ctx, + const opcua::OpcUaNodeId&, + nodeId) + +inline PropertyObjectPtr TmsClientPropertyObject(const ContextPtr& daqContext, const TmsClientContextPtr& ctx, const OpcUaNodeId& nodeId) +{ + auto obj(TmsClientPropertyObject_Create(daqContext, ctx, nodeId)); + return obj; +} + + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h new file mode 100644 index 0000000..995e5de --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h @@ -0,0 +1,123 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "coreobjects/property_object_impl.h" +#include "opcuaclient/opcuaclient.h" +#include "opcuatms/opcuatms.h" +#include "opcuatms_client/objects/tms_client_object_impl.h" +#include "opcuaclient/reference_utils.h" +#include "opendaq/channel_impl.h" +#include "opendaq/streaming_info_impl.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +namespace detail +{ + template + using enable_if_any = std::enable_if_t<(std::is_same_v || ...), int>; + + template + using enable_if_none = std::enable_if_t || ...), int>; +} + +template +class TmsClientPropertyObjectBaseImpl; + +using TmsClientPropertyObjectImpl = TmsClientPropertyObjectBaseImpl; + +template +class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl +{ +public: + + template = 0> + TmsClientPropertyObjectBaseImpl(const ContextPtr& daqContext, const TmsClientContextPtr& clientContext, const opcua::OpcUaNodeId& nodeId) + : TmsClientObjectImpl(daqContext, clientContext, nodeId) + , Impl() + , referenceUtils(client) + { + browseRawProperties(); + } + + template = 0> + TmsClientPropertyObjectBaseImpl(const ContextPtr& daqContext, + const StringPtr& protocolId, + const TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId) + : TmsClientObjectImpl(daqContext, clientContext, nodeId) + , Impl(protocolId) + , referenceUtils(client) + { + browseRawProperties(); + } + + template = 0> + TmsClientPropertyObjectBaseImpl(const ContextPtr& ctx, + const ComponentPtr& parent, + const StringPtr& localId, + const TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId) + : TmsClientObjectImpl(ctx, clientContext, nodeId) + , Impl(ctx, parent, localId) + , referenceUtils(client) + { + browseRawProperties(); + } + + template = 0> + TmsClientPropertyObjectBaseImpl(const ContextPtr& ctx, + const ComponentPtr& parent, + const StringPtr& localId, + const TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId, + const FunctionBlockTypePtr& type) + : TmsClientObjectImpl(ctx, clientContext, nodeId) + , Impl(type, ctx, parent, localId) + , referenceUtils(client) + { + browseRawProperties(); + } + + ErrCode INTERFACE_FUNC setPropertyValue(IString* propertyName, IBaseObject* value) override; + ErrCode INTERFACE_FUNC setProtectedPropertyValue(IString* propertyName, IBaseObject* value) override; + ErrCode INTERFACE_FUNC getPropertyValue(IString* propertyName, IBaseObject** value) override; + ErrCode INTERFACE_FUNC getPropertySelectionValue(IString* propertyName, IBaseObject** value) override; + ErrCode INTERFACE_FUNC clearPropertyValue(IString* propertyName) override; + ErrCode INTERFACE_FUNC getProperty(IString* propertyName, IProperty** value) override; + ErrCode INTERFACE_FUNC addProperty(IProperty* property) override; + ErrCode INTERFACE_FUNC removeProperty(IString* propertyName) override; + ErrCode INTERFACE_FUNC getOnPropertyValueWrite(IString* propertyName, IEvent** event) override; + ErrCode INTERFACE_FUNC getOnPropertyValueRead(IString* propertyName, IEvent** event) override; + ErrCode INTERFACE_FUNC getVisibleProperties(IList** properties) override; + ErrCode INTERFACE_FUNC hasProperty(IString* propertyName, Bool* hasProperty) override; + ErrCode INTERFACE_FUNC getAllProperties(IList** properties) override; + ErrCode INTERFACE_FUNC setPropertyOrder(IList* orderedPropertyNames) override; + +protected: + opcua::ReferenceUtils referenceUtils; + std::unordered_map introspectionVariableIdMap; + std::unordered_map referenceVariableIdMap; + std::unordered_map objectTypeIdMap; + opcua::OpcUaNodeId methodParentNodeId; + + void addProperties(const tsl::ordered_map>& references); + void addMethodProperties(const tsl::ordered_map>& references, const opcua::OpcUaNodeId& parentNodeId); + void browseRawProperties(); + ErrCode INTERFACE_FUNC setPropertyValueInternal(IString* propertyName, IBaseObject* value, bool protectedWrite); +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_factory.h new file mode 100644 index 0000000..26ca65a --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_factory.h @@ -0,0 +1,67 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once +#include "opcuatms_client/objects/tms_client_context.h" +#include "opcuatms_client/objects/tms_client_signal_impl.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +inline SignalPtr TmsClientSignal( + const ContextPtr& ctx, + const ComponentPtr& parent, + const StringPtr& localId, + const daq::opcua::tms::TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId) +{ + SignalPtr obj(createWithImplementation(ctx, parent, localId, clientContext, nodeId)); + return obj; +} + +namespace details +{ + inline bool endsWith(std::string const& str, std::string const& suffix) + { + if (str.length() < suffix.length()) + { + return false; + } + return str.compare(str.length() - suffix.length(), suffix.length(), suffix) == 0; + } +} + +inline SignalPtr FindOrCreateTmsClientSignal(const ContextPtr& ctx, + const ComponentPtr& parent, + const daq::opcua::tms::TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId) +{ + SignalPtr clientSignal = clientContext->getObject(nodeId); + if (!clientSignal.assigned()) + { + auto localId = clientContext->getClient()->readBrowseName(nodeId); + clientSignal = TmsClientSignal(ctx, parent, localId, clientContext, nodeId); + + // TODO current client implementation limitation: The order of populating signals is important. + // The linked signal must be populated after the main signal; otherwise, the signal will have the wrong global ID. + if (!details::endsWith(clientSignal.getGlobalId(), nodeId.getIdentifier())) + ctx.getLogger() + .getOrAddComponent("OpcUaTmsClient") + .logMessage(SourceLocation(), "Wrong global ID of the signal on the client side (TODO)", LogLevel::Warn); + } + + return clientSignal; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h new file mode 100644 index 0000000..6020840 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h @@ -0,0 +1,74 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "opendaq/signal_remote_impl.h" +#include "opcuatms_client/objects/tms_client_component_impl.h" +#include "opendaq/data_descriptor_ptr.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +// TmsClientSignalImpl + +using SignalRemoteNoProps = SignalRemote; + +class TmsClientSignalImpl final : public TmsClientComponentBaseImpl +{ +public: + explicit TmsClientSignalImpl(const ContextPtr& ctx, + const ComponentPtr& parent, + const StringPtr& localId, + const TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId); + + ErrCode INTERFACE_FUNC getPublic(Bool* active) override; + ErrCode INTERFACE_FUNC setPublic(Bool active) override; + + ErrCode INTERFACE_FUNC getDescriptor(IDataDescriptor** descriptor) override; + ErrCode INTERFACE_FUNC setDescriptor(IDataDescriptor* descriptor) override; + + ErrCode INTERFACE_FUNC getDomainSignal(ISignal** signal) override; + SignalPtr onGetDomainSignal(); + ErrCode INTERFACE_FUNC setDomainSignal(ISignal* signal) override; + + ErrCode INTERFACE_FUNC getRelatedSignals(IList** signals) override; + ListPtr onGetRelatedSignals(); + ErrCode INTERFACE_FUNC setRelatedSignals(IList* signals) override; + ErrCode INTERFACE_FUNC addRelatedSignal(ISignal* signal) override; + ErrCode INTERFACE_FUNC removeRelatedSignal(ISignal* signal) override; + ErrCode INTERFACE_FUNC clearRelatedSignals() override; + + ErrCode INTERFACE_FUNC getName(IString** name) override; + ErrCode INTERFACE_FUNC setName(IString* name) override; + + StringPtr onGetRemoteId() const override; + Bool onTriggerEvent(EventPacketPtr eventPacket) override; + +protected: + EventPacketPtr createDataDescriptorChangedEventPacket() override; + void triggerDataDescriptorChanged(const EventPacketPtr& eventPacket); + + std::atomic isPublic = true; + DataDescriptorPtr lastSignalDescriptor; + DataDescriptorPtr lastDomainDescriptor; + std::mutex signalMutex; + std::string deviceSignalId; + +private: + std::unique_ptr descriptorNodeId; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_streaming_info_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_streaming_info_factory.h new file mode 100644 index 0000000..84cafeb --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_streaming_info_factory.h @@ -0,0 +1,33 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once +#include "opcuatms_client/objects/tms_client_context.h" +#include "opcuatms_client/objects/tms_client_streaming_info_impl.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS +inline StreamingInfoConfigPtr TmsClientStreamingInfo(const ContextPtr& daqContext, + const StringPtr& protocolId, + const daq::opcua::tms::TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId) +{ + StreamingInfoConfigPtr obj( + createWithImplementation(daqContext, protocolId, clientContext, nodeId) + ); + return obj; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_streaming_info_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_streaming_info_impl.h new file mode 100644 index 0000000..7523ae1 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_streaming_info_impl.h @@ -0,0 +1,32 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "opcuatms_client/objects/tms_client_property_object_impl.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class TmsClientStreamingInfoImpl : public TmsClientPropertyObjectBaseImpl +{ +public: + explicit TmsClientStreamingInfoImpl(const ContextPtr& daqContext, + const StringPtr& protocolId, + const TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId); +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h new file mode 100644 index 0000000..922ab5d --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h @@ -0,0 +1,51 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include "opcuatms/opcuatms.h" +#include "opcuaclient/opcuaclient.h" +#include "opcuatms_client/objects/tms_client_device_factory.h" +#include "opcuatms_client/objects/tms_client_context.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class TmsClient final +{ +public: + TmsClient(const ContextPtr& context, + const ComponentPtr& parent, + const std::string& opcUaUrl, + const FunctionPtr& createStreamingCallback); + + daq::DevicePtr connect(); + +protected: + daq::opcua::OpcUaNodeId getRootDeviceNodeId(); + + tms::TmsClientContextPtr tmsClientContext; + ContextPtr context; + daq::opcua::OpcUaClientPtr client; + std::string opcUaUrl; + FunctionPtr createStreamingCallback; + ComponentPtr parent; + +private: + StringPtr getUniqueLocalId(const StringPtr& localId, int iteration = 0); +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt new file mode 100644 index 0000000..bb0cf40 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt @@ -0,0 +1,130 @@ +set(LIB_NAME opcuatms_client) + +set(SRC_Cpp tms_client.cpp +) + +set(SRC_PublicHeaders +) + +set(SRC_PrivateHeaders tms_client.h +) + +# objects + +set(OBJECT_SRC_DIR "objects") + +set(SRC_Objects_Headers ${OBJECT_SRC_DIR}/tms_client_object_impl.h + ${OBJECT_SRC_DIR}/tms_client_context.h + + ${OBJECT_SRC_DIR}/tms_client_signal_impl.h + ${OBJECT_SRC_DIR}/tms_client_signal_factory.h + + ${OBJECT_SRC_DIR}/tms_client_function_block_impl.h + ${OBJECT_SRC_DIR}/tms_client_function_block_factory.h + + ${OBJECT_SRC_DIR}/tms_client_channel_impl.h + ${OBJECT_SRC_DIR}/tms_client_channel_factory.h + + ${OBJECT_SRC_DIR}/tms_client_property_impl.h + ${OBJECT_SRC_DIR}/tms_client_property_factory.h + + ${OBJECT_SRC_DIR}/tms_client_input_port_impl.h + ${OBJECT_SRC_DIR}/tms_client_input_port_factory.h + + ${OBJECT_SRC_DIR}/tms_client_property_object_impl.h + ${OBJECT_SRC_DIR}/tms_client_property_object_factory.h + + ${OBJECT_SRC_DIR}/tms_client_device_impl.h + ${OBJECT_SRC_DIR}/tms_client_device_factory.h + + ${OBJECT_SRC_DIR}/tms_client_folder_impl.h + ${OBJECT_SRC_DIR}/tms_client_folder_factory.h + + ${OBJECT_SRC_DIR}/tms_client_io_folder_impl.h + ${OBJECT_SRC_DIR}/tms_client_io_folder_factory.h + + ${OBJECT_SRC_DIR}/tms_client_component_impl.h + ${OBJECT_SRC_DIR}/tms_client_component_factory.h + + ${OBJECT_SRC_DIR}/tms_client_streaming_info_impl.h + ${OBJECT_SRC_DIR}/tms_client_streaming_info_factory.h + + ${OBJECT_SRC_DIR}/tms_client_function_impl.h + ${OBJECT_SRC_DIR}/tms_client_function_factory.h + + ${OBJECT_SRC_DIR}/tms_client_procedure_impl.h + ${OBJECT_SRC_DIR}/tms_client_procedure_factory.h +) + +set(SRC_Objects ${OBJECT_SRC_DIR}/tms_client_object_impl.cpp + ${OBJECT_SRC_DIR}/tms_client_context.cpp + ${OBJECT_SRC_DIR}/tms_client_signal_impl.cpp + ${OBJECT_SRC_DIR}/tms_client_function_block_impl.cpp + ${OBJECT_SRC_DIR}/tms_client_channel_impl.cpp + ${OBJECT_SRC_DIR}/tms_client_input_port_impl.cpp + ${OBJECT_SRC_DIR}/tms_client_property_impl.cpp + ${OBJECT_SRC_DIR}/tms_client_property_object_impl.cpp + ${OBJECT_SRC_DIR}/tms_client_device_impl.cpp + ${OBJECT_SRC_DIR}/tms_client_folder_impl.cpp + ${OBJECT_SRC_DIR}/tms_client_io_folder_impl.cpp + ${OBJECT_SRC_DIR}/tms_client_component_impl.cpp + ${OBJECT_SRC_DIR}/tms_client_streaming_info_impl.cpp + ${OBJECT_SRC_DIR}/tms_client_function_impl.cpp + ${OBJECT_SRC_DIR}/tms_client_procedure_impl.cpp +) + +set(SRC_PublicHeaders ${SRC_PublicHeaders} ${SRC_Objects_Headers}) +set(SRC_Cpp ${SRC_Cpp} ${SRC_Objects}) + +source_group("objects\\client_object" "${OBJECT_SRC_DIR}/(tms_client_object.*|tms_client_context.*)") +source_group("objects\\signal" "${OBJECT_SRC_DIR}/tms_client_signal.*") +source_group("objects\\function_block" "${OBJECT_SRC_DIR}/tms_client_function_block.*") +source_group("objects\\channel" "${OBJECT_SRC_DIR}/tms_client_channel.*") +source_group("objects\\input_port" "${OBJECT_SRC_DIR}/tms_client_input_port.*") +source_group("objects\\property" "${OBJECT_SRC_DIR}/tms_client_property.*") +source_group("objects\\property_object" "${OBJECT_SRC_DIR}/tms_client_property_object.*") +source_group("objects\\device" "${OBJECT_SRC_DIR}/tms_client_device.*") +source_group("objects\\folder" "${OBJECT_SRC_DIR}/tms_client_folder.*") +source_group("objects\\component" "${OBJECT_SRC_DIR}/tms_client_component.*") +source_group("objects\\io_folder" "${OBJECT_SRC_DIR}/tms_client_io_folder.*") +source_group("objects\\streaming_info" "${OBJECT_SRC_DIR}/tms_client_streaming_info.*") +source_group("objects\\function" "${OBJECT_SRC_DIR}/(tms_client_function_impl.*|tms_client_function_factory.h|tms_client_procedure.*)") + +# /objects + +prepend_include(${LIB_NAME} SRC_PrivateHeaders) +prepend_include(${LIB_NAME} SRC_PublicHeaders) + +add_library(${LIB_NAME} STATIC ${SRC_Cpp} + ${SRC_PublicHeaders} + ${SRC_PrivateHeaders} +) + +add_library(${SDK_TARGET_NAMESPACE}::${LIB_NAME} ALIAS ${LIB_NAME}) + +if(BUILD_64Bit OR BUILD_ARM) + set_target_properties(${LIB_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON) +else() + set_target_properties(${LIB_NAME} PROPERTIES POSITION_INDEPENDENT_CODE OFF) +endif() + +target_link_libraries(${LIB_NAME} + PUBLIC + daq::opcuatms + daq::opcuaclient + PRIVATE + daq::signal_dev + daq::streaming_dev + daq::device_dev + daq::component_dev +) + +target_include_directories(${LIB_NAME} PUBLIC $ + $ + + $ +) + +set_target_properties(${LIB_NAME} PROPERTIES PUBLIC_HEADER "${SRC_PublicHeaders}") + +opendaq_set_output_lib_name(${LIB_NAME} ${PROJECT_VERSION_MAJOR}) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_channel_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_channel_impl.cpp new file mode 100644 index 0000000..0da0900 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_channel_impl.cpp @@ -0,0 +1,19 @@ +#include "opcuatms_client/objects/tms_client_channel_impl.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace opcua; + +TmsClientChannelImpl::TmsClientChannelImpl( + const ContextPtr& context, + const ComponentPtr& parent, + const StringPtr& localId, + const daq::opcua::tms::TmsClientContextPtr& clientContext, + const OpcUaNodeId& nodeId +) + : TmsClientFunctionBlockBaseImpl(context, parent, localId, clientContext, nodeId) +{ + +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp new file mode 100644 index 0000000..b3ca8ad --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp @@ -0,0 +1,53 @@ +#include "opcuatms_client/objects/tms_client_component_impl.h" +#include "opendaq/device_impl.h" +#include "opendaq/folder_impl.h" +#include "opendaq/io_folder_impl.h" +#include "opendaq/signal_remote_impl.h" +#include "opendaq/input_port_impl.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace daq::opcua; + +template +ErrCode TmsClientComponentBaseImpl::getActive(Bool* active) +{ + return daqTry([&]() { + *active = this->template readValue("Active"); + return OPENDAQ_SUCCESS; + }); +} + +template +ErrCode TmsClientComponentBaseImpl::setActive(Bool active) +{ + return daqTry([&]() { + this->template writeValue("Active", active); + return OPENDAQ_SUCCESS; + }); +} + +template +ErrCode TmsClientComponentBaseImpl::getTags(ITagsConfig** tags) +{ + return daqTry([&]() { + ListPtr tagValues = this->template readList("Tags"); + auto tagsObj = Tags(); + for (auto tag : tagValues) + tagsObj.add(tag); + tagsObj.freeze(); + *tags = tagsObj.detach(); + return OPENDAQ_SUCCESS; + }); +} + +template class TmsClientComponentBaseImpl>; +template class TmsClientComponentBaseImpl>; +template class TmsClientComponentBaseImpl; +template class TmsClientComponentBaseImpl; +template class TmsClientComponentBaseImpl; +template class TmsClientComponentBaseImpl; +template class TmsClientComponentBaseImpl>; +template class TmsClientComponentBaseImpl; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp new file mode 100644 index 0000000..c51f2e5 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp @@ -0,0 +1,51 @@ +#include "opcuatms_client/objects/tms_client_context.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace opcua; + +TmsClientContext::TmsClientContext(const OpcUaClientPtr& client) + : client(client) +{ +} + +const opcua::OpcUaClientPtr& TmsClientContext::getClient() const +{ + return client; +} + +void TmsClientContext::registerObject(const OpcUaNodeId& nodeId, const BaseObjectPtr& object) +{ + std::lock_guard guard(mutex); + objects[nodeId] = object.getObject(); +} + +void TmsClientContext::unregisterObject(const OpcUaNodeId& nodeId) +{ + std::lock_guard guard(mutex); + objects.extract(nodeId); +} + +BaseObjectPtr TmsClientContext::getObject(const opcua::OpcUaNodeId& nodeId) const +{ + std::lock_guard guard(mutex); + auto it = objects.find(nodeId); + if (it != objects.end()) + { + IBaseObject* obj = it->second; + return BaseObjectPtr(obj); + } + + return {}; +} +opcua::OpcUaNodeId TmsClientContext::getNodeId(const BaseObjectPtr object) const +{ + for (auto pair : objects) + { + if (object == pair.second) + return pair.first; + } + return opcua::OpcUaNodeId(); +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp new file mode 100644 index 0000000..67d3af4 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -0,0 +1,349 @@ +#include "opcuatms_client/objects/tms_client_device_impl.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "opcuatms_client/objects/tms_client_component_factory.h" +#include "opcuatms_client/objects/tms_client_io_folder_factory.h" +#include "opcuatms_client/objects/tms_client_streaming_info_factory.h" +#include +#include "open62541/tmsbt_nodeids.h" +#include +#include +#include +#include +#include "opcuatms/core_types_utils.h" +#include "opcuatms/exceptions.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS +using namespace daq::opcua; + +namespace detail +{ + static std::unordered_set defaultComponents = {"Signals", "FunctionBlocks", "InputsOutputs", "StreamingOptions"}; + + static std::unordered_map> deviceInfoSetterMap = { + {"AssetId", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setAssetId(v.toString()); }}, + {"ComponentName", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v){ info.setName(v.toString()); }}, + {"DeviceClass", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setDeviceClass(v.toString()); }}, + {"DeviceManual", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setDeviceManual(v.toString()); }}, + {"DeviceRevision", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setDeviceRevision(v.toString()); }}, + {"HardwareRevision", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setHardwareRevision(v.toString()); }}, + {"Manufacturer", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setManufacturer(v.toString()); }}, + {"ManufacturerUri", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setManufacturerUri(v.toString()); }}, + {"Model", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setModel(v.toString()); }}, + {"ProductCode", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setProductCode(v.toString()); }}, + {"ProductInstanceUri", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setProductInstanceUri(v.toString()); }}, + {"RevisionCounter", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setRevisionCounter(v.toInteger()); }}, + {"SerialNumber", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setSerialNumber(v.toString()); }}, + {"SoftwareRevision", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setSoftwareRevision(v.toString()); }}, + {"MacAddress", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setMacAddress(v.toString()); }}, + {"ParentMacAddress", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setParentMacAddress(v.toString()); }}, + {"Platform", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setPlatform(v.toString()); }}, + {"Position", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setPosition(v.toInteger()); }}, + {"SystemType", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setSystemType(v.toString()); }}, + {"SystemUUID", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setSystemUuid(v.toString()); }} + }; +} + +TmsClientDeviceImpl::TmsClientDeviceImpl(const ContextPtr& ctx, + const ComponentPtr& parent, + const StringPtr& localId, + const TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId, + const FunctionPtr& createStreamingCallback, + bool isRootDevice) + : TmsClientComponentBaseImpl(ctx, parent, localId, clientContext, nodeId) + , createStreamingCallback(createStreamingCallback) + , isRootDevice(isRootDevice) + , logger(ctx.getLogger()) + , loggerComponent( this->logger.assigned() + ? this->logger.getOrAddComponent("TmsClientDevice") + : throw ArgumentNullException("Logger must not be null")) +{ + findAndCreateSubdevices(); + findAndCreateFunctionBlocks(); + findAndCreateSignals(); + findAndCreateInputsOutputs(); + findAndCreateCustomComponents(); + + findAndCreateStreamingOptions(); + connectToStreamings(); + setUpStreamings(); +} + +void TmsClientDeviceImpl::findAndCreateSubdevices() +{ + auto subdeviceNodeIds = this->getChildNodes(client, nodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQDEVICETYPE)); + for (const auto& subdeviceNodeId : subdeviceNodeIds) + { + auto browseName = client->readBrowseName(subdeviceNodeId); + auto clientSubdevice = TmsClientDevice(context, devices, browseName, clientContext, subdeviceNodeId, createStreamingCallback); + addSubDevice(clientSubdevice); + } +} + +DevicePtr TmsClientDeviceImpl::onAddDevice(const StringPtr& /*connectionString*/, const PropertyObjectPtr& /*config*/) +{ + throw OpcUaClientCallNotAvailableException(); +} + +void TmsClientDeviceImpl::onRemoveDevice(const DevicePtr& /*device*/) +{ + throw OpcUaClientCallNotAvailableException(); +} + +DeviceInfoPtr TmsClientDeviceImpl::onGetInfo() +{ + if (deviceInfo.assigned()) + return deviceInfo; + + deviceInfo = DeviceInfo(""); + + BrowseRequest request(nodeId, OpcUaNodeClass::Variable); + OpcUaBrowser browser(request, client); + const auto& browseResult = browser.browse(); + + for (const UA_ReferenceDescription& reference : browseResult) + { + std::string browseName = daq::opcua::utils::ToStdString(reference.browseName.name); + if (detail::deviceInfoSetterMap.count(browseName)) + detail::deviceInfoSetterMap[browseName](deviceInfo, client->readValue(OpcUaNodeId(reference.nodeId.nodeId))); + else if (browseName != "NumberInList" && browseName != "OpenDaqPackageVersion") + { + // TODO: Group requests for data type and scalar/array checks and only read required values + try + { + auto value = client->readValue(OpcUaNodeId(reference.nodeId.nodeId)); + if (value.isScalar()) + { + if (value.isString()) + deviceInfo.addProperty(StringProperty(browseName, value.toString())); + else if(value.isBool()) + deviceInfo.addProperty(BoolProperty(browseName, value.toBool())); + else if(value.isDouble()) + deviceInfo.addProperty(FloatProperty(browseName, value.toDouble())); + else if(value.isInteger()) + deviceInfo.addProperty(IntProperty(browseName, value.toInteger())); + } + } + catch(...) + { + } + } + } + + deviceInfo.freeze(); + return deviceInfo; +} + +void TmsClientDeviceImpl::fetchTimeDomain() +{ + if (timeDomainFetched) + return; + auto timeDomainNodeId = getNodeId("Domain"); + auto variant = client->readValue(timeDomainNodeId); + + UA_DeviceDomainStructure* deviceDomain; + deviceDomain = (UA_DeviceDomainStructure*) variant.getValue().data; + + auto numerator = deviceDomain->resolution.numerator; + auto denominator = deviceDomain->resolution.denominator; + if (denominator == 0) + denominator = 1; + resolution = Ratio(numerator, denominator); + origin = ConvertToDaqCoreString(deviceDomain->origin); + if (deviceDomain->unit.unitId > 0) + domainUnit = Unit(ConvertToDaqCoreString(deviceDomain->unit.displayName.text), + deviceDomain->unit.unitId, + ConvertToDaqCoreString(deviceDomain->unit.description.text), + ConvertToDaqCoreString(deviceDomain->unit.quantity)); + else + domainUnit = Unit(""); + timeDomainFetched = true; +} + +void TmsClientDeviceImpl::fetchTicksSinceOrigin() +{ + auto timeDomainNodeId = getNodeId("Domain"); + auto variant = client->readValue(timeDomainNodeId); + + UA_DeviceDomainStructure* deviceDomain; + deviceDomain = (UA_DeviceDomainStructure*) variant.getValue().data; + ticksSinceOrigin = deviceDomain->ticksSinceOrigin; +} + +RatioPtr TmsClientDeviceImpl::onGetResolution() +{ + fetchTimeDomain(); + return resolution; +} + +uint64_t TmsClientDeviceImpl::onGetTicksSinceOrigin() +{ + if(!timeDomainFetched) + fetchTimeDomain(); + else + fetchTicksSinceOrigin(); + + return ticksSinceOrigin; +} + +std::string TmsClientDeviceImpl::onGetOrigin() +{ + fetchTimeDomain(); + return origin; +} + +UnitPtr TmsClientDeviceImpl::onGetDomainUnit() +{ + fetchTimeDomain(); + return domainUnit; +} + +void TmsClientDeviceImpl::findAndCreateFunctionBlocks() +{ + auto functionBlocksNodeId = getNodeId("FunctionBlocks"); + auto functionBlockNodeIds = + this->getChildNodes(client, functionBlocksNodeId, OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_FUNCTIONBLOCKTYPE)); + for (const auto& functionBlockNodeId : functionBlockNodeIds) + { + auto browseName = client->readBrowseName(functionBlockNodeId); + auto clientFunctionBlock = TmsClientFunctionBlock(context, this->functionBlocks, browseName, clientContext, functionBlockNodeId); + this->addNestedFunctionBlock(clientFunctionBlock); + } +} + +void TmsClientDeviceImpl::findAndCreateSignals() +{ + auto signalsNodeId = getNodeId("Signals"); + auto signalNodeIds = this->getChildNodes(client, signalsNodeId, OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_SIGNALTYPE)); + for (const auto& signalNodeId : signalNodeIds) + { + auto clientSignal = FindOrCreateTmsClientSignal(context, signals, clientContext, signalNodeId); + this->addSignal(clientSignal); + } +} + +void TmsClientDeviceImpl::findAndCreateInputsOutputs() +{ + this->ioFolder.clear(); + auto inputsOutputsNodeId = getNodeId("InputsOutputs"); + + auto channelNodeIds = this->getChildNodes(client, inputsOutputsNodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_CHANNELTYPE)); + for (const auto& channelNodeId : channelNodeIds) + { + auto browseName = client->readBrowseName(channelNodeId); + auto tmsClientChannel = TmsClientChannel(context, this->ioFolder, browseName, clientContext, channelNodeId); + this->ioFolder.addItem(tmsClientChannel); + } + + auto folderNodeIds = this->getChildNodes(client, inputsOutputsNodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_IOCOMPONENTTYPE)); + for (const auto& folderNodeId : folderNodeIds) + { + auto browseName = client->readBrowseName(folderNodeId); + auto tmsClientFolder = TmsClientIoFolder(context, this->ioFolder, browseName, clientContext, folderNodeId); + this->ioFolder.addItem(tmsClientFolder); + } +} + +void TmsClientDeviceImpl::findAndCreateStreamingOptions() +{ + this->streamingOptions.clear(); + auto streamingOptionsNodeId = getNodeId("StreamingOptions"); + try + { + auto streamingOptionNodeIds = + this->getChildNodes(client, streamingOptionsNodeId, OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_VARIABLEBLOCKTYPE)); + for (const auto& streamingOptionNodeId : streamingOptionNodeIds) + { + auto browseName = client->readBrowseName(streamingOptionNodeId); + auto clientStreamingInfo = TmsClientStreamingInfo(daqContext, browseName, clientContext, streamingOptionNodeId); + this->streamingOptions.push_back(clientStreamingInfo); + } + } + catch (const std::exception& e) + { + LOG_E("Failed to find 'StreamingOptions' OpcUa node: {}", e.what()); + // FIXME this is a temporary workaround for compability with legacy simulator + if (isRootDevice) + { + auto streamingInfo = StreamingInfo("daq.wss"); + streamingInfo.addProperty(IntProperty("Port", 7414)); + this->streamingOptions.push_back(streamingInfo); + } + } +} + +void TmsClientDeviceImpl::findAndCreateCustomComponents() +{ + auto componentId = OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQCOMPONENTTYPE); + auto folderNodeIds = this->getChildNodes(client, nodeId, componentId); + for (const auto& folderNodeId : folderNodeIds) + { + auto browseName = client->readBrowseName(folderNodeId); + if (detail::defaultComponents.count(browseName)) + continue; + + auto childComponents = this->getChildNodes(client, folderNodeId, componentId); + if (childComponents.size()) + { + this->components.push_back(TmsClientFolder(context, this->thisPtr(), browseName, clientContext, folderNodeId)); + } + else + { + this->components.push_back(TmsClientComponent(context, this->thisPtr(), browseName, clientContext, folderNodeId)); + } + } +} + +FunctionBlockPtr TmsClientDeviceImpl::onAddFunctionBlock(const StringPtr& /*typeId*/, const PropertyObjectPtr& /*config*/) +{ + throw OpcUaClientCallNotAvailableException(); +} + +void TmsClientDeviceImpl::onRemoveFunctionBlock(const FunctionBlockPtr& /*functionBlock*/) +{ + throw OpcUaClientCallNotAvailableException(); +} + +void TmsClientDeviceImpl::setUpStreamings() +{ + auto self = this->borrowPtr(); + const auto signals = self.getSignalsRecursive(); + LOG_I("Device \"{}\" has established {} streaming connections", globalId, streamings.size()); + for (const auto& streaming : streamings) + { + LOG_I("Device \"{}\" adding signals to a streaming connection on url: {}", globalId, streaming.getConnectionString()); + streaming.addSignals(signals); + streaming.setActive(true); + } +} + +void TmsClientDeviceImpl::connectToStreamings() +{ + if (createStreamingCallback.assigned()) + { + for (const auto& option : streamingOptions) + { + StreamingPtr streaming; + ErrCode errCode = wrapHandlerReturn(createStreamingCallback, streaming, option, isRootDevice); + + if (OPENDAQ_FAILED(errCode) || !streaming.assigned()) + { + LOG_W("Device \"{}\" had not connected to published streaming protocol \"{}\".", globalId, option.getProtocolId()); + } + else + { + streamings.push_back(streaming); + } + } + } +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp new file mode 100644 index 0000000..a9ec05a --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp @@ -0,0 +1,44 @@ +#include +#include +#include "opcuatms_client/objects/tms_client_folder_impl.h" +#include "opendaq/io_folder_impl.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace daq::opcua; + +template +TmsClientFolderImpl::TmsClientFolderImpl(const ContextPtr& ctx, + const ComponentPtr& parent, + const StringPtr& localId, + const TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId, + bool customFolderType) + : TmsClientComponentBaseImpl(ctx, parent, localId, clientContext, nodeId) +{ + if (!customFolderType) + findAndCreateFolders(); +} + +template +void TmsClientFolderImpl::findAndCreateFolders() +{ + auto componentId = OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQCOMPONENTTYPE); + auto folderNodeIds = this->getChildNodes(this->client, this->nodeId, componentId); + for (const auto& folderNodeId : folderNodeIds) + { + auto browseName = this->client->readBrowseName(folderNodeId); + auto thisPtr = this->template borrowPtr(); + + auto childComponents = this->getChildNodes(this->client, folderNodeId, componentId); + if (childComponents.size()) + thisPtr.addItem(TmsClientFolder(this->context, thisPtr, browseName, this->clientContext, folderNodeId)); + else + thisPtr.addItem(TmsClientComponent(this->context, thisPtr, browseName, this->clientContext, folderNodeId)); + } +} + +template class TmsClientFolderImpl>; +template class TmsClientFolderImpl; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp new file mode 100644 index 0000000..f71421c --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp @@ -0,0 +1,133 @@ +#include +#include +#include "opcuatms_client/objects/tms_client_function_block_impl.h" +#include "opcuatms_client/objects/tms_client_signal_factory.h" +#include "opcuatms_client/objects/tms_client_function_block_factory.h" +#include "opcuatms_client/objects/tms_client_input_port_factory.h" +#include "open62541/tmsbsp_nodeids.h" + + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace opcua; + +template +TmsClientFunctionBlockBaseImpl::TmsClientFunctionBlockBaseImpl( + const ContextPtr& context, + const ComponentPtr& parent, + const StringPtr& localId, + const TmsClientContextPtr& clientContext, + const OpcUaNodeId& nodeId +) + : TmsClientComponentBaseImpl(context, parent, localId, clientContext, nodeId, nullptr) +{ + readFbType(); + findAndCreateFunctionBlocks(); + findAndCreateSignals(); + findAndCreateInputPorts(); +} + +template +tsl::ordered_set TmsClientFunctionBlockBaseImpl::getFunctionBlockNodeIds() +{ + const OpcUaNodeId referenceTypeId(UA_NS0ID_HASCOMPONENT); + const OpcUaNodeId functionBlockType(NAMESPACE_TMSBSP, UA_TMSBSPID_FUNCTIONBLOCKTYPE); // TODO subtypes + return this->referenceUtils.getReferencedNodes(this->nodeId, referenceTypeId, true, functionBlockType); +} + +template +tsl::ordered_set TmsClientFunctionBlockBaseImpl::getOutputSignalNodeIds() +{ + auto signalsNodeId = this->getNodeId("OutputSignals"); + OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASVALUESIGNAL); + + return this->referenceUtils.getReferencedNodes(signalsNodeId, referenceTypeId, true); +} + +template +void TmsClientFunctionBlockBaseImpl::findAndCreateFunctionBlocks() +{ + auto functionBlockNodeIds = getFunctionBlockNodeIds(); + for (const auto& functionBlockNodeId : functionBlockNodeIds) + { + auto browseName = this->client->readBrowseName(functionBlockNodeId); + try + { + // TODO: If there is no access to the nodes within a function blocks an exeption + // is thrown which results that the application stops. However, this block should + // just be ignored. It is not an error at all. + auto clientFunctionBlock = TmsClientFunctionBlock(this->context, this->functionBlocks, browseName, this->clientContext, functionBlockNodeId); + this->addNestedFunctionBlock(clientFunctionBlock); + } + catch(...) + { + // TODO: Log failure to add function/procedure. + continue; + } + } +} + +template +void TmsClientFunctionBlockBaseImpl::findAndCreateSignals() +{ + auto signalNodeIds = getOutputSignalNodeIds(); + for (const auto& signalNodeId : signalNodeIds) + { + auto clientSignal = FindOrCreateTmsClientSignal(this->context, this->signals, this->clientContext, signalNodeId); + this->addSignal(clientSignal); + } +} + +template +tsl::ordered_set TmsClientFunctionBlockBaseImpl::getInputPortNodeIds() +{ + auto inputPortsNodeId = this->getNodeId("InputPorts"); + OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASINPUTPORT); + + return this->referenceUtils.getReferencedNodes(inputPortsNodeId, referenceTypeId, true); +} + +template +void TmsClientFunctionBlockBaseImpl::findAndCreateInputPorts() +{ + auto inputPortNodeIds = getInputPortNodeIds(); + for (const auto& inputPortNodeId : inputPortNodeIds) + { + auto browseName = this->client->readBrowseName(inputPortNodeId); + auto clientInputPort = TmsClientInputPort(this->context, this->inputPorts, browseName, this->clientContext, inputPortNodeId); + + this->addInputPort(clientInputPort); + } +} + +template +void TmsClientFunctionBlockBaseImpl::readFbType() +{ + auto variant = this->readValue("FunctionBlockInfo"); + this->type = VariantConverter::ToDaqObject(variant).detach(); +} + +template +SignalPtr TmsClientFunctionBlockBaseImpl::onGetStatusSignal() +{ + OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASSTATUSSIGNAL); + + auto nodeIds = this->referenceUtils.getReferencedNodes(this->nodeId, referenceTypeId, true); + + assert(nodeIds.size() <= 1); + if (!nodeIds.empty()) + { + auto signalNodeId = *nodeIds.begin(); + return this->findSignal(signalNodeId); + } + + // Not Found + return nullptr; +} + +// To force the compiler to generate the template classes that are used elsewhere +// If this is not done, then you will get linker errors if using it outside the static library +template class TmsClientFunctionBlockBaseImpl; +template class TmsClientFunctionBlockBaseImpl; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_impl.cpp new file mode 100644 index 0000000..2da85f5 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_impl.cpp @@ -0,0 +1,61 @@ +#include "coretypes/validation.h" +#include "opcuatms_client/objects/tms_client_function_factory.h" +#include "opcuatms/converters/variant_converter.h" +#include "opcuatms/converters/list_conversion_utils.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + using namespace opcua; + +TmsClientFunctionImpl::TmsClientFunctionImpl(const TmsClientContextPtr& ctx, + const ContextPtr& daqContext, + const OpcUaNodeId& parentId, + const OpcUaNodeId& methodId) + : ctx(ctx) + , daqContext(daqContext) + , parentId(parentId) + , methodId(methodId) +{ +} + +ErrCode TmsClientFunctionImpl::call(IBaseObject* args, IBaseObject** result) +{ + // TODO: Return more specific error depending on OPC UA status code + return daqTry([&]() + { + auto argsPtr = BaseObjectPtr::Borrow(args); + OpcUaCallMethodRequest callRequest; + + if (!argsPtr.assigned()) + { + callRequest = OpcUaCallMethodRequest(methodId, parentId, 0); + } + else if (argsPtr.asPtrOrNull().assigned()) + { + auto argsList = argsPtr.asPtrOrNull(); + OpcUaVariant varArgs = ListConversionUtils::ToVariantTypeArrayVariant(argsList, daqContext); + callRequest = OpcUaCallMethodRequest(methodId, parentId, argsList.getCount(), (UA_Variant*) varArgs->data); + } + else + { + OpcUaVariant varArgs = VariantConverter::ToVariant(argsPtr, nullptr, daqContext); + callRequest = OpcUaCallMethodRequest(methodId, parentId, 1, &varArgs.getValue()); + } + + OpcUaObject callResult = ctx->getClient()->callMethod(callRequest); + if (OPCUA_STATUSCODE_FAILED(callResult->statusCode) || (callResult->outputArgumentsSize != 1)) + return OPENDAQ_ERR_CALLFAILED; + + *result = VariantConverter::ToDaqObject(OpcUaVariant(callResult->outputArguments[0]), daqContext).detach(); + return OPENDAQ_SUCCESS; + }); +} + +ErrCode TmsClientFunctionImpl::getCoreType(CoreType* coreType) +{ + OPENDAQ_PARAM_NOT_NULL(coreType); + + *coreType = ctFunc; + return OPENDAQ_SUCCESS; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp new file mode 100644 index 0000000..4dfd00d --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp @@ -0,0 +1,128 @@ +#include "open62541/tmsbsp_nodeids.h" +#include "opcuatms/converters/variant_converter.h" +#include "opcuatms_client/objects/tms_client_input_port_impl.h" +#include "opcuatms/errors.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + using namespace opcua; + +TmsClientInputPortImpl::TmsClientInputPortImpl(const ContextPtr& ctx, + const ComponentPtr& parent, + const StringPtr& localId, + const TmsClientContextPtr& tmsCtx, + const opcua::OpcUaNodeId& nodeId) + : TmsClientComponentBaseImpl(ctx, parent, localId, tmsCtx, nodeId) +{ +} + +ErrCode TmsClientInputPortImpl::getRequiresSignal(Bool* value) +{ + return daqTry([&]() { + *value = readValue("RequiresSignal"); + return OPENDAQ_SUCCESS; + }); +} + +ErrCode TmsClientInputPortImpl::setRequiresSignal(Bool value) +{ + return OPENDAQ_ERR_NOTIMPLEMENTED; +} + +ErrCode TmsClientInputPortImpl::acceptsSignal(ISignal* signal, Bool* accepts) +{ + return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; + + //return daqTry([&]() { + // OpcUaNodeId methodId(NAMESPACE_TMSBSP, UA_TMSBSPID_INPUTPORTTYPE_ACCEPTSSIGNAL); + + // auto signalNodeId = clientContext->getNodeId(signal); + // OpcUaVariant inputArg; + // inputArg.setScalar(*signalNodeId); + + // OpcUaCallMethodRequest callRequest(methodId, nodeId, 1, inputArg.get()); + // OpcUaObject result = client->callMethod(callRequest); + // if (OPCUA_STATUSCODE_FAILED(result->statusCode) || (result->outputArgumentsSize != 1)) + // return OPENDAQ_ERR_CALLFAILED; + + // *accepts = OpcUaVariant(result->outputArguments[0]).toBool(); + // + // return OPENDAQ_SUCCESS; + // + //}); +} + +ErrCode TmsClientInputPortImpl::connect(ISignal* signal) +{ + return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; + //return daqTry([&]() { + // OpcUaNodeId methodId(NAMESPACE_TMSBSP, UA_TMSBSPID_INPUTPORTTYPE_CONNECTSIGNAL); + + // auto signalNodeId = clientContext->getNodeId(signal); + // OpcUaVariant inputArg; + // inputArg.setScalar(*signalNodeId); + + // OpcUaCallMethodRequest callRequest(methodId, nodeId, 1, inputArg.get()); + // OpcUaObject result = client->callMethod(callRequest); + // if (OPCUA_STATUSCODE_FAILED(result->statusCode)) + // return OPENDAQ_ERR_CALLFAILED; + // else + // { + // referenceUtils.updateReferences(nodeId); + // return OPENDAQ_SUCCESS; + // + // } + //}); +} + +ErrCode TmsClientInputPortImpl::disconnect() +{ + return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; + + //return daqTry([&]() { + // OpcUaNodeId methodId(NAMESPACE_TMSBSP, UA_TMSBSPID_INPUTPORTTYPE_DISCONNECTSIGNAL); + + // OpcUaCallMethodRequest callRequest(methodId, nodeId, 0, nullptr); + // OpcUaObject result = client->callMethod(callRequest); + // if (OPCUA_STATUSCODE_FAILED(result->statusCode)) + // return OPENDAQ_ERR_CALLFAILED; + // else + // { + // referenceUtils.updateReferences(nodeId); + // return OPENDAQ_SUCCESS; + // } + //}); +} + +ErrCode TmsClientInputPortImpl::getSignal(ISignal** signal) +{ + SignalPtr signalPtr; + ErrCode errCode = wrapHandlerReturn(this, &TmsClientInputPortImpl::onGetSignal, signalPtr); + + *signal = signalPtr.detach(); + return errCode; +} + +SignalPtr TmsClientInputPortImpl::onGetSignal() +{ + OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_CONNECTEDTOSIGNAL); + auto nodeIds = referenceUtils.getReferencedNodes(nodeId, referenceTypeId, true); + assert(nodeIds.size() <= 1); + + if (!nodeIds.empty()) + { + auto connectedSignalNodeId = *nodeIds.begin(); + return findSignal(connectedSignalNodeId); + } + + return nullptr; +} + +ErrCode TmsClientInputPortImpl::getConnection(IConnection** connection) +{ + return daqTry([&]() { + // TODO: Implement. Awaits support to implement + return OPENDAQ_ERR_NOTIMPLEMENTED; + }); +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp new file mode 100644 index 0000000..c22c2b1 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp @@ -0,0 +1,46 @@ +#include "opcuatms_client/objects/tms_client_io_folder_impl.h" +#include "opcuatms_client/objects/tms_client_channel_factory.h" +#include "opcuatms_client/objects/tms_client_io_folder_factory.h" +#include "open62541/tmsdevice_nodeids.h" +#include "opendaq/folder_config_ptr.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace daq::opcua; + +TmsClientIoFolderImpl::TmsClientIoFolderImpl(const ContextPtr& ctx, + const ComponentPtr& parent, + const StringPtr& localId, + const TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId) + : TmsClientFolderImpl(ctx, parent, localId, clientContext, nodeId, true) +{ + findAndCreateIoFolders(); + findAndCreateChannels(); +} + +void TmsClientIoFolderImpl::findAndCreateChannels() +{ + auto channelNodeIds = getChildNodes(this->client, this->nodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_CHANNELTYPE)); + for (const auto& channelNodeId : channelNodeIds) + { + auto browseName = this->client->readBrowseName(channelNodeId); + auto thisPtr = this->borrowPtr(); + auto tmsClientChannel = TmsClientChannel(this->context, thisPtr, browseName, this->clientContext, channelNodeId); + thisPtr.addItem(tmsClientChannel); + } +} + +void TmsClientIoFolderImpl::findAndCreateIoFolders() +{ + auto folderNodeIds = getChildNodes(this->client, this->nodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_IOCOMPONENTTYPE)); + for (const auto& folderNodeId : folderNodeIds) + { + auto browseName = this->client->readBrowseName(folderNodeId); + auto thisPtr = this->template borrowPtr(); + auto tmsClientFolder = TmsClientIoFolder(this->context, thisPtr, browseName, this->clientContext, folderNodeId); + thisPtr.addItem(tmsClientFolder); + } +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_object_impl.cpp new file mode 100644 index 0000000..661e1a1 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_object_impl.cpp @@ -0,0 +1,110 @@ +#include "opcuatms_client/objects/tms_client_object_impl.h" +#include "opcuaclient/browse_request.h" +#include "opcuaclient/browser/opcuabrowser.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace opcua; +using namespace opcua::utils; + +TmsClientObjectImpl::TmsClientObjectImpl(const ContextPtr& daqContext, const TmsClientContextPtr& clientContext, const OpcUaNodeId& nodeId) + : clientContext(clientContext) + , client(clientContext->getClient()) + , nodeId(nodeId) + , referenceUtils(client) + , daqContext(daqContext) +{ +} + +TmsClientObjectImpl::~TmsClientObjectImpl() +{ + clientContext->unregisterObject(nodeId); +} + +void TmsClientObjectImpl::registerObject(const BaseObjectPtr& obj) +{ + clientContext->registerObject(nodeId, obj); +} + +SignalPtr TmsClientObjectImpl::findSignal(const opcua::OpcUaNodeId& nodeId) const +{ + return clientContext->getObject(nodeId); +} + +bool TmsClientObjectImpl::hasReference(const std::string& name) +{ + return referenceUtils.hasReference(nodeId, name); +} + +OpcUaNodeId TmsClientObjectImpl::getNodeId(const std::string& nodeName) +{ + return referenceUtils.getChildNodeId(nodeId, nodeName); +} + +void TmsClientObjectImpl::writeValue(const std::string& nodeName, const OpcUaVariant& value) +{ + const auto nodeId = getNodeId(nodeName); + client->writeValue(nodeId, value); +} + +OpcUaVariant TmsClientObjectImpl::readValue(const std::string& nodeName) +{ + const auto nodeId = getNodeId(nodeName); + return client->readValue(nodeId); +} + +MonitoredItem* TmsClientObjectImpl::monitoredItemsCreateEvent(const EventMonitoredItemCreateRequest& item, + const EventNotificationCallbackType& eventNotificationCallback) +{ + return getSubscription()->monitoredItemsCreateEvent(UA_TIMESTAMPSTORETURN_BOTH, *item, eventNotificationCallback); +} + +MonitoredItem* TmsClientObjectImpl::monitoredItemsCreateDataChange(const UA_MonitoredItemCreateRequest& item, + const DataChangeNotificationCallbackType& dataChangeNotificationCallback) +{ + return getSubscription()->monitoredItemsCreateDataChange(UA_TIMESTAMPSTORETURN_BOTH, item, dataChangeNotificationCallback); +} + +Subscription* TmsClientObjectImpl::getSubscription() +{ + if (!subscription) + subscription = client->createSubscription(UA_CreateSubscriptionRequest_default(), std::bind(&TmsClientObjectImpl::subscriptionStatusChangeCallback, this, std::placeholders::_3)); + + return subscription; +} + +void TmsClientObjectImpl::subscriptionStatusChangeCallback(UA_StatusChangeNotification* notification) +{ + //TODO report on disconnect +} + +std::vector TmsClientObjectImpl::getChildNodes(const opcua::OpcUaClientPtr& client, + const opcua::OpcUaNodeId& nodeId, + const opcua::OpcUaNodeId& typeId, + const bool subTypeEnabled) +{ + using namespace daq::opcua; + ReferenceUtils referenceUtilities(client); + std::vector results; + BrowseRequest request(nodeId, OpcUaNodeClass::Object); + OpcUaBrowser browser(request, client); + auto browseResult = browser.browse(); + + for (const UA_ReferenceDescription& reference : browseResult) + { + if (OpcUaNodeId(reference.typeDefinition.nodeId) == typeId) + results.push_back(OpcUaNodeId(reference.nodeId.nodeId)); + else + { + if (subTypeEnabled) + { + if (referenceUtilities.isInstanceOf(reference.typeDefinition.nodeId, typeId)) + results.push_back(OpcUaNodeId(reference.nodeId.nodeId)); + } + } + } + + return results; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_procedure_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_procedure_impl.cpp new file mode 100644 index 0000000..2b8e6ae --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_procedure_impl.cpp @@ -0,0 +1,61 @@ +#include "coretypes/validation.h" +#include "opcuatms_client/objects/tms_client_procedure_factory.h" +#include "opcuatms/converters/variant_converter.h" +#include "opcuatms/converters/list_conversion_utils.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace opcua; + +TmsClientProcedureImpl::TmsClientProcedureImpl(const TmsClientContextPtr& ctx, + const ContextPtr& daqContext, + const OpcUaNodeId& parentId, + const OpcUaNodeId& methodId) + : ctx(ctx) + , daqContext(daqContext) + , parentId(parentId) + , methodId(methodId) +{ +} + +ErrCode TmsClientProcedureImpl::dispatch(IBaseObject* args) +{ + // TODO: Return more specific error depending on OPC UA status code + return daqTry([&]() + { + auto argsPtr = BaseObjectPtr::Borrow(args); + OpcUaCallMethodRequest callRequest; + + if (!argsPtr.assigned()) + { + callRequest = OpcUaCallMethodRequest(methodId, parentId, 0); + } + else if (argsPtr.asPtrOrNull().assigned()) + { + auto argsList = argsPtr.asPtrOrNull(); + OpcUaVariant varArgs = ListConversionUtils::ToVariantTypeArrayVariant(argsList, daqContext); + callRequest = OpcUaCallMethodRequest(methodId, parentId, argsList.getCount(), (UA_Variant*) varArgs->data); + } + else + { + OpcUaVariant varArgs = VariantConverter::ToVariant(argsPtr, nullptr, daqContext); + callRequest = OpcUaCallMethodRequest(methodId, parentId, 1, &varArgs.getValue()); + } + + OpcUaObject callResult = ctx->getClient()->callMethod(callRequest); + if (OPCUA_STATUSCODE_FAILED(callResult->statusCode) || (callResult->outputArgumentsSize != 0)) + return OPENDAQ_ERR_CALLFAILED; + + return OPENDAQ_SUCCESS; + }); +} + +ErrCode TmsClientProcedureImpl::getCoreType(CoreType* coreType) +{ + OPENDAQ_PARAM_NOT_NULL(coreType); + + *coreType = ctProc; + return OPENDAQ_SUCCESS; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp new file mode 100644 index 0000000..3cd7220 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp @@ -0,0 +1,180 @@ +#include "opcuatms_client/objects/tms_client_property_impl.h" +#include "coreobjects/coercer_factory.h" +#include "coreobjects/eval_value_factory.h" +#include "coreobjects/validator_factory.h" +#include "opcuatms/converters/variant_converter.h" +#include "opcuatms/converters/selection_converter.h" +#include "open62541/tmsbt_nodeids.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace daq::opcua; + +namespace details +{ + enum class PropertyField + { + CoercionExpression = 0, + ValidationExpression, + DefaultValue, + IsReadOnly, + IsVisible, + Unit, + MaxValue, + MinValue, + SuggestedValues, + SelectionValues + }; + + static std::unordered_map stringToPropertyFieldEnum{ + {"CoercionExpression", PropertyField::CoercionExpression}, + {"ValidationExpression", PropertyField::ValidationExpression}, + {"DefaultValue", PropertyField::DefaultValue}, + {"IsReadOnly", PropertyField::IsReadOnly}, + {"IsVisible", PropertyField::IsVisible}, + {"Unit", PropertyField::Unit}, + {"MaxValue", PropertyField::MaxValue}, + {"MinValue", PropertyField::MinValue}, + {"SuggestedValues", PropertyField::SuggestedValues}, + {"SelectionValues", PropertyField::SelectionValues}, + }; +} + +TmsClientPropertyImpl::TmsClientPropertyImpl(const ContextPtr& daqContext, const TmsClientContextPtr& ctx, const opcua::OpcUaNodeId& nodeId) + : TmsClientObjectImpl(daqContext, ctx, nodeId) +{ + readBasicInfo(); + configurePropertyFields(); +} + +void TmsClientPropertyImpl::readBasicInfo() +{ + const auto variant = client->readValue(nodeId); + const auto object = VariantConverter::ToDaqObject(variant, daqContext); + this->valueType = object.getCoreType(); + + this->name = String(client->readDisplayName(nodeId)); + this->description = String(client->readDescription(nodeId)); +} + +void TmsClientPropertyImpl::configurePropertyFields() +{ + const auto evaluationVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_EVALUATIONVARIABLETYPE); + + for (auto [childNodeId, ref] : referenceUtils.getReferences(nodeId)) + { + if (referenceUtils.getBrowseName(ref) == "CoercionExpression") + { + this->coercer = Coercer(VariantConverter::ToDaqObject(client->readValue(childNodeId))); + } + else if (referenceUtils.getBrowseName(ref) == "ValidationExpression") + { + this->validator = Validator(VariantConverter::ToDaqObject(client->readValue(childNodeId))); + } + else if (referenceUtils.isInstanceOf(ref->typeDefinition.nodeId, evaluationVariableTypeId)) + { + auto evalId = referenceUtils.getChildNodeId(childNodeId, "EvaluationExpression"); + const auto browseName = referenceUtils.getBrowseName(ref); + StringPtr evalStr = VariantConverter::ToDaqObject(client->readValue(evalId)); + if (details::stringToPropertyFieldEnum.count(browseName)) + { + bool strHasValue = false; + const auto propertyField = details::stringToPropertyFieldEnum[browseName]; + if (evalStr.assigned()) + { + if (evalStr.getLength() > 0) + strHasValue = true; + } + if (strHasValue) + { + switch (propertyField) + { + case details::PropertyField::DefaultValue: + + this->defaultValue = EvalValue(evalStr); + break; + + case details::PropertyField::IsReadOnly: + this->readOnly = EvalValue(evalStr).asPtr(); + break; + + case details::PropertyField::IsVisible: + this->visible = EvalValue(evalStr).asPtr(); + break; + + case details::PropertyField::Unit: + this->unit = EvalValue(evalStr).asPtr(); + break; + + case details::PropertyField::MaxValue: + this->maxValue = EvalValue(evalStr).asPtr(); + break; + + case details::PropertyField::MinValue: + this->minValue = EvalValue(evalStr).asPtr(); + break; + + case details::PropertyField::SuggestedValues: + this->suggestedValues = EvalValue(evalStr).asPtr(); + break; + + case details::PropertyField::SelectionValues: + this->selectionValues = EvalValue(evalStr); + break; + case details::PropertyField::CoercionExpression: + case details::PropertyField::ValidationExpression: + break; + } + } + else + { + switch (propertyField) + { + case details::PropertyField::DefaultValue: + this->defaultValue = VariantConverter::ToDaqObject(client->readValue(childNodeId), daqContext); + if (this->defaultValue.assigned() && this->defaultValue.asPtrOrNull().assigned()) + this->defaultValue.freeze(); + break; + + case details::PropertyField::IsReadOnly: + this->readOnly = VariantConverter::ToDaqObject(client->readValue(childNodeId)); + break; + + case details::PropertyField::IsVisible: + this->visible = VariantConverter::ToDaqObject(client->readValue(childNodeId)); + break; + + case details::PropertyField::Unit: + this->unit = VariantConverter::ToDaqObject(client->readValue(childNodeId)); + break; + + case details::PropertyField::MaxValue: + this->maxValue = VariantConverter::ToDaqObject(client->readValue(childNodeId)); + break; + + case details::PropertyField::MinValue: + this->minValue = VariantConverter::ToDaqObject(client->readValue(childNodeId)); + break; + + case details::PropertyField::SuggestedValues: + this->suggestedValues = VariantConverter::ToDaqList(client->readValue(childNodeId), daqContext); + if (this->suggestedValues.assigned() && this->suggestedValues.asPtrOrNull().assigned()) + this->suggestedValues.freeze(); + break; + + case details::PropertyField::SelectionValues: + this->selectionValues = SelectionVariantConverter::ToDaqObject(client->readValue(childNodeId)); + if (this->selectionValues.assigned() && this->selectionValues.asPtrOrNull().assigned()) + this->selectionValues.freeze(); + break; + case details::PropertyField::CoercionExpression: + case details::PropertyField::ValidationExpression: + break; + } + } + } + } + } +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp new file mode 100644 index 0000000..41260ea --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -0,0 +1,351 @@ +#include "opcuatms_client/objects/tms_client_property_object_impl.h" +#include "coreobjects/callable_info_factory.h" +#include "coreobjects/eval_value_factory.h" +#include "coreobjects/property_object_factory.h" +#include "opcuaclient/browser/opcuabrowser.h" +#include "opcuatms_client/objects/tms_client_property_factory.h" +#include "open62541/tmsbt_nodeids.h" +#include "opcuatms/converters/variant_converter.h" +#include "opcuatms_client/objects/tms_client_property_object_factory.h" +#include "opcuatms_client/objects/tms_client_function_factory.h" +#include "opcuatms_client/objects/tms_client_procedure_factory.h" +#include "opendaq/signal_remote_impl.h" +#include "opendaq/input_port_impl.h" +#include "opendaq/channel_impl.h" +#include "opendaq/device_impl.h" +#include "opendaq/io_folder_impl.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace opcua; + +template +ErrCode TmsClientPropertyObjectBaseImpl::setPropertyValueInternal(IString* propertyName, IBaseObject* value, bool protectedWrite) +{ + return daqTry( + [&]() + { + if (const auto& it = introspectionVariableIdMap.find((StringPtr) propertyName); it != introspectionVariableIdMap.cend()) + { + if (protectedWrite) + { + PropertyPtr prop; + checkErrorInfo(getProperty(propertyName, &prop)); + const bool readOnly = prop.getReadOnly(); + if (readOnly) + return OPENDAQ_SUCCESS; + } + + const auto variant = VariantConverter::ToVariant(value, nullptr, daqContext); + client->writeValue(it->second, variant); + return OPENDAQ_SUCCESS; + } + + if (const auto& it = referenceVariableIdMap.find((StringPtr) propertyName); it != referenceVariableIdMap.cend()) + { + const auto refProp = this->objPtr.getProperty(propertyName).getReferencedProperty(); + return setPropertyValue(refProp.getName(), value); + } + + if (const auto& it = objectTypeIdMap.find((StringPtr) propertyName); it != objectTypeIdMap.cend()) + { + return this->makeErrorInfo(OPENDAQ_ERR_NOTIMPLEMENTED, "Object type properties cannot be set over OPC UA"); + } + + return OPENDAQ_ERR_NOTFOUND; + }); +} + +template +ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::setPropertyValue(IString* propertyName, IBaseObject* value) +{ + return setPropertyValueInternal(propertyName, value, false); +} + +template +ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::setProtectedPropertyValue(IString* propertyName, IBaseObject* value) +{ + return setPropertyValueInternal(propertyName, value, true); +} + +template +ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::getPropertyValue(IString* propertyName, IBaseObject** value) +{ + return daqTry([&]() { + if (const auto& introIt = introspectionVariableIdMap.find((StringPtr) propertyName); introIt != introspectionVariableIdMap.cend()) + { + const auto variant = client->readValue(introIt->second); + const auto object = VariantConverter::ToDaqObject(variant, daqContext); + Impl::setProtectedPropertyValue(propertyName, object); + } + else if (referenceVariableIdMap.count((StringPtr) propertyName)) + { + const auto refProp = this->objPtr.getProperty(propertyName).getReferencedProperty(); + return getPropertyValue(refProp.getName(), value); + } + else if (const auto& objIt = objectTypeIdMap.find((StringPtr) propertyName); objIt != objectTypeIdMap.cend()) + { + *value = TmsClientPropertyObject(daqContext, clientContext, objIt->second).detach(); + return OPENDAQ_SUCCESS; + } + + return Impl::getPropertyValue(propertyName, value); + }); +} + +template +ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::getPropertySelectionValue(IString* propertyName, IBaseObject** value) +{ + BaseObjectPtr object; + TmsClientPropertyObjectBaseImpl::getPropertyValue(propertyName, &object); + return Impl::getPropertySelectionValue(propertyName, value); +} + +template +ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::clearPropertyValue(IString* propertyName) +{ + return OPENDAQ_ERR_INVALID_OPERATION; +} + +template +ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::getProperty(IString* propertyName, IProperty** value) +{ + return Impl::getProperty(propertyName, value); +} + +template +ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::addProperty(IProperty* property) +{ + return OPENDAQ_ERR_INVALID_OPERATION; +} + +template +ErrCode TmsClientPropertyObjectBaseImpl::removeProperty(IString* propertyName) +{ + return OPENDAQ_ERR_INVALID_OPERATION; +} + +template +ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::getOnPropertyValueWrite(IString* propertyName, IEvent** event) +{ + return Impl::getOnPropertyValueWrite(propertyName, event); +} + +template +ErrCode TmsClientPropertyObjectBaseImpl::getOnPropertyValueRead(IString* propertyName, IEvent** event) +{ + return Impl::getOnPropertyValueRead(propertyName, event); +} + +template +ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::getVisibleProperties(IList** properties) +{ + return Impl::getVisibleProperties(properties); +} + +template +ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::hasProperty(IString* propertyName, Bool* hasProperty) +{ + return Impl::hasProperty(propertyName, hasProperty); +} + +template +ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::getAllProperties(IList** properties) +{ + return Impl::getAllProperties(properties); +} + +template +ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::setPropertyOrder(IList* orderedPropertyNames) +{ + return OPENDAQ_ERR_INVALID_OPERATION; +} + +template +void TmsClientPropertyObjectBaseImpl::addProperties(const tsl::ordered_map>& references) +{ + const auto introspectionVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_INTROSPECTIONVARIABLETYPE); + const auto structureVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_STRUCTUREVARIABLETYPE); + const auto referenceVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_REFERENCEVARIABLETYPE); + const auto variableBlockTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_VARIABLEBLOCKTYPE); + + for (auto& [childNodeId, ref] : references) + { + const auto typeId = OpcUaNodeId(ref->typeDefinition.nodeId); + auto propName = String(client->readBrowseName(childNodeId)); + Bool hasProp; + daq::checkErrorInfo(Impl::hasProperty(propName, &hasProp)); + + if (referenceUtils.isInstanceOf(typeId, referenceVariableTypeId)) + { + try + { + if (!hasProp) + { + StringPtr refPropEval = VariantConverter::ToDaqObject(client->readValue(childNodeId)); + auto refProp = ReferenceProperty(propName, EvalValue(refPropEval)); + daq::checkErrorInfo(Impl::addProperty(refProp)); + } + + referenceVariableIdMap.insert(std::pair(propName, childNodeId)); + const auto& refPropReferences = referenceUtils.getReferences(childNodeId); + addProperties(refPropReferences); + } + catch(...) + { + // TODO: Log failure to add function/procedure. + continue; + } + } + else if (referenceUtils.isInstanceOf(typeId, introspectionVariableTypeId) || + referenceUtils.isInstanceOf(typeId, structureVariableTypeId)) + { + try + { + if (!hasProp) + { + auto prop = TmsClientProperty(daqContext, clientContext, ref->nodeId.nodeId); + daq::checkErrorInfo(Impl::addProperty(prop)); + } + introspectionVariableIdMap.insert(std::pair(propName, childNodeId)); + } + catch(...) + { + // TODO: Log failure to add function/procedure. + continue; + } + } + else if (referenceUtils.isInstanceOf(typeId, variableBlockTypeId)) + { + if (!hasProp) + { + auto obj = TmsClientPropertyObject(daqContext, clientContext, childNodeId); + auto prop = ObjectPropertyBuilder(propName, obj).setDescription(String(client->readDescription(childNodeId))); + + const auto evaluationVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_EVALUATIONVARIABLETYPE); + const auto variableBlockRefs = referenceUtils.getReferences(childNodeId); + + for (auto& [variableBlockNodeId, variableBlockRef] : variableBlockRefs) + { + const auto browseName = referenceUtils.getBrowseName(variableBlockRef); + if (referenceUtils.isInstanceOf(variableBlockRef->typeDefinition.nodeId, evaluationVariableTypeId)) + { + auto evalId = referenceUtils.getChildNodeId(variableBlockNodeId, "EvaluationExpression"); + + StringPtr evalStr = VariantConverter::ToDaqObject(client->readValue(evalId)); + + if (browseName == "IsReadOnly") + { + if (evalStr.assigned()) + prop.setReadOnly(EvalValue(evalStr).asPtr()); + else + prop.setReadOnly(VariantConverter::ToDaqObject(client->readValue(variableBlockNodeId))); + } + else if (browseName == "IsVisible") + { + if (evalStr.assigned()) + prop.setVisible(EvalValue(evalStr).asPtr()); + else + prop.setVisible(VariantConverter::ToDaqObject(client->readValue(variableBlockNodeId))); + } + } + } + + daq::checkErrorInfo(Impl::addProperty(prop.build())); + } + + objectTypeIdMap.insert(std::pair(propName, childNodeId)); + } + + } +} + +template +void TmsClientPropertyObjectBaseImpl::addMethodProperties( + const tsl::ordered_map>& references, const OpcUaNodeId& parentNodeId) +{ + const auto methodTypeId = OpcUaNodeId(0, UA_NS0ID_METHODNODE); + + for (auto& [childNodeId, ref] : references) + { + const auto typeId = OpcUaNodeId(ref->typeDefinition.nodeId); + auto propName = String(client->readBrowseName(childNodeId)); + Bool hasProp; + daq::checkErrorInfo(Impl::hasProperty(propName, &hasProp)); + + if (ref->nodeClass == UA_NODECLASS_METHOD) + { + if (!hasProp) + { + ListPtr inputArgs; + ListPtr outputArgs; + + try + { + if (referenceUtils.hasReference(childNodeId, "InputArguments")) + inputArgs = VariantConverter::ToDaqList(client->readValue(referenceUtils.getChildNodeId(childNodeId, "InputArguments"))); + + if (referenceUtils.hasReference(childNodeId, "OutputArguments")) + outputArgs = VariantConverter::ToDaqList(client->readValue(referenceUtils.getChildNodeId(childNodeId, "OutputArguments"))); + } + catch(...) + { + // TODO: Log failure to add function/procedure. + continue; + } + + if (outputArgs.assigned() && outputArgs.getCount() == 1) + { + auto callableInfo = FunctionInfo(outputArgs[0].getType(), inputArgs); + auto prop = FunctionPropertyBuilder(propName, callableInfo).setReadOnly(true).build(); + daq::checkErrorInfo(Impl::addProperty(prop)); + + auto clientFunc = TmsClientFunction(clientContext, daqContext, parentNodeId, childNodeId); + daq::checkErrorInfo(Impl::setProtectedPropertyValue(propName, clientFunc)); + } + else + { + auto callableInfo = ProcedureInfo(inputArgs); + auto prop = FunctionPropertyBuilder(propName, callableInfo).setReadOnly(true).build(); + daq::checkErrorInfo(Impl::addProperty(prop)); + + auto clientProcedure = TmsClientProcedure(clientContext, daqContext, parentNodeId, childNodeId); + daq::checkErrorInfo(Impl::setProtectedPropertyValue(propName, clientProcedure)); + } + } + } + } +} + +template +void TmsClientPropertyObjectBaseImpl::browseRawProperties() +{ + const auto& references = referenceUtils.getReferences(nodeId); + addProperties(references); + + // TODO: Make sure that this is a DeviceType node + if (hasReference("MethodSet")) + { + const auto methodNodeId = referenceUtils.getChildNodeId(nodeId, "MethodSet"); + const auto& methodReferences = referenceUtils.getReferences(methodNodeId); + addMethodProperties(methodReferences, methodNodeId); + } + else + { + addMethodProperties(references, nodeId); + } +} + +template class TmsClientPropertyObjectBaseImpl; +template class TmsClientPropertyObjectBaseImpl>; +template class TmsClientPropertyObjectBaseImpl>; +template class TmsClientPropertyObjectBaseImpl; +template class TmsClientPropertyObjectBaseImpl; +template class TmsClientPropertyObjectBaseImpl; +template class TmsClientPropertyObjectBaseImpl; +template class TmsClientPropertyObjectBaseImpl>; +template class TmsClientPropertyObjectBaseImpl; +template class TmsClientPropertyObjectBaseImpl; + + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp new file mode 100644 index 0000000..51a0aa3 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp @@ -0,0 +1,196 @@ +#include +#include "open62541/tmsbsp_nodeids.h" +#include "opcuashared/opcuacommon.h" +#include "opcuatms/exceptions.h" +#include "opcuatms_client/objects/tms_client_signal_impl.h" +#include "opcuatms/converters/variant_converter.h" +#include +#include + + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace opcua; + +TmsClientSignalImpl::TmsClientSignalImpl( + const ContextPtr& ctx, + const ComponentPtr& parent, + const StringPtr& localId, + const TmsClientContextPtr& clientContext, + const OpcUaNodeId& nodeId +) + : TmsClientComponentBaseImpl(ctx, parent, localId, clientContext, nodeId) +{ + deviceSignalId = nodeId.getIdentifier(); + + if (referenceUtils.hasReference(nodeId, "Value")) + descriptorNodeId = std::make_unique(referenceUtils.getChildNodeId(referenceUtils.getChildNodeId(nodeId, "Value"), "DataDescriptor")); + + registerObject(this->borrowPtr()); +} + +ErrCode TmsClientSignalImpl::getPublic(Bool* valPublic) +{ + *valPublic = isPublic; + return OPENDAQ_SUCCESS; +} + +ErrCode TmsClientSignalImpl::setPublic(Bool valPublic) +{ + isPublic = valPublic; + return OPENDAQ_SUCCESS; +} + +ErrCode TmsClientSignalImpl::getDescriptor(IDataDescriptor** descriptor) +{ + return daqTry([&]() { + *descriptor = nullptr; + + if (descriptorNodeId) + { + OpcUaVariant opcUaVariant = client->readValue(*descriptorNodeId); + if (!opcUaVariant.isNull()) + { + DataDescriptorPtr descriptorPtr = VariantConverter::ToDaqObject(opcUaVariant); + *descriptor = descriptorPtr.addRefAndReturn(); + } + } + + return OPENDAQ_SUCCESS; + }); +} + +ErrCode TmsClientSignalImpl::setDescriptor(IDataDescriptor* /*descriptor*/) +{ + return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; +} + +ErrCode TmsClientSignalImpl::getDomainSignal(ISignal** signal) +{ + SignalPtr signalPtr; + ErrCode errCode = wrapHandlerReturn(this, &TmsClientSignalImpl::onGetDomainSignal, signalPtr); + + *signal = signalPtr.detach(); + + return errCode; +} + +SignalPtr TmsClientSignalImpl::onGetDomainSignal() +{ + OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASDOMAINSIGNAL); + auto nodeIds = referenceUtils.getReferencedNodes(nodeId, referenceTypeId, true); + assert(nodeIds.size() <= 1); + + if (!nodeIds.empty()) + { + auto domainSignalNodeId = *nodeIds.begin(); + return findSignal(domainSignalNodeId); + } + + return nullptr; +} + +ErrCode TmsClientSignalImpl::setDomainSignal(ISignal* signal) +{ + return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; +} + +ErrCode TmsClientSignalImpl::getRelatedSignals(IList** signals) +{ + ListPtr signalsPtr; + ErrCode errCode = wrapHandlerReturn(this, &TmsClientSignalImpl::onGetRelatedSignals, signalsPtr); + *signals = signalsPtr.detach(); + return errCode; +} + + +ListPtr TmsClientSignalImpl::onGetRelatedSignals() +{ + OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_RELATESTOSIGNAL); + auto nodeIds = referenceUtils.getReferencedNodes(nodeId, referenceTypeId, true); + ListPtr resultList = List(); + for (auto signalNodeId : nodeIds) + { + auto signal = findSignal(signalNodeId); + resultList.pushBack(signal); + } + return resultList.detach(); +} + +ErrCode TmsClientSignalImpl::setRelatedSignals(IList* signals) +{ + return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; +} + +ErrCode TmsClientSignalImpl::addRelatedSignal(ISignal* signal) +{ + return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; +} + +ErrCode TmsClientSignalImpl::removeRelatedSignal(ISignal* signal) +{ + return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; +} + +ErrCode TmsClientSignalImpl::clearRelatedSignals() +{ + return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; +} + +ErrCode TmsClientSignalImpl::getName(IString** name) +{ + OPENDAQ_PARAM_NOT_NULL(name); + + auto objPtr = this->borrowPtr(); + + return daqTry( + [&name, &objPtr]() + { + *name = objPtr.getPropertyValue("Name").asPtr().detach(); + return OPENDAQ_SUCCESS; + }); +} + +ErrCode TmsClientSignalImpl::setName(IString* name) +{ + return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; +} + +Bool TmsClientSignalImpl::onTriggerEvent(EventPacketPtr eventPacket) +{ + if (eventPacket.assigned() && eventPacket.getEventId() == event_packet_id::DATA_DESCRIPTOR_CHANGED) + triggerDataDescriptorChanged(eventPacket); + + // No new duplicated event packets have been created so returns true to forward original packet + return True; +} + +StringPtr TmsClientSignalImpl::onGetRemoteId() const +{ + return String(deviceSignalId); +} + +EventPacketPtr TmsClientSignalImpl::createDataDescriptorChangedEventPacket() +{ + const std::lock_guard lock(signalMutex); + return DataDescriptorChangedEventPacket(lastSignalDescriptor, lastDomainDescriptor); +} + +void TmsClientSignalImpl::triggerDataDescriptorChanged(const EventPacketPtr& eventPacket) +{ + const auto params = eventPacket.getParameters(); + DataDescriptorPtr newSignalDescriptor = params[event_packet_param::DATA_DESCRIPTOR]; + DataDescriptorPtr newDomainDescriptor = params[event_packet_param::DOMAIN_DATA_DESCRIPTOR]; + + const std::lock_guard lock(signalMutex); + if (newSignalDescriptor.assigned()) + { + lastSignalDescriptor = newSignalDescriptor; + } + if (newDomainDescriptor.assigned()) + { + lastDomainDescriptor = newDomainDescriptor; + } +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_streaming_info_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_streaming_info_impl.cpp new file mode 100644 index 0000000..c80bdc9 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_streaming_info_impl.cpp @@ -0,0 +1,15 @@ +#include "opcuatms_client/objects/tms_client_streaming_info_impl.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace daq::opcua; + +TmsClientStreamingInfoImpl::TmsClientStreamingInfoImpl(const ContextPtr& daqContext, + const StringPtr& protocolId, + const TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId) + : TmsClientPropertyObjectBaseImpl(daqContext, protocolId, clientContext, nodeId) +{ +} +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp new file mode 100644 index 0000000..8855b95 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp @@ -0,0 +1,104 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace daq::opcua; +using namespace daq::opcua::tms; + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +TmsClient::TmsClient(const ContextPtr& context, + const ComponentPtr& parent, + const std::string& opcUaUrl, + const FunctionPtr& createStreamingCallback) + : context(context) + , opcUaUrl(opcUaUrl) + , createStreamingCallback(createStreamingCallback) + , parent(parent) +{ +} + +daq::DevicePtr TmsClient::connect() +{ + OpcUaEndpoint endpoint("TmsClient", opcUaUrl); + endpoint.registerCustomTypes(UA_TYPES_DI_COUNT, UA_TYPES_DI); + endpoint.registerCustomTypes(UA_TYPES_TMSBT_COUNT, UA_TYPES_TMSBT); + endpoint.registerCustomTypes(UA_TYPES_TMSBSP_COUNT, UA_TYPES_TMSBSP); + endpoint.registerCustomTypes(UA_TYPES_TMSDEVICE_COUNT, UA_TYPES_TMSDEVICE); + endpoint.registerCustomTypes(UA_TYPES_TMSESP_COUNT, UA_TYPES_TMSESP); + + client = std::make_shared(endpoint); + if (!client->connect()) + throw NotFoundException(); + client->runIterate(); + + tmsClientContext = std::make_shared(client); + + auto rootDeviceNodeId = getRootDeviceNodeId(); + + BrowseRequest request(rootDeviceNodeId, OpcUaNodeClass::Variable); + auto localId = getUniqueLocalId(client->readBrowseName(rootDeviceNodeId)); + + auto device = TmsClientRootDevice(context, parent, localId, tmsClientContext, rootDeviceNodeId, createStreamingCallback); + return device; +} + +OpcUaNodeId TmsClient::getRootDeviceNodeId() +{ + const OpcUaNodeId rootNodeId(NAMESPACE_DI, UA_DIID_DEVICESET); + BrowseRequest br(rootNodeId, OpcUaNodeClass::Object, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT)); + + OpcUaBrowser browser(br, client); + auto results = browser.browse(); + + const OpcUaNodeId daqDeviceTypeNodeId( NAMESPACE_TMSDEVICE, // TODO NAMESPACE_TMSDEVICE is server namespace id. You need + UA_TMSDEVICEID_DAQDEVICETYPE); // to map it to client. Or use namespace URI. + + + for (const auto& result : results) + { + ReferenceUtils referenceUtilities(client); + if (daqDeviceTypeNodeId == result.typeDefinition.nodeId) + return result.nodeId.nodeId; + else + { + // Else check if this is a subtype of the openDAQ device. + if (referenceUtilities.isInstanceOf(result.typeDefinition.nodeId, daqDeviceTypeNodeId)) + return result.nodeId.nodeId; + } + } + throw NotFoundException(); +} + +StringPtr TmsClient::getUniqueLocalId(const StringPtr& localId, int iteration) +{ + if (!parent.assigned()) + return localId; + + StringPtr uniqueId = localId; + if (iteration != 0) + uniqueId = uniqueId + "_" + std::to_string(iteration); + + const auto parentFolder = parent.asPtrOrNull(); + if (parentFolder.assigned()) + { + for (auto item : parentFolder.getItems()) + { + if (item.getLocalId() == uniqueId) + return getUniqueLocalId(localId, iteration + 1); + } + } + + return uniqueId; +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcuatms/opcuatms_client/tests/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_client/tests/CMakeLists.txt new file mode 100644 index 0000000..b5b9541 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/tests/CMakeLists.txt @@ -0,0 +1,29 @@ +set(MODULE_NAME opcuatms_client) +set(TEST_APP test_${MODULE_NAME}) + +set(TEST_SOURCES test_client_context.cpp +) + +add_executable(${TEST_APP} test_app.cpp + ${TEST_SOURCES} +) + +set_target_properties(${TEST_APP} PROPERTIES DEBUG_POSTFIX _debug) + +if (WIN32) + set(BCRYPT_LIB bcrypt.dll) +endif() + +target_link_libraries(${TEST_APP} PRIVATE ${SDK_TARGET_NAMESPACE}::${MODULE_NAME} + daq::test_utils + ${BCRYPT_LIB} +) + +add_test(NAME ${TEST_APP} + COMMAND $ + WORKING_DIRECTORY bin +) + +if (OPENDAQ_ENABLE_COVERAGE) + setup_target_for_coverage(${MODULE_NAME}coverage ${TEST_APP} ${MODULE_NAME}coverage) +endif() diff --git a/shared/libraries/opcuatms/opcuatms_client/tests/test_app.cpp b/shared/libraries/opcuatms/opcuatms_client/tests/test_app.cpp new file mode 100644 index 0000000..73de271 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/tests/test_app.cpp @@ -0,0 +1,12 @@ +#include +#include + +int main(int argc, char** args) +{ + testing::InitGoogleTest(&argc, args); + + testing::TestEventListeners& listeners = testing::UnitTest::GetInstance()->listeners(); + listeners.Append(new DaqMemCheckListener()); + + return RUN_ALL_TESTS(); +} diff --git a/shared/libraries/opcuatms/opcuatms_client/tests/test_client_context.cpp b/shared/libraries/opcuatms/opcuatms_client/tests/test_client_context.cpp new file mode 100644 index 0000000..2cd1aaf --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/tests/test_client_context.cpp @@ -0,0 +1,100 @@ +#include +#include + +using namespace daq::opcua; +using namespace daq::opcua::tms; +using namespace daq; + +using ClientContextTest = testing::Test; + +static OpcUaClientPtr CreateClient() +{ + return std::make_shared("opc.tcp://localhost"); +} + +TEST_F(ClientContextTest, Create) +{ + auto client = CreateClient(); + ASSERT_NO_THROW(TmsClientContext clientContext(client)); +} + +TEST_F(ClientContextTest, RegisterObject) +{ + auto client = CreateClient(); + TmsClientContext clientContext(client); + + StringPtr str = "TestStrObject"; + ASSERT_NO_THROW(clientContext.registerObject(OpcUaNodeId(1, 1), str)); +} + +TEST_F(ClientContextTest, ContextGetObject) +{ + auto client = CreateClient(); + TmsClientContext clientContext(client); + + BaseObjectPtr baseObj; + ASSERT_NO_THROW(baseObj = clientContext.getObject(OpcUaNodeId(1, 1))); + ASSERT_FALSE(baseObj.assigned()); + + StringPtr str = "TestStrObject"; + clientContext.registerObject(OpcUaNodeId(1, 1), str); + + ASSERT_NO_THROW(baseObj = clientContext.getObject(OpcUaNodeId(1, 1))); + ASSERT_TRUE(baseObj.assigned()); + ASSERT_EQ(baseObj, str); +} + +TEST_F(ClientContextTest, ContextGetObjectTemplate) +{ + auto client = CreateClient(); + TmsClientContext clientContext(client); + + StringPtr strObj; + ASSERT_NO_THROW(strObj = clientContext.getObject(OpcUaNodeId(1, 1))); + ASSERT_FALSE(strObj.assigned()); + + StringPtr str = "TestStrObject"; + clientContext.registerObject(OpcUaNodeId(1, 1), str); + + ASSERT_NO_THROW(strObj = clientContext.getObject(OpcUaNodeId(1, 1))); + ASSERT_TRUE(strObj.assigned()); + ASSERT_EQ(strObj, str); + + FloatPtr floatPtr; + ASSERT_NO_THROW(floatPtr = clientContext.getObject(OpcUaNodeId(1, 1))); + ASSERT_FALSE(floatPtr.assigned()); +} + +TEST_F(ClientContextTest, UnregisterObject) +{ + auto client = CreateClient(); + TmsClientContext clientContext(client); + + ASSERT_NO_THROW(clientContext.unregisterObject(OpcUaNodeId(1, 1))); + + StringPtr str = "TestStrObject"; + clientContext.registerObject(OpcUaNodeId(1, 1), str); + + ASSERT_NO_THROW(clientContext.unregisterObject(OpcUaNodeId(1, 1))); + + auto baseObj = clientContext.getObject(OpcUaNodeId(1, 1)); + ASSERT_FALSE(baseObj.assigned()); +} + +TEST_F(ClientContextTest, TestRefCount) +{ + auto getRefCount = [](const StringPtr& obj) + { + obj->addRef(); + return obj->releaseRef(); + }; + + auto client = CreateClient(); + TmsClientContext clientContext(client); + + StringPtr str = "TestStrObject"; + ASSERT_EQ(getRefCount(str), 1); + + clientContext.registerObject(OpcUaNodeId(1, 1), str); + ASSERT_EQ(getRefCount(str), 1); +} diff --git a/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt new file mode 100644 index 0000000..db7412f --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.2) +set_cmake_folder_context(TARGET_FOLDER_NAME) +project(opcuatms_server VERSION 2.0.0 LANGUAGES CXX) + +add_subdirectory(src) + +if (OPENDAQ_ENABLE_TESTS) + add_subdirectory(tests) +endif() diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_channel.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_channel.h new file mode 100644 index 0000000..de91570 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_channel.h @@ -0,0 +1,38 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include "opcuatms_server/objects/tms_server_function_block.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class TmsServerChannel; +using TmsServerChannelPtr = std::shared_ptr; + +class TmsServerChannel : public TmsServerFunctionBlock +{ +public: + using Super = TmsServerFunctionBlock; + + TmsServerChannel(const ChannelPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context); + +protected: + opcua::OpcUaNodeId getTmsTypeId() override; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h new file mode 100644 index 0000000..abcba4c --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h @@ -0,0 +1,122 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include "opcuatms_server/objects/tms_server_property_object.h" +#include "opcuatms/converters/variant_converter.h" +#include "open62541/tmsdevice_nodeids.h" + + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +template +class TmsServerComponent; +using TmsServerComponentPtr = std::shared_ptr>; + +template +class TmsServerComponent : public TmsServerObjectBaseImpl +{ +public: + using Super = TmsServerObjectBaseImpl; + + TmsServerComponent(const ComponentPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context); + + bool createOptionalNode(const opcua::OpcUaNodeId& nodeId) override; + + std::string getBrowseName() override; + std::string getDisplayName() override; + opcua::OpcUaNodeId getReferenceType() override; + void bindCallbacks() override; + void addChildNodes() override; + +protected: + opcua::OpcUaNodeId getTmsTypeId() override; + + std::unique_ptr tmsPropertyObject; +}; + +using namespace opcua; + +template +TmsServerComponent::TmsServerComponent(const ComponentPtr& object, const OpcUaServerPtr& server, const ContextPtr& context) + : Super(object, server, context) +{ + tmsPropertyObject = std::make_unique(this->object, this->server, this->daqContext); +} + +template +std::string TmsServerComponent::getBrowseName() +{ + return this->object.getLocalId(); +} + +template +std::string TmsServerComponent::getDisplayName() +{ + return this->object.getName(); +} + +template +OpcUaNodeId TmsServerComponent::getReferenceType() +{ + return OpcUaNodeId(0, UA_NS0ID_HASCOMPONENT); +} + +template +OpcUaNodeId TmsServerComponent::getTmsTypeId() +{ + return OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQCOMPONENTTYPE); +} + +template +bool TmsServerComponent::createOptionalNode(const OpcUaNodeId& nodeId) +{ + return false; +} + +template +void TmsServerComponent::bindCallbacks() +{ + this->addReadCallback("Tags",[this]() + { + const TagsPtr tags = this->object.getTags(); + if (tags.assigned()) + return VariantConverter::ToArrayVariant(tags.getList()); + return VariantConverter::ToArrayVariant(List()); + }); + + this->addReadCallback("Active", [this]() { return VariantConverter::ToVariant( this->object.getActive()); }); + if (!this->object.template asPtrOrNull().assigned() || !this->object.isFrozen()) + { + this->addWriteCallback("Active", [this](const OpcUaVariant& variant){ + this->object.setActive(VariantConverter::ToDaqObject(variant)); + return UA_STATUSCODE_GOOD; + }); + } + + // TODO + this->addReadCallback("NumberInList", [this]() { return VariantConverter::ToVariant(0); }); +} + +template +void TmsServerComponent::addChildNodes() +{ + tmsPropertyObject->registerToExistingOpcUaNode(this->nodeId); +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h new file mode 100644 index 0000000..3235f84 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h @@ -0,0 +1,60 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include "opcuatms_server/objects/tms_server_function_block.h" +#include "opcuatms_server/objects/tms_server_channel.h" +#include "opcuatms_server/objects/tms_server_folder.h" +#include "opcuatms_server/objects/tms_server_component.h" +#include "opcuatms_server/objects/tms_server_property_object.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class TmsServerDevice; +using TmsServerDevicePtr = std::shared_ptr; + +class TmsServerDevice : public TmsServerComponent +{ +public: + using Super = TmsServerComponent; + + TmsServerDevice(const DevicePtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context); + + bool createOptionalNode(const opcua::OpcUaNodeId& nodeId) override; + + void bindCallbacks() override; + void addChildNodes() override; + + void createNonhierarchicalReferences() override; + +protected: + opcua::OpcUaNodeId getTmsTypeId() override; + void populateDeviceInfo(); + void populateStreamingOptions(); + + // TODO we need following list to keep this because of handlers. Move handlers (TmsServerObject) to context and use UA_NodeTypeLifecycle + // for deleting it + std::list signals; + std::list devices; + std::list functionBlocks; + std::list folders; + std::list components; + std::list streamingOptions; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_eval_value.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_eval_value.h new file mode 100644 index 0000000..6934f8d --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_eval_value.h @@ -0,0 +1,58 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "coreobjects/eval_value_factory.h" +#include "opcuatms_server/objects/tms_server_variable.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +// TmsServerEvalValue + +class TmsServerEvalValue; +using TmsServerEvalValuePtr = std::shared_ptr; + +class TmsServerEvalValue : public TmsServerVariable +{ +public: + using Super = TmsServerVariable; + using ReadCallback = std::function; + using WriteCallback = std::function; + + TmsServerEvalValue(const EvalValuePtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context); + TmsServerEvalValue(const opcua::OpcUaServerPtr& server, const ContextPtr& context); + std::string getBrowseName() override; + void setReadCallback(ReadCallback readCallback); + void setWriteCallback(WriteCallback writeCallback); + void setIsSelectionType(bool isSelection); + +protected: + opcua::OpcUaNodeId getTmsTypeId() override; + void bindCallbacks() override; + void configureVariableNodeAttributes(opcua::OpcUaObject& attr) override; + +private: + opcua::OpcUaVariant readEvaluationExpression(); + opcua::OpcUaVariant readRoot(); + UA_StatusCode writeRoot(const opcua::OpcUaVariant& variant); + + ReadCallback readCallback; + WriteCallback writeCallback; + + bool isSelection = false; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_folder.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_folder.h new file mode 100644 index 0000000..cd988ba --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_folder.h @@ -0,0 +1,44 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include "opcuatms_server/objects/tms_server_channel.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class TmsServerFolder; +using TmsServerFolderPtr = std::shared_ptr; + +class TmsServerFolder : public TmsServerComponent +{ +public: + using Super = TmsServerComponent; + + TmsServerFolder(const FolderPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context); + + void createNonhierarchicalReferences() override; + void addChildNodes() override; + +protected: + opcua::OpcUaNodeId getTmsTypeId() override; + + std::list channels; + std::list folders; + std::list components; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block.h new file mode 100644 index 0000000..f4fa9f6 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block.h @@ -0,0 +1,55 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include "opcuatms_server/objects/tms_server_property_object.h" +#include "opcuatms_server/objects/tms_server_signal.h" +#include "opcuatms_server/objects/tms_server_input_port.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +template +class TmsServerFunctionBlock; + +using TmsServerFunctionBlockPtr = std::shared_ptr>; + +template +class TmsServerFunctionBlock : public TmsServerComponent +{ +public: + using Super = TmsServerComponent; + + TmsServerFunctionBlock(const FunctionBlockPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context); + + bool createOptionalNode(const opcua::OpcUaNodeId& nodeId) override; + void bindCallbacks() override; + + void addChildNodes() override; + void createNonhierarchicalReferences() override; + +protected: + opcua::OpcUaNodeId getTmsTypeId() override; + + // TODO we need following list to keep this becouse of handlers. Move handlers (TmsServerObject) to context and use UA_NodeTypeLifecycle + // for deleting it + std::list signals; + std::list inputPorts; + std::list functionBlocks; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h new file mode 100644 index 0000000..5ff3a0f --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h @@ -0,0 +1,41 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include "opcuatms_server/objects/tms_server_component.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class TmsServerInputPort; +using TmsServerInputPortPtr = std::shared_ptr; + +class TmsServerInputPort : public TmsServerComponent +{ +public: + using Super = TmsServerComponent; + + TmsServerInputPort(const InputPortPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context); + + opcua::OpcUaNodeId getReferenceType() override; + void bindCallbacks() override; + void createNonhierarchicalReferences() override; + +protected: + opcua::OpcUaNodeId getTmsTypeId() override; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h new file mode 100644 index 0000000..e112231 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h @@ -0,0 +1,168 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include +#include "opcuaserver/node_event_manager.h" +#include "opcuaserver/opcuaserver.h" +#include "opcuatms/opcuatms.h" + +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +template +struct RequestedNodeId +{ + opcua::OpcUaNodeId operator()(const CoreType& object) + { + return {}; + } +}; + +template +struct RequestedNodeId::Value>> +{ + opcua::OpcUaNodeId operator()(const CoreType& object) + { + return opcua::OpcUaNodeId(NAMESPACE_TMSBSP, object.getGlobalId().toStdString()); + } +}; + +class TmsServerObject; +using TmsServerObjectPtr = std::shared_ptr; + +class TmsServerObject : public std::enable_shared_from_this +{ +public: + using ReadVariantCallback = std::function; + using WriteVariantCallback = std::function; + + TmsServerObject(const opcua::OpcUaServerPtr& server, const ContextPtr& context); + virtual ~TmsServerObject(); + + virtual std::string getBrowseName(); + virtual std::string getDisplayName(); + opcua::NodeEventManagerPtr addEvent(const StringPtr& nodeName); + opcua::NodeEventManagerPtr addEvent(const opcua::OpcUaNodeId& nodeId); + opcua::OpcUaNodeId registerOpcUaNode( + const opcua::OpcUaNodeId& parentNodeId = opcua::OpcUaNodeId(UA_NS0ID_OBJECTSFOLDER)); + opcua::OpcUaNodeId registerToExistingOpcUaNode(const opcua::OpcUaNodeId& nodeId); + opcua::OpcUaNodeId getNodeId(); + + void addHierarchicalReference(const opcua::OpcUaNodeId& parent); + virtual void createNonhierarchicalReferences(); + +protected: + virtual void validate(); + virtual opcua::OpcUaNodeId getRequestedNodeId(); + virtual opcua::OpcUaNodeId getReferenceType(); + virtual opcua::OpcUaNodeId getTmsTypeId() = 0; + virtual BaseObjectPtr getObject() = 0; + virtual opcua::OpcUaNodeId createNode(const opcua::OpcUaNodeId& parentNodeId); + virtual void addChildNodes(); + virtual void bindCallbacks(); + virtual int64_t getCurrentClock(); + std::string readTypeBrowseName(); + virtual bool createOptionalNode(const opcua::OpcUaNodeId& nodeId); + virtual void configureNodeAttributes(opcua::OpcUaObject& attr); + void addReadCallback(const std::string& nodeName, ReadVariantCallback readFunc); + void addWriteCallback(const std::string& nodeName, WriteVariantCallback writeFunc); + void addReadCallback(const opcua::OpcUaNodeId& nodeId, ReadVariantCallback readFunc); + void addWriteCallback(const opcua::OpcUaNodeId& nodeId, WriteVariantCallback writeFunc); + void addReference(const opcua::OpcUaNodeId& targetNodeId, const opcua::OpcUaNodeId& referenceTypeId); + void bindReadWriteCallbacks(); + void browseReferences(); + bool hasChildNode(const std::string& nodeName) const; + opcua::OpcUaNodeId getChildNodeId(const std::string& nodeName); + opcua::OpcUaNodeId findSignalNodeId(const SignalPtr& signal) const; + + template + opcua::OpcUaNodeId findTmsObjectNodeId(const C& signal) const + { + auto nodeId = RequestedNodeId{}(signal); + return server->nodeExists(nodeId) ? nodeId : opcua::OpcUaNodeId(); + } + + template + void createChildNonhierarchicalReferences(const C& container) + { + for (const auto& item : container) + item->createNonhierarchicalReferences(); + } + + template + std::shared_ptr registerTmsObjectOrAddReference(const opcua::OpcUaNodeId& parentNodeId, + const DAQ_T& daqObject, + Params... params) + { + auto tmsObjectNodeId = findTmsObjectNodeId(daqObject); + if (!tmsObjectNodeId.isNull()) + { + void* nodeContext = {}; + opcua::CheckStatusCodeException(UA_Server_getNodeContext(this->server->getUaServer(), *tmsObjectNodeId, &nodeContext)); + auto tmsObject = std::dynamic_pointer_cast(static_cast(nodeContext)->shared_from_this()); + tmsObject->addHierarchicalReference(parentNodeId); + return tmsObject; + } + else + { + auto tmsObject = std::make_shared(daqObject, this->server, daqContext, std::forward(params)...); + tmsObject->registerOpcUaNode(parentNodeId); + return tmsObject; + } + } + + opcua::OpcUaServerPtr server; + std::string typeBrowseName; + std::mutex valueMutex; + opcua::OpcUaNodeId nodeId; + ContextPtr daqContext; + +private: + std::unordered_map readCallbacks; + std::unordered_map writeCallbacks; + std::unordered_map> references; + std::unordered_map eventManagers; +}; + +template +class TmsServerObjectBaseImpl : public TmsServerObject +{ +public: + TmsServerObjectBaseImpl(const BaseObjectPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context) + : TmsServerObject(server, context) + , object(object) + { + } + +protected: + BaseObjectPtr getObject() override + { + return object; + } + + opcua::OpcUaNodeId getRequestedNodeId() override + { + return RequestedNodeId{}(object); + } + + CoreType object; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h new file mode 100644 index 0000000..6e8e3bd --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h @@ -0,0 +1,77 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "property_internal_ptr.h" +#include "coreobjects/property_ptr.h" +#include "coretypes/listobject.h" +#include "opcuatms_server/objects/tms_server_eval_value.h" +#include "opcuatms_server/objects/tms_server_object.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class TmsServerProperty; +using TmsServerPropertyPtr = std::shared_ptr; + +class TmsServerProperty : public TmsServerVariable +{ +public: + using Super = TmsServerVariable; + + TmsServerProperty(const PropertyPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context); + TmsServerProperty(const PropertyPtr& object, + const opcua::OpcUaServerPtr& server, + const ContextPtr& context, + const PropertyObjectPtr& parent); + + std::string getBrowseName() override; + void bindCallbacks() override; + +protected: + opcua::OpcUaNodeId getTmsTypeId() override; + bool createOptionalNode(const opcua::OpcUaNodeId& nodeId) override; + void addChildNodes() override; + void configureVariableNodeAttributes(opcua::OpcUaObject& attr) override; + void validate() override; + +private: + void registerEvalValueNode(const std::string& nodeName, TmsServerEvalValue::ReadCallback readCallback, bool isSelection = false); + bool isSelectionType(); + bool isNumericType(); + bool isIntrospectionType(); + bool isReferenceType(); + bool isStructureType(); + + void hideReferenceTypeChildren(); + void hideNumericTypeChildren(); + void hideSelectionTypeChildren(); + void hideIntrospectionTypeChildren(); + void hideStructureTypeChildren(); + + void addReferenceTypeChildNodes(); + void addNumericTypeChildNodes(); + void addSelectionTypeChildNodes(); + void addIntrospectionTypeChildNodes(); + + std::unordered_map childObjects; + PropertyInternalPtr objectInternal; + WeakRefPtr parent; + + std::unordered_set HiddenNodes = {"FieldCoercionExpression", "FieldValidationExpression", ""}; + std::unordered_map childProperties; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h new file mode 100644 index 0000000..77ec298 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h @@ -0,0 +1,72 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "coreobjects/property_object_ptr.h" +#include "opcuatms_server/objects/tms_server_object.h" +#include "opcuatms_server/objects/tms_server_property.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class TmsServerPropertyObject; +using TmsServerPropertyObjectPtr = std::shared_ptr; + +class TmsServerPropertyObject : public TmsServerObjectBaseImpl +{ +public: + using Super = TmsServerObjectBaseImpl; + + TmsServerPropertyObject(const PropertyObjectPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context); + TmsServerPropertyObject(const PropertyObjectPtr& object, + const opcua::OpcUaServerPtr& server, + const ContextPtr& context, + const StringPtr& name); + TmsServerPropertyObject(const PropertyObjectPtr& object, + const opcua::OpcUaServerPtr& server, + const ContextPtr& context, + const StringPtr& name, + const PropertyPtr& objProp); + ~TmsServerPropertyObject(); + + std::string getBrowseName() override; + void addChildNodes() override; + void bindCallbacks() override; + bool createOptionalNode(const opcua::OpcUaNodeId& nodeId) override; + void setMethodParentNodeId(const opcua::OpcUaNodeId& methodParentNodeId); + +protected: + void configureNodeAttributes(opcua::OpcUaObject& attr) override; + void triggerEvent(PropertyObjectPtr& sender, PropertyValueEventArgsPtr& args); + opcua::OpcUaNodeId getTmsTypeId() override; + void addPropertyNode(const std::string& name, const opcua::OpcUaNodeId& parentId); + void bindPropertyCallbacks(const std::string& name); + + std::unordered_map childProperties; + std::unordered_map childObjects; + std::unordered_map childEvalValues; + std::unordered_map> methodProps; + +private: + void registerEvalValueNode(const std::string& nodeName, TmsServerEvalValue::ReadCallback readCallback); + void addMethodPropertyNode(const PropertyPtr& prop); + void bindMethodCallbacks(); + + StringPtr name; + PropertyInternalPtr objProp; + opcua::OpcUaNodeId methodParentNodeId; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h new file mode 100644 index 0000000..27b87c4 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h @@ -0,0 +1,45 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include "opcuatms_server/objects/tms_server_component.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class TmsServerSignal; +using TmsServerSignalPtr = std::shared_ptr; + +class TmsServerSignal : public TmsServerComponent +{ +public: + using Super = TmsServerComponent; + + TmsServerSignal(const SignalPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context); + + std::string getBrowseName() override; + std::string getDisplayName() override; + opcua::OpcUaNodeId getReferenceType() override; + void bindCallbacks() override; + bool createOptionalNode(const opcua::OpcUaNodeId& nodeId) override; + + void createNonhierarchicalReferences() override; + +protected: + opcua::OpcUaNodeId getTmsTypeId() override; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h new file mode 100644 index 0000000..16a1e47 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h @@ -0,0 +1,36 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "opcuatms_server/objects/tms_server_object.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +template +class TmsServerVariable : public TmsServerObjectBaseImpl +{ +public: + using Super = TmsServerObjectBaseImpl; + + TmsServerVariable(const CoreType& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context); + + opcua::OpcUaNodeId createNode(const opcua::OpcUaNodeId& parentNodeId) override; + +protected: + virtual void configureVariableNodeAttributes(opcua::OpcUaObject& attr); +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h new file mode 100644 index 0000000..043d48c --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h @@ -0,0 +1,47 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include +#include "opcuaserver/opcuaserver.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class TmsServer +{ +public: + TmsServer(const InstancePtr& instance); + TmsServer(const DevicePtr& device, const ContextPtr& context); + ~TmsServer(); + + void setOpcUaPort(uint16_t port); + void setOpendaqVersion(const std::string& version); + void start(); + void stop(); + +protected: + DevicePtr device; + ContextPtr context; + std::unique_ptr tmsDevice; + daq::opcua::OpcUaServerPtr server; + uint16_t opcUaPort = 4840; + std::string versionStr = ""; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcuatms/opcuatms_server/src/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_server/src/CMakeLists.txt new file mode 100644 index 0000000..5a7646b --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/src/CMakeLists.txt @@ -0,0 +1,91 @@ +set(LIB_NAME opcuatms_server) + +set(SRC_Cpp tms_server.cpp +) + +set(SRC_PublicHeaders +) + +set(SRC_PrivateHeaders tms_server.h +) + +# objects + +set(OBJECT_SRC_DIR "objects") + +set(SRC_Objects_Headers ${OBJECT_SRC_DIR}/tms_server_object.h + ${OBJECT_SRC_DIR}/tms_server_variable.h + ${OBJECT_SRC_DIR}/tms_server_signal.h + ${OBJECT_SRC_DIR}/tms_server_function_block.h + ${OBJECT_SRC_DIR}/tms_server_channel.h + ${OBJECT_SRC_DIR}/tms_server_input_port.h + ${OBJECT_SRC_DIR}/tms_server_property_object.h + ${OBJECT_SRC_DIR}/tms_server_device.h + ${OBJECT_SRC_DIR}/tms_server_folder.h + ${OBJECT_SRC_DIR}/tms_server_component.h + ${OBJECT_SRC_DIR}/tms_server_property.h + ${OBJECT_SRC_DIR}/tms_server_eval_value.h +) + +set(SRC_Objects ${OBJECT_SRC_DIR}/tms_server_object.cpp + ${OBJECT_SRC_DIR}/tms_server_variable.cpp + ${OBJECT_SRC_DIR}/tms_server_signal.cpp + ${OBJECT_SRC_DIR}/tms_server_function_block.cpp + ${OBJECT_SRC_DIR}/tms_server_channel.cpp + ${OBJECT_SRC_DIR}/tms_server_input_port.cpp + ${OBJECT_SRC_DIR}/tms_server_property_object.cpp + ${OBJECT_SRC_DIR}/tms_server_device.cpp + ${OBJECT_SRC_DIR}/tms_server_folder.cpp + ${OBJECT_SRC_DIR}/tms_server_component.cpp + ${OBJECT_SRC_DIR}/tms_server_property.cpp + ${OBJECT_SRC_DIR}/tms_server_eval_value.cpp +) + +set(SRC_PublicHeaders ${SRC_PublicHeaders} ${SRC_Objects_Headers}) +set(SRC_Cpp ${SRC_Cpp} ${SRC_Objects}) + +source_group("objects\\server_object" "${OBJECT_SRC_DIR}/tms_server_object.*") +source_group("objects\\server_variable" "${OBJECT_SRC_DIR}/tms_server_variable.*") +source_group("objects\\signal" "${OBJECT_SRC_DIR}/tms_server_signal.*") +source_group("objects\\function_block" "${OBJECT_SRC_DIR}/tms_server_function_block.*") +source_group("objects\\channel" "${OBJECT_SRC_DIR}/tms_server_channel.*") +source_group("objects\\input_port" "${OBJECT_SRC_DIR}/tms_server_input_port.*") +source_group("objects\\property_object" "${OBJECT_SRC_DIR}/tms_server_property_object.*") +source_group("objects\\device" "${OBJECT_SRC_DIR}/tms_server_device.*") +source_group("objects\\folder" "${OBJECT_SRC_DIR}/tms_server_folder.*") +source_group("objects\\component" "${OBJECT_SRC_DIR}/tms_server_component.*") +source_group("objects\\property" "${OBJECT_SRC_DIR}/tms_server_property.*") +source_group("objects\\eval_value" "${OBJECT_SRC_DIR}/tms_server_eval_value.*") + +# /objects + +prepend_include(${LIB_NAME} SRC_PrivateHeaders) +prepend_include(${LIB_NAME} SRC_PublicHeaders) + + +add_library(${LIB_NAME} STATIC ${SRC_Cpp} + ${SRC_PublicHeaders} + ${SRC_PrivateHeaders} +) + +add_library(${SDK_TARGET_NAMESPACE}::${LIB_NAME} ALIAS ${LIB_NAME}) + +if(BUILD_64Bit OR BUILD_ARM) + set_target_properties(${LIB_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON) +else() + set_target_properties(${LIB_NAME} PROPERTIES POSITION_INDEPENDENT_CODE OFF) +endif() + +target_include_directories(${LIB_NAME} PUBLIC $ + $ + + $ +) + +target_link_libraries(${LIB_NAME} PUBLIC daq::opcuatms + daq::opcuaserver +) + +set_target_properties(${LIB_NAME} PROPERTIES PUBLIC_HEADER "${SRC_PublicHeaders}") + +opendaq_set_output_lib_name(${LIB_NAME} ${PROJECT_VERSION_MAJOR}) diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_channel.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_channel.cpp new file mode 100644 index 0000000..0d6b65e --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_channel.cpp @@ -0,0 +1,20 @@ +#include "opcuatms_server/objects/tms_server_function_block.h" +#include "opcuatms_server/objects/tms_server_channel.h" +#include "opcuatms/converters/variant_converter.h" +#include "open62541/tmsdevice_nodeids.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace opcua; + +TmsServerChannel::TmsServerChannel(const ChannelPtr& object, const OpcUaServerPtr& server, const ContextPtr& context) + : Super(object, server, context) +{ +} + +OpcUaNodeId TmsServerChannel::getTmsTypeId() +{ + return OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_CHANNELTYPE); +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_component.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_component.cpp new file mode 100644 index 0000000..e69de29 diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp new file mode 100644 index 0000000..7f0b058 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -0,0 +1,299 @@ +#include +#include +#include +#include +#include "opcuatms_server/objects/tms_server_device.h" +#include "opcuatms/core_types_utils.h" +#include "opcuatms/type_mappings.h" +#include +#include "opcuatms/converters/struct_converter.h" +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace opcua; + +namespace detail +{ + static OpcUaVariant createLocalizedTextVariant(ConstCharPtr text) + { + OpcUaVariant v; + OpcUaObject localizedText = UA_LOCALIZEDTEXT_ALLOC("", text); + v.setScalar(std::move(localizedText.getValue())); + return v; + } + + static std::unordered_map> componentFieldToVariant = { + {"AssetId", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getAssetId().getCharPtr()}; }}, + {"ComponentName", [](const DeviceInfoPtr& info){ return createLocalizedTextVariant(info.getName().getCharPtr()); }}, + {"DeviceClass", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getDeviceClass().getCharPtr()}; }}, + {"DeviceManual", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getDeviceManual().getCharPtr()}; }}, + {"DeviceRevision", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getDeviceRevision().getCharPtr()}; }}, + {"HardwareRevision", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getHardwareRevision().getCharPtr()}; }}, + {"Manufacturer", [](const DeviceInfoPtr& info) { return createLocalizedTextVariant(info.getManufacturer().getCharPtr()); }}, + {"ManufacturerUri", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getManufacturerUri().getCharPtr()}; }}, + {"Model", [](const DeviceInfoPtr& info) { return createLocalizedTextVariant(info.getModel().getCharPtr()); }}, + {"ProductCode", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getProductCode().getCharPtr()}; }}, + {"ProductInstanceUri", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getProductInstanceUri().getCharPtr()}; }}, + {"RevisionCounter", [](const DeviceInfoPtr& info) { return OpcUaVariant{static_cast(info.getRevisionCounter())}; }}, + {"SerialNumber", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getSerialNumber().getCharPtr()}; }}, + {"SoftwareRevision", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getSoftwareRevision().getCharPtr()}; }}, + {"MacAddress", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getMacAddress().getCharPtr()}; }}, + {"ParentMacAddress", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getParentMacAddress().getCharPtr()}; }}, + {"Platform", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getPlatform().getCharPtr()}; }}, + {"Position", [](const DeviceInfoPtr& info) { return OpcUaVariant{static_cast(info.getPosition())}; }}, + {"SystemType", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getSystemType().getCharPtr()}; }}, + {"SystemUUID", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getSystemUuid().getCharPtr()}; }} + }; +} + +TmsServerDevice::TmsServerDevice(const DevicePtr& object, const OpcUaServerPtr& server, const ContextPtr& context) + : Super(object, server, context) +{ +} + +OpcUaNodeId TmsServerDevice::getTmsTypeId() +{ + return OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQDEVICETYPE); +} + +bool TmsServerDevice::createOptionalNode(const OpcUaNodeId& nodeId) +{ + const auto name = server->readBrowseNameString(nodeId); + + if (name == "AssetId" && object.getInfo().getAssetId() != "") + return true; + if (name == "ComponentName" && object.getInfo().getName() != "") + return true; + if (name == "DeviceClass" && object.getInfo().getDeviceClass() != "") + return true; + if (name == "ManufacturerUri" && object.getInfo().getManufacturerUri() != "") + return true; + if (name == "ProductCode" && object.getInfo().getProductCode() != "") + return true; + if (name == "ProductInstanceUri" && object.getInfo().getProductInstanceUri() != "") + return true; + + return Super::createOptionalNode(nodeId); +} + +void TmsServerDevice::bindCallbacks() +{ + this->addReadCallback("Domain",[this]() + { + + const auto deviceDomain = object.getDomain(); + if (!deviceDomain.assigned()) + return OpcUaVariant{}; + + const auto functionBlockNodeId = getChildNodeId("Domain"); + try + { + OpcUaObject uaDeviceDomain; + uaDeviceDomain->resolution.numerator = deviceDomain.getTickResolution().getNumerator(); + uaDeviceDomain->resolution.denominator = deviceDomain.getTickResolution().getDenominator(); + uaDeviceDomain->origin = ConvertToOpcUaString(deviceDomain.getOrigin()).getDetachedValue(); + uaDeviceDomain->ticksSinceOrigin = deviceDomain.getTicksSinceOrigin(); + auto unit = StructConverter::ToTmsType(deviceDomain.getUnit()); + uaDeviceDomain->unit = unit.getDetachedValue(); + + OpcUaVariant v; + v.setScalar(*uaDeviceDomain); + return v; + } + catch (...) + { + return OpcUaVariant{}; + } + }); + + Super::bindCallbacks(); +} + +void TmsServerDevice::populateDeviceInfo() +{ + auto createNode = [this](std::string name, CoreType type) + { + OpcUaNodeId newNodeId(0); + AddVariableNodeParams params(newNodeId, nodeId); + params.setBrowseName(name); + switch (type) + { + case ctBool: + params.setDataType(OpcUaNodeId(UA_TYPES[UA_TYPES_BOOLEAN].typeId)); + break; + case ctInt: + params.setDataType(OpcUaNodeId(UA_TYPES[UA_TYPES_INT64].typeId)); + break; + case ctFloat: + params.setDataType(OpcUaNodeId(UA_TYPES[UA_TYPES_DOUBLE].typeId)); + break; + case ctString: + params.setDataType(OpcUaNodeId(UA_TYPES[UA_TYPES_STRING].typeId)); + break; + default: + throw; + } + + params.typeDefinition = OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE)); + server->addVariableNode(params); + }; + + auto deviceInfo = object.getInfo(); + + const auto customInfoNames = deviceInfo.getCustomInfoPropertyNames(); + std::unordered_set customInfoNamesSet; + + for (auto propName : customInfoNames) + { + try + { + createNode(propName, deviceInfo.getProperty(propName).getValueType()); + customInfoNamesSet.insert(propName); + } + catch(...) + { + + } + } + + OpcUaObject bd; + bd->nodeId = nodeId.copyAndGetDetachedValue(); + bd->resultMask = UA_BROWSERESULTMASK_ALL; + auto result = server->browse(bd); + + for (size_t i = 0; i < result->referencesSize; i++) + { + const auto& reference = result->references[i]; + std::string browseName = opcua::utils::ToStdString(reference.browseName.name); + + if (detail::componentFieldToVariant.count(browseName)) + { + auto v = detail::componentFieldToVariant[browseName](deviceInfo); + server->writeValue(reference.nodeId.nodeId, *v); + } + else if (customInfoNamesSet.count(browseName)) + { + const auto valueType = deviceInfo.getProperty(browseName).getValueType(); + OpcUaVariant v; + if (valueType == ctBool) + { + bool val = deviceInfo.getPropertyValue(browseName); + v = OpcUaVariant(val); + } + else if (valueType == ctInt) + { + int64_t val = deviceInfo.getPropertyValue(browseName); + v = OpcUaVariant(val); + } + else if (valueType == ctFloat) + { + double val = deviceInfo.getPropertyValue(browseName); + v = OpcUaVariant(val); + } + else if (valueType == ctString) + { + v = OpcUaVariant(deviceInfo.getPropertyValue(browseName).asPtr().getCharPtr()); + } + else + { + continue; + } + + server->writeValue(reference.nodeId.nodeId, *v); + } + } +} + +void TmsServerDevice::populateStreamingOptions() +{ + auto params = AddObjectNodeParams(UA_NODEID_NULL, nodeId); + params.setBrowseName("StreamingOptions"); + auto streamingOptionsNodeId = server->addObjectNode(params); + + auto devicePrivatePtr = object.asPtrOrNull(); + if (devicePrivatePtr == nullptr) // Instance does not implement IDevicePrivate + return; + + ListPtr streamingOptions; + devicePrivatePtr->getStreamingOptions(&streamingOptions); + for (const auto& streamingOption : streamingOptions) + { + auto tmsStreamingOption = registerTmsObjectOrAddReference( + streamingOptionsNodeId, streamingOption.asPtr(), streamingOption.getProtocolId()); + this->streamingOptions.push_back(std::move(tmsStreamingOption)); + } +} + +void TmsServerDevice::addChildNodes() +{ + populateDeviceInfo(); + populateStreamingOptions(); + auto methodSetNodeId = getChildNodeId("MethodSet"); + tmsPropertyObject->setMethodParentNodeId(methodSetNodeId); + + for (const auto& device : object.getDevices()) + { + auto tmsDevice = registerTmsObjectOrAddReference(nodeId, device); + devices.push_back(std::move(tmsDevice)); + } + + auto functionBlockNodeId = getChildNodeId("FunctionBlocks"); + assert(!functionBlockNodeId.isNull()); + for (const auto& functionBlock : object.getFunctionBlocks()) + { + auto tmsFunctionBlock = registerTmsObjectOrAddReference>(functionBlockNodeId, functionBlock); + functionBlocks.push_back(std::move(tmsFunctionBlock)); + } + + auto signalsNodeId = getChildNodeId("Signals"); + assert(!signalsNodeId.isNull()); + for (const auto& signal : object.getSignals()) + { + auto tmsSignal = registerTmsObjectOrAddReference(signalsNodeId, signal); + signals.push_back(std::move(tmsSignal)); + } + + auto inputsOutputsNodeId = getChildNodeId("InputsOutputs"); + assert(!inputsOutputsNodeId.isNull()); + + auto topFolder = object.getInputsOutputsFolder(); + auto inputsOutputsNode = std::make_unique(topFolder, server, daqContext); + inputsOutputsNode->registerToExistingOpcUaNode(inputsOutputsNodeId); + folders.push_back(std::move(inputsOutputsNode)); + + for (auto component : object.getItems()) + { + auto id = component.getName(); + if (id == "dev" || id == "fb" || id == "io" || id == "sig") + continue; + + if (component.asPtrOrNull().assigned()) + { + auto folderNode = registerTmsObjectOrAddReference(nodeId, component); + folders.push_back(std::move(folderNode)); + } + else + { + auto componentNode = registerTmsObjectOrAddReference>(nodeId, component); + components.push_back(std::move(componentNode)); + } + } + + Super::addChildNodes(); +} + + +void TmsServerDevice::createNonhierarchicalReferences() +{ + createChildNonhierarchicalReferences(signals); + createChildNonhierarchicalReferences(devices); + createChildNonhierarchicalReferences(functionBlocks); + createChildNonhierarchicalReferences(folders); + createChildNonhierarchicalReferences(components); +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS + diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_eval_value.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_eval_value.cpp new file mode 100644 index 0000000..55ed1b5 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_eval_value.cpp @@ -0,0 +1,124 @@ +#include "opcuatms_server/objects/tms_server_eval_value.h" +#include "opcuatms/converters/variant_converter.h" +#include "opcuatms/converters/selection_converter.h" +#include "open62541/tmsbt_nodeids.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace opcua; + +// TmsServerEvalValue + +TmsServerEvalValue::TmsServerEvalValue(const EvalValuePtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context) + : Super(nullptr, server, context) +{ + this->readCallback = [this, object]() { return object; }; + this->writeCallback = [](const BaseObjectPtr& object) { return UA_STATUSCODE_BADNOTWRITABLE; }; +} + +TmsServerEvalValue::TmsServerEvalValue(const opcua::OpcUaServerPtr& server, const ContextPtr& context) + : TmsServerEvalValue(nullptr, server, context) +{ +} + +std::string TmsServerEvalValue::getBrowseName() +{ + return "EvalValue"; +} + +void TmsServerEvalValue::setReadCallback(ReadCallback readCallback) +{ + this->readCallback = std::move(readCallback); +} + +void TmsServerEvalValue::setWriteCallback(WriteCallback writeCallback) +{ + this->writeCallback = writeCallback; +} + +void TmsServerEvalValue::setIsSelectionType(bool isSelection) +{ + this->isSelection = isSelection; +} + +opcua::OpcUaNodeId TmsServerEvalValue::getTmsTypeId() +{ + return OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_EVALUATIONVARIABLETYPE); +} + +void TmsServerEvalValue::configureVariableNodeAttributes(opcua::OpcUaObject& attr) +{ + attr->accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; +} + +void TmsServerEvalValue::bindCallbacks() +{ + addReadCallback(nodeId, [this]() { return readRoot(); }); + addWriteCallback(nodeId, [this](const OpcUaVariant& variant) -> UA_StatusCode { return writeRoot(variant); }); + addReadCallback("EvaluationExpression", [this]() { return readEvaluationExpression(); }); +} + +opcua::OpcUaVariant TmsServerEvalValue::readEvaluationExpression() +{ + const auto object = this->readCallback(); + if (!object.assigned()) + return OpcUaVariant(); + + try + { + const auto eval = object.asPtrOrNull(); + if (eval.assigned()) + return VariantConverter::ToVariant(eval.getEval()); + } + catch (const ConversionFailedException&) + { + } + + return OpcUaVariant(); +} + +opcua::OpcUaVariant TmsServerEvalValue::readRoot() +{ + const auto object = this->readCallback(); + if (!object.assigned()) + return OpcUaVariant(); + + try + { + if (isSelection) + { + const auto eval = object.asPtrOrNull(); + if (eval.assigned()) + return SelectionVariantConverter::ToVariant(eval.getResult()); + + return SelectionVariantConverter::ToVariant(object); + } + + const auto eval = object.asPtrOrNull(); + if (eval.assigned()) + return VariantConverter::ToVariant(eval.getResult(), nullptr, daqContext); + + return VariantConverter::ToVariant(object, nullptr, daqContext); + } + catch (const ConversionFailedException&) + { + return OpcUaVariant(); + } +} + +UA_StatusCode TmsServerEvalValue::writeRoot(const OpcUaVariant& variant) +{ + try + { + const auto object = VariantConverter::ToDaqObject(variant, daqContext); + return writeCallback(object); + } + catch (const ConversionFailedException&) + { + return UA_STATUSCODE_BADINVALIDARGUMENT; + } + + return UA_STATUSCODE_GOOD; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp new file mode 100644 index 0000000..ca9852c --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp @@ -0,0 +1,62 @@ +#include "opcuatms_server/objects/tms_server_channel.h" +#include "opcuatms_server/objects/tms_server_folder.h" +#include "opcuatms/converters/variant_converter.h" +#include "open62541/tmsdevice_nodeids.h" +#include "opendaq/io_folder_config.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace opcua; + +TmsServerFolder::TmsServerFolder(const FolderPtr& object, const OpcUaServerPtr& server, const ContextPtr& context) + : Super(object, server, context) +{ +} + +void TmsServerFolder::addChildNodes() +{ + for (auto item : object.getItems()) + { + auto folder = item.asPtrOrNull(); + auto channel = item.asPtrOrNull(); + auto component = item.asPtrOrNull(); + + if (channel.assigned()) + { + auto tmsChannel = registerTmsObjectOrAddReference(this->nodeId, channel); + channels.push_back(std::move(tmsChannel)); + } + else if (folder.assigned()) // It is important to test for folder last as a channel also is a folder! + { + auto tmsFolder = registerTmsObjectOrAddReference(this->nodeId, folder); + folders.push_back(std::move(tmsFolder)); + } + else if (component.assigned()) // It is important to test for component after folder! + { + auto tmsComponent = registerTmsObjectOrAddReference>(this->nodeId, component); + components.push_back(std::move(tmsComponent)); + } + else + { + throw daq::NotImplementedException("Unhandled item: " + item.getGlobalId()); + } + } + + Super::addChildNodes(); +} + +OpcUaNodeId TmsServerFolder::getTmsTypeId() +{ + if (object.asPtrOrNull().assigned()) + return OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_IOCOMPONENTTYPE); + return OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQCOMPONENTTYPE); +} + +void TmsServerFolder::createNonhierarchicalReferences() +{ + createChildNonhierarchicalReferences(channels); + createChildNonhierarchicalReferences(folders); +} + + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp new file mode 100644 index 0000000..f8f9079 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp @@ -0,0 +1,89 @@ +#include +#include "opcuatms_server/objects/tms_server_function_block.h" +#include "opcuatms/converters/variant_converter.h" +#include "open62541/statuscodes.h" +#include "open62541/tmsbsp_nodeids.h" +#include "open62541/di_nodeids.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace opcua; + +template +TmsServerFunctionBlock::TmsServerFunctionBlock(const FunctionBlockPtr& object, const OpcUaServerPtr& server, const ContextPtr& context) + : Super(object, server, context) +{ +} + +template +OpcUaNodeId TmsServerFunctionBlock::getTmsTypeId() +{ + return OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_FUNCTIONBLOCKTYPE); +} + +template +bool TmsServerFunctionBlock::createOptionalNode(const OpcUaNodeId& nodeId) +{ + auto browseName = this->server->readBrowseName(nodeId); + auto create = browseName->name == "OutputSignals" || browseName->name == "InputPorts"; + return create || Super::createOptionalNode(nodeId); +} + +template +void TmsServerFunctionBlock::bindCallbacks() +{ + this->addReadCallback("FunctionBlockInfo", [this]() { + auto info = this->object.getFunctionBlockType(); + if (info != nullptr) + return VariantConverter::ToVariant(info); + else + return OpcUaVariant(); + }); + + Super::bindCallbacks(); +} + +template +void TmsServerFunctionBlock::addChildNodes() +{ + auto signalsNodeId = this->getChildNodeId("OutputSignals"); + assert(!signalsNodeId.isNull()); + + for (const auto& signal : this->object.getSignals()) + { + auto tmsSignal = this->template registerTmsObjectOrAddReference(signalsNodeId, signal); + signals.push_back(std::move(tmsSignal)); + } + + auto inputPortsNodeId = this->getChildNodeId("InputPorts"); + assert(!inputPortsNodeId.isNull()); + + for (const auto& inputPort : this->object.getInputPorts()) + { + auto tmsInputPort = this->template registerTmsObjectOrAddReference(inputPortsNodeId, inputPort); + inputPorts.push_back(std::move(tmsInputPort)); + } + + for (const auto& fb : this->object.getFunctionBlocks()) + { + auto tmsFunctionBlock = this->template registerTmsObjectOrAddReference>(this->nodeId, fb); + functionBlocks.push_back(std::move(tmsFunctionBlock)); + } + + Super::addChildNodes(); +} + +template +void TmsServerFunctionBlock::createNonhierarchicalReferences() +{ + this->createChildNonhierarchicalReferences(signals); + this->createChildNonhierarchicalReferences(inputPorts); + this->createChildNonhierarchicalReferences(functionBlocks); +} + +// To force the compiler to generate the template classes that are used elsewhere +// If this is not done, then you will get linker errors if using it outside the static library +template class TmsServerFunctionBlock; +template class TmsServerFunctionBlock; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp new file mode 100644 index 0000000..8ad41f1 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp @@ -0,0 +1,101 @@ +#include +#include "opcuatms_server/objects/tms_server_input_port.h" +#include "opcuatms/converters/variant_converter.h" +#include "open62541/statuscodes.h" +#include "open62541/tmsbsp_nodeids.h" +#include "open62541/di_nodeids.h" +#include "open62541/tmsbsp_nodeids.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace opcua; + +TmsServerInputPort::TmsServerInputPort(const InputPortPtr& object, const OpcUaServerPtr& server, const ContextPtr& context) + : Super(object, server, context) +{ +} + +OpcUaNodeId TmsServerInputPort::getReferenceType() +{ + return OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASINPUTPORT); +} + +OpcUaNodeId TmsServerInputPort::getTmsTypeId() +{ + return OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_INPUTPORTTYPE); +} + +void TmsServerInputPort::bindCallbacks() +{ + + addReadCallback("RequiresSignal", [this]() { return VariantConverter::ToVariant(object.getRequiresSignal()); }); + + //addEvent("AcceptsSignal")->onMethodCall([this](NodeEventManager::MethodArgs args) + //{ + // if (args.inputSize != 1 || args.outputSize != 1) + // return static_cast(UA_STATUSCODE_BADINTERNALERROR); + + // auto nodeId = OpcUaVariant(args.input[0]).toNodeId(); + // //TODO: check if signal can be accepted, for now allow all signals + // // Pseudocode: + // // signal = lookUpSignal(nodeId) + // // if (signal == nullptr) + // // return static_cast(UA_STATUSCODE_BADNOTFOUND); + // // Whatever else that needs to be done... + + // bool accepts = true; + // + // OpcUaVariant result; + // result.setScalar(accepts); + // args.output[0] = result.getDetachedValue(); + // return static_cast(UA_STATUSCODE_GOOD); + //}); + + //addEvent("ConnectSignal")->onMethodCall([this](NodeEventManager::MethodArgs args) + //{ + // if (args.inputSize != 1) + // return static_cast(UA_STATUSCODE_BADINTERNALERROR); + + // auto nodeId = OpcUaVariant(args.input[0]).toNodeId(); + + // //TODO: Connect the signal to the input port + // // Pseudocode: + // // signalNodeId = lookUpSignal(nodeId) + // // if (signalNodeId == nullptr) + // // return static_cast(UA_STATUSCODE_BADNOTFOUND); + // // OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_CONNECTEDTO); + // // server->addReference(signalNodeId, referenceTypeId, getNodeId(), true); + // // Whatever else that needs to be done... + + // return static_cast(UA_STATUSCODE_GOOD); + //}); + + //addEvent("DisconnectSignal")->onMethodCall([this](NodeEventManager::MethodArgs args) + //{ + // // TODO: Disconnect the signal to the input port + // // Pseudocode: + // // auto signal = object.getSignal(); + // // if (signal == nullptr) + // // return static_cast(UA_STATUSCODE_BADNOTFOUND); + // // OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_CONNECTEDTO); + // // server->deleteReference(this->getNodeId(), referenceTypeId, false); + // // Whatever else that needs to be done... + // auto signal = object.getSignal(); + // return static_cast(UA_STATUSCODE_GOOD); + //}); + + Super::bindCallbacks(); +} + +void TmsServerInputPort::createNonhierarchicalReferences() +{ + auto connectedSignal = object.getSignal(); + if (connectedSignal.assigned()) + { + auto connectedSignalNodeId = findSignalNodeId(connectedSignal); + if (!connectedSignalNodeId.isNull()) + addReference(connectedSignalNodeId, OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_CONNECTEDTOSIGNAL)); + } +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp new file mode 100644 index 0000000..d42aeb1 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp @@ -0,0 +1,268 @@ +#include +#include +#include +#include +#include +#include +#include "open62541/server.h" +#include "open62541/tmsbsp_nodeids.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace opcua; +namespace opcua_utils = opcua::utils; + +TmsServerObject::TmsServerObject(const OpcUaServerPtr& server, const ContextPtr& context) + : server(server) + , daqContext(context) +{ +} + +TmsServerObject::~TmsServerObject() +{ +} + +std::string TmsServerObject::getBrowseName() +{ + return typeBrowseName; +} + +OpcUaNodeId TmsServerObject::getRequestedNodeId() +{ + return {}; +} + +std::string TmsServerObject::getDisplayName() +{ + return ""; +} + +OpcUaNodeId TmsServerObject::getReferenceType() +{ + return OpcUaNodeId(UA_NS0ID_HASCOMPONENT); +} + +OpcUaNodeId TmsServerObject::registerOpcUaNode(const OpcUaNodeId& parentNodeId) +{ + validate(); + this->nodeId = createNode(parentNodeId); + return registerToExistingOpcUaNode(this->nodeId); +} + +OpcUaNodeId TmsServerObject::registerToExistingOpcUaNode(const OpcUaNodeId& nodeId) +{ + if (this->nodeId.isNull()) + validate(); + + this->nodeId = nodeId; + browseReferences(); + addChildNodes(); + browseReferences(); + bindCallbacks(); + bindReadWriteCallbacks(); + return this->nodeId; +} + +OpcUaNodeId TmsServerObject::getNodeId() +{ + return nodeId; +} + +void TmsServerObject::addHierarchicalReference(const OpcUaNodeId& parent) +{ + server->addReference(parent, getReferenceType(), getNodeId(), true); +} + +void TmsServerObject::createNonhierarchicalReferences() +{ +} + +NodeEventManagerPtr TmsServerObject::addEvent(const StringPtr& nodeName) +{ + auto nodeId = getChildNodeId(nodeName); + return addEvent(nodeId); +} + +NodeEventManagerPtr TmsServerObject::addEvent(const OpcUaNodeId& nodeId) +{ + if (eventManagers.count(nodeId) > 0) + return eventManagers[nodeId]; + + auto eventManager = std::make_shared(nodeId, server); + eventManagers.insert({nodeId, eventManager}); + return eventManager; +} + +void TmsServerObject::validate() +{ +} + +OpcUaNodeId TmsServerObject::createNode(const OpcUaNodeId& parentNodeId) +{ + OpcUaNodeId newNodeId; + auto typeNodeId = getTmsTypeId(); + + std::string browseName; + auto blueberryComponent = getObject().asPtrOrNull(true); + if (blueberryComponent.assigned()) + { + browseName = blueberryComponent.getLocalId().toStdString(); + } + else + { + typeBrowseName = readTypeBrowseName(); + browseName = getBrowseName(); + if (browseName.empty()) + browseName = typeBrowseName; + } + + auto params = AddObjectNodeParams(getRequestedNodeId(), parentNodeId); + configureNodeAttributes(params.attr); + params.referenceTypeId = getReferenceType(); + params.setBrowseName(browseName); + params.typeDefinition = typeNodeId; + params.nodeContext = this; + params.addOptionalNodeCallback = [this](const OpcUaNodeId& nodeId) { return this->createOptionalNode(nodeId); }; + newNodeId = server->addObjectNode(params); + + return OpcUaNodeId(newNodeId); +} + +void TmsServerObject::addChildNodes() +{ +} + +bool TmsServerObject::hasChildNode(const std::string& nodeName) const +{ + return references.count(nodeName) != 0; +} + +OpcUaNodeId TmsServerObject::getChildNodeId(const std::string& nodeName) +{ + return references[nodeName]->nodeId.nodeId; +} + +OpcUaNodeId TmsServerObject::findSignalNodeId(const SignalPtr& signal) const +{ + return findTmsObjectNodeId(signal); +} + +void TmsServerObject::bindCallbacks() +{ +} + +void TmsServerObject::bindReadWriteCallbacks() +{ + for (const auto& entry : readCallbacks) + { + const OpcUaNodeId nodeId = entry.first; + auto readCallback = entry.second; + + addEvent(nodeId)->onDataSourceRead([this, readCallback](NodeEventManager::DataSourceReadArgs args) -> UA_StatusCode { + std::lock_guard lock(this->valueMutex); + try + { + auto& dataVelue = args.value; + dataVelue->hasServerTimestamp = UA_TRUE; + dataVelue->sourceTimestamp = getCurrentClock(); + OpcUaVariant variant = readCallback(); + dataVelue->value = variant.getDetachedValue(); + return UA_STATUSCODE_GOOD; + } + catch (...) + { + return UA_STATUSCODE_BADINTERNALERROR; + } + }); + } + + for (const auto& entry : writeCallbacks) + { + const OpcUaNodeId nodeId = entry.first; + auto writeCallback = entry.second; + + addEvent(nodeId)->onDataSourceWrite([this, writeCallback](NodeEventManager::DataSourceWriteArgs args) -> UA_StatusCode { + std::lock_guard lock(this->valueMutex); + try + { + auto variant = OpcUaVariant(std::move(args.value->value)); + return writeCallback(variant); + } + catch (...) + { + return UA_STATUSCODE_BADINTERNALERROR; + } + }); + } +} + +int64_t TmsServerObject::getCurrentClock() +{ + // later we will probably have a getClockProvider() method or something similar + return -1; +} + +std::string TmsServerObject::readTypeBrowseName() +{ + auto typeNodeId = getTmsTypeId(); + OpcUaObject browseName; + UA_Server_readBrowseName(server->getUaServer(), *typeNodeId, browseName.get()); + return opcua_utils::ToStdString(browseName->name); +} + +bool TmsServerObject::createOptionalNode(const OpcUaNodeId& nodeId) +{ + return true; +} + +void TmsServerObject::configureNodeAttributes(OpcUaObject& attr) +{ + attr->eventNotifier = UA_EVENTNOTIFIER_SUBSCRIBE_TO_EVENT; + auto displayName = getDisplayName(); + if (!displayName.empty()) + attr->displayName = UA_LOCALIZEDTEXT_ALLOC("", displayName.c_str()); +} + +void TmsServerObject::addReadCallback(const std::string& nodeName, ReadVariantCallback readFunc) +{ + auto nodeId = getChildNodeId(nodeName); + readCallbacks.insert({nodeId, std::move(readFunc)}); +} + +void TmsServerObject::addWriteCallback(const std::string& nodeName, WriteVariantCallback writeFunc) +{ + auto nodeId = getChildNodeId(nodeName); + writeCallbacks.insert({nodeId, std::move(writeFunc)}); +} + +void TmsServerObject::addReadCallback(const OpcUaNodeId& nodeId, ReadVariantCallback readFunc) +{ + readCallbacks.insert({nodeId, std::move(readFunc)}); +} + +void TmsServerObject::addWriteCallback(const OpcUaNodeId& nodeId, WriteVariantCallback writeFunc) +{ + writeCallbacks.insert({nodeId, std::move(writeFunc)}); +} + +void TmsServerObject::addReference(const OpcUaNodeId& targetNodeId, const OpcUaNodeId& referenceTypeId) +{ + server->addReference(nodeId, referenceTypeId, targetNodeId, true); +} + +void TmsServerObject::browseReferences() +{ + OpcUaObject bd; + bd->nodeId = nodeId.copyAndGetDetachedValue(); + bd->resultMask = UA_BROWSERESULTMASK_ALL; + auto result = server->browse(bd); + + for (size_t i = 0; i < result->referencesSize; i++) + { + auto reference = result->references[i]; + std::string browseName = opcua_utils::ToStdString(reference.browseName.name); + references.insert({browseName, OpcUaObject(reference)}); + } +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp new file mode 100644 index 0000000..0f985c8 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp @@ -0,0 +1,278 @@ +#include "opcuatms_server/objects/tms_server_property.h" +#include +#include +#include +#include +#include +#include "opcuatms/converters/variant_converter.h" +#include "open62541/tmsbsp_nodeids.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace opcua; + +TmsServerProperty::TmsServerProperty(const PropertyPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context) + : Super(object, server, context) +{ + objectInternal = object.asPtr(false); + if (isReferenceType()) + hideReferenceTypeChildren(); + if (isNumericType()) + hideNumericTypeChildren(); + if (isIntrospectionType()) + hideIntrospectionTypeChildren(); + if (isSelectionType()) + hideSelectionTypeChildren(); + if (isStructureType()) + hideStructureTypeChildren(); + +} + +TmsServerProperty::TmsServerProperty(const PropertyPtr& object, + const opcua::OpcUaServerPtr& server, + const ContextPtr& context, + const PropertyObjectPtr& parent) + : TmsServerProperty(object, server, context) +{ + this->parent = parent; +} + +std::string TmsServerProperty::getBrowseName() +{ + return this->object.getName(); +} + +void TmsServerProperty::bindCallbacks() +{ + if (!HiddenNodes.count("CoercionExpression")) + { + addReadCallback("CoercionExpression", [this]() { return VariantConverter::ToVariant(object.getCoercer().getEval()); }); + } + + if (!HiddenNodes.count("ValidationExpression")) + { + addReadCallback("ValidationExpression", [this]() { return VariantConverter::ToVariant(object.getValidator().getEval()); }); + } + + for (auto childProp : childProperties) + { + auto name = childProp.second->getBrowseName(); + auto parentObj = this->parent.getRef(); + if (!parentObj.getProperty(name).asPtr().getReferencedPropertyUnresolved().assigned()) + { + addReadCallback(name, [this, name]() { + const auto value = this->parent.getRef().getPropertyValue(name); + return VariantConverter::ToVariant(value, nullptr, daqContext); + }); + + if (!parentObj.asPtrOrNull().assigned() || !parentObj.isFrozen()) + { + addWriteCallback(name, [this, name](const OpcUaVariant& variant) { + const auto value = VariantConverter::ToDaqObject(variant, daqContext); + this->parent.getRef().setPropertyValue(name, value); + return UA_STATUSCODE_GOOD; + }); + } + } + else + { + addReadCallback(name, [this, name]() { + const auto refProp = this->parent.getRef().getProperty(name).asPtr().getReferencedPropertyUnresolved(); + return VariantConverter::ToVariant(refProp.getEval(), nullptr, daqContext); + }); + } + + } +} + +opcua::OpcUaNodeId TmsServerProperty::getTmsTypeId() +{ + if (objectInternal.getSelectionValuesUnresolved().assigned()) + return OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_SELECTIONVARIABLETYPE); + + if (objectInternal.getReferencedPropertyUnresolved().assigned()) + return OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_REFERENCEVARIABLETYPE); + + const auto type = object.getValueType(); + switch (type) + { + case CoreType::ctInt: + case CoreType::ctFloat: + return OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_NUMERICVARIABLETYPE); + case CoreType::ctStruct: + return OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_STRUCTUREVARIABLETYPE); + default: + break; + } + + return OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_INTROSPECTIONVARIABLETYPE); +} + +bool TmsServerProperty::createOptionalNode(const opcua::OpcUaNodeId& nodeId) +{ + const auto name = server->readBrowseNameString(nodeId); + + return HiddenNodes.count(name) == 0; +} + +void TmsServerProperty::addChildNodes() +{ + if (isReferenceType()) + { + addReferenceTypeChildNodes(); + return; + } + + addIntrospectionTypeChildNodes(); + if (isNumericType()) + addNumericTypeChildNodes(); + else if (isSelectionType()) + addSelectionTypeChildNodes(); +} + +void TmsServerProperty::configureVariableNodeAttributes(opcua::OpcUaObject& attr) +{ + Super::configureVariableNodeAttributes(attr); + + attr->writeMask = attr->writeMask & ~UA_WRITEMASK_DISPLAYNAME; + attr->writeMask = attr->writeMask & ~UA_WRITEMASK_DESCRIPTION; + + if (object.getDescription().assigned()) + attr->description = UA_LOCALIZEDTEXT_ALLOC("", object.getDescription().getCharPtr()); +} + +void TmsServerProperty::validate() +{ +} + +void TmsServerProperty::registerEvalValueNode(const std::string& nodeName, TmsServerEvalValue::ReadCallback readCallback, bool isSelection) +{ + auto nodeId = getChildNodeId(nodeName); + auto serverObject = std::make_shared(server, daqContext); + serverObject->setReadCallback(std::move(readCallback)); + serverObject->setIsSelectionType(isSelection); + auto childNodeId = serverObject->registerToExistingOpcUaNode(nodeId); + + childObjects.insert({childNodeId, serverObject}); +} + +bool TmsServerProperty::isSelectionType() +{ + return getTmsTypeId() == OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_SELECTIONVARIABLETYPE); +} + +bool TmsServerProperty::isNumericType() +{ + return getTmsTypeId() == OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_NUMERICVARIABLETYPE); +} + +bool TmsServerProperty::isIntrospectionType() +{ + return getTmsTypeId() == OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_INTROSPECTIONVARIABLETYPE); +} + +bool TmsServerProperty::isReferenceType() +{ + return getTmsTypeId() == OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_REFERENCEVARIABLETYPE); +} + +bool TmsServerProperty::isStructureType() +{ + return getTmsTypeId() == OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_STRUCTUREVARIABLETYPE); +} + +void TmsServerProperty::hideReferenceTypeChildren() +{ + // TODO: Adjust model to reference type variables not having the IsVisible field + HiddenNodes.insert("IsVisible"); +} + +void TmsServerProperty::hideNumericTypeChildren() +{ + hideIntrospectionTypeChildren(); + + if (const auto pos = HiddenNodes.find("DefaultValue"); pos != HiddenNodes.cend()) + HiddenNodes.erase(pos); + if (!objectInternal.getMaxValueUnresolved().assigned()) + HiddenNodes.insert("MaxValue"); + if (!objectInternal.getMinValueUnresolved().assigned()) + HiddenNodes.insert("MinValue"); + if (!objectInternal.getSuggestedValuesUnresolved().assigned()) + HiddenNodes.insert("SuggestedValues"); +} + +void TmsServerProperty::hideSelectionTypeChildren() +{ + hideIntrospectionTypeChildren(); + + if (const auto pos = HiddenNodes.find("DefaultValue"); pos != HiddenNodes.cend()) + HiddenNodes.erase(pos); +} + +void TmsServerProperty::hideIntrospectionTypeChildren() +{ + if (!objectInternal.getVisibleUnresolved().assigned()) + HiddenNodes.insert("IsVisible"); + if (!objectInternal.getReadOnlyUnresolved().assigned()) + HiddenNodes.insert("IsReadOnly"); + if (!objectInternal.getDefaultValueUnresolved().assigned()) + HiddenNodes.insert("DefaultValue"); + if (!objectInternal.getUnitUnresolved().assigned()) + HiddenNodes.insert("Unit"); + if (!object.getValidator().assigned()) + HiddenNodes.insert("ValidationExpression"); + if (!object.getCoercer().assigned()) + HiddenNodes.insert("CoercionExpression"); +} + +void TmsServerProperty::hideStructureTypeChildren() +{ + // TODO: Add support for these + HiddenNodes.insert("FieldCoercionExpression"); + HiddenNodes.insert("FieldValidationExpression"); +} + +void TmsServerProperty::addReferenceTypeChildNodes() +{ + const auto refNames = objectInternal.getReferencedPropertyUnresolved().getPropertyReferences(); + for (auto propName : refNames) + { + auto prop = parent.getRef().getProperty(propName); + if (prop.getValueType() != ctObject) + { + auto serverInfo = registerTmsObjectOrAddReference(nodeId, prop, parent.getRef()); + auto childNodeId = serverInfo->getNodeId(); + childProperties.insert({childNodeId, serverInfo}); + } + } +} + +void TmsServerProperty::addNumericTypeChildNodes() +{ + if (!HiddenNodes.count("MinValue")) + registerEvalValueNode("MinValue", [this]() { return this->objectInternal.getMinValueUnresolved(); }); + if (!HiddenNodes.count("MaxValue")) + registerEvalValueNode("MaxValue", [this]() { return this->objectInternal.getMaxValueUnresolved(); }); + if (!HiddenNodes.count("SuggestedValues")) + registerEvalValueNode("SuggestedValues", [this]() { return this->objectInternal.getSuggestedValuesUnresolved(); }); +} + +void TmsServerProperty::addSelectionTypeChildNodes() +{ + registerEvalValueNode("SelectionValues", [this]() { return this->objectInternal.getSelectionValuesUnresolved(); }, true); +} + +void TmsServerProperty::addIntrospectionTypeChildNodes() +{ + if (!HiddenNodes.count("IsReadOnly")) + registerEvalValueNode("IsReadOnly", [this]() { return this->objectInternal.getReadOnlyUnresolved(); }); + if (!HiddenNodes.count("IsVisible")) + registerEvalValueNode("IsVisible", [this]() { return this->objectInternal.getVisibleUnresolved(); }); + if (!HiddenNodes.count("DefaultValue")) + registerEvalValueNode("DefaultValue", [this]() { return this->objectInternal.getDefaultValueUnresolved(); }); + if (!HiddenNodes.count("Unit")) + registerEvalValueNode("Unit", [this]() { return this->objectInternal.getUnitUnresolved(); }); +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp new file mode 100644 index 0000000..9c1c84f --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp @@ -0,0 +1,301 @@ +#include "opcuatms_server/objects/tms_server_property_object.h" +#include +#include +#include "coreobjects/argument_info_factory.h" +#include "coreobjects/property_object_internal_ptr.h" +#include "opcuatms/converters/variant_converter.h" +#include "opcuatms_server/objects/tms_server_property.h" +#include "open62541/statuscodes.h" +#include "open62541/tmsbsp_nodeids.h" +#include "open62541/tmsbt_nodeids.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + using namespace opcua; + +TmsServerPropertyObject::TmsServerPropertyObject(const PropertyObjectPtr& object, + const OpcUaServerPtr& server, + const ContextPtr& context) + : Super(object, server, context) +{ +} + +TmsServerPropertyObject::TmsServerPropertyObject(const PropertyObjectPtr& object, + const opcua::OpcUaServerPtr& server, + const ContextPtr& context, + const StringPtr& name) + : TmsServerPropertyObject(object, server, context) +{ + this->name = name; +} + +TmsServerPropertyObject::TmsServerPropertyObject(const PropertyObjectPtr& object, + const opcua::OpcUaServerPtr& server, + const ContextPtr& context, + const StringPtr& name, + const PropertyPtr& objProp) + : TmsServerPropertyObject(object, server, context, name) +{ + this->objProp = objProp; +} + +TmsServerPropertyObject::~TmsServerPropertyObject() +{ + for (auto prop : this->object.getAllProperties()) + this->object.getOnPropertyValueWrite(prop.getName()) -= event(this, &TmsServerPropertyObject::triggerEvent); +} + +std::string TmsServerPropertyObject::getBrowseName() +{ + if (name.assigned()) + return name; + + const auto className = object.getClassName(); + return className != "" ? className : "PropertyObject"; +} + +OpcUaNodeId TmsServerPropertyObject::getTmsTypeId() +{ + return OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_VARIABLEBLOCKTYPE); +} + +void TmsServerPropertyObject::addChildNodes() +{ + if (objProp.assigned()) + { + if (objProp.getVisibleUnresolved().assigned()) + registerEvalValueNode("IsVisible", [this]() { return objProp.getVisibleUnresolved(); }); + if (objProp.getReadOnlyUnresolved().assigned()) + registerEvalValueNode("IsReadOnly", [this]() { return objProp.getReadOnlyUnresolved(); }); + } + + for (const auto& prop : object.getAllProperties()) + { + // NOTE: ctObject types cannot be placed below ReferenceVariableType properties + if (prop.getValueType() != ctObject || prop.getReferencedProperty().assigned()) + { + if (prop.getIsReferenced()) + continue; + if (prop.getValueType() == ctFunc || prop.getValueType() == ctProc) + { + addMethodPropertyNode(prop); + continue; + } + + OpcUaNodeId childNodeId; + std::shared_ptr serverInfo; + if (hasChildNode(prop.getName())) + { + serverInfo = std::make_shared(prop, server, daqContext, object); + childNodeId = serverInfo->registerToExistingOpcUaNode(nodeId); + } + else + { + serverInfo = registerTmsObjectOrAddReference(nodeId, prop, object); + childNodeId = serverInfo->getNodeId(); + } + + childProperties.insert({childNodeId, serverInfo}); + } + else + { + const auto propName = prop.getName(); + PropertyObjectPtr obj = object.getPropertyValue(propName); + auto serverInfo = registerTmsObjectOrAddReference(nodeId, obj, propName, prop); + auto childNodeId = serverInfo->getNodeId(); + childObjects.insert({childNodeId, serverInfo}); + } + } +} + +void TmsServerPropertyObject::bindCallbacks() +{ + for (const auto& [id, prop] : childProperties) + { + this->object.getOnPropertyValueWrite(prop->getBrowseName()) += event(this, &TmsServerPropertyObject::triggerEvent); + bindPropertyCallbacks(prop->getBrowseName()); + } + + bindMethodCallbacks(); +} + +bool TmsServerPropertyObject::createOptionalNode(const opcua::OpcUaNodeId& nodeId) +{ + const auto name = server->readBrowseNameString(nodeId); + + if (name == "" || name == "") + return false; + + if (!objProp.assigned() && (name == "IsReadOnly" || name == "IsVisible")) + return false; + + return true; +} + +void TmsServerPropertyObject::bindPropertyCallbacks(const std::string& name) +{ + if (!this->object.getProperty(name).asPtr().getReferencedPropertyUnresolved().assigned()) + { + addReadCallback(name, [this, name]() { + const auto value = this->object.getPropertyValue(name); + return VariantConverter::ToVariant(value, nullptr, daqContext); + }); + + const auto freezable = this->object.asPtrOrNull(); + if (!freezable.assigned() || !this->object.isFrozen()) + { + addWriteCallback(name, [this, name](const OpcUaVariant& variant) { + const auto value = VariantConverter::ToDaqObject(variant, daqContext); + this->object.setPropertyValue(name, value); + return UA_STATUSCODE_GOOD; + }); + } + } + else + { + addReadCallback(name, [this, name]() { + const auto refProp = this->object.getProperty(name).asPtr().getReferencedPropertyUnresolved(); + return VariantConverter::ToVariant(refProp.getEval(), nullptr, daqContext); + }); + } +} + +void TmsServerPropertyObject::setMethodParentNodeId(const OpcUaNodeId& methodParentNodeId) +{ + this->methodParentNodeId = methodParentNodeId; +} + +void TmsServerPropertyObject::registerEvalValueNode(const std::string& nodeName, TmsServerEvalValue::ReadCallback readCallback) +{ + auto nodeId = getChildNodeId(nodeName); + auto serverObject = std::make_shared(server, daqContext); + serverObject->setReadCallback(std::move(readCallback)); + auto childNodeId = serverObject->registerToExistingOpcUaNode(nodeId); + + childEvalValues.insert({childNodeId, serverObject}); +} + +void TmsServerPropertyObject::addMethodPropertyNode(const PropertyPtr& prop) +{ + const auto name = prop.getName(); + OpcUaNodeId parentId = methodParentNodeId.isNull() ? nodeId : methodParentNodeId; + OpcUaNodeId newNodeId(0); + AddMethodNodeParams params(newNodeId, parentId); + params.referenceTypeId = OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT)); + + const auto callableInfo = prop.getCallableInfo(); + const auto returnType = callableInfo.getReturnType(); + + try + { + if (returnType != ctUndefined) + { + auto outputArg = VariantConverter::ToVariant(ArgumentInfo("", returnType)); + CheckStatusCodeException(UA_Array_copy(outputArg->data, 1, (void**) ¶ms.outputArguments, GetUaDataType())); + params.outputArgumentsSize = 1; + } + + const auto args = callableInfo.getArguments(); + if (args.assigned() && args.getCount() > 0) + { + auto inputArg = VariantConverter::ToArrayVariant(args); + CheckStatusCodeException(UA_Array_copy(inputArg->data, args.getCount(), (void**) ¶ms.inputArguments, GetUaDataType())); + params.inputArgumentsSize = args.getCount(); + } + + params.setBrowseName(name); + auto methodNodeId = server->addMethodNode(params); + + methodProps.insert({methodNodeId, {name, prop.getValueType()}}); + } + catch(...) + { + // TODO: Log failure to add method node + } +} + +void TmsServerPropertyObject::bindMethodCallbacks() +{ + for (const auto& [nodeId, props] : methodProps) + { + auto methodName = props.first; + auto coreType = props.second; + + // TODO: Return more specific errors + addEvent(nodeId)->onMethodCall( + [this, methodName, coreType](NodeEventManager::MethodArgs args) -> UA_StatusCode + { + try + { + const BaseObjectPtr method = this->object.getPropertyValue(methodName); + if (args.inputSize > 0) + { + BaseObjectPtr daqArg; + if (args.inputSize > 1) + { + daqArg = List(); + for (size_t i = 0; i < args.inputSize; ++i) + { + auto variant = daq::opcua::OpcUaVariant(args.input[i]); + daqArg.asPtr().pushBack(VariantConverter::ToDaqObject(variant, daqContext)); + } + } + else + { + auto variant = daq::opcua::OpcUaVariant(args.input[0]); + daqArg = VariantConverter::ToDaqObject(variant, daqContext); + } + + if (coreType == ctFunc && args.outputSize > 0) + args.output[0] = VariantConverter::ToVariant(method.asPtr()(daqArg), nullptr, daqContext) + .getDetachedValue(); + else + method.asPtr()(daqArg); + + return UA_STATUSCODE_GOOD; + } + + if (coreType == ctFunc && args.outputSize > 0) + args.output[0] = + VariantConverter::ToVariant(method.asPtr()(), nullptr, daqContext).getDetachedValue(); + else + method.asPtr()(); + + + return UA_STATUSCODE_GOOD; + } + catch(...) + { + return UA_STATUSCODE_BAD; + } + }); + } +} + +void TmsServerPropertyObject::addPropertyNode(const std::string& name, const opcua::OpcUaNodeId& parentId) +{ + auto params = AddVariableNodeParams(UA_NODEID_NULL, parentId); + params.setBrowseName(name); + params.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES); + params.attr->accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; + server->addVariableNode(params); +} + +void TmsServerPropertyObject::configureNodeAttributes(opcua::OpcUaObject& attr) +{ + Super::configureNodeAttributes(attr); + + attr->writeMask |= UA_WRITEMASK_DISPLAYNAME; +} + +void TmsServerPropertyObject::triggerEvent(PropertyObjectPtr& sender, PropertyValueEventArgsPtr& args) +{ + if(!this->server->getUaServer()) + return; + + EventAttributes attributes; + attributes.setTime(UA_DateTime_now()); + attributes.setMessage("Property value changed"); + this->server->triggerEvent(OpcUaNodeId(UA_NS0ID_BASEEVENTTYPE), nodeId, attributes); +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp new file mode 100644 index 0000000..e3443ed --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp @@ -0,0 +1,100 @@ +#include "opcuatms_server/objects/tms_server_signal.h" +#include "opcuatms/converters/variant_converter.h" +#include "open62541/statuscodes.h" +#include "open62541/tmsbsp_nodeids.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace opcua; + +TmsServerSignal::TmsServerSignal(const SignalPtr& object, const OpcUaServerPtr& server, const ContextPtr& context) + : Super(object, server, context) +{ +} + +std::string TmsServerSignal::getBrowseName() +{ + return this->object.getLocalId(); +} + +std::string TmsServerSignal::getDisplayName() +{ + const auto name = object.getName(); + if (name.assigned()) + return name; + + return {}; +} + +OpcUaNodeId TmsServerSignal::getReferenceType() +{ + //TODO UA_TMSBSPID_HASSTATUSSIGNAL + return OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASVALUESIGNAL); +} + +OpcUaNodeId TmsServerSignal::getTmsTypeId() +{ + return OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_SIGNALTYPE); +} + +void TmsServerSignal::bindCallbacks() +{ + auto valueId = getChildNodeId("Value"); + OpcUaObject bd; + bd->nodeId = valueId.copyAndGetDetachedValue(); + bd->resultMask = UA_BROWSERESULTMASK_ALL; + auto result = server->browse(bd); + + for (size_t i = 0; i < result->referencesSize; i++) + { + auto reference = result->references[i]; + std::string browseName = opcua::utils::ToStdString(reference.browseName.name); + if (browseName == "DataDescriptor") + { + OpcUaNodeId descriptorId{reference.nodeId.nodeId}; + addReadCallback(descriptorId, [this]() { + DataDescriptorPtr descriptor = object.getDescriptor(); + if (descriptor != nullptr) + return VariantConverter::ToVariant(descriptor, nullptr, daqContext); + else + return OpcUaVariant(); + }); + } + } + + // TODO: Value, AnalogValue, Status + Super::bindCallbacks(); +} + +bool TmsServerSignal::createOptionalNode(const opcua::OpcUaNodeId& nodeId) +{ + const auto name = server->readBrowseNameString(nodeId); + if (name == "Value") + return true; + + return Super::createOptionalNode(nodeId); +} + +void TmsServerSignal::createNonhierarchicalReferences() +{ + auto domainSignal = object.getDomainSignal(); + if (domainSignal.assigned()) + { + auto domainSignalNodeId = findSignalNodeId(domainSignal); + if (!domainSignalNodeId.isNull()) + { + try + { + addReference(domainSignalNodeId, OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASDOMAINSIGNAL)); + } + catch (const OpcUaException& ex) + { + if (ex.getStatusCode() != UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED) + throw; + } + + } + } +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp new file mode 100644 index 0000000..e702bf1 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp @@ -0,0 +1,48 @@ +#include "opcuatms_server/objects/tms_server_variable.h" +#include "coreobjects/eval_value_ptr.h" +#include "open62541/server.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace daq::opcua; + +template +TmsServerVariable::TmsServerVariable(const CoreType& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context) + : Super(object, server, context) +{ +} + +template +opcua::OpcUaNodeId TmsServerVariable::createNode(const opcua::OpcUaNodeId& parentNodeId) +{ + OpcUaNodeId newNodeId; + + this->typeBrowseName = this->readTypeBrowseName(); + std::string name = this->getBrowseName(); + + auto params = AddVariableNodeParams(UA_NODEID_NULL, parentNodeId); + configureVariableNodeAttributes(params.attr); + params.setBrowseName(name); + params.typeDefinition = this->getTmsTypeId(); + params.nodeContext = this; + params.addOptionalNodeCallback = [this](const OpcUaNodeId& nodeId) { return this->createOptionalNode(nodeId); }; + newNodeId = this->server->addVariableNode(params); + + return OpcUaNodeId(newNodeId); +} + +template +void TmsServerVariable::configureVariableNodeAttributes(opcua::OpcUaObject& attr) +{ + const auto dataTypeId = this->server->readDataType(this->getTmsTypeId()); + + attr->dataType = *dataTypeId; + attr->accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; + attr->writeMask |= UA_WRITEMASK_DISPLAYNAME | UA_WRITEMASK_DESCRIPTION; +} + +template class TmsServerVariable>; +template class TmsServerVariable; +template class TmsServerVariable; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp new file mode 100644 index 0000000..9c5864f --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include + +using namespace daq::opcua; +using namespace daq::opcua::tms; + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +TmsServer::~TmsServer() +{ + stop(); +} + +TmsServer::TmsServer(const InstancePtr& instance) + : TmsServer(instance.getRootDevice(), instance.getContext()) +{ +} + +TmsServer::TmsServer(const DevicePtr& device, const ContextPtr& context) + : device(device) + , context(context) +{ +} + +void TmsServer::setOpcUaPort(uint16_t port) +{ + this->opcUaPort = port; +} + +void TmsServer::setOpendaqVersion(const std::string& version) +{ + this->versionStr = version; +} + +void TmsServer::start() +{ + if (!device.assigned()) + throw InvalidStateException("Device is not set."); + if (!context.assigned()) + throw InvalidStateException("Context is not set."); + + server = std::make_shared(); + server->setPort(opcUaPort); + server->prepare(); + + tmsDevice = std::make_unique(device, server, context); + tmsDevice->registerOpcUaNode(OpcUaNodeId(NAMESPACE_DI, UA_DIID_DEVICESET)); + if (!versionStr.empty()) + { + OpcUaNodeId newNodeId(0); + AddVariableNodeParams params(newNodeId, tmsDevice->getNodeId()); + params.setBrowseName("OpenDaqPackageVersion"); + params.setDataType(OpcUaNodeId(UA_TYPES[UA_TYPES_STRING].typeId)); + params.typeDefinition = OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE)); + const auto nodeId = server->addVariableNode(params); + + server->writeValue(nodeId, OpcUaVariant(versionStr.c_str())); + } + + tmsDevice->createNonhierarchicalReferences(); + + server->start(); +} + +void TmsServer::stop() +{ + if (server) + server->stop(); + + server.reset(); + tmsDevice.reset(); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt new file mode 100644 index 0000000..8bc5883 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt @@ -0,0 +1,33 @@ +set(MODULE_NAME opcuatms_server) +set(TEST_APP test_${MODULE_NAME}) + +set(TEST_SOURCES test_helpers.h + test_tms_device.cpp + test_tms_signal.cpp + test_tms_function_block.cpp + test_tms_channel.cpp + test_tms_input_port.cpp + test_tms_property_object.cpp + test_tms_server.cpp +) + +add_executable(${TEST_APP} testapp.cpp + ${TEST_SOURCES} +) + +set_target_properties(${TEST_APP} PROPERTIES DEBUG_POSTFIX _debug) + +target_link_libraries(${TEST_APP} PRIVATE ${SDK_TARGET_NAMESPACE}::${MODULE_NAME} + daq::opcuatms_test_utils + daq::opcuaclient + daq::opendaq_mocks +) + +add_test(NAME ${TEST_APP} + COMMAND $ + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +) + +if (OPENDAQ_ENABLE_COVERAGE) + setup_target_for_coverage(opcuatmsservercoverage ${TEST_APP} opcuatmsservercoverage) +endif() diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h b/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h new file mode 100644 index 0000000..10e7064 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h @@ -0,0 +1,132 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include "opendaq/mock/mock_device_module.h" +#include "opendaq/mock/mock_fb_module.h" +#include "opendaq/mock/mock_physical_device.h" +#include "open62541/tmsbsp_nodeids.h" + +namespace test_helpers +{ + inline daq::InstancePtr SetupInstance() + { + using namespace daq; + const auto logger = Logger(); + const auto moduleManager = ModuleManager("[[none]]"); + const auto context = Context(nullptr, logger, TypeManager(), moduleManager); + + const ModulePtr deviceModule(MockDeviceModule_Create(context)); + moduleManager.addModule(deviceModule); + + const ModulePtr fbModule(MockFunctionBlockModule_Create(context)); + moduleManager.addModule(fbModule); + + auto instance = InstanceCustom(context, "localInstance"); + instance.addDevice("daq_client_device"); + instance.addDevice("mock_phys_device"); + instance.addFunctionBlock("mock_fb_uid"); + + return instance; + } + + inline daq::opcua::OpcUaNodeId BrowseForChild(const daq::opcua::OpcUaClientPtr& client, + const daq::opcua::OpcUaNodeId& rootNodeId, + const std::string& browseName) + { + using namespace daq::opcua; + std::vector results; + + BrowseRequest request(rootNodeId, OpcUaNodeClass::Object); + OpcUaBrowser browser(request, client); + auto browseResult = browser.browse(); + + for (const UA_ReferenceDescription& reference : browseResult) + { + if (daq::opcua::utils::ToStdString(reference.browseName.name) == browseName) + return OpcUaNodeId(reference.nodeId.nodeId); + } + + return {}; + } + + inline std::vector BrowseForChildWithTypeId(const daq::opcua::OpcUaClientPtr& client, + const daq::opcua::OpcUaNodeId& rootNodeId, + const daq::opcua::OpcUaNodeId& typeNodeId) + { + using namespace daq::opcua; + std::vector results; + + BrowseRequest request(rootNodeId, OpcUaNodeClass::Object); + OpcUaBrowser browser(request, client); + auto browseResult = browser.browse(); + + for (const UA_ReferenceDescription& reference : browseResult) + { + if (OpcUaNodeId(reference.typeDefinition.nodeId) == typeNodeId) + results.push_back(OpcUaNodeId(reference.nodeId.nodeId)); + } + + return results; + } + + inline std::vector BrowseSubDevices(const daq::opcua::OpcUaClientPtr& client, + const daq::opcua::OpcUaNodeId& nodeId) + { + using namespace daq::opcua; + return BrowseForChildWithTypeId(client, nodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQDEVICETYPE)); + } + + inline std::vector BrowseFunctionBlocks(const daq::opcua::OpcUaClientPtr& client, + const daq::opcua::OpcUaNodeId& nodeId) + { + using namespace daq::opcua; + return BrowseForChildWithTypeId(client, nodeId, OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_FUNCTIONBLOCKTYPE)); + } + + inline std::vector BrowseChannels(const daq::opcua::OpcUaClientPtr& client, + const daq::opcua::OpcUaNodeId& nodeId) + { + using namespace daq::opcua; + return BrowseForChildWithTypeId(client, nodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_CHANNELTYPE)); + } + + inline std::vector BrowseSignals(const daq::opcua::OpcUaClientPtr& client, + const daq::opcua::OpcUaNodeId& nodeId) + { + using namespace daq::opcua; + return BrowseForChildWithTypeId(client, nodeId, OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_SIGNALTYPE)); + } + + inline daq::opcua::OpcUaNodeId GetMockPhysicalDevice(const daq::opcua::OpcUaClientPtr& client) + { + using namespace daq::opcua; + auto firstLvlDevices = BrowseSubDevices(client, OpcUaNodeId(NAMESPACE_DI, UA_DIID_DEVICESET)); + auto secondLvlDevices = BrowseSubDevices(client, firstLvlDevices[0]); + for (const auto& dev : secondLvlDevices) + { + if (client->readBrowseName(dev) == "mockdev") + return dev; + } + throw std::runtime_error("Mock device not found"); + } +} diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_channel.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_channel.cpp new file mode 100644 index 0000000..afccc09 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_channel.cpp @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include "coreobjects/property_object_factory.h" +#include "gtest/gtest.h" +#include "opendaq/mock/mock_channel_factory.h" +#include "opcuaclient/opcuaclient.h" +#include "opcuatms_server/objects/tms_server_channel.h" +#include "tms_object_test.h" +#include "open62541/tmsbsp_nodeids.h" + +using namespace daq; +using namespace opcua::tms; +using namespace opcua; +using namespace daq::opcua::utils; + +class TmsChannelTest : public TmsObjectTest +{ +public: + ChannelPtr createChannel() + { + const auto context = NullContext(); + return MockChannel(context, nullptr, "mockch"); + } +}; + +TEST_F(TmsChannelTest, Create) +{ + ChannelPtr channel = createChannel(); + auto tmsChannel = TmsServerChannel(channel, this->getServer(), NullContext()); +} + +TEST_F(TmsChannelTest, Register) +{ + ChannelPtr channel = createChannel(); + auto serverChannel = TmsServerChannel(channel, this->getServer(), NullContext()); + auto nodeId = serverChannel.registerOpcUaNode(); + + ASSERT_TRUE(this->getClient()->nodeExists(nodeId)); +} + +TEST_F(TmsChannelTest, AttrFunctionBlockType) +{ + ChannelPtr channel = createChannel(); + auto serverChannel = TmsServerChannel(channel, this->getServer(), NullContext()); + + auto nodeId = serverChannel.registerOpcUaNode(); + + auto variant = readChildNode(nodeId, "FunctionBlockInfo"); + ASSERT_TRUE(variant.isType()); + + UA_FunctionBlockInfoStructure type = variant.readScalar(); + + ASSERT_EQ(ToStdString(type.id), "mock_ch"); + ASSERT_EQ(ToStdString(type.name), "mock_ch"); + ASSERT_EQ(ToStdString(type.description), ""); +} + +TEST_F(TmsChannelTest, BrowseSignals) +{ + ChannelPtr channel = createChannel(); + auto serverChannel = TmsServerChannel(channel, this->getServer(), NullContext()); + auto nodeId = serverChannel.registerOpcUaNode(); + + OpcUaServerNode serverNodeFB(*this->getServer(), nodeId); + auto signalServerNode = serverNodeFB.getChildNode(UA_QUALIFIEDNAME_ALLOC(NAMESPACE_TMSBSP, "OutputSignals")); + auto signalReferences = signalServerNode->browse(OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASVALUESIGNAL)); + ASSERT_EQ(signalReferences.size(), 10u); +} + +TEST_F(TmsChannelTest, Property) +{ + // Build server channel + auto serverChannel = createChannel(); + + const auto sampleRateProp = + FloatPropertyBuilder("SampleRate", 100.0).setUnit(Unit("Hz")).setMinValue(1.0).setMaxValue(1000000.0).build(); + + serverChannel.addProperty(sampleRateProp); + + auto tmsServerChannel = TmsServerChannel(serverChannel, this->getServer(), NullContext()); + auto nodeId = tmsServerChannel.registerOpcUaNode(); + + auto sampleRateNodeId = this->getChildNodeId(nodeId, "SampleRate"); + ASSERT_FALSE(sampleRateNodeId.isNull()); + + auto srValue = this->getServer()->readValue(sampleRateNodeId); + ASSERT_TRUE(srValue.hasScalarType()); + ASSERT_DOUBLE_EQ(srValue.readScalar(), 100.0); + + serverChannel.setPropertyValue("SampleRate", 14.0); + + srValue = this->getServer()->readValue(sampleRateNodeId); + ASSERT_TRUE(srValue.hasScalarType()); + ASSERT_DOUBLE_EQ(srValue.readScalar(), 14.0); + + this->getServer()->writeValue(sampleRateNodeId, OpcUaVariant(22.2)); + + srValue = this->getServer()->readValue(sampleRateNodeId); + ASSERT_TRUE(srValue.hasScalarType()); + ASSERT_DOUBLE_EQ(srValue.readScalar(), 22.2); +} diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_device.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_device.cpp new file mode 100644 index 0000000..1463246 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_device.cpp @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include +#include +#include +#include "gtest/gtest.h" +#include "opcuaclient/opcuaclient.h" +#include "opcuatms_server/objects/tms_server_device.h" +#include "test_helpers.h" +#include "tms_object_test.h" + +using namespace daq; +using namespace opcua::tms; +using namespace opcua; +using namespace std::chrono_literals; + +using TmsDeviceTest = TmsObjectTest; + +TEST_F(TmsDeviceTest, Create) +{ + DevicePtr device = test_helpers::SetupInstance(); + auto tmsDevice = TmsServerDevice(device, this->getServer(), NullContext()); +} + +TEST_F(TmsDeviceTest, Register) +{ + DevicePtr device = test_helpers::SetupInstance(); + auto tmsDevice = TmsServerDevice(device, this->getServer(), NullContext()); + auto nodeId = tmsDevice.registerOpcUaNode(); + + ASSERT_TRUE(this->getClient()->nodeExists(nodeId)); +} + +TEST_F(TmsDeviceTest, SubDevices) +{ + DevicePtr device = test_helpers::SetupInstance(); + auto tmsDevice = TmsServerDevice(device, this->getServer(), NullContext()); + auto nodeId = tmsDevice.registerOpcUaNode(); + + ASSERT_EQ(test_helpers::BrowseSubDevices(client, nodeId).size(), 2u); +} + +TEST_F(TmsDeviceTest, FunctionBlock) +{ + DevicePtr device = test_helpers::SetupInstance(); + auto tmsDevice = TmsServerDevice(device, this->getServer(), NullContext()); + auto nodeId = tmsDevice.registerOpcUaNode(); + + auto functionBlockNodeId = getChildNodeId(nodeId, "FunctionBlocks"); + ASSERT_EQ(test_helpers::BrowseFunctionBlocks(client, functionBlockNodeId).size(), 1u); +} + +TEST_F(TmsDeviceTest, Property) +{ + DevicePtr device = test_helpers::SetupInstance(); + + const auto sampleRateProp = + FloatPropertyBuilder("SampleRate", 100.0).setUnit(Unit("Hz")).setMinValue(1.0).setMaxValue(1000000.0).build(); + + device.addProperty(sampleRateProp); + + auto tmsDevice = TmsServerDevice(device, this->getServer(), NullContext()); + auto nodeId = tmsDevice.registerOpcUaNode(); + + auto sampleRateNodeId = this->getChildNodeId(nodeId, "SampleRate"); + ASSERT_FALSE(sampleRateNodeId.isNull()); + + auto srValue = this->getServer()->readValue(sampleRateNodeId); + ASSERT_TRUE(srValue.hasScalarType()); + ASSERT_DOUBLE_EQ(srValue.readScalar(), 100.0); + + device.setPropertyValue("SampleRate", 14.0); + + srValue = this->getServer()->readValue(sampleRateNodeId); + ASSERT_TRUE(srValue.hasScalarType()); + ASSERT_DOUBLE_EQ(srValue.readScalar(), 14.0); + + this->getServer()->writeValue(sampleRateNodeId, OpcUaVariant(22.2)); + + srValue = this->getServer()->readValue(sampleRateNodeId); + ASSERT_TRUE(srValue.hasScalarType()); + ASSERT_DOUBLE_EQ(srValue.readScalar(), 22.2); +} + +TEST_F(TmsDeviceTest, Components) +{ + DevicePtr device = test_helpers::SetupInstance(); + auto tmsDevice = TmsServerDevice(device, this->getServer(), NullContext()); + auto nodeId = tmsDevice.registerOpcUaNode(); + + auto devices = test_helpers::BrowseSubDevices(client, nodeId); + auto componentA = getChildNodeId(devices[1], "componentA"); + ASSERT_FALSE(componentA.isNull()); + auto componentA1 = getChildNodeId(componentA, "componentA1"); + ASSERT_FALSE(componentA1.isNull()); + auto componentB = getChildNodeId(devices[1], "componentB"); + ASSERT_FALSE(componentB.isNull()); +} diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp new file mode 100644 index 0000000..730be18 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include "gtest/gtest.h" +#include +#include "opcuaclient/opcuaclient.h" +#include "opcuatms_server/objects/tms_server_function_block.h" +#include "tms_object_test.h" +#include "open62541/tmsbsp_nodeids.h" +#include + +using namespace daq; +using namespace opcua::tms; +using namespace opcua; +using namespace daq::opcua::utils; + +class TmsFunctionBlockTest : public TmsObjectTest +{ +public: + + FunctionBlockPtr createFunctionBlock(const FunctionBlockTypePtr& type = FunctionBlockType("uid", "name", "desc")) + { + const auto context = NullContext(); + + return MockFunctionBlock(type, context, nullptr, "mockfb"); + } +}; + +TEST_F(TmsFunctionBlockTest, Create) +{ + FunctionBlockPtr functionBlock = createFunctionBlock(); + auto tmsFunctionBlock = TmsServerFunctionBlock(functionBlock, this->getServer(), NullContext()); +} + +TEST_F(TmsFunctionBlockTest, Register) +{ + FunctionBlockPtr functionBlock = createFunctionBlock(); + auto serverFunctionBlock = TmsServerFunctionBlock(functionBlock, this->getServer(), NullContext()); + auto nodeId = serverFunctionBlock.registerOpcUaNode(); + + ASSERT_TRUE(this->getClient()->nodeExists(nodeId)); +} + +TEST_F(TmsFunctionBlockTest, AttrFunctionBlockType) +{ + // Build functionBlock info: + const FunctionBlockTypePtr type = FunctionBlockType("ID", "NAME", "DESCRIPTION"); + + // Build server functionBlock + auto serverFunctionBlock = createFunctionBlock(type); + + ASSERT_EQ(serverFunctionBlock.getFunctionBlockType(), type); + + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto nodeId = tmsServerFunctionBlock.registerOpcUaNode(); + + auto variant = readChildNode(nodeId, "FunctionBlockInfo"); + ASSERT_TRUE(variant.isType()); + + UA_FunctionBlockInfoStructure tmsType = variant.readScalar(); + + ASSERT_EQ(ToStdString(tmsType.id), "ID"); + ASSERT_EQ(ToStdString(tmsType.name), "NAME"); + ASSERT_EQ(ToStdString(tmsType.description), "DESCRIPTION"); +} + +TEST_F(TmsFunctionBlockTest, BrowseSignals) +{ + FunctionBlockPtr functionBlock = createFunctionBlock(); + auto serverFunctionBlock = TmsServerFunctionBlock(functionBlock, this->getServer(), NullContext()); + auto nodeId = serverFunctionBlock.registerOpcUaNode(); + + OpcUaServerNode serverNodeFB(*this->getServer(), nodeId); + auto signalServerNode = serverNodeFB.getChildNode(UA_QUALIFIEDNAME_ALLOC(NAMESPACE_TMSBSP, "OutputSignals")); + auto signalReferences = signalServerNode->browse(OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASVALUESIGNAL)); + ASSERT_EQ(signalReferences.size(), 5u); +} + +TEST_F(TmsFunctionBlockTest, Property) +{ + // Build functionBlock info: + const FunctionBlockTypePtr type = FunctionBlockType("uid", "name", "desc"); + + // Build server functionBlock + auto serverFunctionBlock = createFunctionBlock(type); + + const auto sampleRateProp = + FloatPropertyBuilder("SampleRate", 100.0).setUnit(Unit("Hz")).setMinValue(1.0).setMaxValue(1000000.0).build(); + + serverFunctionBlock.addProperty(sampleRateProp); + + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto nodeId = tmsServerFunctionBlock.registerOpcUaNode(); + + auto sampleRateNodeId = this->getChildNodeId(nodeId, "SampleRate"); + ASSERT_FALSE(sampleRateNodeId.isNull()); + + auto srValue = this->getServer()->readValue(sampleRateNodeId); + ASSERT_TRUE(srValue.hasScalarType()); + ASSERT_DOUBLE_EQ(srValue.readScalar(), 100.0); + + serverFunctionBlock.setPropertyValue("SampleRate", 14.0); + + srValue = this->getServer()->readValue(sampleRateNodeId); + ASSERT_TRUE(srValue.hasScalarType()); + ASSERT_DOUBLE_EQ(srValue.readScalar(), 14.0); + + this->getServer()->writeValue(sampleRateNodeId, OpcUaVariant(22.2)); + + srValue = this->getServer()->readValue(sampleRateNodeId); + ASSERT_TRUE(srValue.hasScalarType()); + ASSERT_DOUBLE_EQ(srValue.readScalar(), 22.2); +} + +TEST_F(TmsFunctionBlockTest, NestedFunctionBlocks) +{ + FunctionBlockPtr functionBlock = createFunctionBlock(); + + auto serverFunctionBlock = TmsServerFunctionBlock(functionBlock, this->getServer(), NullContext()); + auto nodeId = serverFunctionBlock.registerOpcUaNode(); + + auto firstFB = functionBlock.getFunctionBlocks()[0]; + auto firstFBNodeId = OpcUaNodeId(nodeId.getNamespaceIndex(), firstFB.getGlobalId().toStdString()); + ASSERT_TRUE(getServer()->nodeExists(firstFBNodeId)); +} diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp new file mode 100644 index 0000000..00a5043 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp @@ -0,0 +1,75 @@ +#include +#include +#include +#include "gtest/gtest.h" +#include "opcuaclient/opcuaclient.h" +#include "opcuatms_server/objects/tms_server_input_port.h" +#include "opcuatms_server/objects/tms_server_signal.h" +#include "tms_object_test.h" +#include +#include +#include +#include +#include +#include + +using namespace daq; +using namespace opcua::tms; +using namespace opcua; + +class TmsInputPortTest : public TmsObjectTest +{ +public: + InputPortPtr createInputPort() + { + auto port = InputPort(NullContext(), nullptr, "port"); + port.getTags().add("port"); + return port; + } +}; + +TEST_F(TmsInputPortTest, Create) +{ + InputPortPtr inputPort = createInputPort(); + auto tmsInputPort = TmsServerInputPort(inputPort, this->getServer(), NullContext()); +} + +TEST_F(TmsInputPortTest, Register) +{ + InputPortPtr inputPort = createInputPort(); + auto serverInputPort = TmsServerInputPort(inputPort, this->getServer(), NullContext()); + auto nodeId = serverInputPort.registerOpcUaNode(); + + ASSERT_TRUE(this->getClient()->nodeExists(nodeId)); +} + +TEST_F(TmsInputPortTest, ConnectedToReference) +{ + const auto logger = Logger(); + const auto scheduler = Scheduler(logger); + const auto context = Context(scheduler, logger, nullptr, nullptr); + + SignalPtr signal = Signal(context, nullptr, "sig"); + + auto serverSignal = TmsServerSignal(signal, this->getServer(), NullContext()); + auto signalNodeId = serverSignal.registerOpcUaNode(); + + InputPortNotificationsPtr inputPortNotification = TestInputPortNotifications(); + + InputPortConfigPtr inputPort = InputPort(context, nullptr, "TestInputPort"); + inputPort.setListener(inputPortNotification); + inputPort.connect(signal); + + auto serverInputPort = TmsServerInputPort(inputPort, this->getServer(), NullContext()); + auto inputPortNodeId = serverInputPort.registerOpcUaNode(); + + ASSERT_NO_THROW(serverInputPort.createNonhierarchicalReferences()); + + ASSERT_TRUE(this->getClient()->nodeExists(signalNodeId)); + ASSERT_TRUE(this->getClient()->nodeExists(inputPortNodeId)); + + OpcUaServerNode inputPortNode(*this->getServer(), inputPortNodeId); + auto connectedToNodes = inputPortNode.browse(OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_CONNECTEDTOSIGNAL)); + ASSERT_EQ(connectedToNodes.size(), 1u); + ASSERT_EQ(connectedToNodes[0]->getNodeId(), signalNodeId); +} diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_property_object.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_property_object.cpp new file mode 100644 index 0000000..71128e3 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_property_object.cpp @@ -0,0 +1,79 @@ +#include "coreobjects/property_object_factory.h" +#include "gtest/gtest.h" +#include "opcuaclient/opcuaclient.h" +#include +#include +#include +#include "coreobjects/property_object_class_ptr.h" +#include "opcuatms_server/objects/tms_server_property_object.h" +#include "tms_object_test.h" +#include +#include +#include "opendaq/context_factory.h" + +using namespace daq; +using namespace opcua::tms; +using namespace opcua; +using namespace std::chrono_literals; + +class TmsPropertyObjectTest : public TmsObjectTest +{ +public: + PropertyObjectPtr createPropertyObject() + { + GenericPropertyObjectPtr object = PropertyObject(); + + auto intProp = IntProperty("IntProp", 1); + object.addProperty(intProp); + + return object; + } +}; + +TEST_F(TmsPropertyObjectTest, Create) +{ + PropertyObjectPtr propertyObject = createPropertyObject(); + auto tmsPropertyObject = TmsServerPropertyObject(propertyObject, this->getServer(), NullContext()); +} + +TEST_F(TmsPropertyObjectTest, Register) +{ + PropertyObjectPtr propertyObject = createPropertyObject(); + + auto tmsPropertyObject = TmsServerPropertyObject(propertyObject, this->getServer(), NullContext()); + auto nodeId = tmsPropertyObject.registerOpcUaNode(); + + ASSERT_TRUE(this->getClient()->nodeExists(nodeId)); +} + +TEST_F(TmsPropertyObjectTest, OnPropertyValueChangeEvent) +{ + PropertyObjectPtr propertyObject = createPropertyObject(); + + auto tmsPropertyObject = TmsServerPropertyObject(propertyObject, this->getServer(), NullContext()); + auto nodeId = tmsPropertyObject.registerOpcUaNode(); + + OpcUaObject request = UA_CreateSubscriptionRequest_default(); + + auto subscription = client->createSubscription(request); + + EventMonitoredItemCreateRequest monitoredItem(nodeId); + EventFilter filter(1); + filter.setSelectClause(0, SimpleAttributeOperand::CreateMessageValue()); + + monitoredItem.setEventFilter(std::move(filter)); + + std::promise waitForChangeEvent; + subscription->monitoredItemsCreateEvent( + UA_TIMESTAMPSTORETURN_BOTH, + *monitoredItem, + [&waitForChangeEvent]( + OpcUaClient* client, Subscription* subContext, MonitoredItem* monContext, size_t nEventFields, UA_Variant* eventFields) { + waitForChangeEvent.set_value(); + }); + + propertyObject.setPropertyValue("IntProp", 1); + + auto future = waitForChangeEvent.get_future(); + ASSERT_NE(future.wait_for(2s), std::future_status::timeout); +} diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_server.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_server.cpp new file mode 100644 index 0000000..aa5a1a1 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_server.cpp @@ -0,0 +1,86 @@ +#include +#include +#include +#include +#include +#include +#include "test_helpers.h" + +using TmsServerTest = testing::Test; + +using namespace daq; +using namespace daq::opcua; +using namespace daq::opcua; +using namespace test_helpers; + + +TEST_F(TmsServerTest, Create) +{ + auto daqInstance = SetupInstance(); + TmsServer server(daqInstance); +} + +TEST_F(TmsServerTest, StartStop) +{ + auto daqInstance = SetupInstance(); + TmsServer server(daqInstance); + server.start(); + server.stop(); +} + +TEST_F(TmsServerTest, Connect) +{ + auto daqInstance = SetupInstance(); + TmsServer server(daqInstance); + server.start(); + + auto client = TmsObjectTest::CreateAndConnectTestClient(); + ASSERT_TRUE(client->isConnected()); +} + +TEST_F(TmsServerTest, DeviceTopology) +{ + auto daqInstance = SetupInstance(); + TmsServer server(daqInstance); + server.start(); + + auto client = TmsObjectTest::CreateAndConnectTestClient(); + + auto firstLvlDevices = BrowseSubDevices(client, OpcUaNodeId(NAMESPACE_DI, UA_DIID_DEVICESET)); + ASSERT_EQ(firstLvlDevices.size(), 1u); + + auto secondLvlDevices = BrowseSubDevices(client, firstLvlDevices[0]); + ASSERT_EQ(secondLvlDevices.size(), 2u); +} + +TEST_F(TmsServerTest, Channels) +{ + auto daqInstance = SetupInstance(); + TmsServer server(daqInstance); + server.start(); + + auto client = TmsObjectTest::CreateAndConnectTestClient(); + auto mockPhysicalDevice = GetMockPhysicalDevice(client); + + auto inputsOutputsFolder = BrowseForChild(client, mockPhysicalDevice, "InputsOutputs"); + ASSERT_FALSE(inputsOutputsFolder.isNull()); + + auto channels = BrowseChannels(client, inputsOutputsFolder); + ASSERT_EQ(channels.size(), 1u); + + auto signalsNode = BrowseForChild(client, channels[0], "OutputSignals"); + ASSERT_FALSE(signalsNode.isNull()); + + auto signals = BrowseSignals(client, signalsNode); + ASSERT_EQ(signals.size(), 10u); + + auto byteStepSignal = BrowseForChild(client, signalsNode, "ByteStep"); + auto timeSignal = BrowseForChild(client, signalsNode, "Time"); + + ReferenceUtils referenceUtils(client); + referenceUtils.updateReferences(byteStepSignal); + + auto references = referenceUtils.getReferencedNodes(byteStepSignal, OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASDOMAINSIGNAL), true); + ASSERT_EQ(references.size(), 1u); + ASSERT_EQ(*references.begin(), timeSignal); +} diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_signal.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_signal.cpp new file mode 100644 index 0000000..944160a --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_signal.cpp @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include +#include "gtest/gtest.h" +#include "opcuaclient/opcuaclient.h" +#include "opcuatms_server/objects/tms_server_input_port.h" +#include "opcuatms_server/objects/tms_server_signal.h" +#include "tms_object_test.h" +#include + +using namespace daq; +using namespace opcua::tms; +using namespace opcua; + +class TmsSignalTest : public TmsObjectTest +{ +public: + SignalPtr createSignal(const ContextPtr& context, const StringPtr& localId = "sig") + { + SignalPtr signal = Signal(context, nullptr, localId); + signal->setActive(false); + return signal; + } +}; + +TEST_F(TmsSignalTest, Create) +{ + SignalPtr signal = Signal(NullContext(), nullptr, "sig"); + auto tmsSignal = TmsServerSignal(signal, this->getServer(), NullContext()); +} + +TEST_F(TmsSignalTest, Register) +{ + SignalPtr signal = Signal(NullContext(), nullptr, "sig"); + auto serverSignal = TmsServerSignal(signal, this->getServer(), NullContext()); + auto nodeId = serverSignal.registerOpcUaNode(); + + ASSERT_TRUE(this->getClient()->nodeExists(nodeId)); +} + +TEST_F(TmsSignalTest, DomainSignalReference) +{ + SignalPtr signal = createSignal(NullContext(), "signal"); + SignalPtr domainSignal = createSignal(NullContext(), "time signal"); + signal.asPtr(true).setDomainSignal(domainSignal); + + auto serverSignal = TmsServerSignal(signal, this->getServer(), NullContext()); + auto signalNodeId = serverSignal.registerOpcUaNode(); + + auto serverDomainSignal = TmsServerSignal(domainSignal, this->getServer(), NullContext()); + auto domainSignalNodeId = serverDomainSignal.registerOpcUaNode(); + + ASSERT_NO_THROW(serverSignal.createNonhierarchicalReferences()); + + ASSERT_TRUE(this->getClient()->nodeExists(signalNodeId)); + ASSERT_TRUE(this->getClient()->nodeExists(domainSignalNodeId)); + + OpcUaServerNode signalNode(*this->getServer(), signalNodeId); + auto hasDomainNodes = signalNode.browse(OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASDOMAINSIGNAL)); + ASSERT_EQ(hasDomainNodes.size(), 1u); + ASSERT_EQ(hasDomainNodes[0]->getNodeId(), domainSignalNodeId); +} diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/testapp.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/testapp.cpp new file mode 100644 index 0000000..242492a --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/tests/testapp.cpp @@ -0,0 +1,23 @@ +#include +#include + +#include +#include +#include +#include + +int main(int argc, char** args) +{ + daq::daqInitializeCoreObjectsTesting(); + daqInitModuleManagerLibrary(); + daqInitOpenDaqLibrary(); + + testing::InitGoogleTest(&argc, args); + + testing::TestEventListeners& listeners = testing::UnitTest::GetInstance()->listeners(); + listeners.Append(new DaqMemCheckListener()); + + auto res = RUN_ALL_TESTS(); + + return res; +} diff --git a/shared/libraries/opcuatms/tests/CMakeLists.txt b/shared/libraries/opcuatms/tests/CMakeLists.txt new file mode 100644 index 0000000..a56ceac --- /dev/null +++ b/shared/libraries/opcuatms/tests/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.2) +set_cmake_folder_context(TARGET_FOLDER_NAME) +project(opcuatms_integration_tests CXX) + +add_subdirectory(test_utils) +add_subdirectory(opcuatms_integration) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt b/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt new file mode 100644 index 0000000..ed24d03 --- /dev/null +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt @@ -0,0 +1,73 @@ +set(MODULE_NAME opcuatms_integration) +set(TEST_APP test_${MODULE_NAME}) + +set(TEST_SOURCES main.cpp + tms_object_integration_test.h + tms_object_integration_test.cpp + test_tms_signal.cpp + test_tms_function_block.cpp + test_tms_channel.cpp + test_tms_input_port.cpp + test_tms_property.cpp + test_tms_property_object.cpp + test_tms_device.cpp + test_tms_integration.cpp + test_property_object_advanced.cpp + test_tms_amplifier.cpp + test_tms_component.cpp + test_tms_folder.cpp + test_tms_function_property.cpp +) + +if (OPENDAQ_ENABLE_WEBSOCKET_STREAMING) + list(APPEND TEST_SOURCES test_streaming_integration.cpp) +endif() + +set(SUPPORTS_ASAN 0) + +if(CXX_COMPILER_ID EQUAL Clang OR CXX_COMPILER_ID EQUAL AppleClang OR CXX_COMPILER_ID EQUAL GNU) + set(SUPPORTS_ASAN 1) + set(ASAN_COMPILE_FLAGS -fsanitize=address -fno-omit-frame-pointer) +endif() + +add_executable(${TEST_APP} ${TEST_SOURCES}) + +set_target_properties(${TEST_APP} PROPERTIES DEBUG_POSTFIX _debug) + +if (WIN32) + set(BCRYPT_LIB bcrypt.dll) +endif() + +set(StreamingLibraries ) + +if (OPENDAQ_ENABLE_WEBSOCKET_STREAMING) + list(APPEND StreamingLibraries PRIVATE daq::opendaq_websocket_streaming) +endif() + +target_link_libraries(${TEST_APP} PRIVATE daq::opcuatms_test_utils + daq::opcuatms_server + $ + daq::opcuatms_client + daq::opendaq_mocks + ${BCRYPT_LIB} + Taskflow::Taskflow + ${StreamingLibraries} +) + +if(SUPPORTS_ASAN) + target_link_libraries(${TEST_APP} PRIVATE asan) + target_compile_options(${TEST_APP} PRIVATE -Wall -Werror ${CGOV_COMPILE_FLAGS} ${ASAN_COMPILE_FLAGS}) +endif() + +add_test(NAME ${TEST_APP} + COMMAND $ + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +) + +if (MSVC) + target_compile_options(${TEST_APP} PRIVATE /wd4324) +endif() + +if (OPENDAQ_ENABLE_COVERAGE) + setup_target_for_coverage(${MODULE_NAME}testcoverage ${TEST_APP} ${MODULE_NAME}testcoverage) +endif() diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/main.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/main.cpp new file mode 100644 index 0000000..d7951f9 --- /dev/null +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/main.cpp @@ -0,0 +1,30 @@ +#include +#include + +#ifdef OPENDAQ_ENABLE_WEBSOCKET_STREAMING +#include +#endif + +#include +#include +#include +#include + +int main(int argc, char** args) +{ + daq::daqInitializeCoreObjectsTesting(); +#ifdef OPENDAQ_ENABLE_WEBSOCKET_STREAMING + daqInitStreamingLibrary(); +#endif + daqInitModuleManagerLibrary(); + daqInitOpenDaqLibrary(); + + testing::InitGoogleTest(&argc, args); + + testing::TestEventListeners& listeners = testing::UnitTest::GetInstance()->listeners(); + listeners.Append(new DaqMemCheckListener()); + + auto res = RUN_ALL_TESTS(); + + return res; +} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp new file mode 100644 index 0000000..9a2e318 --- /dev/null +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp @@ -0,0 +1,751 @@ +#include +#include "coreobjects/property_object_factory.h" +#include "gtest/gtest.h" +#include "opcuaclient/opcuaclient.h" +#include "opcuatms_client/objects/tms_client_property_object_factory.h" +#include "opcuatms_client/objects/tms_client_property_object_impl.h" +#include "opcuatms_server/objects/tms_server_property_object.h" +#include "tms_object_integration_test.h" +#include "coreobjects/argument_info_factory.h" +#include "coreobjects/callable_info_factory.h" +#include "coreobjects/coercer_factory.h" +#include "coreobjects/validator_factory.h" +#include "opendaq/instance_factory.h" +#include "coreobjects/unit_factory.h" +#include "coretypes/struct_factory.h" +#include "coretypes/type_manager_factory.h" +#include + +using namespace daq; +using namespace opcua::tms; +using namespace opcua; +using namespace std::chrono_literals; + +struct RegisteredPropertyObject +{ + TmsServerPropertyObjectPtr serverProp; + PropertyObjectPtr clientProp; +}; + +// TODO: Add complex number type property test cases once implemented + +class TmsPropertyObjectAdvancedTest : public TmsObjectIntegrationTest +{ +public: + TypeManagerPtr manager; + + void SetUp() override + { + TmsObjectIntegrationTest::SetUp(); + + manager = TypeManager(); + + manager.addType(StructType("ListRuleDescriptionStructure", + List("Type", "Elements"), + List(SimpleType(ctString), SimpleType(ctList)))); + + manager.addType(StructType("CustomRuleDescriptionStructure", + List("Type", "Parameters"), + List(SimpleType(ctString), SimpleType(ctDict)))); + + manager.addType(StructType("AdditionalParametersType", + List("Parameters"), + List(SimpleType(ctList)))); + + manager.addType(StructType("KeyValuePair", + List("Key", "Value"), + List(SimpleType(ctString), SimpleType(ctUndefined)))); + + + auto functionProp = FunctionProperty( + "function", FunctionInfo(ctString, List(ArgumentInfo("int", ctInt), ArgumentInfo("float", ctFloat)))); + FunctionPtr funcCallback = Function( + [](ListPtr args) + { + int intVal = args[0]; + double floatVal = args[1]; + + if (floatVal > intVal) + return String("Float is greater."); + + return String("Int is greater or equal."); + }); + + auto procProp = + FunctionProperty("procedure", + ProcedureInfo(List( + ArgumentInfo("ratio", ctRatio), + ArgumentInfo("string", ctString), + ArgumentInfo("bool", ctBool)))); + ProcedurePtr procCallback = Procedure( + [&](ListPtr args) + { + testRatio = args[0]; + testString = args[1]; + testBool = args[2]; + }); + + const auto obj = PropertyObject(); + obj.addProperty(IntProperty("ObjNumber", 0)); + obj.addProperty(functionProp); + obj.setPropertyValue("function", funcCallback); + obj.addProperty(procProp); + obj.setPropertyValue("procedure", procCallback); + + auto obj1 = PropertyObject(); + obj1.addProperty(StringProperty("foo", "bar")); + + auto objClass = PropertyObjectClassBuilder("TestClass") + .addProperty(IntPropertyBuilder("Integer", 1) + .setDescription("MyInteger") + .setMaxValue(10) + .setMinValue(0) + .setSuggestedValues(List(1, 3, 5, 7, 10)) + .setUnit(EvalValue("Unit(%IntegerUnit:SelectedValue)")) + .build()) + .addProperty(FloatPropertyBuilder("Float", EvalValue("$Integer - 0.123")) + .setDescription("MyFloat") + .setMaxValue(EvalValue("$Integer + 1")) + .setMinValue(0) + .setSuggestedValues(EvalValue("[1.0, 3.0, 5.0, 7.0, 10.0] * if($Integer < 5, 1.0, 0.5)")) + .build()) + .addProperty(ListProperty("IntList", List(1, 2, 3, 4, 5))) + .addProperty(ListProperty("StringList", List("foo", "bar"))) + .addProperty(BoolPropertyBuilder("BoolReadOnly", False).setReadOnly(True).build()) + .addProperty(DictProperty("IntFloatDict", Dict({{0, 1.123}, {2, 2.345}, {4, 3.456}}))) + .addProperty(SelectionProperty("IntegerUnit", List("s", "ms"), 0, false)) + .addProperty(SelectionProperty("Range", EvalValue("[50.0, 10.0, 1.0, 0.1] * if($Integer < 5, 1.0, 1.123)"), 0)) + .addProperty(SparseSelectionProperty( + "StringSparseSelection", Dict({{0, "foo"}, {10, "bar"}}), 10, EvalValue("$Integer < 5"))) + .addProperty(ReferenceProperty("IntOrFloat", EvalValue("if($Float < 1, %Integer, %Float)"))) + .addProperty(ObjectProperty("Object", obj)) + .addProperty(StringPropertyBuilder("String", "foo").setReadOnly(EvalValue("$Float < 1.0")).build()) + .addProperty(ReferenceProperty("ObjectOrString", EvalValue("if($Integer < 5, %Object, %String)"))) + .addProperty(IntPropertyBuilder("ValidatedInt", 5).setValidator(Validator("Value < 10")).build()) + .addProperty(IntPropertyBuilder("CoercedInt", 10).setCoercer(Coercer("if(Value > 10, 10, Value)")).build()) + .addProperty(RatioProperty("Ratio", Ratio(1, 1000))) + .addProperty(ObjectPropertyBuilder("ObjectWithMetadata", obj1).setReadOnly(true).setVisible(false).build()) + .addProperty(StructProperty("UnitStruct", Unit("s", -1, "second", "time"))) + .addProperty(StructProperty("ArgumentStruct", ArgumentInfo("Arg", ctInt))) + .addProperty(StructProperty("DeviceDomainStructure", + Struct("DeviceDomainStructure", + Dict({{"Resolution", Ratio(10, 20)}, + {"TicksSinceOrigin", 1000}, + {"Origin", "origin"}, + {"Unit", + Unit("symbol", -1, "name", "quantity")}}), + manager))) + .addProperty(StructProperty("ListRuleDescriptionStructure", + Struct("ListRuleDescriptionStructure", + Dict( + {{"Type", "list"}, {"Elements", List("foo", "bar")}}), + manager))) + .addProperty(StructProperty("CustomRuleDescriptionStructure", + Struct("CustomRuleDescriptionStructure", + Dict( + {{"Type", "list"}, + {"Parameters", + Dict({{"foo", "bar"}, {"foo1", "bar1"}})}}), + manager))) + .addProperty(StructProperty("AdditionalParametersType", + Struct("AdditionalParametersType", + Dict({{"Parameters", List( + Struct("KeyValuePair", + Dict( + {{"Key", "key1"}, + {"Value", "value1"}}), + manager), + Struct("KeyValuePair", + Dict( + {{"Key", "key1"}, + {"Value", "value1"}}), + manager))}}), + manager))) + .build(); + + manager.addType(objClass); + } + + void TearDown() override + { + TmsObjectIntegrationTest::TearDown(); + } + + RegisteredPropertyObject registerPropertyObject(const PropertyObjectPtr& prop) + { + const auto logger = Logger(); + const auto serverProp = + std::make_shared(prop, server, Context(nullptr, logger, manager, nullptr)); + const auto nodeId = serverProp->registerOpcUaNode(); + const auto clientProp = TmsClientPropertyObject(Context(nullptr, logger, manager,nullptr), clientContext, nodeId); + return {serverProp, clientProp}; + } + + RatioPtr testRatio; + StringPtr testString; + BoolPtr testBool; +}; + +TEST_F(TmsPropertyObjectAdvancedTest, SetUpServer) +{ + const auto obj = PropertyObject(manager, "TestClass"); + + const auto serverProp = std::make_shared(obj, server, NullContext()); + const auto nodeId = serverProp->registerOpcUaNode(); +} + +TEST_F(TmsPropertyObjectAdvancedTest, SetUp) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); +} + +TEST_F(TmsPropertyObjectAdvancedTest, PropertyCount) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + ASSERT_EQ(obj.getAllProperties().getCount(), clientObj.getAllProperties().getCount()); + ASSERT_EQ(obj.getVisibleProperties().getCount(), clientObj.getVisibleProperties().getCount()); +} + +TEST_F(TmsPropertyObjectAdvancedTest, MinMax) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + const auto serverIntProp = obj.getProperty("Integer"); + const auto clientIntProp = clientObj.getProperty("Integer"); + + const auto serverFloatProp = obj.getProperty("Float"); + const auto clientFloatProp = clientObj.getProperty("Float"); + + ASSERT_EQ(serverIntProp.getMinValue(), clientIntProp.getMinValue()); + ASSERT_EQ(serverIntProp.getMaxValue(), clientIntProp.getMaxValue()); + + ASSERT_EQ(serverFloatProp.getMinValue(), clientFloatProp.getMinValue()); + ASSERT_EQ(serverFloatProp.getMaxValue(), clientFloatProp.getMaxValue()); + + obj.setPropertyValue("Integer", 8); + ASSERT_EQ(serverFloatProp.getMaxValue(), 9); + ASSERT_EQ(clientFloatProp.getMaxValue(), 9); +} + +TEST_F(TmsPropertyObjectAdvancedTest, SuggestedValues) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + const auto serverIntProp = obj.getProperty("Integer"); + const auto clientIntProp = clientObj.getProperty("Integer"); + + const auto serverFloatProp = obj.getProperty("Float"); + const auto clientFloatProp = clientObj.getProperty("Float"); + + ASSERT_EQ(serverIntProp.getSuggestedValues(), clientIntProp.getSuggestedValues()); + + ListPtr serverFloatSuggestedValues = serverFloatProp.getSuggestedValues(); + ListPtr clientFloatSuggestedValues = clientFloatProp.getSuggestedValues(); + + ASSERT_EQ(serverFloatSuggestedValues, clientFloatSuggestedValues); + + obj.setPropertyValue("Integer", 8); + + serverFloatSuggestedValues = serverFloatProp.getSuggestedValues(); + clientFloatSuggestedValues = clientFloatProp.getSuggestedValues(); + + ASSERT_EQ(serverFloatSuggestedValues, clientFloatSuggestedValues); +} + +TEST_F(TmsPropertyObjectAdvancedTest, Unit) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + const auto serverIntProp = obj.getProperty("Integer"); + const auto clientIntProp = clientObj.getProperty("Integer"); + + UnitPtr serverUnit = serverIntProp.getUnit(); + UnitPtr clientUnit = clientIntProp.getUnit(); + + ASSERT_EQ(serverUnit, clientUnit); + + obj.setPropertyValue("IntegerUnit", 1); + + serverUnit = serverIntProp.getUnit(); + clientUnit = clientIntProp.getUnit(); + + ASSERT_EQ(serverUnit, clientUnit); +} + +TEST_F(TmsPropertyObjectAdvancedTest, Description) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + const auto serverIntProp = obj.getProperty("Integer"); + const auto clientIntProp = clientObj.getProperty("Integer"); + + const StringPtr serverDesc = serverIntProp.getDescription(); + const StringPtr clientDesc = clientIntProp.getDescription(); + + ASSERT_EQ(serverDesc, clientDesc); +} + +TEST_F(TmsPropertyObjectAdvancedTest, Visible) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + //const auto serverIntUnitProp = obj.getProperty("IntegerUnit"); + //const auto clientIntUnitProp = clientObj.getProperty("IntegerUnit"); + + const auto serverSparseSelectionProp = obj.getProperty("StringSparseSelection"); + const auto clientSparseSelectionProp = clientObj.getProperty("StringSparseSelection"); + + //ASSERT_EQ(serverIntUnitProp.getVisible(), clientIntUnitProp.getVisible()); + ASSERT_EQ(serverSparseSelectionProp.getVisible(), clientSparseSelectionProp.getVisible()); + + obj.setPropertyValue("Integer", 9); + + ASSERT_EQ(serverSparseSelectionProp.getVisible(), false); + ASSERT_EQ(clientSparseSelectionProp.getVisible(), false); +} + +TEST_F(TmsPropertyObjectAdvancedTest, ReadOnly) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + const auto serverStringProp = obj.getProperty("String"); + const auto clientStringProp = clientObj.getProperty("String"); + + ASSERT_EQ(serverStringProp.getReadOnly(), clientStringProp.getReadOnly()); + + obj.setPropertyValue("Float", 3.0); + ASSERT_EQ(serverStringProp.getReadOnly(), false); + ASSERT_EQ(serverStringProp.getReadOnly(), false); +} + +TEST_F(TmsPropertyObjectAdvancedTest, ReadOnlyPropValue) +{ + const auto obj = PropertyObject(manager, "TestClass"); + obj.asPtr().setProtectedPropertyValue("BoolReadOnly", True); + + auto [serverObj, clientObj] = registerPropertyObject(obj); + + const bool value = clientObj.getPropertyValue("BoolReadOnly"); + ASSERT_TRUE(value); +} + +TEST_F(TmsPropertyObjectAdvancedTest, DefaultValues) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + for (auto serverProp : obj.getAllProperties()) + { + auto name = serverProp.getName(); + auto clientProp = clientObj.getProperty(name); + + if (serverProp.getValueType() != ctObject && serverProp.getValueType() != ctUndefined) + ASSERT_EQ(serverProp.getDefaultValue(), clientProp.getDefaultValue()); + } + + obj.setPropertyValue("Integer", 5); + ASSERT_DOUBLE_EQ(obj.getProperty("Float").getDefaultValue(), 4.877); + ASSERT_DOUBLE_EQ(clientObj.getProperty("Float").getDefaultValue(), 4.877); +} + +TEST_F(TmsPropertyObjectAdvancedTest, IntFloatGetSet) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + ASSERT_EQ(obj.getPropertyValue("Integer"), clientObj.getPropertyValue("Integer")); + ASSERT_DOUBLE_EQ(obj.getPropertyValue("Float"), clientObj.getPropertyValue("Float")); + + ASSERT_NO_THROW(clientObj.setPropertyValue("Integer", 5)); + ASSERT_NO_THROW(clientObj.setPropertyValue("Integer", -1)); + ASSERT_NO_THROW(clientObj.setPropertyValue("Integer", 11)); + + ASSERT_NO_THROW(clientObj.setPropertyValue("Float", 2.5)); + ASSERT_NO_THROW(clientObj.setPropertyValue("Float", 8.8)); + ASSERT_NO_THROW(clientObj.setPropertyValue("Float", -1.2)); + + ASSERT_EQ(obj.getPropertyValue("Integer"), clientObj.getPropertyValue("Integer")); + ASSERT_EQ(10, clientObj.getPropertyValue("Integer")); + ASSERT_DOUBLE_EQ(obj.getPropertyValue("Float"), clientObj.getPropertyValue("Float")); + ASSERT_DOUBLE_EQ(0, clientObj.getPropertyValue("Float")); +} + +TEST_F(TmsPropertyObjectAdvancedTest, StringGetSet) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + ASSERT_EQ(obj.getPropertyValue("String"), clientObj.getPropertyValue("String")); + + ASSERT_NO_THROW(clientObj.setPropertyValue("Float", 5.123)); + ASSERT_NO_THROW(clientObj.setPropertyValue("String", "bar")); + + ASSERT_EQ(obj.getPropertyValue("String"), "bar"); + ASSERT_EQ(clientObj.getPropertyValue("String"), "bar"); +} + +TEST_F(TmsPropertyObjectAdvancedTest, IntListGetSet) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + ListPtr serverListObj = obj.getPropertyValue("IntList"); + ListPtr clientListObj = clientObj.getPropertyValue("IntList"); + + for (SizeT i = 0; i < serverListObj.getCount(); ++i) + ASSERT_EQ(serverListObj[i], clientListObj[i]); + + clientObj.setPropertyValue("IntList", List(3, 4, 5, 6, 7)); + + serverListObj = obj.getPropertyValue("IntList"); + clientListObj = clientObj.getPropertyValue("IntList"); + + for (SizeT i = 0; i < serverListObj.getCount(); ++i) + ASSERT_EQ(serverListObj[i], clientListObj[i]); + +} + +TEST_F(TmsPropertyObjectAdvancedTest, RatioGetSet) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + ASSERT_EQ(obj.getPropertyValue("Ratio"), clientObj.getPropertyValue("Ratio")); + + ASSERT_NO_THROW(clientObj.setPropertyValue("Ratio", Ratio(1, 2000))); + + ASSERT_EQ(obj.getPropertyValue("Ratio"), Ratio(1, 2000)); + ASSERT_EQ(clientObj.getPropertyValue("Ratio"), Ratio(1, 2000)); +} + +TEST_F(TmsPropertyObjectAdvancedTest, StringListGetSet) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + ListPtr serverListObj = obj.getPropertyValue("StringList"); + ListPtr clientListObj = clientObj.getPropertyValue("StringList"); + + ASSERT_EQ(serverListObj[0], clientListObj[0]); + ASSERT_EQ(serverListObj[1], clientListObj[1]); + + const auto list = List("bar", "foo"); + clientObj.setPropertyValue("StringList", list); + + serverListObj = obj.getPropertyValue("StringList"); + clientListObj = clientObj.getPropertyValue("StringList"); + + ASSERT_EQ(serverListObj[0], clientListObj[0]); + ASSERT_EQ(serverListObj[1], clientListObj[1]); +} + +TEST_F(TmsPropertyObjectAdvancedTest, IntFloatDictGetSet) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + DictPtr serverDict = obj.getPropertyValue("IntFloatDict"); + DictPtr clientDict = clientObj.getPropertyValue("IntFloatDict"); + + for (auto key : serverDict.getKeyList()) + ASSERT_EQ(serverDict.get(key), clientDict.get(key)); + + auto dict = Dict(); + dict.set(10, 5.678); + clientObj.setPropertyValue("IntFloatDict", dict); + + serverDict = obj.getPropertyValue("IntFloatDict"); + clientDict = clientObj.getPropertyValue("IntFloatDict"); + + for (auto key : serverDict.getKeyList()) + ASSERT_EQ(serverDict.get(key), clientDict.get(key)); +} + + +TEST_F(TmsPropertyObjectAdvancedTest, ObjectGetSet) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto nonClassObj = PropertyObject(); + nonClassObj.addProperty(IntProperty("test", 0)); + obj.addProperty(ObjectProperty("NonClassObj", nonClassObj)); + + auto [serverObj, clientObj] = registerPropertyObject(obj); + + PropertyObjectPtr serverChildObj = obj.getPropertyValue("Object"); + PropertyObjectPtr clientChildObj = clientObj.getPropertyValue("Object"); + ASSERT_EQ(serverChildObj.getPropertyValue("ObjNumber"), clientChildObj.getPropertyValue("ObjNumber")); + + auto testObj = PropertyObject(); + testObj.addProperty(IntProperty("test", 0)); + + ASSERT_ANY_THROW(clientObj.setPropertyValue("Object", testObj)); + ASSERT_ANY_THROW(clientChildObj.setPropertyValue("ObjNumber", 1)); + + PropertyObjectPtr serverNonClassObj = obj.getPropertyValue("NonClassObj"); + PropertyObjectPtr clientNonClassObj = clientObj.getPropertyValue("NonClassObj"); + ASSERT_EQ(serverNonClassObj.getPropertyValue("test"), clientNonClassObj.getPropertyValue("test")); + + clientNonClassObj.setPropertyValue("test", 1); + ASSERT_EQ(serverNonClassObj.getPropertyValue("test"), clientNonClassObj.getPropertyValue("test")); + + serverNonClassObj.setPropertyValue("test", 2); + ASSERT_EQ(serverNonClassObj.getPropertyValue("test"), clientNonClassObj.getPropertyValue("test")); +} + +TEST_F(TmsPropertyObjectAdvancedTest, ReferencedGetSet) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + auto serverReferenceProp = obj.getProperty("IntOrFloat"); + auto clientReferenceProp = clientObj.getProperty("IntOrFloat"); + + auto defValue1 = serverReferenceProp.getDefaultValue(); + auto defValue2 = clientReferenceProp.getDefaultValue(); + ASSERT_EQ(serverReferenceProp.getDefaultValue(), clientReferenceProp.getDefaultValue()); + + ASSERT_EQ(obj.getPropertyValue("IntOrFloat"), 1); + ASSERT_EQ(clientObj.getPropertyValue("IntOrFloat"), 1); + + clientObj.setPropertyValue("Integer", 5); + clientObj.setPropertyValue("Float", 1.123); + + ASSERT_DOUBLE_EQ(serverReferenceProp.getDefaultValue(), 4.877); + ASSERT_DOUBLE_EQ(clientReferenceProp.getDefaultValue(), 4.877); + + clientObj.setPropertyValue("IntOrFloat", 2.345); + ASSERT_DOUBLE_EQ(obj.getPropertyValue("Float"), 2.345); + ASSERT_DOUBLE_EQ(clientObj.getPropertyValue("Float"), 2.345); + + ASSERT_EQ(obj.getPropertyValue("IntOrFloat"), 2.345); + ASSERT_EQ(clientObj.getPropertyValue("IntOrFloat"), 2.345); +} + +TEST_F(TmsPropertyObjectAdvancedTest, ReferencedGetSetObj) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + auto serverReferenceProp = obj.getProperty("ObjectOrString"); + auto clientReferenceProp = clientObj.getProperty("ObjectOrString"); + + PropertyObjectPtr serverDefaultValue = serverReferenceProp.getDefaultValue(); + PropertyObjectPtr clientDefaultValue = clientReferenceProp.getDefaultValue(); + + ASSERT_EQ(serverDefaultValue.getPropertyValue("ObjNumber"), clientDefaultValue.getPropertyValue("ObjNumber")); + + clientObj.setPropertyValue("Integer", 7); + + ASSERT_EQ(serverReferenceProp.getDefaultValue(), clientReferenceProp.getDefaultValue()); + + clientObj.setPropertyValue("ObjectOrString", "foobar"); + ASSERT_EQ(clientObj.getPropertyValue("String"), "foobar"); + ASSERT_EQ(obj.getPropertyValue("String"), "foobar"); +} + +TEST_F(TmsPropertyObjectAdvancedTest, SelectionListGetSet) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + auto serverIntegerUnitProp = obj.getProperty("IntegerUnit"); + auto clientIntegerUnitProp = clientObj.getProperty("IntegerUnit"); + + auto serverRangeProp = obj.getProperty("Range"); + auto clientRangeProp = clientObj.getProperty("Range"); + + ListPtr serverRangeSelectionValues = serverRangeProp.getSelectionValues(); + ListPtr clientRangeSelectionValues = clientRangeProp.getSelectionValues(); + + for (SizeT i = 0; i < serverRangeSelectionValues.getCount(); ++i) + ASSERT_DOUBLE_EQ(serverRangeSelectionValues[i], clientRangeSelectionValues[i]); + + ListPtr serverIntegerUnitSelectionValues = serverIntegerUnitProp.getSelectionValues(); + ListPtr clientIntegerUnitSelectionValues = clientIntegerUnitProp.getSelectionValues(); + + for (SizeT i = 0; i < serverIntegerUnitSelectionValues.getCount(); ++i) + ASSERT_EQ(serverIntegerUnitSelectionValues[i], clientIntegerUnitSelectionValues[i]); + + ASSERT_DOUBLE_EQ(clientObj.getPropertySelectionValue("Range"), obj.getPropertySelectionValue("Range")); + clientObj.setPropertyValue("Range", 1); + ASSERT_DOUBLE_EQ(clientObj.getPropertySelectionValue("Range"), obj.getPropertySelectionValue("Range")); + + ASSERT_EQ(clientObj.getPropertySelectionValue("IntegerUnit"), obj.getPropertySelectionValue("IntegerUnit")); + clientObj.setPropertyValue("IntegerUnit", 1); + ASSERT_EQ(clientObj.getPropertySelectionValue("IntegerUnit"), obj.getPropertySelectionValue("IntegerUnit")); +} + +TEST_F(TmsPropertyObjectAdvancedTest, SelectionDictGetSet) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + auto serverStringSparseSelectionProp = obj.getProperty("StringSparseSelection"); + auto clientStringSparseSelectionProp = clientObj.getProperty("StringSparseSelection"); + + ASSERT_EQ(serverStringSparseSelectionProp.getSelectionValues(), clientStringSparseSelectionProp.getSelectionValues()); +} + +TEST_F(TmsPropertyObjectAdvancedTest, ValidationCoercion) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + ASSERT_EQ(obj.getPropertyValue("ValidatedInt"), clientObj.getPropertyValue("ValidatedInt")); + ASSERT_EQ(obj.getPropertyValue("CoercedInt"), clientObj.getPropertyValue("CoercedInt")); + + ASSERT_ANY_THROW(clientObj.setPropertyValue("ValidatedInt", 11)); + ASSERT_EQ(obj.getPropertyValue("ValidatedInt"), 5); + ASSERT_EQ(clientObj.getPropertyValue("ValidatedInt"), 5); + + ASSERT_NO_THROW(clientObj.setPropertyValue("CoercedInt", 15)); + ASSERT_EQ(obj.getPropertyValue("CoercedInt"), 10); + ASSERT_EQ(clientObj.getPropertyValue("CoercedInt"), 10); +} + +TEST_F(TmsPropertyObjectAdvancedTest, NestedObjTest) +{ + const auto obj = PropertyObject(manager, "TestClass"); + + auto obj1 = PropertyObject(); + auto obj2 = PropertyObject(); + obj2.addProperty(IntProperty("foo", 10)); + obj1.addProperty(ObjectProperty("child", obj2)); + obj.addProperty(ObjectProperty("child", obj1)); + + auto [serverObj, clientObj] = registerPropertyObject(obj); + + ASSERT_EQ(clientObj.getPropertyValue("child.child.foo"), 10); +} + +TEST_F(TmsPropertyObjectAdvancedTest, ObjectPropWithMetadata) +{ + const auto obj = PropertyObject(manager, "TestClass"); + + const auto propObj = PropertyObject(); + propObj.addProperty(StringProperty("foo", "bar")); + const auto newObjProp = ObjectPropertyBuilder("LocalObjectWithMetadata", propObj).setReadOnly(true).setVisible(false).build(); + obj.addProperty(newObjProp); + + auto [serverObj, clientObj] = registerPropertyObject(obj); + + PropertyObjectPtr clientObjWithMetadata = clientObj.getPropertyValue("ObjectWithMetadata"); + ASSERT_ANY_THROW(clientObjWithMetadata.setPropertyValue("foo", "notbar")); + + PropertyObjectPtr clientLocalObjWithMetadata = clientObj.getPropertyValue("LocalObjectWithMetadata"); + ASSERT_ANY_THROW(clientLocalObjWithMetadata.setPropertyValue("foo", "notbar")); + + PropertyPtr clientObjectWithMetadataProp = clientObj.getProperty("ObjectWithMetadata"); + PropertyPtr serverObjectWithMetadataProp = obj.getProperty("ObjectWithMetadata"); + ASSERT_EQ(clientObjectWithMetadataProp.getVisible(), serverObjectWithMetadataProp.getVisible()); + ASSERT_EQ(clientObjectWithMetadataProp.getReadOnly(), serverObjectWithMetadataProp.getReadOnly()); + + PropertyPtr clientLocalObjectWithMetadataProp = clientObj.getProperty("LocalObjectWithMetadata"); + PropertyPtr serverLocalObjectWithMetadataProp = obj.getProperty("LocalObjectWithMetadata"); + ASSERT_EQ(clientLocalObjectWithMetadataProp.getVisible(), serverLocalObjectWithMetadataProp.getVisible()); + ASSERT_EQ(clientLocalObjectWithMetadataProp.getReadOnly(), serverLocalObjectWithMetadataProp.getReadOnly()); +} + +TEST_F(TmsPropertyObjectAdvancedTest, FunctionCall) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + PropertyObjectPtr serverChildObj = obj.getPropertyValue("Object"); + PropertyObjectPtr clientChildObj = clientObj.getPropertyValue("Object"); + + ListPtr inputArgs = List(1, 1.123); + + FunctionPtr serverFunc = serverChildObj.getPropertyValue("function"); + FunctionPtr clientFunc = clientChildObj.getPropertyValue("function"); + + ASSERT_EQ(serverFunc(inputArgs), clientFunc(inputArgs)); + + inputArgs = List(-5, -7.23); + ASSERT_EQ(serverFunc(inputArgs), clientFunc(inputArgs)); +} + +TEST_F(TmsPropertyObjectAdvancedTest, ProcedureCall) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + PropertyObjectPtr clientChildObj = clientObj.getPropertyValue("Object"); + + ListPtr inputArgs = List(Ratio(1, 2), "foo", true); + + ProcedurePtr clientFunc = clientChildObj.getPropertyValue("procedure"); + ASSERT_NO_THROW(clientFunc(inputArgs)); + + ASSERT_EQ(testRatio, Ratio(1, 2)); + ASSERT_EQ(testString, "foo"); + ASSERT_EQ(testBool, true); + + testRatio = nullptr; + testString = nullptr; + testBool = nullptr; +} + +TEST_F(TmsPropertyObjectAdvancedTest, StructureGet) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + ASSERT_EQ(clientObj.getPropertyValue("UnitStruct"), obj.getPropertyValue("UnitStruct")); + ASSERT_EQ(clientObj.getPropertyValue("ArgumentStruct"), obj.getPropertyValue("ArgumentStruct")); + ASSERT_EQ(clientObj.getPropertyValue("DeviceDomainStructure"), obj.getPropertyValue("DeviceDomainStructure")); + ASSERT_EQ(clientObj.getPropertyValue("ListRuleDescriptionStructure"), obj.getPropertyValue("ListRuleDescriptionStructure")); + ASSERT_EQ(clientObj.getPropertyValue("CustomRuleDescriptionStructure"), obj.getPropertyValue("CustomRuleDescriptionStructure")); + ASSERT_EQ(clientObj.getPropertyValue("AdditionalParametersType"), obj.getPropertyValue("AdditionalParametersType")); +} + +TEST_F(TmsPropertyObjectAdvancedTest, StructureSet) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + clientObj.setPropertyValue("UnitStruct", Unit("V", 5, "volt", "voltage")); + clientObj.setPropertyValue("ArgumentStruct", ArgumentInfo("test", ctFloat)); + clientObj.setPropertyValue("DeviceDomainStructure", + Struct("DeviceDomainStructure", + Dict({{"Resolution", Ratio(20, 30)}, + {"TicksSinceOrigin", 5000}, + {"Origin", "origin1"}, + {"Unit", Unit("symbol1", 2, "name1", "quantity1")}}), + manager)); + clientObj.setPropertyValue("ListRuleDescriptionStructure", + Struct("ListRuleDescriptionStructure", + Dict({{"Type", "list"}, {"Elements", List("foo1", "bar1")}}), + manager)); + clientObj.setPropertyValue("CustomRuleDescriptionStructure", + Struct("CustomRuleDescriptionStructure", + Dict({{"Type", "list"}, + {"Parameters", + Dict({{"foo", "bar"}, {"foo1", "bar1"}})}}), + manager)); + + const auto keyValuePairList = List( + Struct("KeyValuePair", Dict({{"Key", "key2"}, {"Value", "value2"}}), manager), + Struct("KeyValuePair", Dict({{"Key", "key2"}, {"Value", "value2"}}), manager)); + + clientObj.setPropertyValue("AdditionalParametersType", + Struct("AdditionalParametersType", + Dict({{"Parameters", keyValuePairList}}), + manager)); + + ASSERT_EQ(clientObj.getPropertyValue("UnitStruct"), obj.getPropertyValue("UnitStruct")); + ASSERT_EQ(clientObj.getPropertyValue("ArgumentStruct"), obj.getPropertyValue("ArgumentStruct")); + ASSERT_EQ(clientObj.getPropertyValue("DeviceDomainStructure"), obj.getPropertyValue("DeviceDomainStructure")); + ASSERT_EQ(clientObj.getPropertyValue("ListRuleDescriptionStructure"), obj.getPropertyValue("ListRuleDescriptionStructure")); + ASSERT_EQ(clientObj.getPropertyValue("CustomRuleDescriptionStructure"), obj.getPropertyValue("CustomRuleDescriptionStructure")); + ASSERT_EQ(clientObj.getPropertyValue("AdditionalParametersType"), obj.getPropertyValue("AdditionalParametersType")); +} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp new file mode 100644 index 0000000..843607c --- /dev/null +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp @@ -0,0 +1,392 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "websocket_streaming/websocket_streaming_server.h" +#include "stream/WebsocketClientStream.hpp" +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace daq; +using namespace daq::opcua; +using namespace std::chrono_literals; +using namespace daq::stream; +using namespace daq::websocket_streaming; +using namespace daq::streaming_protocol; + +class StreamingIntegrationTest : public testing::Test +{ +public: + const uint16_t STREAMING_PORT = 7414; + const std::string OPCUA_URL = "opc.tcp://127.0.0.1/"; + const std::string STREAMING_URL = "daq.wss://127.0.0.1/"; + + using ReadCallback = std::function& readPackets)>; + + void SetUp() override + { + logger = Logger(); + auto clientLogger = Logger(); + clientContext = Context(Scheduler(clientLogger, 1), clientLogger, nullptr, nullptr); + instance = createDevice(); + + createStreamingCallback = Function([this](const StreamingInfoPtr& /*streamingConfig*/, + bool /*isRootDevice*/) + { + return createStreaming(); + }); + } + + void TearDown() override + { + std::this_thread::sleep_for(10ms); + } + + InstancePtr getInstance() + { + return instance; + } + + void generatePackets(size_t packetCount) + { + auto devices = instance.getDevices(); + + for (const auto& device : devices) + { + auto name = device.getInfo().getName(); + if (name == "MockPhysicalDevice") + device.setPropertyValue("GeneratePackets", packetCount); + } + } + + PacketReaderPtr createReader(const DevicePtr& device, const std::string& signalName) + { + auto signals = device.getSignalsRecursive(); + + for (const auto& signal : signals) + { + const auto descriptor = signal.getDescriptor(); + if (descriptor.assigned() && descriptor.getName() == signalName) + return PacketReader(signal); + } + + throw NotFoundException(); + } + + ListPtr tryReadPackets(const PacketReaderPtr& reader, size_t packetCount, uint64_t timeoutMs = 500) + { + auto allPackets = List(); + auto lastPacketReceived = std::chrono::system_clock::now(); + + while (allPackets.getCount() < packetCount) + { + if (reader.getAvailableCount() == 0) + { + auto now = std::chrono::system_clock::now(); + uint64_t diffMs = (uint64_t) std::chrono::duration_cast(now - lastPacketReceived).count(); + if (diffMs > timeoutMs) + break; + + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + continue; + } + + auto packets = reader.readAll(); + + for (const auto& packet : packets) + allPackets.pushBack(packet); + + lastPacketReceived = std::chrono::system_clock::now(); + } + + return allPackets; + } + + bool packetsEqual(const ListPtr& listA, const ListPtr& listB, bool compareDescriptors = true) + { + if (listA.getCount() != listB.getCount()) + return false; + + for (SizeT i = 0; i < listA.getCount(); i++) + { + if (!BaseObjectPtr::Equals(listA.getItemAt(i), listB.getItemAt(i))) + return false; + } + + return true; + } + +protected: + InstancePtr createDevice() + { + + const auto moduleManager = ModuleManager("[[none]]"); + auto context = Context(Scheduler(logger, 1), logger, TypeManager(), moduleManager); + + const ModulePtr deviceModule(MockDeviceModule_Create(context)); + moduleManager.addModule(deviceModule); + + + auto instance = InstanceCustom(context, "localInstance"); + + instance.addDevice("mock_phys_device"); + + return instance; + } + + StreamingPtr createStreaming() + { + return WebsocketStreaming(STREAMING_URL, clientContext); + } + + void setActiveStreamingSource(const DevicePtr& device) + { + for (const auto& signal : device.getSignalsRecursive()) + { + auto signalConfigPtr = signal.asPtr(); + signalConfigPtr.setActiveStreamingSource(STREAMING_URL); + } + } + + LoggerPtr logger; + ContextPtr clientContext; + InstancePtr instance; + FunctionPtr createStreamingCallback; +}; + +TEST_F(StreamingIntegrationTest, Connect) +{ + std::string host = "127.0.0.1"; + std::string target = "/"; + uint16_t port = 2000; + + // start server + + boost::asio::io_context serverContext; + auto acceptFunc = [this](StreamPtr stream) {}; + auto server = std::make_shared(serverContext, acceptFunc, port); + + auto serverThread = std::thread([&server, &serverContext]() { + server->start(); + serverContext.run(); + }); + + // start client + + auto signalMetaCallback = [this](const SubscribedSignal& subscribedSignal, const std::string& method, const nlohmann::json& params) {}; + auto protocolMetaCallback = [this](ProtocolHandler& protocolHandler, const std::string& method, const nlohmann::json& params) {}; + auto messageCallback = [this](const SubscribedSignal& subscribedSignal, uint64_t timeStamp, const uint8_t* data, size_t size) {}; + + auto loggerComponent = logger.addComponent("StreamingClient"); + auto logCallback = [loggerComponent](spdlog::source_loc location, spdlog::level::level_enum level, const char* msg) { + loggerComponent.logMessage(SourceLocation{location.filename, location.line, location.funcname}, msg, static_cast(level)); + }; + + daq::streaming_protocol::SignalContainer signalContainer(logCallback); + boost::asio::io_context clientContext; + + signalContainer.setDataAsRawCb(messageCallback); + signalContainer.setSignalMetaCb(signalMetaCallback); + + auto protocolHandler = std::make_shared(clientContext, signalContainer, protocolMetaCallback, logCallback); + auto clientStream = std::make_unique(clientContext, host, std::to_string(port), target); + protocolHandler->startWithSyncInit(std::move(clientStream)); + auto clientThread = std::thread([&clientContext]() { clientContext.run(); }); + + // wait a bit + + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + + // stop client + + clientContext.stop(); + clientThread.join(); + + // stop server + + server->stop(); + serverThread.join(); +} + +TEST_F(StreamingIntegrationTest, ByteStep) +{ + const size_t packetsToRead = 10; + + auto serverStepReader = createReader(instance, "ByteStep"); + + auto streamingServer = WebsocketStreamingServer(instance); + streamingServer.setStreamingPort(STREAMING_PORT); + streamingServer.start(); + + auto server = TmsServer(instance); + server.start(); + + auto client = TmsClient(clientContext, nullptr, OPCUA_URL, createStreamingCallback); + auto clientDevice = client.connect(); + setActiveStreamingSource(clientDevice); + + auto clientStepReader = createReader(clientDevice, "ByteStep"); + + generatePackets(packetsToRead); + + auto serverReceivedPackets = tryReadPackets(serverStepReader, packetsToRead + 1); + auto clientReceivedPackets = tryReadPackets(clientStepReader, packetsToRead + 1); + + ASSERT_EQ(serverReceivedPackets.getCount(), packetsToRead + 1); + ASSERT_EQ(clientReceivedPackets.getCount(), packetsToRead + 1); + ASSERT_TRUE(packetsEqual(serverReceivedPackets, clientReceivedPackets)); +} + +TEST_F(StreamingIntegrationTest, ChangingSignal) +{ + const size_t packetsToGenerate = 5; + const size_t initialEventPackets = 1; + const size_t packetsPerChange = 2; // one triggered by data signal and one trigegred by domain signal + const size_t packetsToRead = initialEventPackets + packetsToGenerate + (packetsToGenerate - 1) * packetsPerChange; + + auto serverStepReader = createReader(instance, "ChangingSignal"); + + auto streamingServer = WebsocketStreamingServer(instance); + streamingServer.setStreamingPort(STREAMING_PORT); + streamingServer.start(); + + auto server = TmsServer(instance); + server.start(); + + auto client = TmsClient(clientContext, nullptr, OPCUA_URL, createStreamingCallback); + auto clientDevice = client.connect(); + setActiveStreamingSource(clientDevice); + + auto clientStepReader = createReader(clientDevice, "ChangingSignal"); + + generatePackets(packetsToGenerate); + + auto serverReceivedPackets = tryReadPackets(serverStepReader, packetsToRead); + auto clientReceivedPackets = tryReadPackets(clientStepReader, packetsToRead); + ASSERT_EQ(serverReceivedPackets.getCount(), packetsToRead); + ASSERT_EQ(clientReceivedPackets.getCount(), packetsToRead); + // TODO: this fails + //ASSERT_TRUE(packetsEqual(serverReceivedPackets, clientReceivedPackets)); +} + +TEST_F(StreamingIntegrationTest, AllSignalsAsync) +{ + const size_t packetsToRead = 50; + + std::vector signals = {"ByteStep", "IntStep", "Sine"}; + std::unordered_map serverReaders; + std::unordered_map clientReaders; + std::unordered_map> serverPackets; + std::unordered_map> clientPackets; + + for (const auto& signal : signals) + serverReaders.insert({signal, createReader(instance, signal)}); + + auto streamingServer = WebsocketStreamingServer(instance); + streamingServer.setStreamingPort(STREAMING_PORT); + streamingServer.start(); + + auto server = TmsServer(instance); + server.start(); + + auto client = TmsClient(clientContext, nullptr, OPCUA_URL, createStreamingCallback); + auto clientDevice = client.connect(); + setActiveStreamingSource(clientDevice); + + for (const auto& signal : signals) + clientReaders.insert({signal, createReader(clientDevice, signal)}); + + generatePackets(packetsToRead); + + std::vector>> serverFetures; + std::vector>> clientFetures; + + for (const auto& signal : signals) + { + auto readFunc = [this](const PacketReaderPtr& reader, size_t packetCount) { return tryReadPackets(reader, packetCount); }; + serverFetures.push_back(std::async(readFunc, serverReaders[signal], packetsToRead + 1)); + auto clientReadFunc = [this](const PacketReaderPtr& reader, size_t packetCount) + { + return tryReadPackets(reader, packetCount); + }; + clientFetures.push_back(std::async(clientReadFunc, clientReaders[signal], packetsToRead + 1)); + } + + for (size_t i = 0; i < serverFetures.size(); i++) + { + auto sentPackets = serverFetures[i].get(); + auto receivedPackets = clientFetures[i].get(); + ASSERT_EQ(sentPackets.getCount(), packetsToRead + 1); + ASSERT_EQ(receivedPackets.getCount(), packetsToRead + 1); + ASSERT_TRUE(packetsEqual(sentPackets, receivedPackets)); + } +} + +TEST_F(StreamingIntegrationTest, DISABLED_StartStopBug) +{ + using namespace daq::websocket_streaming; + DevicePtr device = createDevice(); + + for (size_t i = 0; i < 40; i++) + { + TmsServer tmsServer(device, device.getContext()); + tmsServer.start(); + } +} + +TEST_F(StreamingIntegrationTest, StreamingDeactivate) +{ + const size_t packetsToRead = 10; + + auto serverStepReader = createReader(instance, "Sine"); + + auto streamingServer = WebsocketStreamingServer(instance); + streamingServer.setStreamingPort(STREAMING_PORT); + streamingServer.start(); + + auto server = TmsServer(instance); + server.start(); + + auto streaming = createStreaming(); + auto createStreamingCb = Function([&](const StreamingInfoPtr& /*streamingConfig*/, + bool /*isRootDevice*/) + { + return streaming; + }); + auto client = TmsClient(clientContext, nullptr, OPCUA_URL, createStreamingCb); + auto clientDevice = client.connect(); + setActiveStreamingSource(clientDevice); + + streaming.setActive(False); + + auto clientStepReader = createReader(clientDevice, "Sine"); + + auto clientReceivedPackets = tryReadPackets(clientStepReader, packetsToRead + 1); + ASSERT_EQ(clientReceivedPackets.getCount(), 1u); // Single event packet only + + generatePackets(packetsToRead); + + auto serverReceivedPackets = tryReadPackets(serverStepReader, packetsToRead + 1); + ASSERT_EQ(serverReceivedPackets.getCount(), packetsToRead + 1); + + clientReceivedPackets = tryReadPackets(clientStepReader, packetsToRead + 1); + ASSERT_EQ(clientReceivedPackets.getCount(), 0u); // no data packets since streaming is inactive + + streaming.setActive(True); + + clientReceivedPackets = tryReadPackets(clientStepReader, packetsToRead + 1); + ASSERT_EQ(clientReceivedPackets.getCount(), 0u); // still no data packets available +} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp new file mode 100644 index 0000000..132468f --- /dev/null +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp @@ -0,0 +1,747 @@ +#include +#include "coreobjects/callable_info_factory.h" +#include "coreobjects/property_object_factory.h" +#include "coreobjects/unit_factory.h" +#include "coretypes/type_manager_factory.h" +#include "gtest/gtest.h" +#include "opcuaclient/opcuaclient.h" +#include "opcuatms_client/objects/tms_client_property_object_factory.h" +#include "opcuatms_client/objects/tms_client_property_object_impl.h" +#include "opcuatms_server/objects/tms_server_property_object.h" +#include "tms_object_integration_test.h" +#include "opendaq/instance_factory.h" + +using namespace daq; +using namespace opcua::tms; +using namespace opcua; +using namespace std::chrono_literals; + +struct RegisteredPropertyObject +{ + TmsServerPropertyObjectPtr serverProp; + PropertyObjectPtr clientProp; +}; + +using namespace daq; + +class TMSAmplifierTest : public TmsObjectIntegrationTest +{ +protected: + + TypeManagerPtr objManager; + + void SetUp() override + { + TmsObjectIntegrationTest::SetUp(); + + // create class with name "STGAmplifier" + auto stgAmplClass = + PropertyObjectClassBuilder("StgAmp") + .addProperty(SelectionProperty( + "Measurement", List("Voltage", "Bridge", "Resistance", "Temperature", "Current", "Potentiometer"), 0)) + .addProperty(BoolProperty("DualCore", False)) + .addProperty(ReferenceProperty("Range", + EvalValue("switch($Measurement, 0, %VoltageRange, 1, %BridgeRange, 2, %ResistanceRange, 3, " + "%TemperatureRange, 4, %CurrentRange, 5, %PotentiometerRange)"))) + .addProperty(SelectionProperty("RangeUnit", List("Amplifier range", "Scaled range"), 0)) + .addProperty(SelectionProperty("LowPassFilter", + List("Anti-aliasing filter (IIR)", + "AAF (zero-phase distortion)", + "30 kHz", + "10 kHz", + "3 kHz", + "1 khZ", + "300 Hz", + "100 Hz", + "30 Hz", + "10 Hz"), + 0)) + .addProperty(ReferenceProperty( + "InputType", EvalValue("switch($Measurement, 0, %VoltageInputType, 3, %TemperatureInputType, 4, %CurrentInputType)"))) + .addProperty(ReferenceProperty( + "Excitation", + EvalValue("switch($Measurement, 0, %VoltageExcitation, 4, %CurrentExcitation, 5, %PotentiometerExcitation)"))) + .addProperty(ReferenceProperty("ExcitationUnit", EvalValue("switch($Measurement, 0, %VoltageExcitationUnit))"))) + .addProperty(SelectionProperty("Short", List("On", "Off"), 1)) + .addProperty(FloatProperty("PhysicalScale", 1.0, false)) + .addProperty(FloatProperty("PhysicalOffset", 0.0, false)) + .addProperty(StringProperty("PhysicalUnit", "V", false)) + .addProperty( + SelectionPropertyBuilder( + "VoltageRange", + EvalValue( + "[50.0, 10.0, 1.0, 0.1] * if($RangeUnit == 0, 1, $PhysicalScale) + if($RangeUnit == 0, 0, $PhysicalOffset)"), + 0) + .setUnit(EvalValue("if($RangeUnit == 0, Unit('V'), Unit($PhysicalUnit))")) + .build()) + .addProperty(SelectionProperty("VoltageInputType", List("Differential", "Single ended"), 1)) + .addProperty(FloatPropertyBuilder("VoltageExcitation", 6) + .setVisible(EvalValue("$VoltageInputType == 0")) + .setUnit(EvalValue("Unit(%VoltageExcitationUnit:SelectedValue)")) + .setSuggestedValues(EvalValue("If($VoltageExcitationUnit == 0, [20.0, 15.0, 10.0, 5.0, 2.5, 1.0, 0.0], " + "[60.0, 20.0, 10.0, 5.0, 2.0, 1.0, 0.0])")) + .build()) + .addProperty(SelectionProperty("VoltageExcitationUnit", List("V", "mA"), 0, EvalValue("$VoltageInputType == 0"))) + .addProperty( + SelectionPropertyBuilder( + "PotentiometerRange", + EvalValue( + "[20000.0, 2000.0, 200.0] * if($RangeUnit == 0, 1, $PhysicalScale) + if($RangeUnit == 0, 0, $PhysicalOffset)"), + 0) + .setUnit(EvalValue("if($RangeUnit == 0, Unit('V'), Unit($PhysicalUnit))")) + .build()) + .addProperty(FloatPropertyBuilder("PotentiometerExcitation", 6) + .setSuggestedValues(List(20.0, 15.0, 10.0, 5.0, 2.5, 1.0, 0.0)) + .setUnit(Unit("V")) + .build()) + .addProperty(SelectionPropertyBuilder("TemperatureRange", List("-200 .. 850"), 0) + .setUnit(EvalValue("if($RangeUnit == 0, Unit('C'), Unit($PhysicalUnit))")) + .build()) + .addProperty(SelectionProperty("TemperatureInputType", List("PT100", "PT200", "PT500", "PT1000", "PT2000"), 0)) + .addProperty(SelectionPropertyBuilder("ResistanceRange", + EvalValue("[100000.0, 10000.0, 1000.0, 100.0] * if($RangeUnit == 0, 1, " + "$PhysicalScale) + if($RangeUnit == 0, 0, $PhysicalOffset)"), + 0) + .setUnit(EvalValue("if($RangeUnit == 0, Unit('V'), Unit($PhysicalUnit))")) + .build()) + .addProperty(SelectionPropertyBuilder("BridgeRange", List(1000.0, 200.0, 20.0, 2.0), 0) + .setUnit(EvalValue("if($RangeUnit == 0, Unit('mV'), Unit($PhysicalUnit))")) + .build()) + .addProperty(SelectionProperty( + "BridgeMode", List("Full", "Half", "Quarter 3-wire", "Quarter 4-wire"), 0, EvalValue("$Measurement == 1"))) + .addProperty(ReferenceProperty( + "BridgeResistance", + EvalValue("if($BridgeMode == 0 || $BridgeMode == 1, %BridgeCustomResistance, $BridgeFixedResistance)"))) + .addProperty(FloatPropertyBuilder("BridgeCustomResistance", 120.0) + .setVisible(EvalValue("$Measurement == 1")) + .setUnit(Unit("Ohm")) + .setSuggestedValues(List(120.0, 350.0)) + .build()) + .addProperty(SelectionPropertyBuilder("BridgeFixedResistance", List(120.0, 350.0), 0) + .setVisible( EvalValue("$Measurement == 1")) + .setUnit(Unit("Ohm")) + .build()) + .addProperty(SelectionProperty("BridgeShunt", + List("Off", "Sns + 100kOhm", "Quarter 3-wire", "Quarter 4-wire"), + 0, + EvalValue("$Measurement == 1"))) + .addProperty(FloatPropertyBuilder("BridgeExcitation", 6) + .setSuggestedValues(EvalValue("If($BridgeExcitationUnit == 0, [20.0, 15.0, 10.0, 5.0, 2.5, 1.0, 0.0], " + "[60.0, 20.0, 10.0, 5.0, 2.0, 1.0, 0.0])")) + .setUnit(EvalValue("Unit(%BridgeExcitationUnit:SelectedValue)")) + .build()) + .addProperty(SelectionProperty("BridgeExcitationUnit", List("V", "mA"), 0)) + .addProperty( + SelectionProperty("Shunt", List("On", "Off"), 1, EvalValue("($Measurement == 1) && ($BridgeShunt == 1)"))) + .addProperty(FunctionProperty("Balance", ProcedureInfo(), EvalValue("$Measurement == 1"))) + .addProperty(FunctionProperty("Reset", ProcedureInfo(), EvalValue("$Measurement == 1"))) + .addProperty(FloatPropertyBuilder("SensorUnbalance", 0).setVisible(EvalValue("$Measurement == 1")).setUnit(Unit("mv/V")).build()) + .addProperty(SelectionPropertyBuilder("CurrentRange", EvalValue("[1000.0, 200.0, 20.0, 2.0] * $ResistorDivider"), 1) + .setUnit(EvalValue("if($RangeUnit == 0, Unit($ExternalShuntUnit), Unit($PhysicalUnit))")) + .build()) + .addProperty(SelectionProperty("CurrentInputType", List("Ext. direct shunt", "Ext. loop powered shunt"), 0)) + .addProperty(FloatPropertyBuilder("CurrentExcitation", 6) + .setVisible(EvalValue("$CurrentInputType == 1")) + .setSuggestedValues(List(20.0, 15.0, 10.0, 5.0, 2.5, 1.0, 0.0)) + .setUnit(Unit("V")) + .build()) + .addProperty(SelectionProperty("ExternalShunt", + List("Shunt 1", + "Shunt 2", + "Mini-1mR", + "Mini-500mR", + "Ato-1mR", + "Ato-500mR", + "Maxi-0.2mR", + "Maxi-500mR", + "Strip-0.2mR", + "Strip-500mR", + "Custom"), + 0, + EvalValue("$Measurement == 4"))) + .addProperty( + StringProperty("ExternalShuntUnit", EvalValue("if($ExternalShunt == 0 || $ExternalShunt == 1, 'mA', 'A')"), false)) + .addProperty(FloatProperty("ResistorDivider", + EvalValue("switch($ExternalShunt," + " 0, 1.0," + " 1, 0.5," + " 2, 50.0," + " 3, 0.1," + " 4, 50.0," + " 5, 0.1," + " 6, 250.0," + " 7, 0.1," + " 8, 250.0," + " 9, 0.1," + " 10, 0.0" + ")"), + false)) + .addProperty(FloatPropertyBuilder("Resistor", + EvalValue("switch($ExternalShunt," + " 0, 50.0," + " 1, 0.1," + " 2, 0.001," + " 3, 0.5," + " 4, 0.001," + " 5, 0.5," + " 6, 0.0002," + " 7, 0.5," + " 8, 0.0002," + " 9, 0.5," + " 10, 50.0" + ")")) + .setVisible( EvalValue("$Measurement == 4")) + .setReadOnly(EvalValue("$ExternalShunt != 10")) + .setUnit(Unit("Ohm")) + .build()) + .addProperty(FloatPropertyBuilder("Pmax", + EvalValue("switch($ExternalShunt," + " 0, 0.25," + " 1, 2.5," + " 2, 0.4," + " 3, 2.0," + " 4, 0.9," + " 5, 2.0," + " 6, 0.32," + " 7, 2.0," + " 8, 2.0," + " 9, 2.0," + " 10, 0.125" + ")")) + .setVisible(EvalValue("$Measurement == 4")) + .setReadOnly(EvalValue("$ExternalShunt != 10")) + .setUnit(Unit("W")) + .build()) + .addProperty(FloatPropertyBuilder("Imax", 0.0) + .setVisible(EvalValue("$Measurement == 4")) + .setReadOnly(true) + .setUnit(EvalValue("Unit($ExternalShuntUnit)")) + .build()) + .build(); + + objManager = TypeManager(); + objManager.addType(stgAmplClass); + + // create class with name "LvAmp" + auto lvAmplClass = + PropertyObjectClassBuilder("LvAmp") + .addProperty(StringPropertyBuilder("ModuleName", "XHS LV").setReadOnly(true).build()) + .addProperty(StringPropertyBuilder("SettingRevision", "1,9").setReadOnly(true).build()) + .addProperty(SelectionProperty("Measurement", List("Voltage", "Bridge", "Current"), 0)) + .addProperty( + ReferenceProperty("Range", EvalValue("switch($Measurement, 0, %VoltageRange, 1, %BridgeRange, 2, %CurrentRange)"))) + .addProperty( + SelectionPropertyBuilder("VoltageRange", List(100.0, 50.0, 20.0, 10.0, 5.0, 2.0, 1.0, 0.5, 0.2, 0.1, 0.05), 0) + .setUnit(Unit("V")) + .build()) + .addProperty(SelectionPropertyBuilder("BridgeRange", + EvalValue("If($Excitation == 0, [0.0], [100.0, 50.0, 20.0, 10.0, 5.0, 2.0, 1.0, 0.5, " + "0.2, 0.1, 0.05] * 1000.0 / $Excitation)"), + 0) + .setUnit(Unit("mv/V")) + .build()) + .addProperty( + SelectionPropertyBuilder("CurrentRange", List(100.0, 50.0, 20.0, 10.0, 5.0, 2.0, 1.0, 0.5, 0.2, 0.1, 0.05), 0) + .setUnit(Unit("V")) + .build()) + .addProperty(SelectionProperty("InputType", List("SingleEnded", "Differential"), 0)) + .addProperty(ReferenceProperty("Excitation", EvalValue("switch($InputType, 0, %SEExcitation, 1, %DiffExcitation)"))) + .addProperty(FloatPropertyBuilder("SEExcitation", 0.0) + .setUnit(Unit("V")) + .setSuggestedValues(List(0.0)) + .setMinValue(0.0) + .setMaxValue(0.0) + .setReadOnly(true) + .build()) + .addProperty(SelectionProperty("ExcitationType", List("Unipolar", "Bipolar"), 0, EvalValue("$InputType == 1"))) + .addProperty(ReferenceProperty("DiffExcitation", + EvalValue("switch($ExcitationType, 0, %UnipolarExcitation, 1, %BipolarExcitation)"))) + .addProperty(FloatPropertyBuilder("UnipolarExcitation", 0) + .setSuggestedValues(List(0.0, 1.0, 2.5, 5.0, 10.0, 12.0, 15.0, 24.0)) + .setMinValue(0.0) + .setMaxValue(24.0) + .setUnit(Unit("V")) + .build()) + .addProperty(FloatPropertyBuilder("BipolarExcitation", 2) + .setSuggestedValues(List(2.0, 2.5, 5.0, 10.0, 12.0, 15.0, 24.0, 30.0)) + .setMinValue(0.0) + .setMaxValue(30.0) + .setUnit(Unit("V")) + .build()) + .build(); + + objManager.addType(lvAmplClass); + } + + void TearDown() override + { + objManager.removeType("StgAmp"); + objManager.removeType("LvAmp"); + } + + RegisteredPropertyObject registerPropertyObject(const PropertyObjectPtr& prop) + { + const auto logger = Logger(); + const auto serverProp = + std::make_shared(prop, server, Context(nullptr, logger, TypeManager(), nullptr)); + const auto nodeId = serverProp->registerOpcUaNode(); + const auto clientProp = TmsClientPropertyObject(Context(nullptr, logger, TypeManager(), nullptr), clientContext, nodeId); + return {serverProp, clientProp}; + } +}; + +TEST_F(TMSAmplifierTest, SetUpServerLv) +{ + const auto obj = PropertyObject(objManager, "LvAmp"); + + const auto serverProp = std::make_shared(obj, server, NullContext()); + const auto nodeId = serverProp->registerOpcUaNode(); +} + +TEST_F(TMSAmplifierTest, SetUpServerStg) +{ + const auto obj = PropertyObject(objManager, "StgAmp"); + + const auto serverProp = std::make_shared(obj, server, NullContext()); + const auto nodeId = serverProp->registerOpcUaNode(); +} + +TEST_F(TMSAmplifierTest, SetUpLv) +{ + const auto obj = PropertyObject(objManager, "LvAmp"); + auto [serverObj, clientObj] = registerPropertyObject(obj); +} + +TEST_F(TMSAmplifierTest, SetUpStg) +{ + const auto obj = PropertyObject(objManager, "StgAmp"); + auto [serverObj, clientObj] = registerPropertyObject(obj); +} + +TEST_F(TMSAmplifierTest, TestVisibleProp) +{ + const auto obj = PropertyObject(objManager, "LvAmp"); + auto [serverObj, lvAmpl] = registerPropertyObject(obj); + + auto boundPropInfo = lvAmpl.getProperty("ExcitationType"); + + lvAmpl.setPropertyValue("InputType", 0); + ASSERT_FALSE(lvAmpl.getProperty("ExcitationType").getVisible()); + ASSERT_FALSE(boundPropInfo.getVisible()); + + lvAmpl.setPropertyValue("InputType", 1); + ASSERT_TRUE(lvAmpl.getProperty("ExcitationType").getVisible()); + ASSERT_TRUE(boundPropInfo.getVisible()); +} + +TEST_F(TMSAmplifierTest, Measurement0) +{ + const auto obj = PropertyObject(objManager, "LvAmp"); + auto [serverObj, lvAmpl] = registerPropertyObject(obj); + + lvAmpl.setPropertyValue("Measurement", 0); + + lvAmpl.setPropertyValue("Range", 0); + Float rangeValue = lvAmpl.getPropertySelectionValue("Range"); + auto rangeProp = lvAmpl.getProperty("Range"); + ListPtr rangeValues = rangeProp.getSelectionValues(); + + ASSERT_EQ(rangeValues[0], rangeValue); + + lvAmpl.setPropertyValue("Measurement", 1); + rangeValue = lvAmpl.getPropertySelectionValue("Range"); + rangeProp = lvAmpl.getProperty("Range"); + rangeValues = rangeProp.getSelectionValues(); + + ASSERT_EQ(rangeValues[0], rangeValue); +} + +TEST_F(TMSAmplifierTest, Measurement1) +{ + const auto obj = PropertyObject(objManager, "LvAmp"); + auto [serverObj, lvAmpl] = registerPropertyObject(obj); + + lvAmpl.setPropertyValue("Measurement", 1); + auto exc = lvAmpl.getPropertyValue("Excitation"); + auto it = lvAmpl.getPropertyValue("InputType"); + auto se = lvAmpl.getPropertyValue("SEExcitation"); + + auto a = lvAmpl.getPropertyValue("BridgeRange"); + auto c = lvAmpl.getPropertyValue("Range"); + + auto aProp = lvAmpl.getProperty("BridgeRange"); + ListPtr bridgeValues = aProp.getSelectionValues(); + + auto cProp = lvAmpl.getProperty("Range"); + ListPtr rangeValues = cProp.getSelectionValues(); +} + +TEST_F(TMSAmplifierTest, Measurement2) +{ + const auto obj = PropertyObject(objManager, "LvAmp"); + auto [serverObj, lvAmpl] = registerPropertyObject(obj); + + lvAmpl.setPropertyValue("Measurement", 2); + + auto a = lvAmpl.getPropertyValue("BridgeRange"); + auto c = lvAmpl.getPropertyValue("Range"); + + auto aProp = lvAmpl.getProperty("BridgeRange"); + auto bridgeValues = aProp.getSelectionValues(); + + auto cProp = lvAmpl.getProperty("Range"); + auto rangeValues = cProp.getSelectionValues(); +} + +TEST_F(TMSAmplifierTest, ReadRefPropertyValues) +{ + const auto obj = PropertyObject(objManager, "StgAmp"); + auto [serverObj, stgAmpl] = registerPropertyObject(obj); + + auto rangeProp = stgAmpl.getProperty("Range"); + ListPtr rangeValues = rangeProp.getSelectionValues(); + ASSERT_EQ(rangeValues.getCount(), 4u); + ASSERT_EQ(rangeValues.getItemAt(0), 50.0); +} + +TEST_F(TMSAmplifierTest, SetAndGetRefProperty) +{ + const auto obj = PropertyObject(objManager, "StgAmp"); + auto [serverObj, stgAmpl] = registerPropertyObject(obj); + + stgAmpl.setPropertyValue("Measurement", 0); + + auto rangeProp = stgAmpl.getProperty("Range"); + ListPtr rangeValues = rangeProp.getSelectionValues(); + + ASSERT_EQ(rangeValues.getCount(), 4u); + ASSERT_EQ(rangeValues.getItemAt(0), 50.0); + + stgAmpl.setPropertyValue("Range", 1); + stgAmpl.setPropertyValue("Measurement", 1); + + rangeProp = stgAmpl.getProperty("Range"); + rangeValues = rangeProp.getSelectionValues(); + + ASSERT_EQ(rangeValues.getCount(), 4u); + ASSERT_EQ(rangeValues.getItemAt(0), 1000.0); + + stgAmpl.setPropertyValue("Range", 2); + stgAmpl.setPropertyValue("Measurement", 0); + + ASSERT_EQ(stgAmpl.getPropertyValue("Range"), 1); +} + +TEST_F(TMSAmplifierTest, CheckVoltage) +{ + const auto obj = PropertyObject(objManager, "StgAmp"); + auto [serverObj, stgAmpl] = registerPropertyObject(obj); + + stgAmpl.setPropertyValue("PhysicalUnit", "Pa"); + + // check if by default is in single ended input mode + ASSERT_EQ(stgAmpl.getPropertyValue("InputType"), 1); + + // switch to input type to differential mode + stgAmpl.setPropertyValue("InputType", 0); + auto props = stgAmpl.getVisibleProperties(); + + // TODO: function properties metadata is not transferred from server + ASSERT_EQ(props.getCount(), 13u); + + // TODO: props are out of order + //ASSERT_EQ(props.getItemAt(0).getName(), "Measurement"); + //ASSERT_EQ(props.getItemAt(1).getName(), "DualCore"); + //ASSERT_EQ(props.getItemAt(2).getName(), "Range"); + //ASSERT_EQ(props.getItemAt(3).getName(), "RangeUnit"); + //ASSERT_EQ(props.getItemAt(4).getName(), "LowPassFilter"); + //ASSERT_EQ(props.getItemAt(5).getName(), "InputType"); + //ASSERT_EQ(props.getItemAt(6).getName(), "Excitation"); + //ASSERT_EQ(props.getItemAt(7).getName(), "ExcitationUnit"); + //ASSERT_EQ(props.getItemAt(8).getName(), "Short"); + + // check if by default excitation unit is V + ASSERT_EQ(stgAmpl.getPropertyValue("ExcitationUnit"), 0); + + ASSERT_EQ(stgAmpl.getProperty("Excitation").getUnit(), Unit("V")); + + // check if excitation values correct + ListPtr excitationValues = stgAmpl.getProperty("Excitation").getSuggestedValues(); + ASSERT_EQ(excitationValues.getCount(), 7u); + ASSERT_EQ(excitationValues.getItemAt(0), 20.0); + ASSERT_EQ(excitationValues.getItemAt(1), 15.0); + + // switch to excitation unit to mA + stgAmpl.setPropertyValue("ExcitationUnit", 1); + props = stgAmpl.getVisibleProperties(); + ASSERT_EQ(stgAmpl.getProperty("Excitation").getUnit(), Unit("mA")); + + // check if excitation values correct + excitationValues = stgAmpl.getProperty("Excitation").getSuggestedValues(); + ASSERT_EQ(excitationValues.getCount(), 7u); + ASSERT_EQ(excitationValues.getItemAt(0), 60.0); + ASSERT_EQ(excitationValues.getItemAt(1), 20.0); + + // switch to single ended input type + // TODO: Clear not supported + //stgAmpl.clearPropertyValue("InputType"); + stgAmpl.setPropertyValue("InputType", 1); + props = stgAmpl.getVisibleProperties(); + + // TODO: function properties metadata is not transferred from server + ASSERT_EQ(props.getCount(), 11u); + + // TODO: props are out of order + //ASSERT_EQ(props.getItemAt(0).getName(), "Measurement"); + //ASSERT_EQ(props.getItemAt(1).getName(), "DualCore"); + //ASSERT_EQ(props.getItemAt(2).getName(), "Range"); + //ASSERT_EQ(props.getItemAt(3).getName(), "RangeUnit"); + //ASSERT_EQ(props.getItemAt(4).getName(), "LowPassFilter"); + //ASSERT_EQ(props.getItemAt(5).getName(), "InputType"); + //ASSERT_EQ(props.getItemAt(6).getName(), "Short"); + + // check voltage range + ASSERT_EQ(stgAmpl.getPropertyValue("RangeUnit"), 0); + ASSERT_EQ(stgAmpl.getProperty("Range").getUnit(), Unit("V")); + ASSERT_EQ(stgAmpl.getProperty("Range").getSelectionValues().asPtr().getItemAt(0), 50.0); + + stgAmpl.setPropertyValue("PhysicalScale", 2.0); + stgAmpl.setPropertyValue("PhysicalOffset", 10.0); + + // change to scaled range unit + stgAmpl.setPropertyValue("RangeUnit", 1); + props = stgAmpl.getVisibleProperties(); + ASSERT_EQ(stgAmpl.getProperty("Range").getUnit(), Unit("Pa")); + ASSERT_EQ(stgAmpl.getProperty("Range").getSelectionValues().asPtr().getItemAt(0), 110.0); +} + +TEST_F(TMSAmplifierTest, CheckPotentiometer) +{ + const auto obj = PropertyObject(objManager, "StgAmp"); + auto [serverObj, stgAmpl] = registerPropertyObject(obj); + + stgAmpl.setPropertyValue("PhysicalUnit", "Pa"); + + stgAmpl.setPropertyValue("Measurement", 5); + + auto props = stgAmpl.getVisibleProperties(); + // TODO: function properties metadata is not transferred from server + ASSERT_EQ(props.getCount(), 11u); + + // TODO: props are out of order + //ASSERT_EQ(props.getItemAt(0).getName(), "Measurement"); + //ASSERT_EQ(props.getItemAt(1).getName(), "DualCore"); + //ASSERT_EQ(props.getItemAt(2).getName(), "Range"); + //ASSERT_EQ(props.getItemAt(3).getName(), "RangeUnit"); + //ASSERT_EQ(props.getItemAt(4).getName(), "LowPassFilter"); + //ASSERT_EQ(props.getItemAt(5).getName(), "Excitation"); + //ASSERT_EQ(props.getItemAt(6).getName(), "Short"); + + // check if by default excitation unit is V + ASSERT_EQ(stgAmpl.getProperty("Excitation").getUnit(), Unit("V")); + + // check if excitation values correct + ListPtr excitationValues = stgAmpl.getProperty("Excitation").getSuggestedValues(); + ASSERT_EQ(excitationValues.getCount(), 7u); + ASSERT_EQ(excitationValues.getItemAt(0), 20.0); + ASSERT_EQ(excitationValues.getItemAt(1), 15.0); + + // check potentiometer range + ASSERT_EQ(stgAmpl.getPropertyValue("RangeUnit"), 0); + ASSERT_EQ(stgAmpl.getProperty("Range").getUnit(), Unit("V")); + ASSERT_EQ(stgAmpl.getProperty("Range").getSelectionValues().asPtr().getItemAt(0), 20000.0); + + stgAmpl.setPropertyValue("PhysicalScale", 2.0); + stgAmpl.setPropertyValue("PhysicalOffset", 10.0); + + // change to scaled range unit + stgAmpl.setPropertyValue("RangeUnit", 1); + props = stgAmpl.getVisibleProperties(); + ASSERT_EQ(stgAmpl.getProperty("Range").getUnit(), Unit("Pa")); + ASSERT_EQ(stgAmpl.getProperty("Range").getSelectionValues().asPtr().getItemAt(0), 40010.0); +} + +TEST_F(TMSAmplifierTest, CheckResistance) +{ + const auto obj = PropertyObject(objManager, "StgAmp"); + auto [serverObj, stgAmpl] = registerPropertyObject(obj); + + stgAmpl.setPropertyValue("PhysicalUnit", "Pa"); + + stgAmpl.setPropertyValue("Measurement", 2); + + auto props = stgAmpl.getVisibleProperties(); + // TODO: function properties metadata is not transferred from server + ASSERT_EQ(props.getCount(), 10u); + + // TODO: props are out of order + //ASSERT_EQ(props.getItemAt(0).getName(), "Measurement"); + //ASSERT_EQ(props.getItemAt(1).getName(), "DualCore"); + //ASSERT_EQ(props.getItemAt(2).getName(), "Range"); + //ASSERT_EQ(props.getItemAt(3).getName(), "RangeUnit"); + //ASSERT_EQ(props.getItemAt(4).getName(), "LowPassFilter"); + //ASSERT_EQ(props.getItemAt(5).getName(), "Short"); + + // check resistance range + ASSERT_EQ(stgAmpl.getPropertyValue("RangeUnit"), 0); + ASSERT_EQ(stgAmpl.getProperty("Range").getUnit(), Unit("V")); + ASSERT_EQ(stgAmpl.getProperty("Range").getSelectionValues().asPtr().getItemAt(0), 100000.0); + + stgAmpl.setPropertyValue("PhysicalScale", 2.0); + stgAmpl.setPropertyValue("PhysicalOffset", 10.0); + + // change to scaled range unit + stgAmpl.setPropertyValue("RangeUnit", 1); + ASSERT_EQ(stgAmpl.getProperty("Range").getUnit(), Unit("Pa")); + ASSERT_EQ(stgAmpl.getProperty("Range").getSelectionValues().asPtr().getItemAt(0), 200010.0); +} + +TEST_F(TMSAmplifierTest, CheckTemperature) +{ + const auto obj = PropertyObject(objManager, "StgAmp"); + auto [serverObj, stgAmpl] = registerPropertyObject(obj); + + stgAmpl.setPropertyValue("PhysicalUnit", "F"); + + stgAmpl.setPropertyValue("Measurement", 3); + + auto props = stgAmpl.getVisibleProperties(); + // TODO: function properties metadata is not transferred from server + ASSERT_EQ(props.getCount(), 11u); + + // TODO: props are out of order + //ASSERT_EQ(props.getItemAt(0).getName(), "Measurement"); + //ASSERT_EQ(props.getItemAt(1).getName(), "DualCore"); + //ASSERT_EQ(props.getItemAt(2).getName(), "Range"); + //ASSERT_EQ(props.getItemAt(3).getName(), "RangeUnit"); + //ASSERT_EQ(props.getItemAt(4).getName(), "LowPassFilter"); + //ASSERT_EQ(props.getItemAt(5).getName(), "InputType"); + //ASSERT_EQ(props.getItemAt(6).getName(), "Short"); + + // check temperature range + ASSERT_EQ(stgAmpl.getPropertyValue("RangeUnit"), 0); + ASSERT_EQ(stgAmpl.getProperty("Range").getUnit(), Unit("C")); + ASSERT_EQ(stgAmpl.getProperty("Range").getSelectionValues().asPtr().getItemAt(0), "-200 .. 850"); + + stgAmpl.setPropertyValue("PhysicalScale", 2.0); + stgAmpl.setPropertyValue("PhysicalOffset", 10.0); + + // change to scaled range unit + stgAmpl.setPropertyValue("RangeUnit", 1); + props = stgAmpl.getVisibleProperties(); + ASSERT_EQ(stgAmpl.getProperty("Range").getUnit(), Unit("F")); + // ASSERT_EQ(props.getItemAt(2).getSelectionValues().getItemAt(0), 200010.0); +} + +TEST_F(TMSAmplifierTest, CheckCurrent) +{ + const auto obj = PropertyObject(objManager, "StgAmp"); + auto [serverObj, stgAmpl] = registerPropertyObject(obj); + + stgAmpl.setPropertyValue("PhysicalUnit", "Pa"); + + // switch to current mode + stgAmpl.setPropertyValue("Measurement", 4); + auto allProps = stgAmpl.getAllProperties(); + auto props = stgAmpl.getVisibleProperties(); + + // TODO: function properties metadata is not transferred from server + ASSERT_EQ(props.getCount(), 15u); + + // TODO: props are out of order + //ASSERT_EQ(props.getItemAt(0).getName(), "Measurement"); + //ASSERT_EQ(props.getItemAt(1).getName(), "DualCore"); + //ASSERT_EQ(props.getItemAt(2).getName(), "Range"); + //ASSERT_EQ(props.getItemAt(3).getName(), "RangeUnit"); + //ASSERT_EQ(props.getItemAt(4).getName(), "LowPassFilter"); + //ASSERT_EQ(props.getItemAt(5).getName(), "InputType"); + //ASSERT_EQ(props.getItemAt(6).getName(), "Short"); + //ASSERT_EQ(props.getItemAt(7).getName(), "BridgeExcitation"); + //ASSERT_EQ(props.getItemAt(8).getName(), "BridgeExcitationUnit"); + //ASSERT_EQ(props.getItemAt(9).getName(), "ExternalShunt"); + //ASSERT_EQ(props.getItemAt(10).getName(), "Resistor"); + //ASSERT_EQ(props.getItemAt(11).getName(), "Pmax"); + //ASSERT_EQ(props.getItemAt(12).getName(), "Imax"); + + // check range + auto currRange = stgAmpl.getProperty("CurrentRange"); + auto rangeProp = stgAmpl.getProperty("Range"); + auto item = rangeProp.getSelectionValues().asPtr().getItemAt(0); + ASSERT_EQ(rangeProp.getSelectionValues().asPtr().getItemAt(0), 1000.0); + + ASSERT_EQ(rangeProp.getUnit(), Unit("mA")); + + auto iMaxProp = stgAmpl.getProperty("Imax"); + ASSERT_EQ(iMaxProp.getUnit(), Unit("mA")); + + stgAmpl.setPropertyValue("ExternalShunt", 1); + + // check range + ASSERT_EQ(rangeProp.getSelectionValues().asPtr().getItemAt(0), 500.0); + + // check shunt values + ASSERT_EQ(stgAmpl.getPropertyValue("Resistor"), 0.1); + ASSERT_EQ(stgAmpl.getPropertyValue("Pmax"), 2.5); + + stgAmpl.setPropertyValue("InputType", 1); + props = stgAmpl.getVisibleProperties(); + + // TODO: function properties metadata is not transferred from server + ASSERT_EQ(props.getCount(), 16u); + + // TODO: props are out of order + //ASSERT_EQ(props.getItemAt(0).getName(), "Measurement"); + //ASSERT_EQ(props.getItemAt(1).getName(), "DualCore"); + //ASSERT_EQ(props.getItemAt(2).getName(), "Range"); + //ASSERT_EQ(props.getItemAt(3).getName(), "RangeUnit"); + //ASSERT_EQ(props.getItemAt(4).getName(), "LowPassFilter"); + //ASSERT_EQ(props.getItemAt(5).getName(), "InputType"); + //ASSERT_EQ(props.getItemAt(6).getName(), "Excitation"); + //ASSERT_EQ(props.getItemAt(7).getName(), "Short"); + //ASSERT_EQ(props.getItemAt(8).getName(), "BridgeExcitation"); + //ASSERT_EQ(props.getItemAt(9).getName(), "BridgeExcitationUnit"); + //ASSERT_EQ(props.getItemAt(10).getName(), "ExternalShunt"); + //ASSERT_EQ(props.getItemAt(11).getName(), "Resistor"); + //ASSERT_EQ(props.getItemAt(12).getName(), "Pmax"); + //ASSERT_EQ(props.getItemAt(13).getName(), "Imax"); + + // set custom shunt + stgAmpl.setPropertyValue("ExternalShunt", 10); + + // check shunt values + ASSERT_EQ(stgAmpl.getPropertyValue("Resistor"), 50.0); + ASSERT_EQ(stgAmpl.getPropertyValue("Pmax"), 0.125); +} + + +TEST_F(TMSAmplifierTest, GetRefPropAfterChange) +{ + const auto obj = PropertyObject(objManager, "StgAmp"); + auto [serverObj, stgAmpl] = registerPropertyObject(obj); + + auto rangeProp = stgAmpl.getProperty("Range"); + + auto voltageRangeProp = stgAmpl.getProperty("VoltageRange"); + stgAmpl.setPropertyValue("Measurement", 0); + ASSERT_EQ(rangeProp.getReferencedProperty().getName(), voltageRangeProp.getName()); + + auto bridgeRangeProp = stgAmpl.getProperty("BridgeRange"); + stgAmpl.setPropertyValue("Measurement", 1); + ASSERT_EQ(rangeProp.getReferencedProperty().getName(), bridgeRangeProp.getName()); +} + +TEST_F(TMSAmplifierTest, GetRefPropSelectionValuesAfterChange) +{ + const auto obj = PropertyObject(objManager, "StgAmp"); + auto [serverObj, stgAmpl] = registerPropertyObject(obj); + + auto rangeProp = stgAmpl.getProperty("Range"); + + auto voltageRangeValues = stgAmpl.getProperty("VoltageRange").getSelectionValues(); + stgAmpl.setPropertyValue("Measurement", 0); + ASSERT_EQ(rangeProp.getSelectionValues(), voltageRangeValues); + + auto bridgeRangeValues = stgAmpl.getProperty("BridgeRange").getSelectionValues(); + stgAmpl.setPropertyValue("Measurement", 1); + ASSERT_EQ(rangeProp.getSelectionValues(), bridgeRangeValues); +} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_channel.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_channel.cpp new file mode 100644 index 0000000..214c7ff --- /dev/null +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_channel.cpp @@ -0,0 +1,149 @@ +#include +#include +#include +#include +#include "gtest/gtest.h" +#include "opcuaclient/opcuaclient.h" +#include "opcuatms/exceptions.h" +#include "opcuatms_server/objects/tms_server_channel.h" +#include +#include "opcuatms_client/objects/tms_client_input_port_factory.h" +#include "opcuatms_client/objects/tms_client_signal_factory.h" +#include "open62541/tmsbsp_nodeids.h" +#include "tms_object_integration_test.h" +#include "opendaq/mock/mock_channel_factory.h" + +using namespace daq; +using namespace opcua::tms; +using namespace opcua; +class TmsChannelTest : public TmsObjectIntegrationTest +{ +public: + + ChannelPtr createChannel(const ContextPtr& ctx) + { + return MockChannel(ctx, nullptr, "mockch"); + } +}; + +TEST_F(TmsChannelTest, Create) +{ + auto ctx = NullContext(); + ChannelPtr channel = createChannel(ctx); + auto tmsChannel = TmsServerChannel(channel, this->getServer(), NullContext()); +} + +TEST_F(TmsChannelTest, Register) +{ + auto ctx = NullContext(); + ChannelPtr channel = createChannel(ctx); + auto serverChannel = TmsServerChannel(channel, this->getServer(), NullContext()); // Not possible either + auto nodeId = serverChannel.registerOpcUaNode(); + + ChannelPtr clientChannel = TmsClientChannel(ctx, nullptr, "ch", clientContext, nodeId); + ASSERT_TRUE(clientChannel.assigned()); +} + +TEST_F(TmsChannelTest, BrowseName) +{ + auto ctx = NullContext(); + ChannelPtr serverChannel = createChannel(ctx); + + auto tmsServerChannel = TmsServerChannel(serverChannel, this->getServer(), NullContext()); + auto nodeId = tmsServerChannel.registerOpcUaNode(); + + ChannelPtr clientChannel = TmsClientChannel(ctx, nullptr, "ch", clientContext, nodeId); + + auto browseName = client->readBrowseName(nodeId); + ASSERT_EQ(browseName, "mockch"); + + auto dsiplayName = client->readDisplayName(nodeId); + ASSERT_EQ(dsiplayName, "mockch"); +} + +TEST_F(TmsChannelTest, AttrFunctionBlockType) +{ + auto ctx = NullContext(); + ChannelPtr serverChannel = createChannel(ctx); + + auto tmsServerChannel = TmsServerChannel(serverChannel, this->getServer(), NullContext()); + auto nodeId = tmsServerChannel.registerOpcUaNode(); + + ChannelPtr clientChannel = TmsClientChannel(ctx, nullptr, "ch", clientContext, nodeId); + + auto type = clientChannel.getFunctionBlockType(); + ASSERT_EQ(type.getId(), "mock_ch"); + ASSERT_EQ(type.getName(), "mock_ch"); + ASSERT_EQ(type.getDescription(), ""); +} + +TEST_F(TmsChannelTest, MethodGetInputPorts) +{ + auto ctx = NullContext(); + ChannelPtr serverChannel = createChannel(ctx); + + auto tmsServerChannel = TmsServerChannel(serverChannel, this->getServer(), NullContext()); + auto channelNodeId = tmsServerChannel.registerOpcUaNode(); + + ChannelPtr clientChannel = TmsClientChannel(ctx, nullptr, "ch", clientContext, channelNodeId); + + auto inputPorts = clientChannel.getInputPorts(); + ASSERT_TRUE(inputPorts != nullptr); + + //TODO: Implement more test when input ports actually can be returned + ASSERT_EQ(inputPorts.getCount(), 2u); // Mock function block creates 2 input ports + ASSERT_EQ(inputPorts[0].getLocalId(), "TestInputPort1"); + ASSERT_EQ(inputPorts[1].getLocalId(), "TestInputPort2"); +} + +TEST_F(TmsChannelTest, MethodGetSignals) +{ + auto ctx = NullContext(); + ChannelPtr serverChannel = createChannel(ctx); + + auto tmsServerChannel = TmsServerChannel(serverChannel, this->getServer(), NullContext()); + auto channelNodeId = tmsServerChannel.registerOpcUaNode(); + + auto clientChannel = TmsClientChannel(ctx, nullptr, "ch", clientContext, channelNodeId); + + ListPtr signals; + ASSERT_NO_THROW(signals = clientChannel.getSignals()); + ASSERT_TRUE(signals.assigned()); + + ASSERT_EQ(signals.getCount(), 10u); + ASSERT_EQ(signals[0].getDescriptor().getName(), "Signal1"); + ASSERT_EQ(signals[1].getDescriptor().getName(), "Signal2"); + ASSERT_EQ(signals[2].getDescriptor().getName(), "Signal3"); + ASSERT_EQ(signals[3].getDescriptor().getName(), "Signal4"); + ASSERT_EQ(signals[4].getDescriptor().getName(), "Time"); + ASSERT_EQ(signals[5].getDescriptor().getName(), "ChangingTime"); + ASSERT_EQ(signals[6].getDescriptor().getName(), "ByteStep"); + ASSERT_EQ(signals[7].getDescriptor().getName(), "IntStep"); + ASSERT_EQ(signals[8].getDescriptor().getName(), "Sine"); + ASSERT_EQ(signals[9].getDescriptor().getName(), "ChangingSignal"); +} + +TEST_F(TmsChannelTest, MethodGetStatusSignal) +{ + auto ctx = NullContext(); + ChannelPtr serverChannel = createChannel(ctx); + + auto tmsServerChannel = TmsServerChannel(serverChannel, this->getServer(), NullContext()); + auto channelNodeId = tmsServerChannel.registerOpcUaNode(); + + SignalPtr serverSignal = Signal(ctx, nullptr, "sig"); + auto tmsServerSignal = TmsServerSignal(serverSignal, this->getServer(), NullContext()); + auto signalNodeId = tmsServerSignal.registerOpcUaNode(); + + OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASSTATUSSIGNAL); + getServer()->addReference(channelNodeId, referenceTypeId, signalNodeId, true); + + ChannelPtr clientChannel = TmsClientChannel(ctx, nullptr, "ch", clientContext, channelNodeId); + + //EXPECT_THROW(clientChannel.getStatusSignal(), daq::opcua::OpcUaClientCallNotAvailableException); + + //TODO: Implement more test when signals actually can be returned + //SignalPtr clientSignal = TmsClientSignal(client, signalNodeId); + //auto statusSignal = clientChannel.getStatusSignal(); + //ASSERT_EQ(statusSignal, clientSignal); +} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_component.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_component.cpp new file mode 100644 index 0000000..d76b7e6 --- /dev/null +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_component.cpp @@ -0,0 +1,92 @@ +#include "opendaq/component_factory.h" +#include "opcuatms_client/objects/tms_client_component_factory.h" +#include "opcuatms_server/objects/tms_server_component.h" +#include "tms_object_integration_test.h" +#include "coreobjects/property_object_factory.h" +#include "opendaq/context_factory.h" + +using namespace daq; +using namespace opcua::tms; +using namespace opcua; + +struct RegisteredComponent +{ + TmsServerComponentPtr serverObject; + ComponentPtr serverComponent; + ComponentPtr clientComponent; +}; + +class TmsComponentTest : public TmsObjectIntegrationTest +{ +public: + ComponentPtr createTestComponent() + { + auto component = Component(NullContext(), nullptr, "test"); + + component.addProperty(StringProperty("foo", "bar")); + auto obj = PropertyObject(); + obj.addProperty(IntProperty("int", 0)); + component.addProperty(ObjectProperty("obj", obj)); + + component.getTags().add("tag1"); + component.getTags().add("tag2"); + + return component; + } + + RegisteredComponent registerTestComponent() + { + RegisteredComponent component{}; + + component.serverComponent = createTestComponent(); + component.serverObject = std::make_shared>(component.serverComponent, this->getServer(), NullContext()); + auto nodeId = component.serverObject->registerOpcUaNode(); + component.clientComponent = TmsClientComponent(NullContext(), nullptr, "test", clientContext, nodeId); + return component; + } +}; + +TEST_F(TmsComponentTest, Create) +{ + auto component = createTestComponent(); + auto serverComponent = TmsServerComponent(component, this->getServer(), NullContext()); +} + +TEST_F(TmsComponentTest, Register) +{ + auto component = registerTestComponent(); +} + +TEST_F(TmsComponentTest, Active) +{ + auto component = registerTestComponent(); + + component.clientComponent.setActive(false); + ASSERT_EQ(component.serverComponent.getActive(), component.clientComponent.getActive()); + + component.clientComponent.setActive(true); + ASSERT_EQ(component.serverComponent.getActive(), component.clientComponent.getActive()); +} + +TEST_F(TmsComponentTest, Tags) +{ + auto component = registerTestComponent(); + + auto serverTags = component.serverComponent.getTags(); + auto clientTags = component.clientComponent.getTags(); + + ASSERT_TRUE(clientTags.query("tag1") && clientTags.query("tag2")); +} + +TEST_F(TmsComponentTest, Properties) +{ + auto component = registerTestComponent(); + + PropertyObjectPtr serverObj = component.serverComponent.getPropertyValue("obj"); + PropertyObjectPtr clientObj = component.clientComponent.getPropertyValue("obj"); + ASSERT_EQ(serverObj.getPropertyValue("int"), clientObj.getPropertyValue("int")); + ASSERT_EQ(component.serverComponent.getPropertyValue("foo"), component.clientComponent.getPropertyValue("foo")); + + component.clientComponent.setPropertyValue("foo", "notbar"); + ASSERT_EQ(component.serverComponent.getPropertyValue("foo"), component.clientComponent.getPropertyValue("foo")); +} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp new file mode 100644 index 0000000..785f464 --- /dev/null +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp @@ -0,0 +1,342 @@ +#include +#include +#include +#include +#include +#include +#include +#include "opcuatms/exceptions.h" +#include +#include +#include "tms_object_integration_test.h" + +using namespace daq; +using namespace opcua::tms; +using namespace opcua; +using namespace std::chrono_literals; + +class TmsDeviceTest : public TmsObjectIntegrationTest +{ +public: + InstancePtr createDevice() + { + const auto moduleManager = ModuleManager("[[none]]"); + auto context = Context(nullptr, Logger(), nullptr, moduleManager); + const ModulePtr deviceModule(MockDeviceModule_Create(context)); + moduleManager.addModule(deviceModule); + + const ModulePtr fbModule(MockFunctionBlockModule_Create(context)); + moduleManager.addModule(fbModule); + + auto instance = InstanceCustom(context, "localInstance"); + instance.addDevice("daq_client_device"); + instance.addDevice("mock_phys_device"); + instance.addFunctionBlock("mock_fb_uid"); + + return instance; + } +}; + +TEST_F(TmsDeviceTest, CreateClientDevice) +{ + DevicePtr serverDevice = createDevice(); + + auto tmsPropertyObject = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto nodeId = tmsPropertyObject.registerOpcUaNode(); + auto ctx = NullContext(); + ASSERT_NO_THROW(TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr)); +} + +TEST_F(TmsDeviceTest, SubDevices) +{ + DevicePtr serverDevice = createDevice(); + + auto tmsPropertyObject = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto nodeId = tmsPropertyObject.registerOpcUaNode(); + + auto ctx = NullContext(); + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + ASSERT_EQ(clientDevice.getDevices().getCount(), 2u); +} + +TEST_F(TmsDeviceTest, FunctionBlocks) +{ + auto ctx = NullContext(); + DevicePtr serverDevice = createDevice(); + + auto tmsPropertyObject = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto nodeId = tmsPropertyObject.registerOpcUaNode(); + + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + ListPtr functionBlocks; + ASSERT_NO_THROW(functionBlocks = clientDevice.getFunctionBlocks()); + ASSERT_EQ(functionBlocks.getCount(), 1u); + + auto type = functionBlocks[0].getFunctionBlockType(); + ASSERT_EQ(type.getId(), "mock_fb_uid"); +} + +TEST_F(TmsDeviceTest, GetSignals) +{ + DevicePtr serverDevice = createDevice(); + + auto tmsPropertyObject = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto nodeId = tmsPropertyObject.registerOpcUaNode(); + + auto ctx = NullContext(); + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + + ListPtr signals; + ASSERT_NO_THROW(signals = clientDevice.getSignals()); + ASSERT_EQ(signals.getCount(), 0u); + + auto devices = clientDevice.getDevices(); + for (auto subDevice : devices) + { + auto name = subDevice.getName(); + ASSERT_NO_THROW(signals = subDevice.getSignals()); + if (name == "mockdev") + ASSERT_EQ(signals.getCount(), 1u); + else + ASSERT_EQ(signals.getCount(), 0u); + } + + ASSERT_NO_THROW(signals = clientDevice.getSignalsRecursive()); + ASSERT_EQ(signals.getCount(), serverDevice.getSignalsRecursive().getCount()); +} + +TEST_F(TmsDeviceTest, GetChannels) +{ + DevicePtr serverDevice = createDevice(); + + auto tmsPropertyObject = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto nodeId = tmsPropertyObject.registerOpcUaNode(); + + auto ctx = NullContext(); + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + ListPtr channels; + ASSERT_NO_THROW(channels = clientDevice.getChannels()); + ASSERT_EQ(channels.getCount(), serverDevice.getChannels().getCount()); + + ASSERT_NO_THROW(channels = clientDevice.getChannelsRecursive()); + ASSERT_EQ(channels.getCount(), serverDevice.getChannelsRecursive().getCount()); +} + +TEST_F(TmsDeviceTest, Property) +{ + DevicePtr serverDevice = createDevice(); + + const auto sampleRateProp = FloatPropertyBuilder("SampleRate", 100.0).setUnit(Unit("Hz")).setMinValue(1.0).setMaxValue(1000000.0).build(); + + serverDevice.addProperty(sampleRateProp); + + auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto nodeId = serverTmsDevice.registerOpcUaNode(); + + auto ctx = NullContext(); + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + + auto visibleProperties = clientDevice.getVisibleProperties(); + ASSERT_EQ(visibleProperties.getCount(), 3u); + ASSERT_EQ(visibleProperties[2].getName(), "SampleRate"); + + auto properties = clientDevice.getAllProperties(); + ASSERT_EQ(properties.getCount(), 3u); + ASSERT_EQ(properties[2].getName(), "SampleRate"); + + ASSERT_TRUE(clientDevice.hasProperty("SampleRate")); + ASSERT_EQ(clientDevice.getPropertyValue("SampleRate"), 100.0); + + clientDevice.setPropertyValue("SampleRate", 14.0); + ASSERT_EQ(clientDevice.getPropertyValue("SampleRate"), 14.0); + ASSERT_EQ(serverDevice.getPropertyValue("SampleRate"), 14.0); + + ASSERT_EQ(clientDevice.getPropertyValue("UserName"), ""); + ASSERT_EQ(clientDevice.getPropertyValue("Location"), ""); +} + +TEST_F(TmsDeviceTest, DeviceInfo) +{ + auto ctx = NullContext(); + DevicePtr serverDevice = createDevice(); + + auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto nodeId = serverTmsDevice.registerOpcUaNode(); + + auto serverSubDevices = serverDevice.getDevices(); + ASSERT_EQ(serverSubDevices.getCount(), 2u); + auto serverSubDevice = serverSubDevices[1]; + auto serverDeviceInfo = serverSubDevice.getInfo(); + + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + + auto clientSubDevices = clientDevice.getDevices(); + ASSERT_EQ(clientSubDevices.getCount(), 2u); + auto clientSubDevice = clientSubDevices[1]; + auto clientDeviceInfo = clientSubDevice.getInfo(); + + //TODO: Test connectionString and Location when implemented + ASSERT_EQ(clientDeviceInfo.getName(), serverDeviceInfo.getName()); + ASSERT_EQ(clientDeviceInfo.getManufacturer(), serverDeviceInfo.getManufacturer()); + ASSERT_EQ(clientDeviceInfo.getManufacturerUri(), serverDeviceInfo.getManufacturerUri()); + ASSERT_EQ(clientDeviceInfo.getModel(), serverDeviceInfo.getModel()); + ASSERT_EQ(clientDeviceInfo.getProductCode(), serverDeviceInfo.getProductCode()); + ASSERT_EQ(clientDeviceInfo.getDeviceRevision(), serverDeviceInfo.getDeviceRevision()); + ASSERT_EQ(clientDeviceInfo.getHardwareRevision(), serverDeviceInfo.getHardwareRevision()); + ASSERT_EQ(clientDeviceInfo.getSoftwareRevision(), serverDeviceInfo.getSoftwareRevision()); + ASSERT_EQ(clientDeviceInfo.getDeviceManual(), serverDeviceInfo.getDeviceManual()); + ASSERT_EQ(clientDeviceInfo.getDeviceClass(), serverDeviceInfo.getDeviceClass()); + ASSERT_EQ(clientDeviceInfo.getSerialNumber(), serverDeviceInfo.getSerialNumber()); + ASSERT_EQ(clientDeviceInfo.getProductInstanceUri(), serverDeviceInfo.getProductInstanceUri()); + ASSERT_EQ(clientDeviceInfo.getMacAddress(), serverDeviceInfo.getMacAddress()); + ASSERT_EQ(clientDeviceInfo.getParentMacAddress(), serverDeviceInfo.getParentMacAddress()); + ASSERT_EQ(clientDeviceInfo.getPlatform(), serverDeviceInfo.getPlatform()); + ASSERT_EQ(clientDeviceInfo.getPosition(), serverDeviceInfo.getPosition()); + ASSERT_EQ(clientDeviceInfo.getSystemType(), serverDeviceInfo.getSystemType()); + ASSERT_EQ(clientDeviceInfo.getSystemUuid(), serverDeviceInfo.getSystemUuid()); + + + ASSERT_EQ(clientDeviceInfo.getName(), "MockPhysicalDevice"); + ASSERT_EQ(clientDeviceInfo.getManufacturer(), "manufacturer"); + ASSERT_EQ(clientDeviceInfo.getManufacturerUri(), "manufacturer_uri"); + ASSERT_EQ(clientDeviceInfo.getModel(), "model"); + ASSERT_EQ(clientDeviceInfo.getProductCode(), "product_code"); + ASSERT_EQ(clientDeviceInfo.getHardwareRevision(), "hardware_revision"); + ASSERT_EQ(clientDeviceInfo.getSoftwareRevision(), "software_revision"); + ASSERT_EQ(clientDeviceInfo.getDeviceManual(), "device_manual"); + ASSERT_EQ(clientDeviceInfo.getDeviceClass(), "device_class"); + ASSERT_EQ(clientDeviceInfo.getSerialNumber(), "serial_number"); + ASSERT_EQ(clientDeviceInfo.getProductInstanceUri(), "product_instance_uri"); + ASSERT_EQ(clientDeviceInfo.getRevisionCounter(), 123); + ASSERT_EQ(clientDeviceInfo.getPropertyValue("custom_string"), "custom_string"); + ASSERT_EQ(clientDeviceInfo.getPropertyValue("custom_float"), 1.123); + ASSERT_EQ(clientDeviceInfo.getPropertyValue("custom_int"), 1); +} + +TEST_F(TmsDeviceTest, DeviceDomain) +{ + auto ctx = NullContext(); + DevicePtr serverDevice = createDevice(); + + auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto nodeId = serverTmsDevice.registerOpcUaNode(); + + auto serverSubDevices = serverDevice.getDevices(); + ASSERT_EQ(serverSubDevices.getCount(), 2u); + auto serverSubDevice = serverSubDevices[1]; + auto serverDeviceInfo = serverSubDevice.getInfo(); + + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + + auto clientSubDevices = clientDevice.getDevices(); + ASSERT_EQ(clientSubDevices.getCount(), 2u); + auto clientSubDevice = clientSubDevices[1]; + + auto deviceDomain = clientSubDevice.getDomain(); + + auto resolution = deviceDomain.getTickResolution(); + ASSERT_EQ(resolution.getNumerator(), 123); + ASSERT_EQ(resolution.getDenominator(), 456); + + auto ticksSinceOrigin = deviceDomain.getTicksSinceOrigin(); + ASSERT_EQ(ticksSinceOrigin, 789); + + auto origin = deviceDomain.getOrigin(); + ASSERT_EQ(origin, "origin"); + + auto unit = deviceDomain.getUnit(); + ASSERT_EQ(unit.getId(), 987); + ASSERT_EQ(unit.getSymbol(), "unit_symbol"); + ASSERT_EQ(unit.getName(), "unit_name"); + ASSERT_EQ(unit.getQuantity(), "unit_quantity"); + +} + +TEST_F(TmsDeviceTest, CustomComponents) +{ + auto ctx = NullContext(); + DevicePtr serverDevice = createDevice(); + + auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto nodeId = serverTmsDevice.registerOpcUaNode(); + + auto serverSubDevice = serverDevice.getDevices()[1]; + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + auto clientSubDevice = clientDevice.getDevices()[1]; + + ASSERT_EQ(serverSubDevice.getItems().getCount(), clientSubDevice.getItems().getCount()); + auto serverComponentA1 = serverSubDevice.getItem("componentA").asPtr().getItems()[0]; + auto clientComponentA1 = clientSubDevice.getItem("componentA").asPtr().getItems()[0]; + ASSERT_EQ(serverComponentA1.getName(), clientComponentA1.getName()); + + auto serverComponentB = serverSubDevice.getItem("componentB"); + auto clientComponentB = clientSubDevice.getItem("componentB"); + ASSERT_EQ(serverComponentB.getName(), clientComponentB.getName()); +} + +TEST_F(TmsDeviceTest, CustomComponentsProperties) +{ + auto ctx = NullContext(); + DevicePtr serverDevice = createDevice(); + + auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto nodeId = serverTmsDevice.registerOpcUaNode(); + + auto serverSubDevice = serverDevice.getDevices()[1]; + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + auto clientSubDevice = clientDevice.getDevices()[1]; + + ASSERT_EQ(serverSubDevice.getItems().getCount(), clientSubDevice.getItems().getCount()); + auto serverComponentA1 = serverSubDevice.getItem("componentA").asPtr().getItems()[0]; + auto clientComponentA1 = clientSubDevice.getItem("componentA").asPtr().getItems()[0]; + ASSERT_EQ(serverComponentA1.getPropertyValue("StringProp"), clientComponentA1.getPropertyValue("StringProp")); + + auto serverComponentB = serverSubDevice.getItem("componentB"); + auto clientComponentB = clientSubDevice.getItem("componentB"); + ASSERT_EQ(serverComponentB.getName(), clientComponentB.getName()); + ASSERT_EQ(clientComponentB.getPropertyValue("IntProp"), clientComponentB.getPropertyValue("IntProp")); +} + +TEST_F(TmsDeviceTest, ComponentMethods) +{ + auto ctx = NullContext(); + DevicePtr serverDevice = createDevice(); + + auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto nodeId = serverTmsDevice.registerOpcUaNode(); + + auto serverSubDevice = serverDevice.getDevices()[1]; + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + auto clientSubDevice = clientDevice.getDevices()[1]; + + ASSERT_EQ(serverSubDevice.getName(), clientSubDevice.getName()); + + auto tags = serverSubDevice.getTags(); + auto clientTags = clientSubDevice.getTags(); + + ASSERT_TRUE(tags.query("phys_device")); + ASSERT_TRUE(clientTags.query("phys_device")); + + clientDevice.setActive(false); + ASSERT_EQ(serverDevice.getActive(), clientDevice.getActive()); + + clientDevice.setActive(true); + ASSERT_EQ(serverDevice.getActive(), clientDevice.getActive()); +} + +TEST_F(TmsDeviceTest, DeviceProcedureProperty) +{ + auto ctx = NullContext(); + DevicePtr serverDevice = createDevice(); + + auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto nodeId = serverTmsDevice.registerOpcUaNode(); + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + auto clientSubDevice = clientDevice.getDevices()[1]; + + auto procProp = clientSubDevice.getProperty("stop"); + ASSERT_EQ(procProp.getValueType(), ctProc); + + ProcedurePtr proc = clientSubDevice.getPropertyValue("stop"); + ASSERT_NO_THROW(proc()); +} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp new file mode 100644 index 0000000..558a621 --- /dev/null +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp @@ -0,0 +1,150 @@ +#include "coreobjects/property_object_factory.h" +#include "opcuatms_client/objects/tms_client_folder_factory.h" +#include "opcuatms_server/objects/tms_server_folder.h" +#include "opendaq/context_factory.h" +#include "tms_object_integration_test.h" +#include "opcuatms_client/objects/tms_client_io_folder_factory.h" +#include "opendaq/io_folder_factory.h" +#include "opendaq/mock/mock_channel_factory.h" + +using namespace daq; +using namespace opcua::tms; +using namespace opcua; + +struct RegisteredFolder +{ + TmsServerFolderPtr serverObject; + FolderPtr serverFolder; + FolderPtr clientFolder; +}; + +class TmsFolderTest : public TmsObjectIntegrationTest +{ +public: + FolderPtr createTestFolder() + { + auto folder1 = Folder(NullContext(), nullptr, "parent"); + auto folder2 = Folder(NullContext(), folder1, "child"); + folder1.addItem(folder2); + auto leafFolder = Folder(NullContext(), folder2, "folder"); + folder2.addItem(leafFolder); + + folder2.addProperty(StringProperty("foo", "bar")); + auto obj = PropertyObject(); + obj.addProperty(IntProperty("int", 0)); + leafFolder.addProperty(ObjectProperty("obj", obj)); + + folder1.getTags().add("tag1"); + folder2.getTags().add("tag2"); + + return folder1; + } + + FolderPtr createTestIOFolder() + { + auto folder1 = IoFolder(NullContext(), nullptr, "parent"); + auto folder2 = IoFolder(NullContext(), folder1, "child"); + folder1.addItem(folder2); + auto channel = MockChannel(NullContext(), folder2, "channel"); + folder2.addItem(channel); + + return folder1; + } + + RegisteredFolder registerTestFolder(const FolderPtr& testFolder) + { + RegisteredFolder folder{}; + + folder.serverFolder = testFolder; + folder.serverObject = std::make_shared(folder.serverFolder, this->getServer(), NullContext()); + auto nodeId = folder.serverObject->registerOpcUaNode(); + if (testFolder.asPtrOrNull().assigned()) + folder.clientFolder = TmsClientIoFolder(NullContext(), nullptr, "test", clientContext, nodeId); + else + folder.clientFolder = TmsClientFolder(NullContext(), nullptr, "test", clientContext, nodeId); + + return folder; + } +}; + +TEST_F(TmsFolderTest, Create) +{ + auto folder = createTestFolder(); + auto serverFolder = TmsServerFolder(folder, this->getServer(), NullContext()); +} + +TEST_F(TmsFolderTest, Register) +{ + auto folder = registerTestFolder(createTestFolder()); +} + +TEST_F(TmsFolderTest, Active) +{ + auto folder = registerTestFolder(createTestFolder()); + + folder.clientFolder.setActive(false); + ASSERT_EQ(folder.serverFolder.getActive(), folder.clientFolder.getActive()); + + folder.clientFolder.setActive(true); + ASSERT_EQ(folder.serverFolder.getActive(), folder.clientFolder.getActive()); + + folder.clientFolder.getItems()[0].setActive(false); + ASSERT_EQ(folder.serverFolder.getItems()[0].getActive(), folder.clientFolder.getItems()[0].getActive()); + + + folder.clientFolder.getItems()[0].setActive(false); + ASSERT_EQ(folder.serverFolder.getItems()[0].getActive(), folder.clientFolder.getItems()[0].getActive()); + + + folder.clientFolder.getItems()[0].asPtr().getItems()[0].setActive(false); + ASSERT_EQ(folder.serverFolder.getItems()[0].asPtr().getItems()[0].getActive(), + folder.clientFolder.getItems()[0].asPtr().getItems()[0].getActive()); + + + folder.clientFolder.getItems()[0].asPtr().getItems()[0].setActive(false); + ASSERT_EQ(folder.serverFolder.getItems()[0].asPtr().getItems()[0].getActive(), + folder.clientFolder.getItems()[0].asPtr().getItems()[0].getActive()); +} + +TEST_F(TmsFolderTest, Tags) +{ + auto folder = registerTestFolder(createTestFolder()); + + auto serverTags = folder.serverFolder.getTags().getList(); + auto clientTags = folder.clientFolder.getTags().getList(); + ASSERT_EQ(serverTags.getCount(), clientTags.getCount()); + ASSERT_EQ(serverTags[0], clientTags[0]); + + auto serverTags1 = folder.serverFolder.getItems()[0].getTags().getList(); + auto clientTags2 = folder.clientFolder.getItems()[0].getTags().getList(); + ASSERT_EQ(serverTags1.getCount(), clientTags2.getCount()); + ASSERT_EQ(serverTags1[0], clientTags2[0]); +} + +TEST_F(TmsFolderTest, Properties) +{ + auto folder = registerTestFolder(createTestFolder()); + + PropertyObjectPtr serverObj = folder.serverFolder.getItems()[0].asPtr().getItems()[0].getPropertyValue("obj"); + PropertyObjectPtr clientObj = folder.clientFolder.getItems()[0].asPtr().getItems()[0].getPropertyValue("obj"); + ASSERT_EQ(serverObj.getPropertyValue("int"), clientObj.getPropertyValue("int")); + + ASSERT_EQ(folder.serverFolder.getItems()[0].getPropertyValue("foo"), folder.clientFolder.getItems()[0].getPropertyValue("foo")); + + folder.clientFolder.getItems()[0].setPropertyValue("foo", "notbar"); + ASSERT_EQ(folder.serverFolder.getItems()[0].getPropertyValue("foo"), folder.clientFolder.getItems()[0].getPropertyValue("foo")); +} + +TEST_F(TmsFolderTest, IOFolder) +{ + auto folder = registerTestFolder(createTestIOFolder()); + + ASSERT_TRUE(folder.serverFolder.asPtrOrNull().assigned()); + ASSERT_TRUE(folder.clientFolder.asPtrOrNull().assigned()); + + ASSERT_TRUE(folder.serverFolder.getItems()[0].asPtrOrNull().assigned()); + ASSERT_TRUE(folder.clientFolder.getItems()[0].asPtrOrNull().assigned()); + + ASSERT_TRUE(folder.serverFolder.getItems()[0].asPtrOrNull().getItems()[0].asPtrOrNull().assigned()); + ASSERT_TRUE(folder.clientFolder.getItems()[0].asPtrOrNull().getItems()[0].asPtrOrNull().assigned()); +} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp new file mode 100644 index 0000000..77cd9ba --- /dev/null +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp @@ -0,0 +1,233 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gtest/gtest.h" +#include "opcuaclient/opcuaclient.h" +#include "opcuatms/exceptions.h" +#include "opcuatms_server/objects/tms_server_function_block.h" +#include +#include "opcuatms_client/objects/tms_client_input_port_factory.h" +#include "opcuatms_client/objects/tms_client_signal_factory.h" +#include "open62541/tmsbsp_nodeids.h" +#include "tms_object_integration_test.h" + +#include "opendaq/mock/mock_fb_factory.h" + +using namespace daq; +using namespace opcua::tms; +using namespace opcua; + +class TmsFunctionBlockTest : public TmsObjectIntegrationTest +{ +public: + FunctionBlockPtr createFunctionBlock(const FunctionBlockTypePtr& type = FunctionBlockType("uid", "name", "desc")) + { + const auto context = NullContext(); + return MockFunctionBlock(type, context, nullptr, "mockfb"); + } +}; + +TEST_F(TmsFunctionBlockTest, Create) +{ + FunctionBlockPtr functionBlock = createFunctionBlock(); + auto tmsFunctionBlock = TmsServerFunctionBlock(functionBlock, this->getServer(), NullContext()); +} + +TEST_F(TmsFunctionBlockTest, Register) +{ + FunctionBlockPtr functionBlock = createFunctionBlock(); + auto serverFunctionBlock = TmsServerFunctionBlock(functionBlock, this->getServer(), NullContext()); // Not possible either + auto nodeId = serverFunctionBlock.registerOpcUaNode(); + + FunctionBlockPtr clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, nodeId); + ASSERT_TRUE(clientFunctionBlock.assigned()); +} + +TEST_F(TmsFunctionBlockTest, BrowseName) +{ + // Build functionBlock info: + const FunctionBlockTypePtr type = FunctionBlockType("UNIQUE ID", "NAME", "DESCRIPTION"); + + // Build server functionBlock + auto serverFunctionBlock = createFunctionBlock(type); + + ASSERT_EQ(serverFunctionBlock.getFunctionBlockType(), type); + + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto nodeId = tmsServerFunctionBlock.registerOpcUaNode(); + + FunctionBlockPtr clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, nodeId); + + auto browseName = client->readBrowseName(nodeId); + ASSERT_EQ(browseName, "mockfb"); + + auto displayName = client->readDisplayName(nodeId); + ASSERT_EQ(displayName, "mockfb"); +} + +TEST_F(TmsFunctionBlockTest, AttrFunctionBlockType) +{ + // Build functionBlock info: + const FunctionBlockTypePtr type = FunctionBlockType("UNIQUE ID", "NAME", "DESCRIPTION"); + + // Build server functionBlock + auto serverFunctionBlock = createFunctionBlock(type); + + ASSERT_EQ(serverFunctionBlock.getFunctionBlockType(), type); + + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto nodeId = tmsServerFunctionBlock.registerOpcUaNode(); + + FunctionBlockPtr clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, nodeId); + + auto clientType = clientFunctionBlock.getFunctionBlockType(); + ASSERT_EQ(clientType.getId(), "UNIQUE ID"); + ASSERT_EQ(clientType.getName(), "NAME"); + ASSERT_EQ(clientType.getDescription(), "DESCRIPTION"); +} + +TEST_F(TmsFunctionBlockTest, MethodGetInputPorts) +{ + const FunctionBlockTypePtr type = FunctionBlockType("UNIQUE ID", "NAME", "DESCRIPTION"); + auto serverFunctionBlock = createFunctionBlock(type); + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto functionBlockNodeId = tmsServerFunctionBlock.registerOpcUaNode(); + + FunctionBlockPtr clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, functionBlockNodeId); + + auto inputPorts = clientFunctionBlock.getInputPorts(); + ASSERT_TRUE(inputPorts != nullptr); + + ASSERT_EQ(inputPorts.getCount(), 2u); // Mock function block creates 2 input ports + ASSERT_EQ(inputPorts[0].getLocalId(), "TestInputPort1"); + ASSERT_EQ(inputPorts[1].getLocalId(), "TestInputPort2"); +} + +TEST_F(TmsFunctionBlockTest, MethodGetSignals) +{ + const FunctionBlockTypePtr type = FunctionBlockType("UNIQUE ID", "NAME", "DESCRIPTION"); + auto serverFunctionBlock = createFunctionBlock(type); + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto functionBlockNodeId = tmsServerFunctionBlock.registerOpcUaNode(); + + auto clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, functionBlockNodeId); + + ListPtr signals; + ASSERT_NO_THROW(signals = clientFunctionBlock.getSignals()); + ASSERT_TRUE(signals.assigned()); + + ASSERT_EQ(signals.getCount(), 5u); + ASSERT_EQ(signals[0].getDescriptor().getName(), "Signal1"); + ASSERT_EQ(signals[1].getDescriptor().getName(), "Signal2"); + ASSERT_EQ(signals[2].getDescriptor().getName(), "Signal3"); + ASSERT_EQ(signals[3].getDescriptor().getName(), "Signal4"); + ASSERT_EQ(signals[4].getDescriptor().getName(), "NestedSignal1"); +} + +TEST_F(TmsFunctionBlockTest, SignalCheckGlobalId) +{ + const FunctionBlockTypePtr type = FunctionBlockType("UNIQUE ID", "NAME", "DESCRIPTION"); + auto serverFunctionBlock = createFunctionBlock(type); + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto functionBlockNodeId = tmsServerFunctionBlock.registerOpcUaNode(); + + auto clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, serverFunctionBlock.getLocalId(), clientContext, functionBlockNodeId); + + ListPtr serverSignals = serverFunctionBlock.getSignals(); + ListPtr clientSignals = clientFunctionBlock.getSignals(); + + for (size_t i = 0; i < serverSignals.getCount(); i++) + ASSERT_EQ(serverSignals[i].getGlobalId(), clientSignals[i].getGlobalId()); +} + +TEST_F(TmsFunctionBlockTest, MethodGetStatusSignal) +{ + const FunctionBlockTypePtr type = FunctionBlockType("UNIQUE ID", "NAME", "DESCRIPTION"); + auto serverFunctionBlock = createFunctionBlock(type); + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto functionBlockNodeId = tmsServerFunctionBlock.registerOpcUaNode(); + + SignalPtr serverSignal = Signal(NullContext(), nullptr, "sig"); + auto tmsServerSignal = TmsServerSignal(serverSignal, this->getServer(), NullContext()); + auto signalNodeId = tmsServerSignal.registerOpcUaNode(); + + OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASSTATUSSIGNAL); + getServer()->addReference(functionBlockNodeId, referenceTypeId, signalNodeId, true); + + FunctionBlockPtr clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, functionBlockNodeId); + SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, signalNodeId); + + auto statusSignal = clientFunctionBlock.getStatusSignal(); + ASSERT_EQ(statusSignal, clientSignal); +} + +TEST_F(TmsFunctionBlockTest, Property) +{ + const FunctionBlockTypePtr serverFunctionBlockType = FunctionBlockType("UNIQUE ID", "NAME", "DESCRIPTION"); + auto serverFunctionBlock = createFunctionBlock(serverFunctionBlockType); + + const auto sampleRateProp = FloatPropertyBuilder("SampleRate", 100.0).setUnit(Unit("Hz")).setMinValue(1.0).setMaxValue(1000000.0).build(); + + serverFunctionBlock.addProperty(sampleRateProp); + + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto nodeId = tmsServerFunctionBlock.registerOpcUaNode(); + + auto clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, nodeId); + + auto visibleProperties = clientFunctionBlock.getVisibleProperties(); + ASSERT_EQ(visibleProperties.getCount(), 1u); + ASSERT_EQ(visibleProperties[0].getName(), "SampleRate"); + + auto properties = clientFunctionBlock.getAllProperties(); + ASSERT_EQ(properties.getCount(), 1u); + ASSERT_EQ(properties[0].getName(), "SampleRate"); + + ASSERT_TRUE(clientFunctionBlock.hasProperty("SampleRate")); + ASSERT_EQ(clientFunctionBlock.getPropertyValue("SampleRate"), 100.0); + + clientFunctionBlock.setPropertyValue("SampleRate", 14.0); + ASSERT_EQ(clientFunctionBlock.getPropertyValue("SampleRate"), 14.0); + ASSERT_EQ(serverFunctionBlock.getPropertyValue("SampleRate"), 14.0); +} + +TEST_F(TmsFunctionBlockTest, NestedFunctionBlocks) +{ + auto serverFunctionBlock = createFunctionBlock(); + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto functionBlockNodeId = tmsServerFunctionBlock.registerOpcUaNode(); + + FunctionBlockPtr clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, functionBlockNodeId); + ASSERT_NO_THROW(clientFunctionBlock.getFunctionBlocks()); + auto nestedFunctionBlocks = clientFunctionBlock.getFunctionBlocks(); + ASSERT_EQ(nestedFunctionBlocks.getCount(), 1u); +} + +TEST_F(TmsFunctionBlockTest, ComponentMethods) +{ + auto serverFunctionBlock = createFunctionBlock(); + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto functionBlockNodeId = tmsServerFunctionBlock.registerOpcUaNode(); + + FunctionBlockPtr clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, functionBlockNodeId); + + ASSERT_EQ(serverFunctionBlock.getName(), clientFunctionBlock.getName()); + + auto tags = serverFunctionBlock.getTags(); + auto clientTags = clientFunctionBlock.getTags(); + + ASSERT_TRUE(tags.query("mock_fb")); + ASSERT_TRUE(clientTags.query("mock_fb")); + + clientFunctionBlock.setActive(false); + ASSERT_EQ(serverFunctionBlock.getActive(), clientFunctionBlock.getActive()); + + clientFunctionBlock.setActive(true); + ASSERT_EQ(serverFunctionBlock.getActive(), clientFunctionBlock.getActive()); +} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_property.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_property.cpp new file mode 100644 index 0000000..ab76f86 --- /dev/null +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_property.cpp @@ -0,0 +1,301 @@ +#include +#include "coreobjects/callable_info_factory.h" +#include "coreobjects/property_object_factory.h" +#include "gtest/gtest.h" +#include "opcuatms_client/objects/tms_client_property_object_factory.h" +#include "opcuatms_client/objects/tms_client_property_object_impl.h" +#include "opcuatms_server/objects/tms_server_property_object.h" +#include "tms_object_integration_test.h" +#include "coreobjects/argument_info_factory.h" +#include "opendaq/context_factory.h" + +using namespace daq; +using namespace opcua::tms; +using namespace opcua; + +struct RegisteredPropertyObject +{ + TmsServerPropertyObjectPtr serverProp; + PropertyObjectPtr clientProp; +}; + +class TmsFunctionTest: public TmsObjectIntegrationTest +{ +public: + RegisteredPropertyObject registerPropertyObject(const PropertyObjectPtr& obj) + { + const auto serverProp = std::make_shared(obj, server, NullContext()); + const auto nodeId = serverProp->registerOpcUaNode(); + const auto clientProp = TmsClientPropertyObject(NullContext(), clientContext, nodeId); + return {serverProp, clientProp}; + } +}; + +TEST_F(TmsFunctionTest, ProcedureNoArgs) +{ + auto obj = PropertyObject(); + obj.addProperty(FunctionProperty("proc", ProcedureInfo())); + bool called = false; + auto proc = Procedure([&called]() { called = true; }); + obj.setPropertyValue("proc", proc); + + auto [serverObj, clientObj] = registerPropertyObject(obj); + ProcedurePtr clientProc = clientObj.getPropertyValue("proc"); + ASSERT_NO_THROW(clientProc()); + ASSERT_EQ(called, true); +} + +TEST_F(TmsFunctionTest, FunctionNoArgs) +{ + auto obj = PropertyObject(); + obj.addProperty(FunctionProperty("func", FunctionInfo(ctBool))); + auto func = Function([]() { return true; }); + obj.setPropertyValue("func", func); + + auto [serverObj, clientObj] = registerPropertyObject(obj); + FunctionPtr clientFunc = clientObj.getPropertyValue("func"); + ASSERT_TRUE(clientFunc()); +} + +TEST_F(TmsFunctionTest, ProcedureOneArg) +{ + auto obj = PropertyObject(); + obj.addProperty(FunctionProperty("proc", ProcedureInfo(List(ArgumentInfo("int", ctInt))))); + Int callValue; + auto proc = Procedure([&callValue](const IntegerPtr& arg) { callValue = arg; }); + obj.setPropertyValue("proc", proc); + + auto [serverObj, clientObj] = registerPropertyObject(obj); + ProcedurePtr clientProc = clientObj.getPropertyValue("proc"); + + ASSERT_NO_THROW(clientProc(10)); + ASSERT_EQ(callValue, 10); + + ASSERT_NO_THROW(clientProc(100)); + ASSERT_EQ(callValue, 100); +} + +TEST_F(TmsFunctionTest, FunctionOneArg) +{ + auto obj = PropertyObject(); + obj.addProperty(FunctionProperty("func", FunctionInfo(ctInt, List(ArgumentInfo("int", ctInt))))); + Int callValue; + auto func = Function([&callValue](const IntegerPtr& arg) { return arg; }); + obj.setPropertyValue("func", func); + + auto [serverObj, clientObj] = registerPropertyObject(obj); + FunctionPtr clientFunc = clientObj.getPropertyValue("func"); + + ASSERT_EQ(clientFunc(10), 10); + ASSERT_EQ(clientFunc(100), 100); +} + +TEST_F(TmsFunctionTest, ProcedureMultipleArgs) +{ + auto obj = PropertyObject(); + obj.addProperty(FunctionProperty( + "proc", ProcedureInfo(List(ArgumentInfo("int", ctInt), ArgumentInfo("ratio", ctRatio), ArgumentInfo("string", ctString))))); + + Int intArg; + RatioPtr ratioArg; + StringPtr stringArg; + auto proc = Procedure([&intArg, &ratioArg, &stringArg](const ListPtr& args) + { + intArg = args[0]; + ratioArg = args[1]; + stringArg = args[2]; + }); + obj.setPropertyValue("proc", proc); + + auto [serverObj, clientObj] = registerPropertyObject(obj); + ProcedurePtr clientProc = clientObj.getPropertyValue("proc"); + + clientProc(10, Ratio(1, 20), "foo"); + + ASSERT_EQ(intArg, 10); + ASSERT_EQ(ratioArg, Ratio(1, 20)); + ASSERT_EQ(stringArg, "foo"); +} + +TEST_F(TmsFunctionTest, FunctionMultipleArgs) +{ + auto obj = PropertyObject(); + obj.addProperty(FunctionProperty( + "func", + FunctionInfo(ctBool, List(ArgumentInfo("int", ctInt), ArgumentInfo("ratio", ctRatio), ArgumentInfo("string", ctString))))); + + auto func = Function([](const ListPtr& args) + { + bool valid = args[0] == 10; + valid = valid && args[1] == Ratio(1, 20); + valid = valid && args[2] == "foo"; + return valid; + }); + obj.setPropertyValue("func", func); + + auto [serverObj, clientObj] = registerPropertyObject(obj); + FunctionPtr clientProc = clientObj.getPropertyValue("func"); + + ASSERT_EQ(clientProc(10, Ratio(1, 20), "foo"), true); + ASSERT_EQ(clientProc(10, Ratio(1, 20), "bar"), false); +} + +TEST_F(TmsFunctionTest, AllArgTypes) +{ + auto obj = PropertyObject(); + obj.addProperty(FunctionProperty( + "proc", + ProcedureInfo(List(ArgumentInfo("int", ctInt), + ArgumentInfo("ratio", ctRatio), + ArgumentInfo("string", ctString), + ArgumentInfo("bool", ctBool), + ArgumentInfo("float", ctFloat))))); + + Int intArg; + RatioPtr ratioArg; + StringPtr stringArg; + Bool boolArg; + Float floatArg; + auto proc = Procedure( + [&intArg, &ratioArg, &stringArg, &boolArg, &floatArg](const ListPtr& args) + { + intArg = args[0]; + ratioArg = args[1]; + stringArg = args[2]; + boolArg = args[3]; + floatArg = args[4]; + }); + obj.setPropertyValue("proc", proc); + + auto [serverObj, clientObj] = registerPropertyObject(obj); + ProcedurePtr clientProc = clientObj.getPropertyValue("proc"); + + clientProc(10, Ratio(1, 20), "foo", false, 1.123); + + ASSERT_EQ(intArg, 10); + ASSERT_EQ(ratioArg, Ratio(1, 20)); + ASSERT_EQ(stringArg, "foo"); + ASSERT_EQ(boolArg, false); + ASSERT_EQ(floatArg, 1.123); +} + +TEST_F(TmsFunctionTest, InvalidArgTypes) +{ + auto obj = PropertyObject(); + obj.addProperty(FunctionProperty("proc", ProcedureInfo(List(ArgumentInfo("int", ctInt))))); + Int callValue; + auto proc = Procedure([&callValue](const IntegerPtr& arg) { callValue = arg; }); + obj.setPropertyValue("proc", proc); + + auto [serverObj, clientObj] = registerPropertyObject(obj); + ProcedurePtr clientProc = clientObj.getPropertyValue("proc"); + + ASSERT_THROW(clientProc("foo"), CallFailedException); +} + +// NOTE: Should this throw an error? +TEST_F(TmsFunctionTest, InvalidReturnType) +{ + auto obj = PropertyObject(); + obj.addProperty(FunctionProperty("func", FunctionInfo(ctBool))); + auto func = Function([]() { return "str"; }); + obj.setPropertyValue("func", func); + + auto [serverObj, clientObj] = registerPropertyObject(obj); + FunctionPtr clientFunc = clientObj.getPropertyValue("func"); + + ASSERT_EQ(clientFunc(), "str"); +} + +TEST_F(TmsFunctionTest, InvalidArgCount) +{ + auto obj = PropertyObject(); + obj.addProperty(FunctionProperty("proc", ProcedureInfo(List(ArgumentInfo("int", ctInt))))); + Int callValue; + auto proc = Procedure([&callValue](const IntegerPtr& arg) { callValue = arg; }); + obj.setPropertyValue("proc", proc); + + auto [serverObj, clientObj] = registerPropertyObject(obj); + ProcedurePtr clientProc = clientObj.getPropertyValue("proc"); + + ASSERT_THROW(clientProc(), CallFailedException); + ASSERT_THROW(clientProc(1, 2), CallFailedException); +} + +TEST_F(TmsFunctionTest, ProcedureArgumentInfo) +{ + auto obj = PropertyObject(); + obj.addProperty(FunctionProperty( + "proc", + ProcedureInfo(List(ArgumentInfo("int", ctInt), + ArgumentInfo("ratio", ctRatio), + ArgumentInfo("string", ctString), + ArgumentInfo("bool", ctBool), + ArgumentInfo("float", ctFloat))))); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + ASSERT_EQ(obj.getProperty("proc").getCallableInfo(), clientObj.getProperty("proc").getCallableInfo()); +} + +TEST_F(TmsFunctionTest, FunctionArgumentInfo) +{ + auto obj = PropertyObject(); + obj.addProperty(FunctionProperty( + "func", + FunctionInfo(ctInt, List(ArgumentInfo("int", ctInt), + ArgumentInfo("ratio", ctRatio), + ArgumentInfo("string", ctString), + ArgumentInfo("bool", ctBool), + ArgumentInfo("float", ctFloat))))); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + ASSERT_EQ(obj.getProperty("func").getCallableInfo(), clientObj.getProperty("func").getCallableInfo()); +} + +TEST_F(TmsFunctionTest, UnsupportedArgumentInfo) +{ + auto obj = PropertyObject(); + obj.addProperty(FunctionProperty("proc1", ProcedureInfo(List(ArgumentInfo("list", ctList))))); + obj.addProperty(FunctionProperty("proc2", ProcedureInfo(List(ArgumentInfo("dict", ctDict))))); + obj.addProperty(FunctionProperty("proc3", ProcedureInfo(List(ArgumentInfo("proc", ctProc))))); + obj.addProperty(FunctionProperty("proc4", ProcedureInfo(List(ArgumentInfo("object", ctObject))))); + obj.addProperty(FunctionProperty("proc5", ProcedureInfo(List(ArgumentInfo("binary_data", ctBinaryData))))); + obj.addProperty(FunctionProperty("proc6", ProcedureInfo(List(ArgumentInfo("func", ctFunc))))); + obj.addProperty(FunctionProperty("proc7", ProcedureInfo(List(ArgumentInfo("complex_number", ctComplexNumber))))); + obj.addProperty(FunctionProperty("proc8", ProcedureInfo(List(ArgumentInfo("undefined", ctUndefined))))); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + ASSERT_EQ(clientObj.getAllProperties().getCount(), 0); +} + +TEST_F(TmsFunctionTest, UnsupportedReturnType) +{ + auto obj = PropertyObject(); + obj.addProperty(FunctionProperty("func1", FunctionInfo(ctList))); + obj.addProperty(FunctionProperty("func2", FunctionInfo(ctDict))); + obj.addProperty(FunctionProperty("func3", FunctionInfo(ctProc))); + obj.addProperty(FunctionProperty("func4", FunctionInfo(ctObject))); + obj.addProperty(FunctionProperty("func5", FunctionInfo(ctBinaryData))); + obj.addProperty(FunctionProperty("func6", FunctionInfo(ctFunc))); + obj.addProperty(FunctionProperty("func7", FunctionInfo(ctComplexNumber))); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + ASSERT_EQ(clientObj.getAllProperties().getCount(), 0); +} + + +TEST_F(TmsFunctionTest, ServerThrow) +{ + auto obj = PropertyObject(); + obj.addProperty(FunctionProperty("func", FunctionInfo(ctBool))); + auto func = Function([]() + { + throw GeneralErrorException{}; + return false; + }); + obj.setPropertyValue("func", func); + + auto [serverObj, clientObj] = registerPropertyObject(obj); + FunctionPtr clientFunc = clientObj.getPropertyValue("func"); + ASSERT_ANY_THROW(clientFunc()); +} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp new file mode 100644 index 0000000..3211944 --- /dev/null +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp @@ -0,0 +1,208 @@ +#include +#include +#include +#include +#include "gtest/gtest.h" +#include "opcuaclient/opcuaclient.h" +#include "opcuatms/exceptions.h" +#include "opcuatms_client/objects/tms_client_input_port_factory.h" +#include "opcuatms_client/objects/tms_client_signal_factory.h" +#include "opcuatms_server/objects/tms_server_input_port.h" +#include "opcuatms_server/objects/tms_server_signal.h" +#include "tms_object_integration_test.h" +#include +#include +#include +#include +#include +#include + +using namespace daq; +using namespace opcua::tms; +using namespace opcua; + +class TmsInputPortTest : public TmsObjectIntegrationTest +{ +public: + InputPortPtr createInputPort(std::string name, Bool requiresSignal) + { + auto ip = InputPort(NullContext(), nullptr, name); + ip.setRequiresSignal(requiresSignal); + ip.getTags().add("port"); + return ip; + } +}; + +TEST_F(TmsInputPortTest, Create) +{ + InputPortPtr inputPort = createInputPort("The Name", false); + auto tmsInputPort = TmsServerInputPort(inputPort, this->getServer(), NullContext()); +} + +TEST_F(TmsInputPortTest, Register) +{ + const std::string name{"Some Name"}; + InputPortPtr daqServerInputPort = createInputPort(name, false); + auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), NullContext()); + auto nodeId = serverInputPort.registerOpcUaNode(); + + InputPortPtr clientInputPort = TmsClientInputPort(NullContext(), nullptr, "inputPort", clientContext, nodeId); + ASSERT_TRUE(clientInputPort.assigned()); +} + +TEST_F(TmsInputPortTest, BrowseName) +{ + const std::string name{"Some Name"}; + InputPortPtr daqServerInputPort = createInputPort(name, false); + auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), NullContext()); + auto nodeId = serverInputPort.registerOpcUaNode(); + + auto browseName = client->readBrowseName(nodeId); + ASSERT_EQ(browseName, name); +} + +TEST_F(TmsInputPortTest, AttrName) +{ + const std::string name{"Test Name"}; + InputPortPtr daqServerInputPort = createInputPort(name, false); + ASSERT_FALSE(daqServerInputPort.getRequiresSignal()); + ASSERT_EQ(daqServerInputPort.getLocalId(), name); + + auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), NullContext()); + auto nodeId = serverInputPort.registerOpcUaNode(); + + auto browseName = clientContext->getClient()->readBrowseName(nodeId); + InputPortPtr clientInputPort = TmsClientInputPort(NullContext(), nullptr, browseName, clientContext, nodeId); + + ASSERT_EQ(daqServerInputPort.getLocalId(), clientInputPort.getLocalId()); + ASSERT_EQ(clientInputPort.getLocalId(), name); +} + +TEST_F(TmsInputPortTest, AttrRequiresSignalFalse) +{ + InputPortPtr daqServerInputPort = createInputPort("The Name", false); + auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), NullContext()); + auto nodeId = serverInputPort.registerOpcUaNode(); + + InputPortPtr clientInputPort = TmsClientInputPort(NullContext(), nullptr, "inputPort", clientContext, nodeId); + + ASSERT_FALSE(IsTrue(daqServerInputPort.getRequiresSignal())); + ASSERT_FALSE(IsTrue(clientInputPort.getRequiresSignal())); +} + +TEST_F(TmsInputPortTest, AttrRequiresSignalTrue) +{ + InputPortPtr daqServerInputPort = createInputPort("The Name", true); + auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), NullContext()); + auto nodeId = serverInputPort.registerOpcUaNode(); + + InputPortPtr clientInputPort = TmsClientInputPort(NullContext(), nullptr, "inputPort", clientContext, nodeId); + + ASSERT_TRUE(IsTrue(daqServerInputPort.getRequiresSignal())); + ASSERT_TRUE(IsTrue(clientInputPort.getRequiresSignal())); +} + +TEST_F(TmsInputPortTest, MethodAcceptsSignal) +{ + SignalPtr signal = Signal(NullContext(), nullptr, "sig"); + InputPortPtr daqServerInputPort = createInputPort("The Name", true); + auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), NullContext()); + auto nodeId = serverInputPort.registerOpcUaNode(); + + InputPortPtr clientInputPort = TmsClientInputPort(NullContext(), nullptr, "inputPort", clientContext, nodeId); + + //TODO: More testing when the server in fact really checks the signal if the signal is ok + EXPECT_THROW(clientInputPort.acceptsSignal(signal), daq::opcua::OpcUaClientCallNotAvailableException); +} + +TEST_F(TmsInputPortTest, MethodConnectSignal) +{ + SignalPtr signal = Signal(NullContext(), nullptr, "sig"); + + InputPortPtr daqServerInputPort = createInputPort("The Name", true); + auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), NullContext()); + auto nodeId = serverInputPort.registerOpcUaNode(); + + InputPortPtr clientInputPort = TmsClientInputPort(NullContext(), nullptr, "inputPort", clientContext, nodeId); + + //TODO: More testing when the server in fact really can connect the signal + EXPECT_THROW(clientInputPort.connect(signal), daq::opcua::OpcUaClientCallNotAvailableException); +} + +TEST_F(TmsInputPortTest, MethodDisconnectSignal) +{ + InputPortPtr daqServerInputPort = createInputPort("The Name", true); + auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), NullContext()); + auto nodeId = serverInputPort.registerOpcUaNode(); + + InputPortPtr clientInputPort = TmsClientInputPort(NullContext(), nullptr, "inputPort", clientContext, nodeId); + + //TODO: More testing when the server in fact really can disconnect the signal + EXPECT_THROW(clientInputPort.disconnect(), daq::opcua::OpcUaClientCallNotAvailableException); + //auto status = clientInputPort->disconnect(); + //ASSERT_EQ(status, OPENDAQ_SUCCESS); //TODO: Should fail when implemented on the server as nothing is connected + + //SignalPtr signal = Signal(nullptr); + //status = clientInputPort->connect(signal); + //ASSERT_EQ(status, OPENDAQ_SUCCESS); + + //status = clientInputPort->disconnect(); + //ASSERT_EQ(status, OPENDAQ_SUCCESS); + + //status = clientInputPort->disconnect(); + //ASSERT_EQ(status, OPENDAQ_SUCCESS); //TODO: Should fail when implemented on the server as nothing is connected +} + +TEST_F(TmsInputPortTest, ConnectedToReference) +{ + const auto logger = Logger(); + const auto scheduler = Scheduler(logger); + const auto context = Context(scheduler, logger, nullptr, nullptr); + + SignalPtr signal = Signal(context, nullptr, "sig"); + + auto serverSignal = TmsServerSignal(signal, this->getServer(), NullContext()); + auto signalNodeId = serverSignal.registerOpcUaNode(); + + InputPortNotificationsPtr inputPortNotification = TestInputPortNotifications(); + + InputPortConfigPtr inputPort = InputPort(NullContext(), nullptr, "inputPort"); + inputPort.setListener(inputPortNotification); + inputPort.connect(signal); + + auto serverInputPort = TmsServerInputPort(inputPort, this->getServer(), NullContext()); + auto inputPortNodeId = serverInputPort.registerOpcUaNode(); + + ASSERT_NO_THROW(serverInputPort.createNonhierarchicalReferences()); + + InputPortPtr clientInputPort = TmsClientInputPort(NullContext(), nullptr, "inputPort", clientContext, inputPortNodeId); + SignalPtr clientSignal = TmsClientSignal(context, nullptr, "sig", clientContext, signalNodeId); + + auto connectedSignal = clientInputPort.getSignal(); + ASSERT_TRUE(connectedSignal.assigned()); + ASSERT_EQ(connectedSignal, clientSignal); +} + +TEST_F(TmsInputPortTest, ComponentMethods) +{ + const std::string name{"inputPort"}; + InputPortPtr daqServerInputPort = createInputPort(name, false); + auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), NullContext()); + auto nodeId = serverInputPort.registerOpcUaNode(); + + InputPortPtr clientInputPort = TmsClientInputPort(NullContext(), nullptr, "inputPort", clientContext, nodeId); + + ASSERT_EQ(daqServerInputPort.getName(), clientInputPort.getName()); + + auto tags = daqServerInputPort.getTags(); + auto clientTags = clientInputPort.getTags(); + + ASSERT_TRUE(tags.query("port")); + ASSERT_TRUE(clientTags.query("port")); + + clientInputPort.setActive(false); + ASSERT_EQ(daqServerInputPort.getActive(), clientInputPort.getActive()); + + clientInputPort.setActive(true); + ASSERT_EQ(daqServerInputPort.getActive(), clientInputPort.getActive()); +} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp new file mode 100644 index 0000000..d59db45 --- /dev/null +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -0,0 +1,238 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace daq; +using namespace daq::opcua; +using namespace std::chrono_literals; + +class TmsIntegrationTest : public testing::Test +{ +public: + const std::string OPC_URL = "opc.tcp://localhost/"; + + InstancePtr createDevice() + { + const auto moduleManager = ModuleManager("[[none]]"); + auto logger = Logger(); + auto context = Context(Scheduler(logger, 1), logger, TypeManager(), moduleManager); + + const ModulePtr deviceModule(MockDeviceModule_Create(context)); + moduleManager.addModule(deviceModule); + + const ModulePtr fbModule(MockFunctionBlockModule_Create(context)); + moduleManager.addModule(fbModule); + + auto instance = InstanceCustom(context, "localInstance"); + instance.addDevice("daq_client_device"); + instance.addDevice("mock_phys_device"); + instance.addFunctionBlock("mock_fb_uid"); + + return instance; + } + + void SetUp() override + { + } + + void TearDown() override + { + } +}; + +TEST_F(TmsIntegrationTest, Connect) +{ + InstancePtr device = createDevice(); + + TmsServer tmsServer(device); + tmsServer.start(); + + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + DevicePtr clientDevice; + ASSERT_NO_THROW(clientDevice = tmsClient.connect()); + ASSERT_TRUE(clientDevice.assigned()); +} + +TEST_F(TmsIntegrationTest, Devices) +{ + InstancePtr device = createDevice(); + + TmsServer tmsServer(device); + tmsServer.start(); + + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + DevicePtr clientDevice = tmsClient.connect(); + auto devices = clientDevice.getDevices(); + ASSERT_EQ(devices.getCount(), 2u); +} + +TEST_F(TmsIntegrationTest, DeviceInfo) +{ + InstancePtr device = createDevice(); + + TmsServer tmsServer(device); + tmsServer.start(); + + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + DevicePtr clientDevice = tmsClient.connect(); + + auto devices = clientDevice.getDevices(); + DeviceInfoPtr deviceInfo; + ASSERT_NO_THROW(deviceInfo = devices[0].getInfo()); +} + +TEST_F(TmsIntegrationTest, FunctionBlocks) +{ + InstancePtr device = createDevice(); + + TmsServer tmsServer(device); + tmsServer.start(); + + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + DevicePtr clientDevice = tmsClient.connect(); + + auto functionBlocks = clientDevice.getFunctionBlocks(); + ASSERT_EQ(functionBlocks.getCount(), 1u); +} + +TEST_F(TmsIntegrationTest, FunctionBlockType) +{ + InstancePtr device = createDevice(); + + TmsServer tmsServer(device); + tmsServer.start(); + + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + DevicePtr clientDevice = tmsClient.connect(); + + auto functionBlocks = clientDevice.getFunctionBlocks(); + FunctionBlockTypePtr type; + ASSERT_NO_THROW(type = functionBlocks[0].getFunctionBlockType()); +} + +TEST_F(TmsIntegrationTest, GetSignals) +{ + InstancePtr device = createDevice(); + + TmsServer tmsServer(device); + tmsServer.start(); + + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + DevicePtr clientDevice = tmsClient.connect(); + + ListPtr signals; + ASSERT_NO_THROW(signals = clientDevice.getSignalsRecursive()); + ASSERT_EQ(signals.getCount(), device.getSignalsRecursive().getCount()); + + ASSERT_NO_THROW(signals = clientDevice.getSignals()); + ASSERT_EQ(signals.getCount(), 0u); +} + +TEST_F(TmsIntegrationTest, GetChannels) +{ + InstancePtr instance = createDevice(); + auto devices = instance.getDevices(); + ASSERT_EQ(devices.getCount(), 2u); + + auto device1 = devices.getItemAt(0); + ASSERT_EQ(device1.getChannels().getCount(), 0u); + + auto device2 = devices.getItemAt(1); + ASSERT_EQ(device2.getChannels().getCount(), 4u); + + ASSERT_EQ(instance.getChannelsRecursive().getCount(), 4u); + ASSERT_EQ(instance.getChannels().getCount(), 0u); +} +TEST_F(TmsIntegrationTest, InputsOutputs) +{ + InstancePtr instance = createDevice(); + auto devices = instance.getDevices(); + ASSERT_EQ(devices.getCount(), 2u); + + auto device1 = devices.getItemAt(0); // device 1: No channels + ASSERT_EQ(device1.getChannels().getCount(), 0u); + auto device1IoFolder = device1.getInputsOutputsFolder(); // io + ASSERT_TRUE(device1IoFolder.assigned()); + ASSERT_EQ(device1IoFolder.getItems().getCount(), 0); + + + auto device2 = devices.getItemAt(1); // device 2: 4 channels + ASSERT_EQ(device2.getChannels().getCount(), 4u); + + auto device2IoFolder = device2.getInputsOutputsFolder(); // io: 1 channnel, 2 folders + ASSERT_TRUE(device2IoFolder.assigned()); + auto ioItems = device2IoFolder.getItems(); + ASSERT_EQ(ioItems.getCount(), 3); + ASSERT_EQ(ioItems[0].getName(), "mockch1"); // io/mockch1 + ASSERT_TRUE(ioItems[0].asPtrOrNull().assigned()); + ASSERT_TRUE(ioItems[0].asPtrOrNull().assigned()); + + ASSERT_EQ(ioItems[1].getName(), "mockfolderA"); // io/mockfolderA: 1 channel + ASSERT_TRUE(ioItems[1].asPtrOrNull().assigned()); + ASSERT_FALSE(ioItems[1].asPtrOrNull().assigned()); + + auto mockFolderAItems = ioItems[1].asPtr().getItems(); + ASSERT_EQ(mockFolderAItems.getCount(), 1); + + ASSERT_EQ(mockFolderAItems[0].getName(), "mockchA1"); // io/mockfolderA/mockchA1 + ASSERT_TRUE(mockFolderAItems[0].asPtrOrNull().assigned()); + ASSERT_TRUE(mockFolderAItems[0].asPtrOrNull().assigned()); + + + ASSERT_EQ(ioItems[2].getName(), "mockfolderB"); // io/mockFolderB: 2 channels + ASSERT_TRUE(ioItems[2].asPtrOrNull().assigned()); + ASSERT_FALSE(ioItems[2].asPtrOrNull().assigned()); + + auto mockFolderBItems = ioItems[2].asPtr().getItems(); + ASSERT_EQ(mockFolderBItems.getCount(), 2); + + ASSERT_EQ(mockFolderBItems[0].getName(), "mockchB1"); // io/mockfolderB/mockchB1 + ASSERT_TRUE(mockFolderBItems[0].asPtrOrNull().assigned()); + ASSERT_TRUE(mockFolderBItems[0].asPtrOrNull().assigned()); + + ASSERT_EQ(mockFolderBItems[1].getName(), "mockchB2"); // io/mockfolderB/mockchB1 + ASSERT_TRUE(mockFolderBItems[1].asPtrOrNull().assigned()); + ASSERT_TRUE(mockFolderBItems[1].asPtrOrNull().assigned()); +} + +TEST_F(TmsIntegrationTest, CustomComponents) +{ + InstancePtr instance = createDevice(); + auto devices = instance.getDevices(); + ASSERT_EQ(devices.getCount(), 2u); + + auto device2 = devices.getItemAt(1); + ASSERT_EQ(device2.getCustomComponents().getCount(), 2u); + + FolderPtr componentA = device2.getCustomComponents()[0]; + ASSERT_EQ(componentA.getItems().getCount(), 1); +} + +TEST_F(TmsIntegrationTest, GetDomainSignal) +{ + InstancePtr device = createDevice(); + + TmsServer tmsServer(device); + tmsServer.start(); + + DevicePtr clientDevice; + { + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); // The device should work after we delete the builder + clientDevice = tmsClient.connect(); + } + + ListPtr signals = clientDevice.getSignalsRecursive(); + + auto byteStepSignal = *std::find_if( + signals.begin(), signals.end(), [](const SignalPtr& signal) { return signal.getDescriptor().getName() == "ByteStep"; }); + + SignalPtr domainSignal; + ASSERT_NO_THROW(domainSignal = byteStepSignal.getDomainSignal()); + ASSERT_TRUE(domainSignal.assigned()); +} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property.cpp new file mode 100644 index 0000000..b891434 --- /dev/null +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property.cpp @@ -0,0 +1,232 @@ +#include "gtest/gtest.h" +#include "tms_object_integration_test.h" +#include "coreobjects/property_factory.h" +#include "coreobjects/property_object_class_ptr.h" +#include "opcuatms_server/objects/tms_server_property.h" +#include "opcuatms_client/objects/tms_client_property_factory.h" +#include +#include + +using namespace daq; +using namespace opcua::tms; +using namespace opcua; +using namespace std::chrono_literals; + +struct RegisteredProperty +{ + TmsServerPropertyPtr serverProp; + PropertyPtr clientProp; +}; + +class TmsPropertyTest : public TmsObjectIntegrationTest +{ +public: + + PropertyBuilderPtr createIntPropertyBuilder() + { + return IntPropertyBuilder("Age", 10).setDescription("Hello world.").setMinValue(-100).setMaxValue(100); + } + + PropertyPtr createIntProperty() + { + return createIntPropertyBuilder().build(); + } + + PropertyBuilderPtr createEnumPropertyBuilder() + { + auto values = List(); + values.pushBack("banana"); + values.pushBack("apple"); + values.pushBack("blueberry"); + + return SelectionPropertyBuilder("Fruits", values, 0).setDescription("Hello world."); + } + + PropertyPtr createEnumProperty() + { + return createEnumPropertyBuilder().build(); + } + + PropertyBuilderPtr createDictEnumPropertyBuilder() + { + auto values = Dict(); + values.set(0, "banana"); + values.set(2, "apple"); + values.set(5, "blueberry"); + + return SparseSelectionPropertyBuilder("FruitsDict", values, 0).setDescription("Hello world."); + } + + PropertyPtr createDictEnumProperty() + { + return createDictEnumPropertyBuilder().build(); + } + + RegisteredProperty registerProperty(const PropertyPtr& prop) + { + auto serverProp = std::make_shared(prop, server, NullContext()); + auto nodeId = serverProp->registerOpcUaNode(); + auto clientProp = TmsClientProperty(NullContext(), clientContext, nodeId); + return {serverProp, clientProp}; + } +}; + +TEST_F(TmsPropertyTest, Create) +{ + auto prop = createIntProperty(); + + auto serverProp = TmsServerProperty(prop, server, NullContext()); + auto nodeId = serverProp.registerOpcUaNode(); + ASSERT_TRUE(server->nodeExists(nodeId)); + + auto clientProp = TmsClientProperty(NullContext(), clientContext, nodeId); + ASSERT_TRUE(clientProp.assigned()); +} + +TEST_F(TmsPropertyTest, Name) +{ + auto prop = createIntProperty(); + auto [serverProp, clientProp] = registerProperty(prop); + + ASSERT_EQ(clientProp.getName(), prop.getName()); + ASSERT_THROW(client->writeDisplayName(serverProp->getNodeId(), "Name"), OpcUaException); +} + +TEST_F(TmsPropertyTest, Description) +{ + auto prop = createIntProperty(); + auto [serverProp, clientProp] = registerProperty(prop); + + ASSERT_EQ(clientProp.getDescription(), prop.getDescription()); + ASSERT_THROW(client->writeDescription(serverProp->getNodeId(), "New description."), OpcUaException); +} + +TEST_F(TmsPropertyTest, Unit) +{ + auto prop = createIntPropertyBuilder().setUnit(Unit("V", 1, "voltage")).build(); + + auto [serverProp, clientProp] = registerProperty(prop); + + ASSERT_TRUE(BaseObjectPtr::Equals(clientProp.getUnit(), prop.getUnit())); + ASSERT_THROW(writeChildNode(serverProp->getNodeId(), "Unit", OpcUaVariant()), OpcUaException); +} + +TEST_F(TmsPropertyTest, UnitEval) +{ + auto prop = createIntPropertyBuilder().setUnit(EvalValue("Unit('V')")).build(); + + auto [serverProp, clientProp] = registerProperty(prop); + ASSERT_TRUE(BaseObjectPtr::Equals(clientProp.getUnit(), prop.getUnit())); +} + +TEST_F(TmsPropertyTest, IsEnumEnum) +{ + auto prop = createEnumProperty(); + auto [serverProp, clientProp] = registerProperty(prop); + ASSERT_TRUE(clientProp.getSelectionValues().assigned()); +} + +TEST_F(TmsPropertyTest, IsEnumInt) +{ + auto prop = createIntProperty(); + auto [serverProp, clientProp] = registerProperty(prop); + ASSERT_FALSE(clientProp.getSelectionValues().assigned()); +} + +TEST_F(TmsPropertyTest, MinValue) +{ + auto prop = createIntProperty(); + auto [serverProp, clientProp] = registerProperty(prop); + + ASSERT_EQ(clientProp.getMinValue(), prop.getMinValue()); + ASSERT_THROW(writeChildNode(serverProp->getNodeId(), "MinValue", OpcUaVariant()), OpcUaException); +} + +TEST_F(TmsPropertyTest, MinValueEnum) +{ + auto prop = createEnumProperty(); + auto [serverProp, clientProp] = registerProperty(prop); + + ASSERT_FALSE(clientProp.getMinValue().assigned()); +} + +TEST_F(TmsPropertyTest, MaxValue) +{ + auto prop = createIntProperty(); + auto [serverProp, clientProp] = registerProperty(prop); + + ASSERT_EQ(clientProp.getMaxValue(), prop.getMaxValue()); + ASSERT_THROW(writeChildNode(serverProp->getNodeId(), "MaxValue", OpcUaVariant()), OpcUaException); +} + +TEST_F(TmsPropertyTest, MaxValueEnum) +{ + auto prop = createEnumProperty(); + auto [serverProp, clientProp] = registerProperty(prop); + + ASSERT_FALSE(clientProp.getMaxValue().assigned()); +} + +TEST_F(TmsPropertyTest, DefaultValue) +{ + auto prop = createEnumProperty(); + auto [serverProp, clientProp] = registerProperty(prop); + + ASSERT_EQ(clientProp.getDefaultValue(), prop.getDefaultValue()); + ASSERT_THROW(writeChildNode(serverProp->getNodeId(), "DefaultValue", OpcUaVariant()), OpcUaException); +} + +TEST_F(TmsPropertyTest, IsVisible) +{ + auto prop = createIntPropertyBuilder().setVisible(true).build(); + auto [serverProp, clientProp] = registerProperty(prop); + + ASSERT_EQ(clientProp.getVisible(), prop.getVisible()); + ASSERT_THROW(writeChildNode(serverProp->getNodeId(), "IsVisible", OpcUaVariant()), OpcUaException); +} + +TEST_F(TmsPropertyTest, IsVisibleEval) +{ + auto prop = createIntPropertyBuilder().setVisible(EvalValue("3 > 0")).build(); + auto [serverProp, clientProp] = registerProperty(prop); + + ASSERT_EQ(clientProp.getVisible(), prop.getVisible()); +} + +TEST_F(TmsPropertyTest, IsReadOnly) +{ + auto prop = createIntPropertyBuilder().setReadOnly(true).build(); + auto [serverProp, clientProp] = registerProperty(prop); + + ASSERT_EQ(clientProp.getReadOnly(), prop.getReadOnly()); + ASSERT_THROW(writeChildNode(serverProp->getNodeId(), "IsReadOnly", OpcUaVariant()), OpcUaException); +} + +TEST_F(TmsPropertyTest, IsReadOnlyEval) +{ + auto prop = createIntPropertyBuilder().setReadOnly(EvalValue("3 < 0")).build(); + auto [serverProp, clientProp] = registerProperty(prop); + + ASSERT_EQ(clientProp.getReadOnly(), prop.getReadOnly()); +} + +TEST_F(TmsPropertyTest, EnumValues) +{ + auto prop = createEnumProperty(); + auto [serverProp, clientProp] = registerProperty(prop); + + auto sel1 = clientProp.getSelectionValues(); + auto sel2 = prop.getSelectionValues(); + + ASSERT_EQ(clientProp.getSelectionValues(), prop.getSelectionValues()); + ASSERT_THROW(writeChildNode(serverProp->getNodeId(), "EnumValues", OpcUaVariant()), OpcUaException); +} + +TEST_F(TmsPropertyTest, DictEnumValues) +{ + auto prop = createDictEnumProperty(); + auto [serverProp, clientProp] = registerProperty(prop); + + ASSERT_EQ(clientProp.getSelectionValues(), prop.getSelectionValues()); + ASSERT_THROW(writeChildNode(serverProp->getNodeId(), "EnumValues", OpcUaVariant()), OpcUaException); +} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp new file mode 100644 index 0000000..806ed6d --- /dev/null +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp @@ -0,0 +1,199 @@ +#include "coreobjects/property_object_factory.h" +#include "gtest/gtest.h" +#include "opcuaclient/opcuaclient.h" +#include "opcuatms_client/objects/tms_client_property_object_impl.h" +#include +#include +#include +#include "coreobjects/property_object_class_ptr.h" +#include "opcuatms_server/objects/tms_server_property_object.h" +#include "tms_object_integration_test.h" +#include "opcuatms_client/objects/tms_client_property_object_factory.h" +#include +#include "opendaq/context_factory.h" + +using namespace daq; +using namespace opcua::tms; +using namespace opcua; +using namespace std::chrono_literals; + +struct RegisteredPropertyObject +{ + TmsServerPropertyObjectPtr serverProp; + PropertyObjectPtr clientProp; +}; + +class TmsPropertyObjectTest : public TmsObjectIntegrationTest +{ +public: + + TypeManagerPtr manager; + + void SetUp() override + { + TmsObjectIntegrationTest::SetUp(); + manager = TypeManager(); + auto personClass = PropertyObjectClassBuilder("PersonObject").build(); + manager.addType(personClass); + } + + void TearDown() override + { + TmsObjectIntegrationTest::TearDown(); + } + + PropertyObjectPtr createPropertyObject() + { + GenericPropertyObjectPtr object = PropertyObject(manager, "PersonObject"); + + auto roles = List(); + roles.pushBack("Software"); + roles.pushBack("Hardware"); + + object.addProperty(SelectionProperty("Role", roles, 0)); + object.addProperty(IntProperty("Height", 180)); + object.addProperty(IntProperty("Age", 0)); + object.setPropertyValue("Age", 999); + + // Is not registered + //object.addProperty(PropertyObjectClassPtr::CreateStringPropInfo("Name")); + //object.setPropertyValue("Name", "Glados"); + + return object; + } + + RegisteredPropertyObject registerPropertyObject(const PropertyObjectPtr& prop) + { + auto serverProp = std::make_shared(prop, server, NullContext()); + auto nodeId = serverProp->registerOpcUaNode(); + auto clientProp = TmsClientPropertyObject(NullContext(), clientContext, nodeId); + return {serverProp, clientProp}; + } +}; + +TEST_F(TmsPropertyObjectTest, Create) +{ + auto prop = createPropertyObject(); + + auto serverProp = TmsServerPropertyObject(prop, server, NullContext()); + auto nodeId = serverProp.registerOpcUaNode(); + ASSERT_TRUE(server->nodeExists(nodeId)); + + auto clientProp = TmsClientPropertyObject(NullContext(), clientContext, nodeId); + ASSERT_TRUE(clientProp.assigned()); +} + +// TODO: Class names cannot be transferred as of now +TEST_F(TmsPropertyObjectTest, DISABLED_ClassName) +{ + auto prop = createPropertyObject(); + + auto propClass = PropertyObjectClassBuilder("Chell").setParentName("PersonObject").build(); + manager.addType(propClass); + + auto [serverProp, clientProp] = registerPropertyObject(prop); + + ASSERT_EQ(clientProp.getClassName(), prop.getClassName()); + + manager.removeType("Chell"); +} + +TEST_F(TmsPropertyObjectTest, PropertyValue) +{ + auto prop = createPropertyObject(); + auto [serverProp, clientProp] = registerPropertyObject(prop); + + ASSERT_EQ(clientProp.getPropertyValue("Height"), prop.getPropertyValue("Height")); + clientProp.setPropertyValue("Height", 100); + ASSERT_EQ(clientProp.getPropertyValue("Height"), 100); + ASSERT_EQ(prop.getPropertyValue("Height"), 100); + + ASSERT_THROW(clientProp.setPropertyValue("Missing", 100), DaqException); +} + +TEST_F(TmsPropertyObjectTest, PropertyValueRole) +{ + auto prop = createPropertyObject(); + auto [serverProp, clientProp] = registerPropertyObject(prop); + + ASSERT_EQ(clientProp.getPropertyValue("Role"), prop.getPropertyValue("Role")); + clientProp.setPropertyValue("Role", 1); + ASSERT_EQ(clientProp.getPropertyValue("Role"), 1); + ASSERT_EQ(prop.getPropertyValue("Role"), 1); + + ASSERT_THROW(clientProp.setPropertyValue("Role", 2), DaqException); +} + +TEST_F(TmsPropertyObjectTest, getPropertySelectionValue) +{ + auto prop = createPropertyObject(); + auto [serverProp, clientProp] = registerPropertyObject(prop); + const auto targetRole = "Hardware"; + + ASSERT_EQ(clientProp.getPropertySelectionValue("Role"), prop.getPropertySelectionValue("Role")); + clientProp.setPropertyValue("Role", 1); + ASSERT_EQ(prop.getPropertySelectionValue("Role"), targetRole); + ASSERT_EQ(clientProp.getPropertySelectionValue("Role"), targetRole); +} + +TEST_F(TmsPropertyObjectTest, GetProperty) +{ + auto prop = createPropertyObject(); + auto [serverProp, clientProp] = registerPropertyObject(prop); + + auto height = clientProp.getProperty("Height"); + ASSERT_TRUE(height.assigned()); +} + +TEST_F(TmsPropertyObjectTest, EnumVisibleProperties) +{ + auto prop = createPropertyObject(); + auto [serverProp, clientProp] = registerPropertyObject(prop); + + auto infos = prop.getVisibleProperties(); + auto clientInfos = clientProp.getVisibleProperties(); + ASSERT_EQ(infos.getCount(), clientInfos.getCount()); +} + +// TODO: hasPropertyValue should only return true of local value is set +TEST_F(TmsPropertyObjectTest, HasProperty) +{ + auto prop = createPropertyObject(); + auto [serverProp, clientProp] = registerPropertyObject(prop); + + ASSERT_TRUE(clientProp.hasProperty("Age")); + ASSERT_TRUE(clientProp.hasProperty("Role")); + ASSERT_TRUE(clientProp.hasProperty("Height")); + ASSERT_FALSE(clientProp.hasProperty("Missing")); +} + +// TODO: Dictionary properties are not yet available on OpcUa TMS +TEST_F(TmsPropertyObjectTest, TestDictProperty) +{ + auto dict = Dict(); + dict.set("BananaCount", 10); + dict.set("AppleCount", 5); + dict.set("BlueberryCount", 999); + + auto prop = DictProperty("DictProp", dict); + auto propObj = PropertyObject(); + propObj.addProperty(prop); + + auto [serverProp, clientProp] = registerPropertyObject(propObj); + auto clientDict = clientProp.getPropertyValue("DictProp"); + ASSERT_EQ(dict, clientDict); +} + +// TODO: List properties are not yet available on OpcUa TMS +TEST_F(TmsPropertyObjectTest, TestListProperty) +{ + auto list = List("Banana", "Apple", "Blueberry"); + + auto prop = ListProperty("ListProp", list); + auto propObj = PropertyObject(); + propObj.addProperty(prop); + + auto [serverProp, clientProp] = registerPropertyObject(propObj); + auto clientDict = clientProp.getPropertyValue("ListProp"); + ASSERT_EQ(list, clientDict); +} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp new file mode 100644 index 0000000..929cfcb --- /dev/null +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp @@ -0,0 +1,316 @@ +#include +#include +#include +#include +#include "gtest/gtest.h" +#include "opcuaclient/opcuaclient.h" +#include "opcuatms/exceptions.h" +#include "opcuatms_client/objects/tms_client_signal_factory.h" +#include "opcuatms_server/objects/tms_server_signal.h" +#include "open62541/tmsbsp_nodeids.h" +#include +#include +#include +#include "tms_object_integration_test.h" + +using namespace daq; +using namespace opcua::tms; +using namespace opcua; + +class TmsSignalTest : public TmsObjectIntegrationTest +{ +public: + SignalPtr createSignal(const std::string& id) + { + SignalPtr signal = Signal(NullContext(), nullptr, id); + signal->setActive(false); + return signal; + } + + SignalPtr createFullSignal(const std::string& signalName) + { + // Build signal descriptor: + auto serverMetadata = Dict(); + for (size_t i = 0; i < 2; i++) + { + serverMetadata.set("Metadata" + std::to_string(i), "Value " + std::to_string(i)); + } + + // Build value descriptor: + auto serverDataDescriptor = DataDescriptorBuilder() + .setSampleType(SampleType::Float32) + .setName("Value Name") + .setDimensions(List()) + .setRule(ConstantDataRule(1.0)) + .setUnit(Unit("symbol", 1, "name", "quantity")) // Optional + .setOrigin("Origin") // Optional + .setValueRange(Range(0.0, 100.0)) // Optional + .setMetadata(serverMetadata) + .build(); + + // Build server signal + auto serverSignal = SignalWithDescriptor(NullContext(), serverDataDescriptor, nullptr, "sig"); + serverSignal->setActive(true); + serverSignal.getTags().add("tag1"); + serverSignal.getTags().add("tag2"); + + return serverSignal; + } +}; + +TEST_F(TmsSignalTest, Create) +{ + SignalPtr signal = Signal(NullContext(), nullptr, "sig"); + auto tmsSignal = TmsServerSignal(signal, this->getServer(), NullContext()); +} + +TEST_F(TmsSignalTest, Register) +{ + SignalPtr signal = createSignal("id"); + auto serverSignal = TmsServerSignal(signal, this->getServer(), NullContext()); + auto nodeId = serverSignal.registerOpcUaNode(); + + SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); + ASSERT_TRUE(clientSignal.assigned()); +} + +TEST_F(TmsSignalTest, AttrUniqueId) +{ + SignalPtr daqServerSignal = createSignal("id"); + daqServerSignal.setActive(true); + + auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), NullContext()); + auto nodeId = serverSignal.registerOpcUaNode(); + + SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "id", clientContext, nodeId); + + // UniqueId is set by core, so only test is that it is transferred correctly: + ASSERT_EQ(daqServerSignal.getLocalId(), clientSignal.getLocalId()); +} + +TEST_F(TmsSignalTest, AttrActive) +{ + SignalPtr daqServerSignal = createSignal("id"); + daqServerSignal.setActive(true); + + auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), NullContext()); + auto nodeId = serverSignal.registerOpcUaNode(); + + SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); + + ASSERT_TRUE(daqServerSignal.getActive()); + ASSERT_TRUE(clientSignal.getActive()); + + daqServerSignal.setActive(false); + + ASSERT_FALSE(daqServerSignal.getActive()); + ASSERT_FALSE(clientSignal.getActive()); + + clientSignal.setActive(true); + + ASSERT_TRUE(daqServerSignal.getActive()); + ASSERT_TRUE(clientSignal.getActive()); +} + +TEST_F(TmsSignalTest, AttrPublic) +{ + SignalPtr daqServerSignal = createSignal("id"); + + auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), NullContext()); + auto nodeId = serverSignal.registerOpcUaNode(); + + SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); + + ASSERT_TRUE(clientSignal.getPublic()); + + // client side change is reflected on client side (public is not transferred): + clientSignal.setPublic(false); + ASSERT_FALSE(clientSignal.getPublic()); + + clientSignal.setPublic(true); + ASSERT_TRUE(clientSignal.getPublic()); +} + +TEST_F(TmsSignalTest, AttrDescriptor) +{ + auto serverMetadata = Dict(); + for (size_t i = 0; i < 2; i++) + { + serverMetadata.set("Metadata" + std::to_string(i), "Value " + std::to_string(i)); + } + + auto serverDataDescriptor = DataDescriptorBuilder() + .setSampleType(SampleType::Float32) + .setDimensions(List()) + .setRule(ConstantDataRule(1.0)) + .setUnit(Unit("symbol", 1, "name", "quantity")) // Optional + .setOrigin("Origin") // Optional + .setValueRange(Range(0.0, 100.0)) // Optional + .setName("Signal Name") + .setMetadata(serverMetadata) + .build(); + + // Build server signal + auto serverSignal = Signal(NullContext(), nullptr, "sig"); + serverSignal.setName("My signal"); + serverSignal.setDescription("My signal description"); + serverSignal->setActive(true); + ASSERT_FALSE(serverSignal.getDescriptor().assigned()); + serverSignal.setDescriptor(serverDataDescriptor); + ASSERT_EQ(serverSignal.getDescriptor(), serverDataDescriptor); + + auto tmsServerSignal = TmsServerSignal(serverSignal, this->getServer(), NullContext()); + auto nodeId = tmsServerSignal.registerOpcUaNode(); + + SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); + + ASSERT_EQ(clientSignal.getActive(), serverSignal.getActive()); + // TODO: TMS signal should be implemented similar as fb, i.e. it needs to include property object + //ASSERT_EQ(clientSignal.getName(), "My signal"); + // ASSERT_EQ(clientSignal.getDescription(), "My signal description"); + auto clientDataDescriptor = clientSignal.getDescriptor(); + ASSERT_EQ(clientDataDescriptor.getName(), "Signal Name"); + + auto clientMetadata = clientDataDescriptor.getMetadata(); + auto keyList = clientMetadata.getKeyList(); + auto valueList = clientMetadata.getValueList(); + ASSERT_EQ(keyList.getCount(), 2u); + ASSERT_EQ(valueList.getCount(), 2u); + for (int i = 0; i < 2; i++) + { + auto key = keyList.getItemAt(i); + auto value = valueList.getItemAt(i); + ASSERT_EQ("Metadata" + std::to_string(i), key); + ASSERT_EQ("Value " + std::to_string(i), value); + } + + ASSERT_EQ(clientDataDescriptor.getDimensions().getCount(), 0u); + ASSERT_EQ(clientDataDescriptor.getOrigin(), "Origin"); + ASSERT_EQ(clientDataDescriptor.getSampleType(), SampleType::Float32); + + auto clientRule = clientDataDescriptor.getRule(); + ASSERT_EQ(clientRule.getType(), DataRuleType::Constant); + auto clientRuleParameters = clientRule.getParameters(); + ASSERT_EQ(clientRuleParameters.getCount(), 1u); + auto clientKeyList = clientRuleParameters.getKeyList(); + auto clientValueList = clientRuleParameters.getValueList(); + auto k = clientKeyList.getItemAt(0); + ASSERT_EQ(clientKeyList.getItemAt(0), "constant"); + auto v = clientValueList.getItemAt(0); + ASSERT_EQ(clientValueList.getItemAt(0), 1.0); + + + auto clientUnit = clientDataDescriptor.getUnit(); + ASSERT_EQ(clientUnit.getQuantity(), "quantity"); + ASSERT_EQ(clientUnit.getName(), "name"); + ASSERT_EQ(clientUnit.getSymbol(), "symbol"); + + auto clientValueRange = clientDataDescriptor.getValueRange(); + ASSERT_EQ(clientValueRange.getLowValue(), 0.0); + ASSERT_EQ(clientValueRange.getHighValue(), 100.0); + + auto browseName = client->readBrowseName(nodeId); + ASSERT_EQ(browseName, "sig"); + + auto displayName = client->readDisplayName(nodeId); + ASSERT_EQ(displayName, "My signal"); +} + +TEST_F(TmsSignalTest, AttrDomainSignal) +{ + SignalPtr daqServerDomainSignal = createSignal("sig1"); + auto serverDomainSignal = TmsServerSignal(daqServerDomainSignal, this->getServer(), NullContext()); + auto domainNodeId = serverDomainSignal.registerOpcUaNode(); + + SignalPtr daqServerSignal = createSignal("sig2"); + auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), NullContext()); + auto nodeId = serverSignal.registerOpcUaNode(); + + OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASDOMAINSIGNAL); + getServer()->addReference(nodeId, referenceTypeId, domainNodeId); + SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); + + [[maybe_unused]] + SignalPtr clientDomainSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, domainNodeId); + + SignalPtr domainSignal; + EXPECT_NO_THROW(domainSignal = clientSignal.getDomainSignal()); + ASSERT_EQ(clientDomainSignal, domainSignal); +} + +TEST_F(TmsSignalTest, AttrRelatedSignals) +{ + SignalPtr daqServerSignal1 = createSignal("id1"); + auto serverSignal1 = TmsServerSignal(daqServerSignal1, this->getServer(), NullContext()); + auto nodeId1 = serverSignal1.registerOpcUaNode(); + + SignalPtr daqServerSignal2 = createSignal("id2"); + auto serverSignal2 = TmsServerSignal(daqServerSignal2, this->getServer(), NullContext()); + auto nodeId2 = serverSignal2.registerOpcUaNode(); + + SignalPtr daqServerSignal3 = createSignal("id3"); + auto serverSignal3 = TmsServerSignal(daqServerSignal3, this->getServer(), NullContext()); + auto nodeId3 = serverSignal3.registerOpcUaNode(); + + OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_RELATESTOSIGNAL); + getServer()->addReference(nodeId2, referenceTypeId, nodeId1); + getServer()->addReference(nodeId3, referenceTypeId, nodeId1); + getServer()->addReference(nodeId3, referenceTypeId, nodeId2); + + SignalPtr clientSignal1 = TmsClientSignal(NullContext(), nullptr, "sig1", clientContext, nodeId1); + SignalPtr clientSignal2 = TmsClientSignal(NullContext(), nullptr, "sig2", clientContext, nodeId2); + SignalPtr clientSignal3 = TmsClientSignal(NullContext(), nullptr, "sig3", clientContext, nodeId3); + + auto relatedSignals1 = clientSignal1.getRelatedSignals(); + auto relatedSignals2 = clientSignal2.getRelatedSignals(); + auto relatedSignals3 = clientSignal3.getRelatedSignals(); + + ASSERT_TRUE(relatedSignals1 != nullptr); + ASSERT_TRUE(relatedSignals2 != nullptr); + ASSERT_TRUE(relatedSignals3 != nullptr); + + ASSERT_EQ(relatedSignals1.getCount(), 0u); + + ASSERT_EQ(relatedSignals2.getCount(), 1u); + ASSERT_EQ(relatedSignals2[0].getLocalId(), "sig1"); + + ASSERT_EQ(relatedSignals3.getCount(), 2u); + // Cannot depend on order... + ASSERT_TRUE((relatedSignals3[0] == clientSignal1 || relatedSignals3[0] == clientSignal2) && relatedSignals3[0] != clientSignal3); + ASSERT_TRUE((relatedSignals3[1] == clientSignal1 || relatedSignals3[1] == clientSignal2) && relatedSignals3[1] != clientSignal3); + ASSERT_TRUE(relatedSignals3[0] != relatedSignals3[1]); +} + +TEST_F(TmsSignalTest, MethodGetConnections) +{ + SignalPtr daqServerSignal1 = createSignal("id"); + auto serverSignal1 = TmsServerSignal(daqServerSignal1, this->getServer(), NullContext()); + auto nodeId1 = serverSignal1.registerOpcUaNode(); + + SignalPtr clientSignal1 = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId1); + ASSERT_EQ(clientSignal1.getConnections().getCount(), 0u); + + //TODO: Implement more test when related signals actually can be returned + //ASSERT_EQ(relatedSignals1.getCount(), 2u); + //ASSERT_EQ(relatedSignals2.getCount(), 2u); + //ASSERT_EQ(relatedSignals3.getCount(), 2u); +} + +TEST_F(TmsSignalTest, ComponentMethods) +{ + auto signal = createFullSignal("sig"); + auto serverSignal = TmsServerSignal(signal, this->getServer(), NullContext()); + auto nodeId = serverSignal.registerOpcUaNode(); + + SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); + + ASSERT_EQ(signal.getName(), clientSignal.getName()); + + // TODO: Support changing read-only properties over OPC UA + ASSERT_ANY_THROW(clientSignal.setName("new_name")); + //ASSERT_EQ(signal.getName(), clientSignal.getName()); + + auto tags = signal.getTags(); + auto clientTags = clientSignal.getTags(); + ASSERT_TRUE(clientTags.query("tag1") && clientTags.query("tag2")); +} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp new file mode 100644 index 0000000..799f298 --- /dev/null +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp @@ -0,0 +1,23 @@ +#include "tms_object_integration_test.h" + +using namespace daq::opcua; +using namespace daq::opcua::tms; + +TmsObjectIntegrationTest::TmsObjectIntegrationTest() + : TmsObjectTest() +{ +} + +void TmsObjectIntegrationTest::SetUp() +{ + TmsObjectTest::SetUp(); + + clientContext = std::make_shared(client); +} + +void TmsObjectIntegrationTest::TearDown() +{ + clientContext.reset(); + + TmsObjectTest::TearDown(); +} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h new file mode 100644 index 0000000..ec9c450 --- /dev/null +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h @@ -0,0 +1,31 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "tms_object_test.h" +#include + +class TmsObjectIntegrationTest : public TmsObjectTest +{ +public: + TmsObjectIntegrationTest(); + + void SetUp() override; + void TearDown() override; + +protected: + daq::opcua::tms::TmsClientContextPtr clientContext; +}; diff --git a/shared/libraries/opcuatms/tests/test_utils/CMakeLists.txt b/shared/libraries/opcuatms/tests/test_utils/CMakeLists.txt new file mode 100644 index 0000000..ce1ae36 --- /dev/null +++ b/shared/libraries/opcuatms/tests/test_utils/CMakeLists.txt @@ -0,0 +1,21 @@ +set(MODULE_NAME opcuatms_test_utils) + +set(MODULE_SOURCES tms_object_test.h + tms_object_test.cpp + test_input_port_notifications.h + test_input_port_notifications.cpp + +) + +add_library(${MODULE_NAME} STATIC ${MODULE_SOURCES}) +add_library(${SDK_TARGET_NAMESPACE}::${MODULE_NAME} ALIAS ${MODULE_NAME}) + +target_include_directories(${MODULE_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_link_libraries(${MODULE_NAME} PUBLIC daq::test_utils + daq::opcuaclient + daq::opcuaserver + daq::opendaq + daq::opcua_tms_types +) diff --git a/shared/libraries/opcuatms/tests/test_utils/test_input_port_notifications.cpp b/shared/libraries/opcuatms/tests/test_utils/test_input_port_notifications.cpp new file mode 100644 index 0000000..db7e6d7 --- /dev/null +++ b/shared/libraries/opcuatms/tests/test_utils/test_input_port_notifications.cpp @@ -0,0 +1,29 @@ +#include "test_input_port_notifications.h" + +using namespace daq; + +TestInputPortNotificationsImpl::TestInputPortNotificationsImpl() + : ImplementationOfWeak() +{ +} + +ErrCode TestInputPortNotificationsImpl::acceptsSignal(IInputPort* port, ISignal* signal, Bool* accept) +{ + *accept = true; + return OPENDAQ_SUCCESS; +} + +ErrCode TestInputPortNotificationsImpl::connected(IInputPort* port) +{ + return OPENDAQ_SUCCESS; +} + +ErrCode TestInputPortNotificationsImpl::disconnected(IInputPort* port) +{ + return OPENDAQ_SUCCESS; +} + +daq::ErrCode TestInputPortNotificationsImpl::packetReceived(daq::IInputPort* port) +{ + return OPENDAQ_SUCCESS; +} diff --git a/shared/libraries/opcuatms/tests/test_utils/test_input_port_notifications.h b/shared/libraries/opcuatms/tests/test_utils/test_input_port_notifications.h new file mode 100644 index 0000000..50d519d --- /dev/null +++ b/shared/libraries/opcuatms/tests/test_utils/test_input_port_notifications.h @@ -0,0 +1,40 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include + +class TestInputPortNotificationsImpl : public daq::ImplementationOfWeak +{ +public: + TestInputPortNotificationsImpl(); + + daq::ErrCode INTERFACE_FUNC acceptsSignal(daq::IInputPort* port, daq::ISignal* signal, daq::Bool* accept) override; + daq::ErrCode INTERFACE_FUNC connected(daq::IInputPort* port) override; + daq::ErrCode INTERFACE_FUNC disconnected(daq::IInputPort* port) override; + daq::ErrCode INTERFACE_FUNC packetReceived(daq::IInputPort* port) override; +}; + +OPENDAQ_DECLARE_CLASS_FACTORY_WITH_INTERFACE(INLINE_FACTORY, TestInputPortNotifications, daq::IInputPortNotifications) +OPENDAQ_DEFINE_CLASS_FACTORY_WITH_INTERFACE(INLINE_FACTORY, TestInputPortNotifications, daq::IInputPortNotifications); + +inline daq::InputPortNotificationsPtr TestInputPortNotifications() +{ + daq::InputPortNotificationsPtr inputPortNotification = TestInputPortNotifications_Create(); + return inputPortNotification; +} diff --git a/shared/libraries/opcuatms/tests/test_utils/tms_object_test.cpp b/shared/libraries/opcuatms/tests/test_utils/tms_object_test.cpp new file mode 100644 index 0000000..1768782 --- /dev/null +++ b/shared/libraries/opcuatms/tests/test_utils/tms_object_test.cpp @@ -0,0 +1,103 @@ +#include "tms_object_test.h" +#include "opcuaclient/opcuaclient.h" +#include +#include +#include + +using namespace daq::opcua; + +TmsObjectTest::TmsObjectTest() +{ +} + +void TmsObjectTest::SetUp() +{ + testing::Test::SetUp(); + + server = CreateAndStartTestServer(); + client = CreateAndConnectTestClient(); +} + +void TmsObjectTest::TearDown() +{ + client.reset(); + server.reset(); + testing::Test::TearDown(); +} + +OpcUaServerPtr TmsObjectTest::getServer() +{ + return server; +} + +OpcUaClientPtr TmsObjectTest::getClient() +{ + return client; +} + +void TmsObjectTest::writeChildNode(const OpcUaNodeId& parent, const std::string& browseName, const OpcUaVariant& variant) +{ + getClient()->writeValue(getChildNodeId(parent, browseName), variant); +} + +OpcUaVariant TmsObjectTest::readChildNode(const OpcUaNodeId& parent, const std::string& browseName) +{ + return getClient()->readValue(getChildNodeId(parent, browseName)); +} + +OpcUaNodeId TmsObjectTest::getChildNodeId(const OpcUaNodeId& parent, const std::string& browseName) +{ + OpcUaObject br; + br->requestedMaxReferencesPerNode = 0; + br->nodesToBrowse = UA_BrowseDescription_new(); + br->nodesToBrowseSize = 1; + br->nodesToBrowse[0].nodeId = parent.copyAndGetDetachedValue(); + br->nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL; + + OpcUaObject result = UA_Client_Service_browse(client->getUaClient(), *br); + + if (result->resultsSize == 0) + return OpcUaNodeId(UA_NODEID_NULL); + + auto references = result->results[0].references; + auto referenceCount = result->results[0].referencesSize; + + for (size_t i = 0; i < referenceCount; i++) + { + auto reference = references[i]; + std::string refBrowseName = utils::ToStdString(reference.browseName.name); + if (refBrowseName == browseName) + return OpcUaNodeId(reference.nodeId.nodeId); + } + + return OpcUaNodeId(UA_NODEID_NULL); +} + +void TmsObjectTest::waitForInput() +{ + std::cout << "Type q to quit..." << std::endl; + std::string input; + std::cin >> input; +} + +daq::opcua::OpcUaServerPtr TmsObjectTest::CreateAndStartTestServer() +{ + auto server = std::make_shared(); + server->setPort(4840); + server->start(); + return server; +} + +daq::opcua::OpcUaClientPtr TmsObjectTest::CreateAndConnectTestClient() +{ + OpcUaEndpoint endpoint("Test", "opc.tcp://127.0.0.1:4840"); + endpoint.registerCustomTypes(UA_TYPES_DI_COUNT, UA_TYPES_DI); + endpoint.registerCustomTypes(UA_TYPES_TMSBT_COUNT, UA_TYPES_TMSBT); + endpoint.registerCustomTypes(UA_TYPES_TMSBSP_COUNT, UA_TYPES_TMSBSP); + endpoint.registerCustomTypes(UA_TYPES_TMSDEVICE_COUNT, UA_TYPES_TMSDEVICE); + + auto client = std::make_shared(endpoint); + client->connect(); + client->runIterate(); + return client; +} diff --git a/shared/libraries/opcuatms/tests/test_utils/tms_object_test.h b/shared/libraries/opcuatms/tests/test_utils/tms_object_test.h new file mode 100644 index 0000000..6df52fc --- /dev/null +++ b/shared/libraries/opcuatms/tests/test_utils/tms_object_test.h @@ -0,0 +1,45 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include "opcuaclient/opcuaclient.h" +#include "opcuaserver/opcuaserver.h" + +class TmsObjectTest : public testing::Test +{ +public: + TmsObjectTest(); + + void SetUp() override; + void TearDown() override; + + daq::opcua::OpcUaServerPtr getServer(); + daq::opcua::OpcUaClientPtr getClient(); + void writeChildNode(const daq::opcua::OpcUaNodeId& parent, + const std::string& browseName, + const daq::opcua::OpcUaVariant& variant); + daq::opcua::OpcUaVariant readChildNode(const daq::opcua::OpcUaNodeId& parent, const std::string& browseName); + daq::opcua::OpcUaNodeId getChildNodeId(const daq::opcua::OpcUaNodeId& parent, const std::string& browseName); + void waitForInput(); + + static daq::opcua::OpcUaServerPtr CreateAndStartTestServer(); + static daq::opcua::OpcUaClientPtr CreateAndConnectTestClient(); + +protected: + daq::opcua::OpcUaServerPtr server; + daq::opcua::OpcUaClientPtr client; +}; From 87c3b20eb2b6b52b02f72eb57c8ed271d93e200a Mon Sep 17 00:00:00 2001 From: Nils Roettger <99480819+nilsRoettgerAtBB@users.noreply.github.com> Date: Thu, 19 Oct 2023 07:31:51 +0200 Subject: [PATCH 002/217] Improve stability (openDAQ/openDAQ#8) * Improve stability If a object could not be paresed it is still possible to connect with an opc-ua server. For this nullptr checks were added. * Add one nullptr check more. --- .../opcuatms/opcuatms/include/opcuatms/converter_maps.h | 6 ++++++ .../opcuatms/src/converters/base_object_converter.cpp | 3 +++ 2 files changed, 9 insertions(+) diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h index be60e3e..458970b 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h @@ -281,6 +281,9 @@ namespace converters static BaseObjectPtr convertToDaqObject(const OpcUaVariant& variant, const ContextPtr& context) { + if (variant.isNull()) + return nullptr; + const auto typeId = variant.getValue().type->typeId; if (const auto it = uaTypeToDaqObject.find(OpcUaNodeId(typeId)); it != uaTypeToDaqObject.cend()) return it->second(variant, context); @@ -290,6 +293,9 @@ namespace converters static BaseObjectPtr convertToDaqList(const OpcUaVariant& variant, const ContextPtr& context) { + if (variant.isNull()) + return nullptr; + const auto typeId = variant.getValue().type->typeId; if (const auto it = uaTypeToDaqList.find(OpcUaNodeId(typeId)); it != uaTypeToDaqList.cend()) return it->second(variant, context); diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp index 906afae..acd1c2a 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp @@ -88,6 +88,9 @@ BaseObjectPtr VariantConverter::ToDaqObject(const OpcUaVariant& var const auto obj = converters::convertToDaqObject(unwrapped, context); if (obj.assigned()) return obj; + + if (unwrapped.isNull()) + return nullptr; const auto typeKind = unwrapped.getValue().type->typeKind; if (typeKind == UA_DATATYPEKIND_STRUCTURE || typeKind == UA_DATATYPEKIND_OPTSTRUCT) From d6e6559a301d15aa4e588fc3f90570537122a817 Mon Sep 17 00:00:00 2001 From: Dejan Crnila Date: Sat, 21 Oct 2023 09:44:17 +0200 Subject: [PATCH 003/217] Enable setting of name property on tms signal --- .../src/objects/tms_client_signal_impl.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp index 51a0aa3..4cfa24e 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp @@ -153,7 +153,16 @@ ErrCode TmsClientSignalImpl::getName(IString** name) ErrCode TmsClientSignalImpl::setName(IString* name) { - return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; + OPENDAQ_PARAM_NOT_NULL(name); + + auto objPtr = this->borrowPtr(); + + return daqTry( + [&name, &objPtr]() + { + objPtr.setPropertyValue("Name", name); + return OPENDAQ_SUCCESS; + }); } Bool TmsClientSignalImpl::onTriggerEvent(EventPacketPtr eventPacket) From 9ac3ea30c77160831c94a89e21362cc8f4be6079 Mon Sep 17 00:00:00 2001 From: Dejan Crnila Date: Mon, 23 Oct 2023 09:10:17 +0200 Subject: [PATCH 004/217] Fix unit test --- .../opcuatms/tests/opcuatms_integration/test_tms_signal.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp index 929cfcb..dff1d93 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp @@ -307,7 +307,7 @@ TEST_F(TmsSignalTest, ComponentMethods) ASSERT_EQ(signal.getName(), clientSignal.getName()); // TODO: Support changing read-only properties over OPC UA - ASSERT_ANY_THROW(clientSignal.setName("new_name")); + ASSERT_NO_THROW(clientSignal.setName("new_name")); //ASSERT_EQ(signal.getName(), clientSignal.getName()); auto tags = signal.getTags(); From d101b16062a548ad38e9cf5745ea5757712fa990 Mon Sep 17 00:00:00 2001 From: Dejan Crnila Date: Tue, 24 Oct 2023 12:56:05 +0200 Subject: [PATCH 005/217] Temporary fix for disabled ws streaming on server (openDAQ/openDAQ#19) Temporary fix for disabled ws streaming on server --- .../src/opcua_client_module_impl.cpp | 29 +++++++++++++++++-- .../tests/test_opcua_client_module.cpp | 2 +- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 44be87a..468f608 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -176,10 +176,10 @@ PropertyObjectPtr OpcUaClientModule::createDeviceDefaultConfig() // when it will have subscribe/unsubscribe support //#if defined(OPENDAQ_ENABLE_WEBSOCKET_STREAMING) // allowedStreamingProtocols.pushBack("daq.wss"); -//#endif -#elif defined(OPENDAQ_ENABLE_WEBSOCKET_STREAMING) +#endif +#if defined(OPENDAQ_ENABLE_WEBSOCKET_STREAMING) allowedStreamingProtocols.pushBack("daq.wss"); - primaryStreamingProtocol = "daq.wss"; +// primaryStreamingProtocol = "daq.wss"; #endif defaultConfig.addProperty(ListProperty("AllowedStreamingProtocols", allowedStreamingProtocols)); @@ -211,6 +211,7 @@ void OpcUaClientModule::configureStreamingSources(const PropertyObjectPtr& devic return; const StringPtr primaryStreamingProtocol = deviceConfig.getPropertyValue("PrimaryStreamingProtocol"); + const ListPtr allowedStreamingProtocols = deviceConfig.getPropertyValue("AllowedStreamingProtocols"); for (const auto& signal : device.getSignalsRecursive()) { @@ -240,6 +241,28 @@ void OpcUaClientModule::configureStreamingSources(const PropertyObjectPtr& devic rootStreaming = streamingConnectionString; } } + + if (!leafStreaming.assigned() || !rootStreaming.assigned()) + { + for (const auto& streamingConnectionString : streamingSources) + { + std::string connectionString = streamingConnectionString.toStdString(); + for (const auto& protocol : allowedStreamingProtocols) + { + std::string protocolPrefix = protocol.toStdString(); + if (connectionString.find(protocolPrefix) == 0) + { + // save the first streaming source as the leaf streaming + if (!leafStreaming.assigned()) + leafStreaming = streamingConnectionString; + + // save the last streaming source as the root streaming + rootStreaming = streamingConnectionString; + } + } + } + } + if (!leafStreaming.assigned() || !rootStreaming.assigned()) continue; diff --git a/modules/opcua_client_module/tests/test_opcua_client_module.cpp b/modules/opcua_client_module/tests/test_opcua_client_module.cpp index 4573324..bd0c6a1 100644 --- a/modules/opcua_client_module/tests/test_opcua_client_module.cpp +++ b/modules/opcua_client_module/tests/test_opcua_client_module.cpp @@ -162,7 +162,7 @@ TEST_F(OpcUaClientModuleTest, DefaultDeviceConfig) #if defined(OPENDAQ_ENABLE_NATIVE_STREAMING) ASSERT_TRUE(config.hasProperty("AllowedStreamingProtocols")); - ASSERT_EQ(config.getPropertyValue("AllowedStreamingProtocols"), List("daq.ns")); + ASSERT_EQ(config.getPropertyValue("AllowedStreamingProtocols"), List("daq.ns", "daq.wss")); ASSERT_TRUE(config.hasProperty("PrimaryStreamingProtocol")); ASSERT_EQ(config.getPropertyValue("PrimaryStreamingProtocol"), "daq.ns"); From 2437067d6721dc75b6382d610ee3a567baf1556c Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Mon, 23 Oct 2023 11:41:31 +0200 Subject: [PATCH 006/217] Add server side implementation for node order TODO: function-type properties --- .../objects/tms_server_component.h | 3 --- .../objects/tms_server_object.h | 4 ++++ .../objects/tms_server_property.h | 14 +++++++++++--- .../src/objects/tms_server_device.cpp | 15 ++++++++++++++- .../src/objects/tms_server_folder.cpp | 4 ++++ .../src/objects/tms_server_function_block.cpp | 12 +++++++++--- .../src/objects/tms_server_object.cpp | 16 ++++++++++++++-- .../src/objects/tms_server_property.cpp | 16 +++++++++++++--- .../src/objects/tms_server_property_object.cpp | 18 ++++++++++++++---- 9 files changed, 83 insertions(+), 19 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h index abcba4c..b0477d1 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h @@ -108,9 +108,6 @@ void TmsServerComponent::bindCallbacks() return UA_STATUSCODE_GOOD; }); } - - // TODO - this->addReadCallback("NumberInList", [this]() { return VariantConverter::ToVariant(0); }); } template diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h index e112231..25bd6db 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h @@ -64,6 +64,7 @@ class TmsServerObject : public std::enable_shared_from_this const opcua::OpcUaNodeId& parentNodeId = opcua::OpcUaNodeId(UA_NS0ID_OBJECTSFOLDER)); opcua::OpcUaNodeId registerToExistingOpcUaNode(const opcua::OpcUaNodeId& nodeId); opcua::OpcUaNodeId getNodeId(); + void setNumberInList(uint32_t numberInList); void addHierarchicalReference(const opcua::OpcUaNodeId& parent); virtual void createNonhierarchicalReferences(); @@ -133,8 +134,11 @@ class TmsServerObject : public std::enable_shared_from_this std::mutex valueMutex; opcua::OpcUaNodeId nodeId; ContextPtr daqContext; + uint32_t numberInList; private: + void bindCallbacksInternal(); + std::unordered_map readCallbacks; std::unordered_map writeCallbacks; std::unordered_map> references; diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h index 6e8e3bd..a658072 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h @@ -30,12 +30,19 @@ class TmsServerProperty : public TmsServerVariable { public: using Super = TmsServerVariable; - - TmsServerProperty(const PropertyPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context); + + TmsServerProperty(const PropertyPtr& object, + const opcua::OpcUaServerPtr& server, + const ContextPtr& context); + TmsServerProperty(const PropertyPtr& object, + const opcua::OpcUaServerPtr& server, + const ContextPtr& context, + const std::unordered_map& propOrder); TmsServerProperty(const PropertyPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, - const PropertyObjectPtr& parent); + const PropertyObjectPtr& parent, + const std::unordered_map& propOrder); std::string getBrowseName() override; void bindCallbacks() override; @@ -72,6 +79,7 @@ class TmsServerProperty : public TmsServerVariable std::unordered_set HiddenNodes = {"FieldCoercionExpression", "FieldValidationExpression", ""}; std::unordered_map childProperties; + std::unordered_map propOrder; }; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index 7f0b058..f9c9fe2 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -219,11 +219,15 @@ void TmsServerDevice::populateStreamingOptions() ListPtr streamingOptions; devicePrivatePtr->getStreamingOptions(&streamingOptions); + + uint32_t numberInList = 0; for (const auto& streamingOption : streamingOptions) { auto tmsStreamingOption = registerTmsObjectOrAddReference( streamingOptionsNodeId, streamingOption.asPtr(), streamingOption.getProtocolId()); + tmsStreamingOption->setNumberInList(numberInList); this->streamingOptions.push_back(std::move(tmsStreamingOption)); + numberInList++; } } @@ -234,25 +238,31 @@ void TmsServerDevice::addChildNodes() auto methodSetNodeId = getChildNodeId("MethodSet"); tmsPropertyObject->setMethodParentNodeId(methodSetNodeId); + uint32_t numberInList = 0; for (const auto& device : object.getDevices()) { auto tmsDevice = registerTmsObjectOrAddReference(nodeId, device); + tmsDevice->setNumberInList(numberInList++); devices.push_back(std::move(tmsDevice)); } auto functionBlockNodeId = getChildNodeId("FunctionBlocks"); assert(!functionBlockNodeId.isNull()); + numberInList = 0; for (const auto& functionBlock : object.getFunctionBlocks()) { auto tmsFunctionBlock = registerTmsObjectOrAddReference>(functionBlockNodeId, functionBlock); + tmsFunctionBlock->setNumberInList(numberInList++); functionBlocks.push_back(std::move(tmsFunctionBlock)); } auto signalsNodeId = getChildNodeId("Signals"); assert(!signalsNodeId.isNull()); + numberInList = 0; for (const auto& signal : object.getSignals()) { auto tmsSignal = registerTmsObjectOrAddReference(signalsNodeId, signal); + tmsSignal->setNumberInList(numberInList++); signals.push_back(std::move(tmsSignal)); } @@ -263,7 +273,8 @@ void TmsServerDevice::addChildNodes() auto inputsOutputsNode = std::make_unique(topFolder, server, daqContext); inputsOutputsNode->registerToExistingOpcUaNode(inputsOutputsNodeId); folders.push_back(std::move(inputsOutputsNode)); - + + numberInList = 0; for (auto component : object.getItems()) { auto id = component.getName(); @@ -273,11 +284,13 @@ void TmsServerDevice::addChildNodes() if (component.asPtrOrNull().assigned()) { auto folderNode = registerTmsObjectOrAddReference(nodeId, component); + folderNode->setNumberInList(numberInList++); folders.push_back(std::move(folderNode)); } else { auto componentNode = registerTmsObjectOrAddReference>(nodeId, component); + componentNode->setNumberInList(numberInList++); components.push_back(std::move(componentNode)); } } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp index ca9852c..601a007 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp @@ -15,6 +15,7 @@ TmsServerFolder::TmsServerFolder(const FolderPtr& object, const OpcUaServerPtr& void TmsServerFolder::addChildNodes() { + uint32_t numberInList = 0; for (auto item : object.getItems()) { auto folder = item.asPtrOrNull(); @@ -24,16 +25,19 @@ void TmsServerFolder::addChildNodes() if (channel.assigned()) { auto tmsChannel = registerTmsObjectOrAddReference(this->nodeId, channel); + tmsChannel->setNumberInList(numberInList++); channels.push_back(std::move(tmsChannel)); } else if (folder.assigned()) // It is important to test for folder last as a channel also is a folder! { auto tmsFolder = registerTmsObjectOrAddReference(this->nodeId, folder); + tmsFolder->setNumberInList(numberInList++); folders.push_back(std::move(tmsFolder)); } else if (component.assigned()) // It is important to test for component after folder! { auto tmsComponent = registerTmsObjectOrAddReference>(this->nodeId, component); + tmsComponent->setNumberInList(numberInList++); components.push_back(std::move(tmsComponent)); } else diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp index f8f9079..84f4638 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp @@ -48,25 +48,31 @@ void TmsServerFunctionBlock::addChildNodes() { auto signalsNodeId = this->getChildNodeId("OutputSignals"); assert(!signalsNodeId.isNull()); - + + uint32_t numberInList = 0; for (const auto& signal : this->object.getSignals()) { auto tmsSignal = this->template registerTmsObjectOrAddReference(signalsNodeId, signal); + tmsSignal->setNumberInList(numberInList++); signals.push_back(std::move(tmsSignal)); } auto inputPortsNodeId = this->getChildNodeId("InputPorts"); assert(!inputPortsNodeId.isNull()); - + + numberInList = 0; for (const auto& inputPort : this->object.getInputPorts()) { auto tmsInputPort = this->template registerTmsObjectOrAddReference(inputPortsNodeId, inputPort); + tmsInputPort->setNumberInList(numberInList++); inputPorts.push_back(std::move(tmsInputPort)); } - + + numberInList = 0; for (const auto& fb : this->object.getFunctionBlocks()) { auto tmsFunctionBlock = this->template registerTmsObjectOrAddReference>(this->nodeId, fb); + tmsFunctionBlock->setNumberInList(numberInList++); functionBlocks.push_back(std::move(tmsFunctionBlock)); } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp index d42aeb1..e37a533 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp @@ -2,8 +2,7 @@ #include #include #include -#include -#include +#include "opcuatms/converters/variant_converter.h" #include "open62541/server.h" #include "open62541/tmsbsp_nodeids.h" @@ -15,6 +14,7 @@ namespace opcua_utils = opcua::utils; TmsServerObject::TmsServerObject(const OpcUaServerPtr& server, const ContextPtr& context) : server(server) , daqContext(context) + , numberInList(0) { } @@ -58,6 +58,7 @@ OpcUaNodeId TmsServerObject::registerToExistingOpcUaNode(const OpcUaNodeId& node browseReferences(); addChildNodes(); browseReferences(); + bindCallbacksInternal(); bindCallbacks(); bindReadWriteCallbacks(); return this->nodeId; @@ -68,6 +69,11 @@ OpcUaNodeId TmsServerObject::getNodeId() return nodeId; } +void TmsServerObject::setNumberInList(uint32_t numberInList) +{ + this->numberInList = numberInList; +} + void TmsServerObject::addHierarchicalReference(const OpcUaNodeId& parent) { server->addReference(parent, getReferenceType(), getNodeId(), true); @@ -147,6 +153,12 @@ OpcUaNodeId TmsServerObject::findSignalNodeId(const SignalPtr& signal) const return findTmsObjectNodeId(signal); } +void TmsServerObject::bindCallbacksInternal() +{ + if (hasChildNode("NumberInList")) + this->addReadCallback("NumberInList", [this]() { return VariantConverter::ToVariant(numberInList); }); +} + void TmsServerObject::bindCallbacks() { } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp index 0f985c8..923ec29 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp @@ -26,14 +26,24 @@ TmsServerProperty::TmsServerProperty(const PropertyPtr& object, const opcua::Opc hideSelectionTypeChildren(); if (isStructureType()) hideStructureTypeChildren(); +} +TmsServerProperty::TmsServerProperty(const PropertyPtr& object, + const opcua::OpcUaServerPtr& server, + const ContextPtr& context, + const std::unordered_map& propOrder) + : TmsServerProperty(object, server, context) +{ + this->propOrder = propOrder; + this->numberInList = propOrder.at(object.getName()); } TmsServerProperty::TmsServerProperty(const PropertyPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, - const PropertyObjectPtr& parent) - : TmsServerProperty(object, server, context) + const PropertyObjectPtr& parent, + const std::unordered_map& propOrder) + : TmsServerProperty(object, server, context, propOrder) { this->parent = parent; } @@ -241,7 +251,7 @@ void TmsServerProperty::addReferenceTypeChildNodes() auto prop = parent.getRef().getProperty(propName); if (prop.getValueType() != ctObject) { - auto serverInfo = registerTmsObjectOrAddReference(nodeId, prop, parent.getRef()); + auto serverInfo = registerTmsObjectOrAddReference(nodeId, prop, parent.getRef(), propOrder); auto childNodeId = serverInfo->getNodeId(); childProperties.insert({childNodeId, serverInfo}); } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp index 9c1c84f..f5c385a 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp @@ -68,6 +68,14 @@ void TmsServerPropertyObject::addChildNodes() registerEvalValueNode("IsReadOnly", [this]() { return objProp.getReadOnlyUnresolved(); }); } + uint32_t propNumber = 0; + std::unordered_map propOrder; + for (const auto& prop : object.getAllProperties()) + { + propOrder.insert(std::pair(prop.getName(), propNumber)); + propNumber++; + } + for (const auto& prop : object.getAllProperties()) { // NOTE: ctObject types cannot be placed below ReferenceVariableType properties @@ -83,17 +91,18 @@ void TmsServerPropertyObject::addChildNodes() OpcUaNodeId childNodeId; std::shared_ptr serverInfo; - if (hasChildNode(prop.getName())) + const auto propName = prop.getName(); + if (hasChildNode(propName)) { - serverInfo = std::make_shared(prop, server, daqContext, object); + serverInfo = std::make_shared(prop, server, daqContext, object, propOrder); childNodeId = serverInfo->registerToExistingOpcUaNode(nodeId); } else { - serverInfo = registerTmsObjectOrAddReference(nodeId, prop, object); + serverInfo = registerTmsObjectOrAddReference(nodeId, prop, object, propOrder); childNodeId = serverInfo->getNodeId(); } - + childProperties.insert({childNodeId, serverInfo}); } else @@ -102,6 +111,7 @@ void TmsServerPropertyObject::addChildNodes() PropertyObjectPtr obj = object.getPropertyValue(propName); auto serverInfo = registerTmsObjectOrAddReference(nodeId, obj, propName, prop); auto childNodeId = serverInfo->getNodeId(); + serverInfo->setNumberInList(propOrder[propName]); childObjects.insert({childNodeId, serverInfo}); } } From feeba88f73b4d6862c301bc925bd5f898a5b7afb Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Tue, 24 Oct 2023 10:23:05 +0200 Subject: [PATCH 007/217] Add node order support on OPC UA client Missing: - Node order of function type properties - Handling of referenced nodes that appear in 2 places in the openDAQ component treee --- .../objects/tms_client_folder_impl.h | 2 +- .../objects/tms_client_io_folder_impl.h | 4 +- .../objects/tms_client_object_impl.h | 4 +- .../objects/tms_client_property_object_impl.h | 7 +- .../src/objects/tms_client_device_impl.cpp | 126 ++++++++++++++---- .../src/objects/tms_client_folder_impl.cpp | 24 +++- .../tms_client_function_block_impl.cpp | 43 +++++- .../src/objects/tms_client_io_folder_impl.cpp | 31 ++++- .../src/objects/tms_client_object_impl.cpp | 34 +++++ .../tms_client_property_object_impl.cpp | 56 +++++--- .../opcuatms_integration/test_tms_device.cpp | 1 + .../test_tms_function_block.cpp | 1 + 12 files changed, 272 insertions(+), 61 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h index bd73ccd..3623d90 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h @@ -31,7 +31,7 @@ class TmsClientFolderImpl : public TmsClientComponentBaseImpl const opcua::OpcUaNodeId& nodeId, bool customFolderType); private: - void findAndCreateFolders(); + void findAndCreateFolders(std::map& orderedComponents, std::vector& unorderedComponents); }; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h index d7230e0..783c052 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h @@ -30,8 +30,8 @@ class TmsClientIoFolderImpl : public TmsClientFolderImpl const opcua::OpcUaNodeId& nodeId); protected: - void findAndCreateChannels(); - void findAndCreateIoFolders(); + void findAndCreateChannels(std::map& orderedComponents, std::vector& unorderedComponents); + void findAndCreateIoFolders(std::map& orderedComponents, std::vector& unorderedComponents); }; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h index 3ffb95b..79f0eaf 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h @@ -41,7 +41,9 @@ class TmsClientObjectImpl void writeValue(const std::string& nodeName, const opcua::OpcUaVariant& value); opcua::OpcUaVariant readValue(const std::string& nodeName); virtual void subscriptionStatusChangeCallback(UA_StatusChangeNotification* notification); - + uint32_t tryReadChildNumberInList(const std::string& nodeName); + uint32_t tryReadChildNumberInList(const opcua::OpcUaNodeId& nodeId); + /*! * @brief Returns child nodes of a specific type. By default it returns also the nodes which are a * a subtype of the specific type. It can be disabled. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h index 995e5de..14621b8 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h @@ -114,8 +114,11 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl std::unordered_map objectTypeIdMap; opcua::OpcUaNodeId methodParentNodeId; - void addProperties(const tsl::ordered_map>& references); - void addMethodProperties(const tsl::ordered_map>& references, const opcua::OpcUaNodeId& parentNodeId); + void addProperties(const tsl::ordered_map>& references, + std::map& orderedProperties, + std::vector unorderedProperties); + void addMethodProperties(const tsl::ordered_map>& references, + const opcua::OpcUaNodeId& parentNodeId); void browseRawProperties(); ErrCode INTERFACE_FUNC setPropertyValueInternal(IString* propertyName, IBaseObject* value, bool protectedWrite); }; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 67d3af4..ce97925 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -79,13 +79,26 @@ TmsClientDeviceImpl::TmsClientDeviceImpl(const ContextPtr& ctx, void TmsClientDeviceImpl::findAndCreateSubdevices() { + std::map orderedDevices; + std::vector unorderedDevices; + auto subdeviceNodeIds = this->getChildNodes(client, nodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQDEVICETYPE)); for (const auto& subdeviceNodeId : subdeviceNodeIds) { auto browseName = client->readBrowseName(subdeviceNodeId); auto clientSubdevice = TmsClientDevice(context, devices, browseName, clientContext, subdeviceNodeId, createStreamingCallback); - addSubDevice(clientSubdevice); + + auto numberInList = this->tryReadChildNumberInList(subdeviceNodeId); + if (numberInList != std::numeric_limits::max() && !orderedDevices.count(numberInList)) + orderedDevices.insert(std::pair(numberInList, clientSubdevice)); + else + unorderedDevices.emplace_back(clientSubdevice); } + + for (const auto& val : orderedDevices) + addSubDevice(val.second); + for (const auto& val : unorderedDevices) + addSubDevice(val); } DevicePtr TmsClientDeviceImpl::onAddDevice(const StringPtr& /*connectionString*/, const PropertyObjectPtr& /*config*/) @@ -208,30 +221,65 @@ UnitPtr TmsClientDeviceImpl::onGetDomainUnit() void TmsClientDeviceImpl::findAndCreateFunctionBlocks() { + + std::map orderedFunctionBlocks; + std::vector unorderedFunctionBlocks; + auto functionBlocksNodeId = getNodeId("FunctionBlocks"); auto functionBlockNodeIds = this->getChildNodes(client, functionBlocksNodeId, OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_FUNCTIONBLOCKTYPE)); for (const auto& functionBlockNodeId : functionBlockNodeIds) { - auto browseName = client->readBrowseName(functionBlockNodeId); - auto clientFunctionBlock = TmsClientFunctionBlock(context, this->functionBlocks, browseName, clientContext, functionBlockNodeId); - this->addNestedFunctionBlock(clientFunctionBlock); + auto browseName = this->client->readBrowseName(functionBlockNodeId); + try + { + auto clientFunctionBlock = TmsClientFunctionBlock(context, this->functionBlocks, browseName, clientContext, functionBlockNodeId); + const auto numberInList = this->tryReadChildNumberInList(functionBlockNodeId); + if (numberInList != std::numeric_limits::max() && !orderedFunctionBlocks.count(numberInList)) + orderedFunctionBlocks.insert(std::pair(numberInList, clientFunctionBlock)); + else + unorderedFunctionBlocks.emplace_back(clientFunctionBlock); + } + catch(...) + { + // TODO: Log failure to add fb + } } + + for (const auto& val : orderedFunctionBlocks) + this->addNestedFunctionBlock(val.second); + for (const auto& val : unorderedFunctionBlocks) + this->addNestedFunctionBlock(val); } void TmsClientDeviceImpl::findAndCreateSignals() { - auto signalsNodeId = getNodeId("Signals"); - auto signalNodeIds = this->getChildNodes(client, signalsNodeId, OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_SIGNALTYPE)); + std::map orderedSignals; + std::vector unorderedSignals; + + const auto signalsNodeId = getNodeId("Signals"); + const auto signalNodeIds = this->getChildNodes(client, signalsNodeId, OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_SIGNALTYPE)); for (const auto& signalNodeId : signalNodeIds) { auto clientSignal = FindOrCreateTmsClientSignal(context, signals, clientContext, signalNodeId); - this->addSignal(clientSignal); + const auto numberInList = this->tryReadChildNumberInList(signalNodeId); + if (numberInList != std::numeric_limits::max() && !orderedSignals.count(numberInList)) + orderedSignals.insert(std::pair(numberInList, clientSignal)); + else + unorderedSignals.emplace_back(clientSignal); } + + for (const auto& val : orderedSignals) + this->addSignal(val.second); + for (const auto& val : unorderedSignals) + this->addSignal(val); } void TmsClientDeviceImpl::findAndCreateInputsOutputs() { + std::map orderedComponents; + std::vector unorderedComponents; + this->ioFolder.clear(); auto inputsOutputsNodeId = getNodeId("InputsOutputs"); @@ -240,7 +288,12 @@ void TmsClientDeviceImpl::findAndCreateInputsOutputs() { auto browseName = client->readBrowseName(channelNodeId); auto tmsClientChannel = TmsClientChannel(context, this->ioFolder, browseName, clientContext, channelNodeId); - this->ioFolder.addItem(tmsClientChannel); + + auto numberInList = this->tryReadChildNumberInList(channelNodeId); + if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) + orderedComponents.insert(std::pair(numberInList, tmsClientChannel)); + else + unorderedComponents.emplace_back(tmsClientChannel); } auto folderNodeIds = this->getChildNodes(client, inputsOutputsNodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_IOCOMPONENTTYPE)); @@ -248,12 +301,25 @@ void TmsClientDeviceImpl::findAndCreateInputsOutputs() { auto browseName = client->readBrowseName(folderNodeId); auto tmsClientFolder = TmsClientIoFolder(context, this->ioFolder, browseName, clientContext, folderNodeId); - this->ioFolder.addItem(tmsClientFolder); + + auto numberInList = this->tryReadChildNumberInList(folderNodeId); + if (numberInList != std::numeric_limits::max()) + orderedComponents.insert(std::pair(numberInList, tmsClientFolder)); + else + unorderedComponents.emplace_back(tmsClientFolder); } + + for (const auto& val : orderedComponents) + this->ioFolder.addItem(val.second); + for (const auto& val : unorderedComponents) + this->ioFolder.addItem(val); } void TmsClientDeviceImpl::findAndCreateStreamingOptions() { + std::map orderedStreamings; + std::vector unorderedStreamings; + this->streamingOptions.clear(); auto streamingOptionsNodeId = getNodeId("StreamingOptions"); try @@ -264,24 +330,30 @@ void TmsClientDeviceImpl::findAndCreateStreamingOptions() { auto browseName = client->readBrowseName(streamingOptionNodeId); auto clientStreamingInfo = TmsClientStreamingInfo(daqContext, browseName, clientContext, streamingOptionNodeId); - this->streamingOptions.push_back(clientStreamingInfo); + + auto numberInList = this->tryReadChildNumberInList(streamingOptionNodeId); + if (numberInList != std::numeric_limits::max()) + orderedStreamings.insert(std::pair(numberInList, clientStreamingInfo)); + else + unorderedStreamings.emplace_back(clientStreamingInfo); } } catch (const std::exception& e) { LOG_E("Failed to find 'StreamingOptions' OpcUa node: {}", e.what()); - // FIXME this is a temporary workaround for compability with legacy simulator - if (isRootDevice) - { - auto streamingInfo = StreamingInfo("daq.wss"); - streamingInfo.addProperty(IntProperty("Port", 7414)); - this->streamingOptions.push_back(streamingInfo); - } } + + for (const auto& val : orderedStreamings) + this->streamingOptions.push_back(val.second); + for (const auto& val : unorderedStreamings) + this->streamingOptions.push_back(val); } void TmsClientDeviceImpl::findAndCreateCustomComponents() { + std::map orderedComponents; + std::vector unorderedComponents; + auto componentId = OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQCOMPONENTTYPE); auto folderNodeIds = this->getChildNodes(client, nodeId, componentId); for (const auto& folderNodeId : folderNodeIds) @@ -291,15 +363,23 @@ void TmsClientDeviceImpl::findAndCreateCustomComponents() continue; auto childComponents = this->getChildNodes(client, folderNodeId, componentId); + ComponentPtr child; if (childComponents.size()) - { - this->components.push_back(TmsClientFolder(context, this->thisPtr(), browseName, clientContext, folderNodeId)); - } + child = TmsClientFolder(context, this->thisPtr(), browseName, clientContext, folderNodeId); else - { - this->components.push_back(TmsClientComponent(context, this->thisPtr(), browseName, clientContext, folderNodeId)); - } + child = TmsClientComponent(context, this->thisPtr(), browseName, clientContext, folderNodeId); + + auto numberInList = this->tryReadChildNumberInList(folderNodeId); + if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) + orderedComponents.insert(std::pair(numberInList, child)); + else + unorderedComponents.push_back(child); } + + for (const auto& val : orderedComponents) + this->components.push_back(val.second); + for (const auto& val : unorderedComponents) + this->components.push_back(val); } FunctionBlockPtr TmsClientDeviceImpl::onAddFunctionBlock(const StringPtr& /*typeId*/, const PropertyObjectPtr& /*config*/) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp index a9ec05a..2a3d87f 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp @@ -17,11 +17,20 @@ TmsClientFolderImpl::TmsClientFolderImpl(const ContextPtr& ctx, : TmsClientComponentBaseImpl(ctx, parent, localId, clientContext, nodeId) { if (!customFolderType) - findAndCreateFolders(); + { + std::map orderedComponents; + std::vector unorderedComponents; + findAndCreateFolders(orderedComponents, unorderedComponents); + auto thisPtr = this->template borrowPtr(); + for (const auto& val : orderedComponents) + thisPtr.addItem(val.second); + for (const auto& val : unorderedComponents) + thisPtr.addItem(val); + } } template -void TmsClientFolderImpl::findAndCreateFolders() +void TmsClientFolderImpl::findAndCreateFolders(std::map& orderedComponents, std::vector& unorderedComponents) { auto componentId = OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQCOMPONENTTYPE); auto folderNodeIds = this->getChildNodes(this->client, this->nodeId, componentId); @@ -31,10 +40,17 @@ void TmsClientFolderImpl::findAndCreateFolders() auto thisPtr = this->template borrowPtr(); auto childComponents = this->getChildNodes(this->client, folderNodeId, componentId); + ComponentPtr child; if (childComponents.size()) - thisPtr.addItem(TmsClientFolder(this->context, thisPtr, browseName, this->clientContext, folderNodeId)); + child = TmsClientFolder(this->context, thisPtr, browseName, this->clientContext, folderNodeId); + else + child = TmsClientComponent(this->context, thisPtr, browseName, this->clientContext, folderNodeId); + + auto numberInList = this->tryReadChildNumberInList(folderNodeId); + if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) + orderedComponents.insert(std::pair(numberInList, child)); else - thisPtr.addItem(TmsClientComponent(this->context, thisPtr, browseName, this->clientContext, folderNodeId)); + unorderedComponents.push_back(child); } } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp index f71421c..4fa53b1 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp @@ -47,6 +47,9 @@ tsl::ordered_set TmsClientFunctionBlockBaseImpl:: template void TmsClientFunctionBlockBaseImpl::findAndCreateFunctionBlocks() { + std::map orderedFunctionBlocks; + std::vector unorderedFunctionBlocks; + auto functionBlockNodeIds = getFunctionBlockNodeIds(); for (const auto& functionBlockNodeId : functionBlockNodeIds) { @@ -57,7 +60,12 @@ void TmsClientFunctionBlockBaseImpl::findAndCreateFunctionBlocks() // is thrown which results that the application stops. However, this block should // just be ignored. It is not an error at all. auto clientFunctionBlock = TmsClientFunctionBlock(this->context, this->functionBlocks, browseName, this->clientContext, functionBlockNodeId); - this->addNestedFunctionBlock(clientFunctionBlock); + + const auto numberInList = this->tryReadChildNumberInList(functionBlockNodeId); + if (numberInList != std::numeric_limits::max() && !orderedFunctionBlocks.count(numberInList)) + orderedFunctionBlocks.insert(std::pair(numberInList, clientFunctionBlock)); + else + unorderedFunctionBlocks.emplace_back(clientFunctionBlock); } catch(...) { @@ -65,17 +73,34 @@ void TmsClientFunctionBlockBaseImpl::findAndCreateFunctionBlocks() continue; } } + + for (const auto& val : orderedFunctionBlocks) + this->addNestedFunctionBlock(val.second); + for (const auto& val : unorderedFunctionBlocks) + this->addNestedFunctionBlock(val); } template void TmsClientFunctionBlockBaseImpl::findAndCreateSignals() { + std::map orderedSignals; + std::vector unorderedSignals; + auto signalNodeIds = getOutputSignalNodeIds(); for (const auto& signalNodeId : signalNodeIds) { auto clientSignal = FindOrCreateTmsClientSignal(this->context, this->signals, this->clientContext, signalNodeId); - this->addSignal(clientSignal); + const auto numberInList = this->tryReadChildNumberInList(signalNodeId); + if (numberInList != std::numeric_limits::max() && !orderedSignals.count(numberInList)) + orderedSignals.insert(std::pair(numberInList, clientSignal)); + else + unorderedSignals.emplace_back(clientSignal); } + + for (const auto& val : orderedSignals) + this->addSignal(val.second); + for (const auto& val : unorderedSignals) + this->addSignal(val); } template @@ -90,14 +115,26 @@ tsl::ordered_set TmsClientFunctionBlockBaseImpl:: template void TmsClientFunctionBlockBaseImpl::findAndCreateInputPorts() { + std::map orderedInputPorts; + std::vector unorderedInputPorts; + auto inputPortNodeIds = getInputPortNodeIds(); for (const auto& inputPortNodeId : inputPortNodeIds) { auto browseName = this->client->readBrowseName(inputPortNodeId); auto clientInputPort = TmsClientInputPort(this->context, this->inputPorts, browseName, this->clientContext, inputPortNodeId); - this->addInputPort(clientInputPort); + const auto numberInList = this->tryReadChildNumberInList(inputPortNodeId); + if (numberInList != std::numeric_limits::max() && !orderedInputPorts.count(numberInList)) + orderedInputPorts.insert(std::pair(numberInList, clientInputPort)); + else + unorderedInputPorts.emplace_back(clientInputPort); } + + for (const auto& val : orderedInputPorts) + this->addInputPort(val.second); + for (const auto& val : unorderedInputPorts) + this->addInputPort(val); } template diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp index c22c2b1..d1c3ec1 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp @@ -15,11 +15,20 @@ TmsClientIoFolderImpl::TmsClientIoFolderImpl(const ContextPtr& ctx, const opcua::OpcUaNodeId& nodeId) : TmsClientFolderImpl(ctx, parent, localId, clientContext, nodeId, true) { - findAndCreateIoFolders(); - findAndCreateChannels(); + std::map orderedComponents; + std::vector unorderedComponents; + + findAndCreateIoFolders(orderedComponents, unorderedComponents); + findAndCreateChannels(orderedComponents, unorderedComponents); + + auto thisPtr = this->template borrowPtr(); + for (const auto& val : orderedComponents) + thisPtr.addItem(val.second); + for (const auto& val : unorderedComponents) + thisPtr.addItem(val); } -void TmsClientIoFolderImpl::findAndCreateChannels() +void TmsClientIoFolderImpl::findAndCreateChannels(std::map& orderedComponents, std::vector& unorderedComponents) { auto channelNodeIds = getChildNodes(this->client, this->nodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_CHANNELTYPE)); for (const auto& channelNodeId : channelNodeIds) @@ -27,11 +36,16 @@ void TmsClientIoFolderImpl::findAndCreateChannels() auto browseName = this->client->readBrowseName(channelNodeId); auto thisPtr = this->borrowPtr(); auto tmsClientChannel = TmsClientChannel(this->context, thisPtr, browseName, this->clientContext, channelNodeId); - thisPtr.addItem(tmsClientChannel); + + auto numberInList = this->tryReadChildNumberInList(channelNodeId); + if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) + orderedComponents.insert(std::pair(numberInList, tmsClientChannel)); + else + unorderedComponents.emplace_back(tmsClientChannel); } } -void TmsClientIoFolderImpl::findAndCreateIoFolders() +void TmsClientIoFolderImpl::findAndCreateIoFolders(std::map& orderedComponents, std::vector& unorderedComponents) { auto folderNodeIds = getChildNodes(this->client, this->nodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_IOCOMPONENTTYPE)); for (const auto& folderNodeId : folderNodeIds) @@ -39,7 +53,12 @@ void TmsClientIoFolderImpl::findAndCreateIoFolders() auto browseName = this->client->readBrowseName(folderNodeId); auto thisPtr = this->template borrowPtr(); auto tmsClientFolder = TmsClientIoFolder(this->context, thisPtr, browseName, this->clientContext, folderNodeId); - thisPtr.addItem(tmsClientFolder); + + auto numberInList = this->tryReadChildNumberInList(folderNodeId); + if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) + orderedComponents.insert(std::pair(numberInList, tmsClientFolder)); + else + unorderedComponents.emplace_back(tmsClientFolder); } } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_object_impl.cpp index 661e1a1..69ef9b1 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_object_impl.cpp @@ -78,6 +78,40 @@ void TmsClientObjectImpl::subscriptionStatusChangeCallback(UA_StatusChangeNotifi //TODO report on disconnect } +uint32_t TmsClientObjectImpl::tryReadChildNumberInList(const std::string& nodeName) +{ + try + { + const auto childId = this->getNodeId(nodeName); + return tryReadChildNumberInList(childId); + } + catch(...) + { + } + + return std::numeric_limits::max(); +} + +uint32_t TmsClientObjectImpl::tryReadChildNumberInList(const opcua::OpcUaNodeId& nodeId) +{ + try + { + const auto& childReferences = referenceUtils.getReferences(nodeId); + for (auto& [addedPropChildId, addedPropChildRef] : childReferences) + { + if (client->readBrowseName(addedPropChildId) == "NumberInList") + { + return VariantConverter::ToDaqObject(client->readValue(addedPropChildId)); + } + } + } + catch(...) + { + } + + return std::numeric_limits::max(); +} + std::vector TmsClientObjectImpl::getChildNodes(const opcua::OpcUaClientPtr& client, const opcua::OpcUaNodeId& nodeId, const opcua::OpcUaNodeId& typeId, diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index 41260ea..5116267 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -162,7 +162,10 @@ ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::setPropertyOrder(I } template -void TmsClientPropertyObjectBaseImpl::addProperties(const tsl::ordered_map>& references) +void TmsClientPropertyObjectBaseImpl::addProperties( + const tsl::ordered_map>& references, + std::map& orderedProperties, + std::vector unorderedProperties) { const auto introspectionVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_INTROSPECTIONVARIABLETYPE); const auto structureVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_STRUCTUREVARIABLETYPE); @@ -175,7 +178,7 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const tsl::ordered_map auto propName = String(client->readBrowseName(childNodeId)); Bool hasProp; daq::checkErrorInfo(Impl::hasProperty(propName, &hasProp)); - + PropertyPtr prop; if (referenceUtils.isInstanceOf(typeId, referenceVariableTypeId)) { try @@ -183,13 +186,12 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const tsl::ordered_map if (!hasProp) { StringPtr refPropEval = VariantConverter::ToDaqObject(client->readValue(childNodeId)); - auto refProp = ReferenceProperty(propName, EvalValue(refPropEval)); - daq::checkErrorInfo(Impl::addProperty(refProp)); + prop = ReferenceProperty(propName, EvalValue(refPropEval)); } referenceVariableIdMap.insert(std::pair(propName, childNodeId)); const auto& refPropReferences = referenceUtils.getReferences(childNodeId); - addProperties(refPropReferences); + addProperties(refPropReferences, orderedProperties, unorderedProperties); } catch(...) { @@ -203,10 +205,8 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const tsl::ordered_map try { if (!hasProp) - { - auto prop = TmsClientProperty(daqContext, clientContext, ref->nodeId.nodeId); - daq::checkErrorInfo(Impl::addProperty(prop)); - } + prop = TmsClientProperty(daqContext, clientContext, ref->nodeId.nodeId); + introspectionVariableIdMap.insert(std::pair(propName, childNodeId)); } catch(...) @@ -220,7 +220,7 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const tsl::ordered_map if (!hasProp) { auto obj = TmsClientPropertyObject(daqContext, clientContext, childNodeId); - auto prop = ObjectPropertyBuilder(propName, obj).setDescription(String(client->readDescription(childNodeId))); + auto propBuilder = ObjectPropertyBuilder(propName, obj).setDescription(String(client->readDescription(childNodeId))); const auto evaluationVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_EVALUATIONVARIABLETYPE); const auto variableBlockRefs = referenceUtils.getReferences(childNodeId); @@ -237,32 +237,41 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const tsl::ordered_map if (browseName == "IsReadOnly") { if (evalStr.assigned()) - prop.setReadOnly(EvalValue(evalStr).asPtr()); + propBuilder.setReadOnly(EvalValue(evalStr).asPtr()); else - prop.setReadOnly(VariantConverter::ToDaqObject(client->readValue(variableBlockNodeId))); + propBuilder.setReadOnly(VariantConverter::ToDaqObject(client->readValue(variableBlockNodeId))); } else if (browseName == "IsVisible") { if (evalStr.assigned()) - prop.setVisible(EvalValue(evalStr).asPtr()); + propBuilder.setVisible(EvalValue(evalStr).asPtr()); else - prop.setVisible(VariantConverter::ToDaqObject(client->readValue(variableBlockNodeId))); + propBuilder.setVisible(VariantConverter::ToDaqObject(client->readValue(variableBlockNodeId))); } } } - - daq::checkErrorInfo(Impl::addProperty(prop.build())); + + prop = propBuilder.build(); } objectTypeIdMap.insert(std::pair(propName, childNodeId)); } - + + if (prop.assigned()) + { + auto numberInList = tryReadChildNumberInList(childNodeId); + if (numberInList != std::numeric_limits::max() && !orderedProperties.count(numberInList)) + orderedProperties.insert(std::pair(numberInList, prop)); + else + unorderedProperties.push_back(prop); + } } } template void TmsClientPropertyObjectBaseImpl::addMethodProperties( - const tsl::ordered_map>& references, const OpcUaNodeId& parentNodeId) + const tsl::ordered_map>& references, + const OpcUaNodeId& parentNodeId) { const auto methodTypeId = OpcUaNodeId(0, UA_NS0ID_METHODNODE); @@ -321,7 +330,16 @@ template void TmsClientPropertyObjectBaseImpl::browseRawProperties() { const auto& references = referenceUtils.getReferences(nodeId); - addProperties(references); + + std::map orderedProperties; + std::vector unorderedProperties; + + addProperties(references, orderedProperties, unorderedProperties); + + for (const auto& val : orderedProperties) + daq::checkErrorInfo(Impl::addProperty(val.second)); + for (const auto& val : unorderedProperties) + daq::checkErrorInfo(Impl::addProperty(val)); // TODO: Make sure that this is a DeviceType node if (hasReference("MethodSet")) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp index 785f464..ef623d6 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp @@ -136,6 +136,7 @@ TEST_F(TmsDeviceTest, Property) auto ctx = NullContext(); auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + auto serverVisibleProps = serverDevice.getVisibleProperties(); auto visibleProperties = clientDevice.getVisibleProperties(); ASSERT_EQ(visibleProperties.getCount(), 3u); ASSERT_EQ(visibleProperties[2].getName(), "SampleRate"); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp index 77cd9ba..7ad92b4 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp @@ -118,6 +118,7 @@ TEST_F(TmsFunctionBlockTest, MethodGetSignals) auto clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, functionBlockNodeId); + ListPtr serverSignals = serverFunctionBlock.getSignals(); ListPtr signals; ASSERT_NO_THROW(signals = clientFunctionBlock.getSignals()); ASSERT_TRUE(signals.assigned()); From af6a6e5c8df92b8e2484beed0c1ebfb5c21d5614 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Tue, 24 Oct 2023 12:36:35 +0200 Subject: [PATCH 008/217] Add node order for function-type properties --- .../include/opcuashared/opcuavariant.h | 1 + .../opcua/opcuashared/src/opcuavariant.cpp | 5 ++ .../objects/tms_client_property_object_impl.h | 5 +- .../tms_client_property_object_impl.cpp | 49 ++++++++++++------- .../objects/tms_server_property_object.h | 2 +- .../objects/tms_server_property_object.cpp | 15 +++++- 6 files changed, 55 insertions(+), 22 deletions(-) diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h index f3c57c8..b393326 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h @@ -107,6 +107,7 @@ class OpcUaVariant : public OpcUaObject OpcUaVariant(); explicit OpcUaVariant(const uint16_t& value); + explicit OpcUaVariant(const uint32_t& value); explicit OpcUaVariant(const int32_t& value); explicit OpcUaVariant(const int64_t& value); explicit OpcUaVariant(const char* value); diff --git a/shared/libraries/opcua/opcuashared/src/opcuavariant.cpp b/shared/libraries/opcua/opcuashared/src/opcuavariant.cpp index 97e0038..e71dc99 100644 --- a/shared/libraries/opcua/opcuashared/src/opcuavariant.cpp +++ b/shared/libraries/opcua/opcuashared/src/opcuavariant.cpp @@ -19,6 +19,11 @@ OpcUaVariant::OpcUaVariant(const uint16_t& value) UA_Variant_setScalarCopy(&this->value, &value, &UA_TYPES[UA_TYPES_UINT16]); } +OpcUaVariant::OpcUaVariant(const uint32_t& value) +{ + UA_Variant_setScalarCopy(&this->value, &value, &UA_TYPES[UA_TYPES_UINT32]); +} + OpcUaVariant::OpcUaVariant(const int32_t& value) : OpcUaVariant() { diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h index 14621b8..8e31c9f 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h @@ -118,7 +118,10 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl std::map& orderedProperties, std::vector unorderedProperties); void addMethodProperties(const tsl::ordered_map>& references, - const opcua::OpcUaNodeId& parentNodeId); + const opcua::OpcUaNodeId& parentNodeId, + std::map& orderedProperties, + std::vector unorderedProperties, + std::unordered_map& functionPropValues); void browseRawProperties(); ErrCode INTERFACE_FUNC setPropertyValueInternal(IString* propertyName, IBaseObject* value, bool protectedWrite); }; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index 5116267..7c1dce3 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -271,7 +271,10 @@ void TmsClientPropertyObjectBaseImpl::addProperties( template void TmsClientPropertyObjectBaseImpl::addMethodProperties( const tsl::ordered_map>& references, - const OpcUaNodeId& parentNodeId) + const OpcUaNodeId& parentNodeId, + std::map& orderedProperties, + std::vector unorderedProperties, + std::unordered_map& functionPropValues) { const auto methodTypeId = OpcUaNodeId(0, UA_NS0ID_METHODNODE); @@ -288,6 +291,7 @@ void TmsClientPropertyObjectBaseImpl::addMethodProperties( { ListPtr inputArgs; ListPtr outputArgs; + uint32_t numberInList = std::numeric_limits::max(); try { @@ -296,6 +300,9 @@ void TmsClientPropertyObjectBaseImpl::addMethodProperties( if (referenceUtils.hasReference(childNodeId, "OutputArguments")) outputArgs = VariantConverter::ToDaqList(client->readValue(referenceUtils.getChildNodeId(childNodeId, "OutputArguments"))); + + if (referenceUtils.hasReference(childNodeId, "NumberInList")) + numberInList = VariantConverter::ToDaqObject(client->readValue(referenceUtils.getChildNodeId(childNodeId, "NumberInList"))); } catch(...) { @@ -303,24 +310,26 @@ void TmsClientPropertyObjectBaseImpl::addMethodProperties( continue; } + BaseObjectPtr prop; + BaseObjectPtr func; if (outputArgs.assigned() && outputArgs.getCount() == 1) { auto callableInfo = FunctionInfo(outputArgs[0].getType(), inputArgs); - auto prop = FunctionPropertyBuilder(propName, callableInfo).setReadOnly(true).build(); - daq::checkErrorInfo(Impl::addProperty(prop)); - - auto clientFunc = TmsClientFunction(clientContext, daqContext, parentNodeId, childNodeId); - daq::checkErrorInfo(Impl::setProtectedPropertyValue(propName, clientFunc)); + prop = FunctionPropertyBuilder(propName, callableInfo).setReadOnly(true).build(); + func = TmsClientFunction(clientContext, daqContext, parentNodeId, childNodeId); } else { auto callableInfo = ProcedureInfo(inputArgs); - auto prop = FunctionPropertyBuilder(propName, callableInfo).setReadOnly(true).build(); - daq::checkErrorInfo(Impl::addProperty(prop)); - - auto clientProcedure = TmsClientProcedure(clientContext, daqContext, parentNodeId, childNodeId); - daq::checkErrorInfo(Impl::setProtectedPropertyValue(propName, clientProcedure)); + prop = FunctionPropertyBuilder(propName, callableInfo).setReadOnly(true).build(); + func = TmsClientProcedure(clientContext, daqContext, parentNodeId, childNodeId); } + + functionPropValues.insert(std::pair(propName, func)); + if (numberInList != std::numeric_limits::max() && !orderedProperties.count(numberInList)) + orderedProperties.insert(std::pair(numberInList, prop)); + else + unorderedProperties.push_back(prop); } } } @@ -333,25 +342,29 @@ void TmsClientPropertyObjectBaseImpl::browseRawProperties() std::map orderedProperties; std::vector unorderedProperties; + std::unordered_map functionPropValues; addProperties(references, orderedProperties, unorderedProperties); - for (const auto& val : orderedProperties) - daq::checkErrorInfo(Impl::addProperty(val.second)); - for (const auto& val : unorderedProperties) - daq::checkErrorInfo(Impl::addProperty(val)); - // TODO: Make sure that this is a DeviceType node if (hasReference("MethodSet")) { const auto methodNodeId = referenceUtils.getChildNodeId(nodeId, "MethodSet"); const auto& methodReferences = referenceUtils.getReferences(methodNodeId); - addMethodProperties(methodReferences, methodNodeId); + addMethodProperties(methodReferences, methodNodeId, orderedProperties, unorderedProperties, functionPropValues); } else { - addMethodProperties(references, nodeId); + addMethodProperties(references, nodeId, orderedProperties, unorderedProperties, functionPropValues); } + + for (const auto& val : orderedProperties) + daq::checkErrorInfo(Impl::addProperty(val.second)); + for (const auto& val : unorderedProperties) + daq::checkErrorInfo(Impl::addProperty(val)); + for (const auto& val : functionPropValues) + daq::checkErrorInfo(Impl::setProtectedPropertyValue(String(val.first), val.second)); + } template class TmsClientPropertyObjectBaseImpl; diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h index 77ec298..1febd4f 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h @@ -61,7 +61,7 @@ class TmsServerPropertyObject : public TmsServerObjectBaseImpladdMethodNode(params); + OpcUaNodeId numberInListRequestedNodeId(0); + AddVariableNodeParams numberInListParams(numberInListRequestedNodeId, methodNodeId); + numberInListParams.setBrowseName("NumberInList"); + numberInListParams.setDataType(OpcUaNodeId(UA_TYPES[UA_TYPES_UINT32].typeId)); + + numberInListParams.typeDefinition = OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE)); + const auto numberInListNodeId = server->addVariableNode(numberInListParams); + server->writeValue(numberInListNodeId, OpcUaVariant(numberInList)); + methodProps.insert({methodNodeId, {name, prop.getValueType()}}); } catch(...) From 5b39d90090ced3b2ce5e4d700a7a847619a8ac43 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Tue, 24 Oct 2023 14:56:04 +0200 Subject: [PATCH 009/217] Refactor NumberInList on OPC UA server --- .../objects/tms_server_object.h | 3 +++ .../src/objects/tms_server_device.cpp | 19 ++++++------------- .../src/objects/tms_server_folder.cpp | 9 +++------ .../src/objects/tms_server_function_block.cpp | 9 +++------ .../src/objects/tms_server_property.cpp | 2 +- .../objects/tms_server_property_object.cpp | 5 ++--- 6 files changed, 18 insertions(+), 29 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h index 25bd6db..93373ee 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h @@ -110,6 +110,7 @@ class TmsServerObject : public std::enable_shared_from_this template std::shared_ptr registerTmsObjectOrAddReference(const opcua::OpcUaNodeId& parentNodeId, const DAQ_T& daqObject, + uint32_t numberInList, Params... params) { auto tmsObjectNodeId = findTmsObjectNodeId(daqObject); @@ -125,6 +126,8 @@ class TmsServerObject : public std::enable_shared_from_this { auto tmsObject = std::make_shared(daqObject, this->server, daqContext, std::forward(params)...); tmsObject->registerOpcUaNode(parentNodeId); + if(numberInList != std::numeric_limits::max()) + tmsObject->setNumberInList(numberInList); return tmsObject; } } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index f9c9fe2..f1f908c 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -224,10 +224,8 @@ void TmsServerDevice::populateStreamingOptions() for (const auto& streamingOption : streamingOptions) { auto tmsStreamingOption = registerTmsObjectOrAddReference( - streamingOptionsNodeId, streamingOption.asPtr(), streamingOption.getProtocolId()); - tmsStreamingOption->setNumberInList(numberInList); + streamingOptionsNodeId, streamingOption.asPtr(), numberInList++, streamingOption.getProtocolId()); this->streamingOptions.push_back(std::move(tmsStreamingOption)); - numberInList++; } } @@ -241,8 +239,7 @@ void TmsServerDevice::addChildNodes() uint32_t numberInList = 0; for (const auto& device : object.getDevices()) { - auto tmsDevice = registerTmsObjectOrAddReference(nodeId, device); - tmsDevice->setNumberInList(numberInList++); + auto tmsDevice = registerTmsObjectOrAddReference(nodeId, device, numberInList++); devices.push_back(std::move(tmsDevice)); } @@ -251,8 +248,7 @@ void TmsServerDevice::addChildNodes() numberInList = 0; for (const auto& functionBlock : object.getFunctionBlocks()) { - auto tmsFunctionBlock = registerTmsObjectOrAddReference>(functionBlockNodeId, functionBlock); - tmsFunctionBlock->setNumberInList(numberInList++); + auto tmsFunctionBlock = registerTmsObjectOrAddReference>(functionBlockNodeId, functionBlock, numberInList++); functionBlocks.push_back(std::move(tmsFunctionBlock)); } @@ -261,8 +257,7 @@ void TmsServerDevice::addChildNodes() numberInList = 0; for (const auto& signal : object.getSignals()) { - auto tmsSignal = registerTmsObjectOrAddReference(signalsNodeId, signal); - tmsSignal->setNumberInList(numberInList++); + auto tmsSignal = registerTmsObjectOrAddReference(signalsNodeId, signal, numberInList++); signals.push_back(std::move(tmsSignal)); } @@ -283,14 +278,12 @@ void TmsServerDevice::addChildNodes() if (component.asPtrOrNull().assigned()) { - auto folderNode = registerTmsObjectOrAddReference(nodeId, component); - folderNode->setNumberInList(numberInList++); + auto folderNode = registerTmsObjectOrAddReference(nodeId, component, numberInList++); folders.push_back(std::move(folderNode)); } else { - auto componentNode = registerTmsObjectOrAddReference>(nodeId, component); - componentNode->setNumberInList(numberInList++); + auto componentNode = registerTmsObjectOrAddReference>(nodeId, component, numberInList++); components.push_back(std::move(componentNode)); } } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp index 601a007..d1e7e5c 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp @@ -24,20 +24,17 @@ void TmsServerFolder::addChildNodes() if (channel.assigned()) { - auto tmsChannel = registerTmsObjectOrAddReference(this->nodeId, channel); - tmsChannel->setNumberInList(numberInList++); + auto tmsChannel = registerTmsObjectOrAddReference(this->nodeId, channel, numberInList++); channels.push_back(std::move(tmsChannel)); } else if (folder.assigned()) // It is important to test for folder last as a channel also is a folder! { - auto tmsFolder = registerTmsObjectOrAddReference(this->nodeId, folder); - tmsFolder->setNumberInList(numberInList++); + auto tmsFolder = registerTmsObjectOrAddReference(this->nodeId, folder, numberInList++); folders.push_back(std::move(tmsFolder)); } else if (component.assigned()) // It is important to test for component after folder! { - auto tmsComponent = registerTmsObjectOrAddReference>(this->nodeId, component); - tmsComponent->setNumberInList(numberInList++); + auto tmsComponent = registerTmsObjectOrAddReference>(this->nodeId, component, numberInList++); components.push_back(std::move(tmsComponent)); } else diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp index 84f4638..0baca55 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp @@ -52,8 +52,7 @@ void TmsServerFunctionBlock::addChildNodes() uint32_t numberInList = 0; for (const auto& signal : this->object.getSignals()) { - auto tmsSignal = this->template registerTmsObjectOrAddReference(signalsNodeId, signal); - tmsSignal->setNumberInList(numberInList++); + auto tmsSignal = this->template registerTmsObjectOrAddReference(signalsNodeId, signal, numberInList++); signals.push_back(std::move(tmsSignal)); } @@ -63,16 +62,14 @@ void TmsServerFunctionBlock::addChildNodes() numberInList = 0; for (const auto& inputPort : this->object.getInputPorts()) { - auto tmsInputPort = this->template registerTmsObjectOrAddReference(inputPortsNodeId, inputPort); - tmsInputPort->setNumberInList(numberInList++); + auto tmsInputPort = this->template registerTmsObjectOrAddReference(inputPortsNodeId, inputPort, numberInList++); inputPorts.push_back(std::move(tmsInputPort)); } numberInList = 0; for (const auto& fb : this->object.getFunctionBlocks()) { - auto tmsFunctionBlock = this->template registerTmsObjectOrAddReference>(this->nodeId, fb); - tmsFunctionBlock->setNumberInList(numberInList++); + auto tmsFunctionBlock = this->template registerTmsObjectOrAddReference>(this->nodeId, fb, numberInList++); functionBlocks.push_back(std::move(tmsFunctionBlock)); } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp index 923ec29..4b558f2 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp @@ -251,7 +251,7 @@ void TmsServerProperty::addReferenceTypeChildNodes() auto prop = parent.getRef().getProperty(propName); if (prop.getValueType() != ctObject) { - auto serverInfo = registerTmsObjectOrAddReference(nodeId, prop, parent.getRef(), propOrder); + auto serverInfo = registerTmsObjectOrAddReference(nodeId, prop, std::numeric_limits::max(), parent.getRef(),propOrder); auto childNodeId = serverInfo->getNodeId(); childProperties.insert({childNodeId, serverInfo}); } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp index 9c3c97d..e444184 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp @@ -101,7 +101,7 @@ void TmsServerPropertyObject::addChildNodes() } else { - serverInfo = registerTmsObjectOrAddReference(nodeId, prop, object, propOrder); + serverInfo = registerTmsObjectOrAddReference(nodeId, prop, std::numeric_limits::max(), object, propOrder); childNodeId = serverInfo->getNodeId(); } @@ -111,9 +111,8 @@ void TmsServerPropertyObject::addChildNodes() { const auto propName = prop.getName(); PropertyObjectPtr obj = object.getPropertyValue(propName); - auto serverInfo = registerTmsObjectOrAddReference(nodeId, obj, propName, prop); + auto serverInfo = registerTmsObjectOrAddReference(nodeId, obj, propOrder[propName], propName, prop); auto childNodeId = serverInfo->getNodeId(); - serverInfo->setNumberInList(propOrder[propName]); childObjects.insert({childNodeId, serverInfo}); } } From 292bb740b8586239dd58ff26155b0991bef3bb50 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Wed, 25 Oct 2023 09:09:57 +0200 Subject: [PATCH 010/217] Add OPC UA node order tests --- .../objects/tms_server_object.h | 2 + .../test_property_object_advanced.cpp | 14 +++ .../test_tms_amplifier.cpp | 28 ++++++ .../opcuatms_integration/test_tms_device.cpp | 95 +++++++++++++++++++ .../opcuatms_integration/test_tms_folder.cpp | 39 ++++++++ .../test_tms_function_block.cpp | 56 +++++++++++ .../test_tms_property_object.cpp | 27 ++++++ 7 files changed, 261 insertions(+) diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h index 93373ee..e11cbbf 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h @@ -107,6 +107,8 @@ class TmsServerObject : public std::enable_shared_from_this item->createNonhierarchicalReferences(); } + // TODO: NumberInList is configured only when object is registered. Order of nodes on objects of which child nodes + // reference other ones will not be correct! template std::shared_ptr registerTmsObjectOrAddReference(const opcua::OpcUaNodeId& parentNodeId, const DAQ_T& daqObject, diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp index 9a2e318..4287f97 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp @@ -749,3 +749,17 @@ TEST_F(TmsPropertyObjectAdvancedTest, StructureSet) ASSERT_EQ(clientObj.getPropertyValue("CustomRuleDescriptionStructure"), obj.getPropertyValue("CustomRuleDescriptionStructure")); ASSERT_EQ(clientObj.getPropertyValue("AdditionalParametersType"), obj.getPropertyValue("AdditionalParametersType")); } + +TEST_F(TmsPropertyObjectAdvancedTest, PropertyOrder) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + auto serverProps = obj.getAllProperties(); + auto clientProps = clientObj.getAllProperties(); + + ASSERT_EQ(serverProps.getCount(), clientProps.getCount()); + + for (SizeT i = 0; i < serverProps.getCount(); ++i) + ASSERT_EQ(serverProps[i].getName(), clientProps[i].getName()); +} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp index 132468f..53d0e00 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp @@ -745,3 +745,31 @@ TEST_F(TMSAmplifierTest, GetRefPropSelectionValuesAfterChange) stgAmpl.setPropertyValue("Measurement", 1); ASSERT_EQ(rangeProp.getSelectionValues(), bridgeRangeValues); } + +TEST_F(TMSAmplifierTest, PropertyOrder1) +{ + const auto obj = PropertyObject(objManager, "StgAmp"); + auto [serverObj, stgAmpl] = registerPropertyObject(obj); + + auto serverProps = obj.getAllProperties(); + auto clientProps = stgAmpl.getAllProperties(); + + ASSERT_EQ(serverProps.getCount(), clientProps.getCount()); + + for (SizeT i = 0; i < serverProps.getCount(); ++i) + ASSERT_EQ(serverProps[i].getName(), clientProps[i].getName()); +} + +TEST_F(TMSAmplifierTest, PropertyOrder2) +{ + const auto obj = PropertyObject(objManager, "LvAmp"); + auto [serverObj, lvAmpl] = registerPropertyObject(obj); + + auto serverProps = obj.getAllProperties(); + auto clientProps = lvAmpl.getAllProperties(); + + ASSERT_EQ(serverProps.getCount(), clientProps.getCount()); + + for (SizeT i = 0; i < serverProps.getCount(); ++i) + ASSERT_EQ(serverProps[i].getName(), clientProps[i].getName()); +} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp index ef623d6..c8a7cd8 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include "opcuatms/exceptions.h" #include #include @@ -341,3 +343,96 @@ TEST_F(TmsDeviceTest, DeviceProcedureProperty) ProcedurePtr proc = clientSubDevice.getPropertyValue("stop"); ASSERT_NO_THROW(proc()); } + +TEST_F(TmsDeviceTest, SignalOrder) +{ + auto serverDevice = DefaultDevice(NullContext(), nullptr, "mock"); + FolderConfigPtr folder = serverDevice.getItem("sig"); + for (int i = 0; i < 100; ++i) + folder.addItem(Signal(NullContext(), folder, "sig_" + std::to_string(i))); + + auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto nodeId = tmsServerDevice.registerOpcUaNode(); + DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "dev", clientContext, nodeId, nullptr); + + const auto serverSignals = serverDevice.getSignals(); + const auto clientSignals = clientDevice.getSignals(); + + for (SizeT i = 0; i < serverSignals.getCount(); ++i) + ASSERT_EQ(serverSignals[i].getName(), clientSignals[i].getName()); +} + +TEST_F(TmsDeviceTest, DeviceOrder) +{ + auto serverDevice = DefaultDevice(NullContext(), nullptr, "mock"); + FolderConfigPtr folder = serverDevice.getItem("dev"); + for (int i = 0; i < 100; ++i) + folder.addItem(DefaultDevice(NullContext(), folder, "dev_" + std::to_string(i))); + + auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto nodeId = tmsServerDevice.registerOpcUaNode(); + DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "dev", clientContext, nodeId, nullptr); + + const auto serverDevices = serverDevice.getDevices(); + const auto clientDevices = clientDevice.getDevices(); + + for (SizeT i = 0; i < serverDevices.getCount(); ++i) + ASSERT_EQ(serverDevices[i].getName(), clientDevices[i].getName()); +} + +TEST_F(TmsDeviceTest, FunctionBlockOrder) +{ + auto serverDevice = DefaultDevice(NullContext(), nullptr, "mock"); + FolderConfigPtr folder = serverDevice.getItem("fb"); + for (int i = 0; i < 100; ++i) + folder.addItem(DefaultFunctionBlock(NullContext(), folder, "fb_" + std::to_string(i))); + + auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto nodeId = tmsServerDevice.registerOpcUaNode(); + DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "dev", clientContext, nodeId, nullptr); + + const auto serverFbs = serverDevice.getFunctionBlocks(); + const auto clientFbs = clientDevice.getFunctionBlocks(); + + for (SizeT i = 0; i < serverFbs.getCount(); ++i) + ASSERT_EQ(serverFbs[i].getName(), clientFbs[i].getName()); +} + +TEST_F(TmsDeviceTest, IOFolderOrder) +{ + auto serverDevice = DefaultDevice(NullContext(), nullptr, "mock"); + FolderConfigPtr folder = serverDevice.getItem("io"); + for (int i = 0; i < 100; ++i) + { + folder.addItem(IoFolder(NullContext(), folder, "cmp_" + std::to_string(i))); + folder.addItem(DefaultChannel(NullContext(), folder, "ch_" + std::to_string(i))); + } + + auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto nodeId = tmsServerDevice.registerOpcUaNode(); + DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "dev", clientContext, nodeId, nullptr); + + const auto serverIO = serverDevice.getInputsOutputsFolder().getItems(); + const auto clientIO = clientDevice.getInputsOutputsFolder().getItems(); + + for (SizeT i = 0; i < serverIO.getCount(); ++i) + ASSERT_EQ(serverIO[i].getName(), clientIO[i].getName()); +} + +TEST_F(TmsDeviceTest, CustomComponentOrder) +{ + auto serverDevice = DefaultDevice(NullContext(), nullptr, "mock"); + auto folder = serverDevice.asPtr(); + for (int i = 0; i < 100; ++i) + folder->addCustomComponent(Component(NullContext(), folder, "cmp_" + std::to_string(i))); + + auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto nodeId = tmsServerDevice.registerOpcUaNode(); + DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "dev", clientContext, nodeId, nullptr); + + const auto serverCmps = serverDevice.getCustomComponents(); + const auto clientCmps = clientDevice.getCustomComponents(); + + for (SizeT i = 0; i < serverCmps.getCount(); ++i) + ASSERT_EQ(serverCmps[i].getName(), clientCmps[i].getName()); +} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp index 558a621..f87e0d6 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp @@ -148,3 +148,42 @@ TEST_F(TmsFolderTest, IOFolder) ASSERT_TRUE(folder.serverFolder.getItems()[0].asPtrOrNull().getItems()[0].asPtrOrNull().assigned()); ASSERT_TRUE(folder.clientFolder.getItems()[0].asPtrOrNull().getItems()[0].asPtrOrNull().assigned()); } + +TEST_F(TmsFolderTest, IOFolderNodeOrder) +{ + auto folder = IoFolder(NullContext(), nullptr, "parent"); + for (int i = 0; i < 100; ++i) + { + folder.addItem(IoFolder(NullContext(), folder, "child" + std::to_string(i))); + } + + for (int i = 0; i < 10; ++i) + { + folder.addItem(MockChannel(NullContext(), folder, "channel" + std::to_string(i))); + } + + auto registered = registerTestFolder(folder); + + auto serverItems = folder.getItems(); + auto clientItems = registered.clientFolder.getItems(); + + for (SizeT i = 0; i < serverItems.getCount(); ++i) + ASSERT_EQ(serverItems[i].getName(), clientItems[i].getName()); +} + +TEST_F(TmsFolderTest, FolderNodeOrder) +{ + auto folder = Folder(NullContext(), nullptr, "parent"); + for (int i = 0; i < 100; ++i) + { + folder.addItem(Folder(NullContext(), folder, "child" + std::to_string(i))); + } + + auto registered = registerTestFolder(folder); + + auto serverItems = folder.getItems(); + auto clientItems = registered.clientFolder.getItems(); + + for (SizeT i = 0; i < serverItems.getCount(); ++i) + ASSERT_EQ(serverItems[i].getName(), clientItems[i].getName()); +} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp index 7ad92b4..a91292a 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp @@ -16,8 +16,10 @@ #include "opcuatms_client/objects/tms_client_signal_factory.h" #include "open62541/tmsbsp_nodeids.h" #include "tms_object_integration_test.h" +#include "opendaq/folder_config_ptr.h" #include "opendaq/mock/mock_fb_factory.h" +#include "opendaq/mock/default_mocks_factory.h" using namespace daq; using namespace opcua::tms; @@ -232,3 +234,57 @@ TEST_F(TmsFunctionBlockTest, ComponentMethods) clientFunctionBlock.setActive(true); ASSERT_EQ(serverFunctionBlock.getActive(), clientFunctionBlock.getActive()); } + +TEST_F(TmsFunctionBlockTest, SignalOrder) +{ + auto serverFunctionBlock = DefaultFunctionBlock(NullContext(), nullptr, "mock"); + FolderConfigPtr folder = serverFunctionBlock.getItem("sig"); + for (int i = 0; i < 100; ++i) + folder.addItem(Signal(NullContext(), folder, "sig_" + std::to_string(i))); + + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto functionBlockNodeId = tmsServerFunctionBlock.registerOpcUaNode(); + FunctionBlockPtr clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, functionBlockNodeId); + + const auto serverSignals = serverFunctionBlock.getSignals(); + const auto clientSignals = clientFunctionBlock.getSignals(); + + for (SizeT i = 0; i < serverSignals.getCount(); ++i) + ASSERT_EQ(serverSignals[i].getName(), clientSignals[i].getName()); +} + +TEST_F(TmsFunctionBlockTest, InputPortOrder) +{ + auto serverFunctionBlock = DefaultFunctionBlock(NullContext(), nullptr, "mock"); + FolderConfigPtr folder = serverFunctionBlock.getItem("ip"); + for (int i = 0; i < 100; ++i) + folder.addItem(InputPort(NullContext(), folder, "ip_" + std::to_string(i))); + + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto functionBlockNodeId = tmsServerFunctionBlock.registerOpcUaNode(); + FunctionBlockPtr clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, functionBlockNodeId); + + const auto serverInputPorts = serverFunctionBlock.getInputPorts(); + const auto clientInputPorts = clientFunctionBlock.getInputPorts(); + + for (SizeT i = 0; i < serverInputPorts.getCount(); ++i) + ASSERT_EQ(serverInputPorts[i].getName(), clientInputPorts[i].getName()); +} + +TEST_F(TmsFunctionBlockTest, FunctionBlockOrder) +{ + auto serverFunctionBlock = DefaultFunctionBlock(NullContext(), nullptr, "mock"); + FolderConfigPtr folder = serverFunctionBlock.getItem("fb"); + for (int i = 0; i < 40; ++i) + folder.addItem(DefaultFunctionBlock(NullContext(), folder, "fb_" + std::to_string(i))); + + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto functionBlockNodeId = tmsServerFunctionBlock.registerOpcUaNode(); + FunctionBlockPtr clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, functionBlockNodeId); + + const auto serverFunctionBlocks = serverFunctionBlock.getFunctionBlocks(); + const auto clientFunctionBlocks = clientFunctionBlock.getFunctionBlocks(); + + for (SizeT i = 0; i < serverFunctionBlocks.getCount(); ++i) + ASSERT_EQ(serverFunctionBlocks[i].getName(), clientFunctionBlocks[i].getName()); +} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp index 806ed6d..d7c9c5c 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp @@ -10,6 +10,8 @@ #include "tms_object_integration_test.h" #include "opcuatms_client/objects/tms_client_property_object_factory.h" #include + +#include "coreobjects/callable_info_factory.h" #include "opendaq/context_factory.h" using namespace daq; @@ -197,3 +199,28 @@ TEST_F(TmsPropertyObjectTest, TestListProperty) auto clientDict = clientProp.getPropertyValue("ListProp"); ASSERT_EQ(list, clientDict); } + +TEST_F(TmsPropertyObjectTest, TestPropertyOrder) +{ + auto obj = PropertyObject(); + for (SizeT i = 0; i < 200; ++i) + obj.addProperty(BoolProperty("bool" + std::to_string(i), true)); + for (SizeT i = 0; i < 200; ++i) + obj.addProperty(StringProperty("string" + std::to_string(i), "test")); + for (SizeT i = 0; i < 200; ++i) + { + obj.addProperty(FunctionProperty("func" + std::to_string(i), ProcedureInfo())); + ProcedurePtr test = Procedure([](){}); + obj.setPropertyValue("func" + std::to_string(i), test); + } + + auto [serverObj, clientObj] = registerPropertyObject(obj); + auto serverProps = obj.getAllProperties(); + auto clientProps = clientObj.getAllProperties(); + + ASSERT_EQ(serverProps.getCount(), clientProps.getCount()); + + for (SizeT i = 0; i < serverProps.getCount(); ++i) + ASSERT_EQ(serverProps[i].getName(), clientProps[i].getName()); + +} From 1a72c0b5ed1a96c839b90a384dfcc722fcbc23bc Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Fri, 3 Nov 2023 11:31:49 +0100 Subject: [PATCH 011/217] Update default component IDs to capital case --- .../opcuashared/tools/generate_datatypes.sh | 10 ------- .../src/objects/tms_client_device_impl.cpp | 8 +++--- .../tms_client_function_block_impl.cpp | 4 +-- .../src/objects/tms_server_device.cpp | 10 +++---- .../src/objects/tms_server_function_block.cpp | 6 ++--- .../tests/test_tms_channel.cpp | 2 +- .../opcuatms_server/tests/test_tms_device.cpp | 2 +- .../tests/test_tms_function_block.cpp | 2 +- .../opcuatms_server/tests/test_tms_server.cpp | 4 +-- .../opcuatms_integration/test_tms_device.cpp | 26 +++++++++---------- .../test_tms_function_block.cpp | 6 ++--- 11 files changed, 35 insertions(+), 45 deletions(-) delete mode 100644 shared/libraries/opcua/opcuashared/tools/generate_datatypes.sh diff --git a/shared/libraries/opcua/opcuashared/tools/generate_datatypes.sh b/shared/libraries/opcua/opcuashared/tools/generate_datatypes.sh deleted file mode 100644 index bb58a5e..0000000 --- a/shared/libraries/opcua/opcuashared/tools/generate_datatypes.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -OPEN62541_ROOT="C:/DXEProjects/Apps/Blueberry/build/x64/msvc-19/full/external/bbopen62541/build/open62541-src" - -python $OPEN62541_ROOT/tools/generate_datatypes.py \ - --namespace="1:https://blueberrydaq.com/ua" \ - --type-csv=schema/BB.NodeIds.csv \ - --type-bsd=schema/BB.Opc.Ua.Types.bsd \ - --no-builtin \ - bb diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index ce97925..2f7a6e5 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -25,7 +25,7 @@ using namespace daq::opcua; namespace detail { - static std::unordered_set defaultComponents = {"Signals", "FunctionBlocks", "InputsOutputs", "StreamingOptions"}; + static std::unordered_set defaultComponents = {"Sig", "FB", "IO", "StreamingOptions"}; static std::unordered_map> deviceInfoSetterMap = { {"AssetId", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setAssetId(v.toString()); }}, @@ -225,7 +225,7 @@ void TmsClientDeviceImpl::findAndCreateFunctionBlocks() std::map orderedFunctionBlocks; std::vector unorderedFunctionBlocks; - auto functionBlocksNodeId = getNodeId("FunctionBlocks"); + auto functionBlocksNodeId = getNodeId("FB"); auto functionBlockNodeIds = this->getChildNodes(client, functionBlocksNodeId, OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_FUNCTIONBLOCKTYPE)); for (const auto& functionBlockNodeId : functionBlockNodeIds) @@ -257,7 +257,7 @@ void TmsClientDeviceImpl::findAndCreateSignals() std::map orderedSignals; std::vector unorderedSignals; - const auto signalsNodeId = getNodeId("Signals"); + const auto signalsNodeId = getNodeId("Sig"); const auto signalNodeIds = this->getChildNodes(client, signalsNodeId, OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_SIGNALTYPE)); for (const auto& signalNodeId : signalNodeIds) { @@ -281,7 +281,7 @@ void TmsClientDeviceImpl::findAndCreateInputsOutputs() std::vector unorderedComponents; this->ioFolder.clear(); - auto inputsOutputsNodeId = getNodeId("InputsOutputs"); + auto inputsOutputsNodeId = getNodeId("IO"); auto channelNodeIds = this->getChildNodes(client, inputsOutputsNodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_CHANNELTYPE)); for (const auto& channelNodeId : channelNodeIds) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp index 4fa53b1..199d681 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp @@ -38,7 +38,7 @@ tsl::ordered_set TmsClientFunctionBlockBaseImpl:: template tsl::ordered_set TmsClientFunctionBlockBaseImpl::getOutputSignalNodeIds() { - auto signalsNodeId = this->getNodeId("OutputSignals"); + auto signalsNodeId = this->getNodeId("Sig"); OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASVALUESIGNAL); return this->referenceUtils.getReferencedNodes(signalsNodeId, referenceTypeId, true); @@ -106,7 +106,7 @@ void TmsClientFunctionBlockBaseImpl::findAndCreateSignals() template tsl::ordered_set TmsClientFunctionBlockBaseImpl::getInputPortNodeIds() { - auto inputPortsNodeId = this->getNodeId("InputPorts"); + auto inputPortsNodeId = this->getNodeId("IP"); OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASINPUTPORT); return this->referenceUtils.getReferencedNodes(inputPortsNodeId, referenceTypeId, true); diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index f1f908c..dd7256e 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -243,7 +243,7 @@ void TmsServerDevice::addChildNodes() devices.push_back(std::move(tmsDevice)); } - auto functionBlockNodeId = getChildNodeId("FunctionBlocks"); + auto functionBlockNodeId = getChildNodeId("FB"); assert(!functionBlockNodeId.isNull()); numberInList = 0; for (const auto& functionBlock : object.getFunctionBlocks()) @@ -252,7 +252,7 @@ void TmsServerDevice::addChildNodes() functionBlocks.push_back(std::move(tmsFunctionBlock)); } - auto signalsNodeId = getChildNodeId("Signals"); + auto signalsNodeId = getChildNodeId("Sig"); assert(!signalsNodeId.isNull()); numberInList = 0; for (const auto& signal : object.getSignals()) @@ -261,7 +261,7 @@ void TmsServerDevice::addChildNodes() signals.push_back(std::move(tmsSignal)); } - auto inputsOutputsNodeId = getChildNodeId("InputsOutputs"); + auto inputsOutputsNodeId = getChildNodeId("IO"); assert(!inputsOutputsNodeId.isNull()); auto topFolder = object.getInputsOutputsFolder(); @@ -272,8 +272,8 @@ void TmsServerDevice::addChildNodes() numberInList = 0; for (auto component : object.getItems()) { - auto id = component.getName(); - if (id == "dev" || id == "fb" || id == "io" || id == "sig") + auto id = component.getLocalId(); + if (id == "Dev" || id == "FB" || id == "IO" || id == "Sig") continue; if (component.asPtrOrNull().assigned()) diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp index 0baca55..301a8e0 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp @@ -25,7 +25,7 @@ template bool TmsServerFunctionBlock::createOptionalNode(const OpcUaNodeId& nodeId) { auto browseName = this->server->readBrowseName(nodeId); - auto create = browseName->name == "OutputSignals" || browseName->name == "InputPorts"; + auto create = browseName->name == "Sig" || browseName->name == "IP"; return create || Super::createOptionalNode(nodeId); } @@ -46,7 +46,7 @@ void TmsServerFunctionBlock::bindCallbacks() template void TmsServerFunctionBlock::addChildNodes() { - auto signalsNodeId = this->getChildNodeId("OutputSignals"); + auto signalsNodeId = this->getChildNodeId("Sig"); assert(!signalsNodeId.isNull()); uint32_t numberInList = 0; @@ -56,7 +56,7 @@ void TmsServerFunctionBlock::addChildNodes() signals.push_back(std::move(tmsSignal)); } - auto inputPortsNodeId = this->getChildNodeId("InputPorts"); + auto inputPortsNodeId = this->getChildNodeId("IP"); assert(!inputPortsNodeId.isNull()); numberInList = 0; diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_channel.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_channel.cpp index afccc09..2bfdc2b 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_channel.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_channel.cpp @@ -64,7 +64,7 @@ TEST_F(TmsChannelTest, BrowseSignals) auto nodeId = serverChannel.registerOpcUaNode(); OpcUaServerNode serverNodeFB(*this->getServer(), nodeId); - auto signalServerNode = serverNodeFB.getChildNode(UA_QUALIFIEDNAME_ALLOC(NAMESPACE_TMSBSP, "OutputSignals")); + auto signalServerNode = serverNodeFB.getChildNode(UA_QUALIFIEDNAME_ALLOC(NAMESPACE_TMSBSP, "Sig")); auto signalReferences = signalServerNode->browse(OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASVALUESIGNAL)); ASSERT_EQ(signalReferences.size(), 10u); } diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_device.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_device.cpp index 1463246..27dbd55 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_device.cpp @@ -48,7 +48,7 @@ TEST_F(TmsDeviceTest, FunctionBlock) auto tmsDevice = TmsServerDevice(device, this->getServer(), NullContext()); auto nodeId = tmsDevice.registerOpcUaNode(); - auto functionBlockNodeId = getChildNodeId(nodeId, "FunctionBlocks"); + auto functionBlockNodeId = getChildNodeId(nodeId, "FB"); ASSERT_EQ(test_helpers::BrowseFunctionBlocks(client, functionBlockNodeId).size(), 1u); } diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp index 730be18..8ab402d 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp @@ -72,7 +72,7 @@ TEST_F(TmsFunctionBlockTest, BrowseSignals) auto nodeId = serverFunctionBlock.registerOpcUaNode(); OpcUaServerNode serverNodeFB(*this->getServer(), nodeId); - auto signalServerNode = serverNodeFB.getChildNode(UA_QUALIFIEDNAME_ALLOC(NAMESPACE_TMSBSP, "OutputSignals")); + auto signalServerNode = serverNodeFB.getChildNode(UA_QUALIFIEDNAME_ALLOC(NAMESPACE_TMSBSP, "Sig")); auto signalReferences = signalServerNode->browse(OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASVALUESIGNAL)); ASSERT_EQ(signalReferences.size(), 5u); } diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_server.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_server.cpp index aa5a1a1..62a3e78 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_server.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_server.cpp @@ -62,13 +62,13 @@ TEST_F(TmsServerTest, Channels) auto client = TmsObjectTest::CreateAndConnectTestClient(); auto mockPhysicalDevice = GetMockPhysicalDevice(client); - auto inputsOutputsFolder = BrowseForChild(client, mockPhysicalDevice, "InputsOutputs"); + auto inputsOutputsFolder = BrowseForChild(client, mockPhysicalDevice, "IO"); ASSERT_FALSE(inputsOutputsFolder.isNull()); auto channels = BrowseChannels(client, inputsOutputsFolder); ASSERT_EQ(channels.size(), 1u); - auto signalsNode = BrowseForChild(client, channels[0], "OutputSignals"); + auto signalsNode = BrowseForChild(client, channels[0], "Sig"); ASSERT_FALSE(signalsNode.isNull()); auto signals = BrowseSignals(client, signalsNode); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp index c8a7cd8..b8b602d 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp @@ -264,7 +264,7 @@ TEST_F(TmsDeviceTest, CustomComponents) auto nodeId = serverTmsDevice.registerOpcUaNode(); auto serverSubDevice = serverDevice.getDevices()[1]; - auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "Dev", clientContext, nodeId, nullptr); auto clientSubDevice = clientDevice.getDevices()[1]; ASSERT_EQ(serverSubDevice.getItems().getCount(), clientSubDevice.getItems().getCount()); @@ -286,7 +286,7 @@ TEST_F(TmsDeviceTest, CustomComponentsProperties) auto nodeId = serverTmsDevice.registerOpcUaNode(); auto serverSubDevice = serverDevice.getDevices()[1]; - auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "Dev", clientContext, nodeId, nullptr); auto clientSubDevice = clientDevice.getDevices()[1]; ASSERT_EQ(serverSubDevice.getItems().getCount(), clientSubDevice.getItems().getCount()); @@ -309,7 +309,7 @@ TEST_F(TmsDeviceTest, ComponentMethods) auto nodeId = serverTmsDevice.registerOpcUaNode(); auto serverSubDevice = serverDevice.getDevices()[1]; - auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "Dev", clientContext, nodeId, nullptr); auto clientSubDevice = clientDevice.getDevices()[1]; ASSERT_EQ(serverSubDevice.getName(), clientSubDevice.getName()); @@ -334,7 +334,7 @@ TEST_F(TmsDeviceTest, DeviceProcedureProperty) auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); auto nodeId = serverTmsDevice.registerOpcUaNode(); - auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "Dev", clientContext, nodeId, nullptr); auto clientSubDevice = clientDevice.getDevices()[1]; auto procProp = clientSubDevice.getProperty("stop"); @@ -347,13 +347,13 @@ TEST_F(TmsDeviceTest, DeviceProcedureProperty) TEST_F(TmsDeviceTest, SignalOrder) { auto serverDevice = DefaultDevice(NullContext(), nullptr, "mock"); - FolderConfigPtr folder = serverDevice.getItem("sig"); + FolderConfigPtr folder = serverDevice.getItem("Sig"); for (int i = 0; i < 100; ++i) folder.addItem(Signal(NullContext(), folder, "sig_" + std::to_string(i))); auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); auto nodeId = tmsServerDevice.registerOpcUaNode(); - DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "dev", clientContext, nodeId, nullptr); + DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "Dev", clientContext, nodeId, nullptr); const auto serverSignals = serverDevice.getSignals(); const auto clientSignals = clientDevice.getSignals(); @@ -365,13 +365,13 @@ TEST_F(TmsDeviceTest, SignalOrder) TEST_F(TmsDeviceTest, DeviceOrder) { auto serverDevice = DefaultDevice(NullContext(), nullptr, "mock"); - FolderConfigPtr folder = serverDevice.getItem("dev"); + FolderConfigPtr folder = serverDevice.getItem("Dev"); for (int i = 0; i < 100; ++i) folder.addItem(DefaultDevice(NullContext(), folder, "dev_" + std::to_string(i))); auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); auto nodeId = tmsServerDevice.registerOpcUaNode(); - DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "dev", clientContext, nodeId, nullptr); + DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "Dev", clientContext, nodeId, nullptr); const auto serverDevices = serverDevice.getDevices(); const auto clientDevices = clientDevice.getDevices(); @@ -383,13 +383,13 @@ TEST_F(TmsDeviceTest, DeviceOrder) TEST_F(TmsDeviceTest, FunctionBlockOrder) { auto serverDevice = DefaultDevice(NullContext(), nullptr, "mock"); - FolderConfigPtr folder = serverDevice.getItem("fb"); + FolderConfigPtr folder = serverDevice.getItem("FB"); for (int i = 0; i < 100; ++i) folder.addItem(DefaultFunctionBlock(NullContext(), folder, "fb_" + std::to_string(i))); auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); auto nodeId = tmsServerDevice.registerOpcUaNode(); - DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "dev", clientContext, nodeId, nullptr); + DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "Dev", clientContext, nodeId, nullptr); const auto serverFbs = serverDevice.getFunctionBlocks(); const auto clientFbs = clientDevice.getFunctionBlocks(); @@ -401,7 +401,7 @@ TEST_F(TmsDeviceTest, FunctionBlockOrder) TEST_F(TmsDeviceTest, IOFolderOrder) { auto serverDevice = DefaultDevice(NullContext(), nullptr, "mock"); - FolderConfigPtr folder = serverDevice.getItem("io"); + FolderConfigPtr folder = serverDevice.getItem("IO"); for (int i = 0; i < 100; ++i) { folder.addItem(IoFolder(NullContext(), folder, "cmp_" + std::to_string(i))); @@ -410,7 +410,7 @@ TEST_F(TmsDeviceTest, IOFolderOrder) auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); auto nodeId = tmsServerDevice.registerOpcUaNode(); - DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "dev", clientContext, nodeId, nullptr); + DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "Dev", clientContext, nodeId, nullptr); const auto serverIO = serverDevice.getInputsOutputsFolder().getItems(); const auto clientIO = clientDevice.getInputsOutputsFolder().getItems(); @@ -428,7 +428,7 @@ TEST_F(TmsDeviceTest, CustomComponentOrder) auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); auto nodeId = tmsServerDevice.registerOpcUaNode(); - DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "dev", clientContext, nodeId, nullptr); + DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "Dev", clientContext, nodeId, nullptr); const auto serverCmps = serverDevice.getCustomComponents(); const auto clientCmps = clientDevice.getCustomComponents(); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp index a91292a..547a103 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp @@ -238,7 +238,7 @@ TEST_F(TmsFunctionBlockTest, ComponentMethods) TEST_F(TmsFunctionBlockTest, SignalOrder) { auto serverFunctionBlock = DefaultFunctionBlock(NullContext(), nullptr, "mock"); - FolderConfigPtr folder = serverFunctionBlock.getItem("sig"); + FolderConfigPtr folder = serverFunctionBlock.getItem("Sig"); for (int i = 0; i < 100; ++i) folder.addItem(Signal(NullContext(), folder, "sig_" + std::to_string(i))); @@ -256,7 +256,7 @@ TEST_F(TmsFunctionBlockTest, SignalOrder) TEST_F(TmsFunctionBlockTest, InputPortOrder) { auto serverFunctionBlock = DefaultFunctionBlock(NullContext(), nullptr, "mock"); - FolderConfigPtr folder = serverFunctionBlock.getItem("ip"); + FolderConfigPtr folder = serverFunctionBlock.getItem("IP"); for (int i = 0; i < 100; ++i) folder.addItem(InputPort(NullContext(), folder, "ip_" + std::to_string(i))); @@ -274,7 +274,7 @@ TEST_F(TmsFunctionBlockTest, InputPortOrder) TEST_F(TmsFunctionBlockTest, FunctionBlockOrder) { auto serverFunctionBlock = DefaultFunctionBlock(NullContext(), nullptr, "mock"); - FolderConfigPtr folder = serverFunctionBlock.getItem("fb"); + FolderConfigPtr folder = serverFunctionBlock.getItem("FB"); for (int i = 0; i < 40; ++i) folder.addItem(DefaultFunctionBlock(NullContext(), folder, "fb_" + std::to_string(i))); From 87b62232428012373c4e713168d3a88e6a5be362 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Mon, 6 Nov 2023 08:49:22 +0100 Subject: [PATCH 012/217] Fix OPC UA client function property error --- .../opcuatms_client/objects/tms_client_property_object_impl.h | 2 +- .../src/objects/tms_client_property_object_impl.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h index 8e31c9f..3be45dd 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h @@ -120,7 +120,7 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl void addMethodProperties(const tsl::ordered_map>& references, const opcua::OpcUaNodeId& parentNodeId, std::map& orderedProperties, - std::vector unorderedProperties, + std::vector& unorderedProperties, std::unordered_map& functionPropValues); void browseRawProperties(); ErrCode INTERFACE_FUNC setPropertyValueInternal(IString* propertyName, IBaseObject* value, bool protectedWrite); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index 7c1dce3..2794fa5 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -273,7 +273,7 @@ void TmsClientPropertyObjectBaseImpl::addMethodProperties( const tsl::ordered_map>& references, const OpcUaNodeId& parentNodeId, std::map& orderedProperties, - std::vector unorderedProperties, + std::vector& unorderedProperties, std::unordered_map& functionPropValues) { const auto methodTypeId = OpcUaNodeId(0, UA_NS0ID_METHODNODE); From 12495a506b081330e6910d15ec5ea4ab80707a7c Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Mon, 6 Nov 2023 08:49:40 +0100 Subject: [PATCH 013/217] Add package version to OPC UA client device --- .../src/opcua_client_module_impl.cpp | 2 -- .../src/objects/tms_client_device_impl.cpp | 2 +- .../opcuatms/opcuatms_client/src/tms_client.cpp | 16 ++++++++++++++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 468f608..6ab8c23 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -67,8 +67,6 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, if (!context.assigned()) throw InvalidParameterException{"Context is not available."}; - - const auto deviceUrl = GetUrlFromConnectionString(connectionString); StringPtr rootDeviceAddress; std::smatch match; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 2f7a6e5..59c45c3 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -127,7 +127,7 @@ DeviceInfoPtr TmsClientDeviceImpl::onGetInfo() std::string browseName = daq::opcua::utils::ToStdString(reference.browseName.name); if (detail::deviceInfoSetterMap.count(browseName)) detail::deviceInfoSetterMap[browseName](deviceInfo, client->readValue(OpcUaNodeId(reference.nodeId.nodeId))); - else if (browseName != "NumberInList" && browseName != "OpenDaqPackageVersion") + else if (browseName != "NumberInList") { // TODO: Group requests for data type and scalar/array checks and only read required values try diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp index 8855b95..30df4f8 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp @@ -49,6 +49,22 @@ daq::DevicePtr TmsClient::connect() auto localId = getUniqueLocalId(client->readBrowseName(rootDeviceNodeId)); auto device = TmsClientRootDevice(context, parent, localId, tmsClientContext, rootDeviceNodeId, createStreamingCallback); + + const auto deviceInfo = device.getInfo(); + if (deviceInfo.hasProperty("OpenDaqPackageVersion")) + { + const std::string packageVersion = deviceInfo.getPropertyValue("OpenDaqPackageVersion"); + if (packageVersion != OPENDAQ_PACKAGE_VERSION) + { + const auto logger = context.getLogger(); + if (logger.assigned()) + { + const auto loggerComponent = logger.getOrAddComponent("OpcUaClient"); + LOG_I("Connected to openDAQ OPC UA server with different version. Client version: {}, server version: {}", OPENDAQ_PACKAGE_VERSION, packageVersion) + } + } + } + return device; } From f258d6aa4f57cf22477c22ea43630a4c8f5e5db2 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Fri, 10 Nov 2023 11:41:44 +0100 Subject: [PATCH 014/217] Add explicit domain rule via opcua --- .../opcuatms/include/opcuatms/type_mappings.h | 1 + .../src/converters/data_rule_converter.cpp | 54 +++++++++++++++++-- .../opcuatms/tests/test_variant_converter.cpp | 10 ++++ .../opcuatms_integration/test_tms_signal.cpp | 12 +++++ 4 files changed, 74 insertions(+), 3 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h index 88f9853..fa56a36 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h @@ -20,6 +20,7 @@ namespace daq::opcua { ADD_CUSTOM_TYPE_MAPPING(UA_BaseRuleDescriptionStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_BASERULEDESCRIPTIONSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_ExplicitDomainRuleDescriptionStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_EXPLICITDOMAINRULEDESCRIPTIONSTRUCTURE]) ADD_CUSTOM_TYPE_MAPPING(UA_CustomRuleDescriptionStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_CUSTOMRULEDESCRIPTIONSTRUCTURE]) ADD_CUSTOM_TYPE_MAPPING(UA_ConstantRuleDescriptionStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_CONSTANTRULEDESCRIPTIONSTRUCTURE]) ADD_CUSTOM_TYPE_MAPPING(UA_LinearRuleDescriptionStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LINEARRULEDESCRIPTIONSTRUCTURE]) diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/data_rule_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/data_rule_converter.cpp index 6d9ce81..f3a8254 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/data_rule_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/data_rule_converter.cpp @@ -89,6 +89,39 @@ OpcUaObject StructConverter +DataRulePtr StructConverter::ToDaqObject( + const UA_ExplicitDomainRuleDescriptionStructure& tmsStruct, + const ContextPtr& /*context*/) +{ + if (tmsStruct.type != "explicit") + throw ConversionFailedException(); + + const NumberPtr minExpectedDelta = VariantConverter::ToDaqObject(OpcUaVariant(tmsStruct.minExpectedDelta)); + const NumberPtr maxExpectedDelta = VariantConverter::ToDaqObject(OpcUaVariant(tmsStruct.maxExpectedDelta)); + + return ExplicitDomainDataRule(minExpectedDelta, maxExpectedDelta); +} + +template <> +OpcUaObject StructConverter::ToTmsType( + const DataRulePtr& object, + const ContextPtr& /*context*/) +{ + const NumberPtr minExpectedDelta = object.getParameters().get("minExpectedDelta"); + const NumberPtr maxExpectedDelta = object.getParameters().get("maxExpectedDelta"); + + OpcUaObject uaRuleDescription; + + uaRuleDescription->type = UA_STRING_ALLOC("explicit"); + uaRuleDescription->minExpectedDelta = VariantConverter::ToVariant(minExpectedDelta).getDetachedValue(); + uaRuleDescription->maxExpectedDelta = VariantConverter::ToVariant(maxExpectedDelta).getDetachedValue(); + + return uaRuleDescription; +} + // UA_CustomRuleDescription template <> @@ -168,6 +201,12 @@ DataRulePtr VariantConverter::ToDaqObject(const OpcUaVariant& variant const auto tmsStruct = static_cast(decodedVariant->data); return StructConverter::ToDaqObject(*tmsStruct); } + + if (decodedVariant.isType()) + { + const auto tmsStruct = static_cast(decodedVariant->data); + return StructConverter::ToDaqObject(*tmsStruct); + } if (decodedVariant.isType()) { @@ -199,7 +238,10 @@ OpcUaVariant VariantConverter::ToVariant(const DataRulePtr& object, c } case DataRuleType::Explicit: { - variant.setScalar(*StructConverter::ToTmsType(object)); + if (object.getParameters().hasKey("minExpectedDelta") && object.getParameters().hasKey("maxExpectedDelta")) + variant.setScalar(*StructConverter::ToTmsType(object)); + else + variant.setScalar(*StructConverter::ToTmsType(object)); break; } case DataRuleType::Other: @@ -217,6 +259,8 @@ OpcUaVariant VariantConverter::ToVariant(const DataRulePtr& object, c variant.setScalar(*StructConverter::ToTmsType(object)); else if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_CUSTOMRULEDESCRIPTIONSTRUCTURE]) variant.setScalar(*StructConverter::ToTmsType(object)); + else if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_EXPLICITDOMAINRULEDESCRIPTIONSTRUCTURE]) + variant.setScalar(*StructConverter::ToTmsType(object)); else throw ConversionFailedException{}; @@ -232,10 +276,12 @@ ListPtr VariantConverter::ToDaqList(const OpcUaVariant& va return ListConversionUtils::VariantToList(variant); if (variant.isType()) return ListConversionUtils::VariantToList(variant); - if (variant.isType()) - return ListConversionUtils::VariantToList(variant); if (variant.isType()) return ListConversionUtils::VariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); throw ConversionFailedException{}; } @@ -251,6 +297,8 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr(list); if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_CONSTANTRULEDESCRIPTIONSTRUCTURE]) return ListConversionUtils::ToArrayVariant(list); + if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_EXPLICITDOMAINRULEDESCRIPTIONSTRUCTURE]) + return ListConversionUtils::ToArrayVariant(list); if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_BASERULEDESCRIPTIONSTRUCTURE]) return ListConversionUtils::ToArrayVariant(list); if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_CUSTOMRULEDESCRIPTIONSTRUCTURE]) diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_variant_converter.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_variant_converter.cpp index 4ff1bf8..5c8819f 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/test_variant_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/tests/test_variant_converter.cpp @@ -242,6 +242,16 @@ TEST_F(VariantConverterTest, ExplicitDataRule) ASSERT_TRUE(daqDataRuleOut.equals(daqDataRule)); } +TEST_F(VariantConverterTest, ExplicitDomainDataRule) +{ + const DataRulePtr daqDataRule = ExplicitDomainDataRule(5.123, 10); + + const auto variant = VariantConverter::ToVariant(daqDataRule); + const auto daqDataRuleOut = VariantConverter::ToDaqObject(variant); + + ASSERT_TRUE(daqDataRuleOut.equals(daqDataRule)); +} + TEST_F(VariantConverterTest, CustomDataRule) { auto params = Dict(); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp index dff1d93..e2e5ed5 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp @@ -314,3 +314,15 @@ TEST_F(TmsSignalTest, ComponentMethods) auto clientTags = clientSignal.getTags(); ASSERT_TRUE(clientTags.query("tag1") && clientTags.query("tag2")); } + +TEST_F(TmsSignalTest, ExplicitDomainRuleDescriptor) +{ + const auto descriptor = DataDescriptorBuilder().setSampleType(SampleType::Int64).setRule(ExplicitDomainDataRule(5.1, 20)).build(); + const auto signal = SignalWithDescriptor(NullContext(), descriptor, nullptr, "sig"); + auto serverSignal = TmsServerSignal(signal, this->getServer(), NullContext()); + auto nodeId = serverSignal.registerOpcUaNode(); + + SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); + + ASSERT_EQ(signal.getDescriptor().getRule(), clientSignal.getDescriptor().getRule()); +} From 7e3c177b7f27e8b12cc8dd762616fdce7801d505 Mon Sep 17 00:00:00 2001 From: Nikolai Shipilov Date: Tue, 7 Nov 2023 17:28:46 +0100 Subject: [PATCH 015/217] Fix websocket streaming compatibility issues: * Remove order dependency for receiving of time/value signal meta-data in ws streaming * Fix websocket streaming for scenarios when tableId does not equal to signalId * Use ws streaming protocol absoluteReference meta as signal origin --- .../opcuatms_integration/test_streaming_integration.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp index 843607c..01ffd8d 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp @@ -250,7 +250,12 @@ TEST_F(StreamingIntegrationTest, ByteStep) ASSERT_TRUE(packetsEqual(serverReceivedPackets, clientReceivedPackets)); } -TEST_F(StreamingIntegrationTest, ChangingSignal) +// TODO websocket streaming does not recreate half assigned data descriptor changed event packet on client side +// both: value and domain descriptors are always assigned in event packet +// while on server side one descriptor can be assigned only +// client side always generates 2 event packets for each server side event packet: +// one for value descriptor changed and another for domain descriptor changed +TEST_F(StreamingIntegrationTest, DISABLED_ChangingSignal) { const size_t packetsToGenerate = 5; const size_t initialEventPackets = 1; From 924a597dc86c7c53943c5239f85e132f499e5915 Mon Sep 17 00:00:00 2001 From: Nikolai Shipilov Date: Sat, 21 Oct 2023 10:11:11 +0200 Subject: [PATCH 016/217] Add automatic signal subscribing: * Signal/Streaming framework: Automatically subscribing mirrored signals when signal has at least one connection to the InputPort and unsubscribing when the connection count decreases to zero. * Native streaming: Subscribing domain signals automatically by client side when value signal is being subscribed. Adding/Removing reader on server side when signal is being subscribed/usubscribed * Streaming framework refactoring: SignalRemote renamed to MirroredSignalConfig for interfaces and smart pointers IMirroredSignalConfig inherits ISignalConfig Streaming source management methods moved from ISignalConfig to IMirroredSignalConfig Streaming and MirroredSignal implement additional private interfaces Mirrored signal gets initial DataDescriptorChanged EventPacket directly from active streaming source --- .../src/opcua_client_module_impl.cpp | 10 ++++--- .../objects/tms_client_signal_impl.h | 12 +++------ .../src/objects/tms_client_component_impl.cpp | 4 +-- .../tms_client_property_object_impl.cpp | 4 +-- .../src/objects/tms_client_signal_impl.cpp | 26 ------------------- .../test_streaming_integration.cpp | 4 +-- 6 files changed, 15 insertions(+), 45 deletions(-) diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 6ab8c23..d163687 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include BEGIN_NAMESPACE_OPENDAQ_OPCUA_CLIENT_MODULE @@ -213,9 +214,10 @@ void OpcUaClientModule::configureStreamingSources(const PropertyObjectPtr& devic for (const auto& signal : device.getSignalsRecursive()) { - auto signalConfigPtr = signal.asPtr(); + MirroredSignalConfigPtr mirroredSignalConfigPtr = signal.template asPtr(); + + auto streamingSources = mirroredSignalConfigPtr.getStreamingSources(); - auto streamingSources = signalConfigPtr.getStreamingSources(); if (streamingSources.empty()) continue; @@ -266,11 +268,11 @@ void OpcUaClientModule::configureStreamingSources(const PropertyObjectPtr& devic if (streamingHeuristic == "MinConnections" || streamingHeuristic == "Fallbacks") { - signalConfigPtr.setActiveStreamingSource(rootStreaming); + mirroredSignalConfigPtr.setActiveStreamingSource(rootStreaming); } else if (streamingHeuristic == "MinHops") { - signalConfigPtr.setActiveStreamingSource(leafStreaming); + mirroredSignalConfigPtr.setActiveStreamingSource(leafStreaming); } } } diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h index 6020840..f80d4f1 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h @@ -15,7 +15,7 @@ */ #pragma once -#include "opendaq/signal_remote_impl.h" +#include "opendaq/mirrored_signal_impl.h" #include "opcuatms_client/objects/tms_client_component_impl.h" #include "opendaq/data_descriptor_ptr.h" @@ -23,9 +23,9 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS // TmsClientSignalImpl -using SignalRemoteNoProps = SignalRemote; +using MirroredSignalNoProps = MirroredSignal; -class TmsClientSignalImpl final : public TmsClientComponentBaseImpl +class TmsClientSignalImpl final : public TmsClientComponentBaseImpl { public: explicit TmsClientSignalImpl(const ContextPtr& ctx, @@ -58,13 +58,7 @@ class TmsClientSignalImpl final : public TmsClientComponentBaseImpl isPublic = true; - DataDescriptorPtr lastSignalDescriptor; - DataDescriptorPtr lastDomainDescriptor; - std::mutex signalMutex; std::string deviceSignalId; private: diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp index b3ca8ad..4c57353 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp @@ -2,7 +2,7 @@ #include "opendaq/device_impl.h" #include "opendaq/folder_impl.h" #include "opendaq/io_folder_impl.h" -#include "opendaq/signal_remote_impl.h" +#include "opendaq/mirrored_signal_impl.h" #include "opendaq/input_port_impl.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -47,7 +47,7 @@ template class TmsClientComponentBaseImpl; template class TmsClientComponentBaseImpl; template class TmsClientComponentBaseImpl; template class TmsClientComponentBaseImpl; -template class TmsClientComponentBaseImpl>; +template class TmsClientComponentBaseImpl>; template class TmsClientComponentBaseImpl; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index 2794fa5..59bd971 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -9,7 +9,7 @@ #include "opcuatms_client/objects/tms_client_property_object_factory.h" #include "opcuatms_client/objects/tms_client_function_factory.h" #include "opcuatms_client/objects/tms_client_procedure_factory.h" -#include "opendaq/signal_remote_impl.h" +#include "opendaq/mirrored_signal_impl.h" #include "opendaq/input_port_impl.h" #include "opendaq/channel_impl.h" #include "opendaq/device_impl.h" @@ -374,7 +374,7 @@ template class TmsClientPropertyObjectBaseImpl; template class TmsClientPropertyObjectBaseImpl; template class TmsClientPropertyObjectBaseImpl; template class TmsClientPropertyObjectBaseImpl; -template class TmsClientPropertyObjectBaseImpl>; +template class TmsClientPropertyObjectBaseImpl>; template class TmsClientPropertyObjectBaseImpl; template class TmsClientPropertyObjectBaseImpl; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp index 4cfa24e..f11d550 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp @@ -167,9 +167,6 @@ ErrCode TmsClientSignalImpl::setName(IString* name) Bool TmsClientSignalImpl::onTriggerEvent(EventPacketPtr eventPacket) { - if (eventPacket.assigned() && eventPacket.getEventId() == event_packet_id::DATA_DESCRIPTOR_CHANGED) - triggerDataDescriptorChanged(eventPacket); - // No new duplicated event packets have been created so returns true to forward original packet return True; } @@ -179,27 +176,4 @@ StringPtr TmsClientSignalImpl::onGetRemoteId() const return String(deviceSignalId); } -EventPacketPtr TmsClientSignalImpl::createDataDescriptorChangedEventPacket() -{ - const std::lock_guard lock(signalMutex); - return DataDescriptorChangedEventPacket(lastSignalDescriptor, lastDomainDescriptor); -} - -void TmsClientSignalImpl::triggerDataDescriptorChanged(const EventPacketPtr& eventPacket) -{ - const auto params = eventPacket.getParameters(); - DataDescriptorPtr newSignalDescriptor = params[event_packet_param::DATA_DESCRIPTOR]; - DataDescriptorPtr newDomainDescriptor = params[event_packet_param::DOMAIN_DATA_DESCRIPTOR]; - - const std::lock_guard lock(signalMutex); - if (newSignalDescriptor.assigned()) - { - lastSignalDescriptor = newSignalDescriptor; - } - if (newDomainDescriptor.assigned()) - { - lastDomainDescriptor = newDomainDescriptor; - } -} - END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp index 01ffd8d..ac51a65 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp @@ -156,8 +156,8 @@ class StreamingIntegrationTest : public testing::Test { for (const auto& signal : device.getSignalsRecursive()) { - auto signalConfigPtr = signal.asPtr(); - signalConfigPtr.setActiveStreamingSource(STREAMING_URL); + auto mirroredSignalConfigPtr = signal.template asPtr(); + mirroredSignalConfigPtr.setActiveStreamingSource(STREAMING_URL); } } From b54f4ad51db3b82d3319ca1062229d084c0a3e97 Mon Sep 17 00:00:00 2001 From: Martin Kraner Date: Mon, 13 Nov 2023 09:14:49 +0100 Subject: [PATCH 017/217] Add a MultiReader option to return values without scaling or converting (allows reading of different value-types per signal) --- modules/opcua_server_module/src/CMakeLists.txt | 1 + modules/opcua_server_module/src/opcua_server.natvis | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 modules/opcua_server_module/src/opcua_server.natvis diff --git a/modules/opcua_server_module/src/CMakeLists.txt b/modules/opcua_server_module/src/CMakeLists.txt index 4582636..3eab755 100644 --- a/modules/opcua_server_module/src/CMakeLists.txt +++ b/modules/opcua_server_module/src/CMakeLists.txt @@ -25,6 +25,7 @@ source_group("module" FILES ${MODULE_HEADERS_DIR}/opcua_server_module_impl.h add_library(${LIB_NAME} SHARED ${SRC_Include} ${SRC_Srcs} + opcua_server.natvis ) add_library(${SDK_TARGET_NAMESPACE}::${LIB_NAME} ALIAS ${LIB_NAME}) diff --git a/modules/opcua_server_module/src/opcua_server.natvis b/modules/opcua_server_module/src/opcua_server.natvis new file mode 100644 index 0000000..04e3e34 --- /dev/null +++ b/modules/opcua_server_module/src/opcua_server.natvis @@ -0,0 +1,12 @@ + + + + OpcUaServerImpl, <{refCount}> + + (daq::ServerImpl*)this,nd + server + config + context + + + \ No newline at end of file From 86ebbf9b3bef6d49265858b532951abd70fd21b5 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Mon, 27 Nov 2023 11:03:11 +0100 Subject: [PATCH 018/217] Fix unorderedProps not being passed as reference --- .../opcuatms_client/objects/tms_client_property_object_impl.h | 2 +- .../src/objects/tms_client_property_object_impl.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h index 3be45dd..28cecd8 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h @@ -116,7 +116,7 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl void addProperties(const tsl::ordered_map>& references, std::map& orderedProperties, - std::vector unorderedProperties); + std::vector& unorderedProperties); void addMethodProperties(const tsl::ordered_map>& references, const opcua::OpcUaNodeId& parentNodeId, std::map& orderedProperties, diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index 59bd971..de68b0a 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -165,7 +165,7 @@ template void TmsClientPropertyObjectBaseImpl::addProperties( const tsl::ordered_map>& references, std::map& orderedProperties, - std::vector unorderedProperties) + std::vector& unorderedProperties) { const auto introspectionVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_INTROSPECTIONVARIABLETYPE); const auto structureVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_STRUCTUREVARIABLETYPE); From 5d0141ff98a2cd2382092d039d5819cd50fff27a Mon Sep 17 00:00:00 2001 From: Nikolai Shipilov Date: Thu, 23 Nov 2023 16:12:06 +0100 Subject: [PATCH 019/217] Integrate control interface into websocket streaming: * 'WebsocketControlPort' property added to websocket streaming server config * streaming server utilizes control server implementation from streaming-protocol-lt library * server subscribes signals only if request received from client --- .../opcuatms_integration/test_streaming_integration.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp index ac51a65..b76fdd1 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp @@ -31,6 +31,7 @@ class StreamingIntegrationTest : public testing::Test { public: const uint16_t STREAMING_PORT = 7414; + const uint16_t STREAMING_CONTROL_PORT = 7438; const std::string OPCUA_URL = "opc.tcp://127.0.0.1/"; const std::string STREAMING_URL = "daq.wss://127.0.0.1/"; @@ -229,6 +230,7 @@ TEST_F(StreamingIntegrationTest, ByteStep) auto streamingServer = WebsocketStreamingServer(instance); streamingServer.setStreamingPort(STREAMING_PORT); + streamingServer.setControlPort(STREAMING_CONTROL_PORT); streamingServer.start(); auto server = TmsServer(instance); @@ -266,6 +268,7 @@ TEST_F(StreamingIntegrationTest, DISABLED_ChangingSignal) auto streamingServer = WebsocketStreamingServer(instance); streamingServer.setStreamingPort(STREAMING_PORT); + streamingServer.setControlPort(STREAMING_CONTROL_PORT); streamingServer.start(); auto server = TmsServer(instance); @@ -302,6 +305,7 @@ TEST_F(StreamingIntegrationTest, AllSignalsAsync) auto streamingServer = WebsocketStreamingServer(instance); streamingServer.setStreamingPort(STREAMING_PORT); + streamingServer.setControlPort(STREAMING_CONTROL_PORT); streamingServer.start(); auto server = TmsServer(instance); @@ -360,6 +364,7 @@ TEST_F(StreamingIntegrationTest, StreamingDeactivate) auto streamingServer = WebsocketStreamingServer(instance); streamingServer.setStreamingPort(STREAMING_PORT); + streamingServer.setControlPort(STREAMING_CONTROL_PORT); streamingServer.start(); auto server = TmsServer(instance); From b894426b5cd2e2c8ca9d64fc0ab943e77f8fca88 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Wed, 22 Nov 2023 15:42:51 +0100 Subject: [PATCH 020/217] Add name and description getter/setters to component TODO: Add OPC UA support --- .../opcuatms_client/objects/tms_client_property_object_impl.h | 4 ++-- .../include/opcuatms_client/objects/tms_client_signal_impl.h | 4 +--- .../opcuatms_client/src/objects/tms_client_component_impl.cpp | 2 +- .../src/objects/tms_client_property_object_impl.cpp | 2 +- .../opcuatms_server/tests/test_tms_function_block.cpp | 3 ++- .../opcuatms/tests/opcuatms_integration/test_tms_device.cpp | 3 ++- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h index 28cecd8..adb3a02 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h @@ -72,7 +72,7 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl const TmsClientContextPtr& clientContext, const opcua::OpcUaNodeId& nodeId) : TmsClientObjectImpl(ctx, clientContext, nodeId) - , Impl(ctx, parent, localId) + , Impl(ctx, parent, localId, nullptr, ComponentStandardProps::Skip) , referenceUtils(client) { browseRawProperties(); @@ -86,7 +86,7 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl const opcua::OpcUaNodeId& nodeId, const FunctionBlockTypePtr& type) : TmsClientObjectImpl(ctx, clientContext, nodeId) - , Impl(type, ctx, parent, localId) + , Impl(type, ctx, parent, localId, nullptr, ComponentStandardProps::Skip) , referenceUtils(client) { browseRawProperties(); diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h index f80d4f1..e13e5e9 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h @@ -23,9 +23,7 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS // TmsClientSignalImpl -using MirroredSignalNoProps = MirroredSignal; - -class TmsClientSignalImpl final : public TmsClientComponentBaseImpl +class TmsClientSignalImpl final : public TmsClientComponentBaseImpl { public: explicit TmsClientSignalImpl(const ContextPtr& ctx, diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp index 4c57353..83ea1ac 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp @@ -47,7 +47,7 @@ template class TmsClientComponentBaseImpl; template class TmsClientComponentBaseImpl; template class TmsClientComponentBaseImpl; template class TmsClientComponentBaseImpl; -template class TmsClientComponentBaseImpl>; +template class TmsClientComponentBaseImpl; template class TmsClientComponentBaseImpl; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index de68b0a..cf2d247 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -374,7 +374,7 @@ template class TmsClientPropertyObjectBaseImpl; template class TmsClientPropertyObjectBaseImpl; template class TmsClientPropertyObjectBaseImpl; template class TmsClientPropertyObjectBaseImpl; -template class TmsClientPropertyObjectBaseImpl>; +template class TmsClientPropertyObjectBaseImpl; template class TmsClientPropertyObjectBaseImpl; template class TmsClientPropertyObjectBaseImpl; diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp index 8ab402d..781a21f 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp @@ -77,7 +77,8 @@ TEST_F(TmsFunctionBlockTest, BrowseSignals) ASSERT_EQ(signalReferences.size(), 5u); } -TEST_F(TmsFunctionBlockTest, Property) +// TODO: Enable once name and description are no longer props +TEST_F(TmsFunctionBlockTest, DISABLED_Property) { // Build functionBlock info: const FunctionBlockTypePtr type = FunctionBlockType("uid", "name", "desc"); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp index b8b602d..0a59368 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp @@ -124,7 +124,8 @@ TEST_F(TmsDeviceTest, GetChannels) ASSERT_EQ(channels.getCount(), serverDevice.getChannelsRecursive().getCount()); } -TEST_F(TmsDeviceTest, Property) +// TODO: Enable once name and description are no longer props +TEST_F(TmsDeviceTest, DISABLED_Property) { DevicePtr serverDevice = createDevice(); From a1318e954536f78ef5c428b72859d30ef7a35a00 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Thu, 23 Nov 2023 13:37:28 +0100 Subject: [PATCH 021/217] Add support for setting/getting name/description to OPC UA --- external/open62541/CMakeLists.txt | 2 +- .../include/opcuaserver/node_event_manager.h | 1 + .../include/opcuaserver/opcuaserver.h | 3 + .../opcuaserver/server_event_manager.h | 12 ++- .../opcuaserver/src/node_event_manager.cpp | 6 ++ .../opcua/opcuaserver/src/opcuaserver.cpp | 12 +++ .../opcuaserver/src/server_event_manager.cpp | 36 ++++++++- .../objects/tms_client_component_impl.h | 8 +- .../objects/tms_client_property_object_impl.h | 10 +-- .../objects/tms_client_signal_impl.h | 3 - .../src/objects/tms_client_component_impl.cpp | 70 ++++++++++++++++ .../src/objects/tms_client_signal_impl.cpp | 28 ------- .../objects/tms_server_component.h | 81 ++++++++++++++++++- .../objects/tms_server_object.h | 1 + .../objects/tms_server_property_object.h | 6 +- .../objects/tms_server_signal.h | 2 - .../src/objects/tms_server_object.cpp | 8 ++ .../objects/tms_server_property_object.cpp | 12 ++- .../src/objects/tms_server_signal.cpp | 14 ---- .../opcuatms_integration/test_tms_signal.cpp | 5 +- 20 files changed, 253 insertions(+), 67 deletions(-) diff --git a/external/open62541/CMakeLists.txt b/external/open62541/CMakeLists.txt index 6e24638..768cd68 100644 --- a/external/open62541/CMakeLists.txt +++ b/external/open62541/CMakeLists.txt @@ -15,7 +15,7 @@ opendaq_dependency( NAME open62541 REQUIRED_VERSION 1.3.6 GIT_REPOSITORY https://github.com/openDAQ/open62541.git - GIT_REF v1.3.6-opendaq-2 + GIT_REF v1.3.6-opendaq-3 GIT_SUBMODULES "" EXPECT_TARGET open62541 ) diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/node_event_manager.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/node_event_manager.h index 3fdac1b..c4fc9e3 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/node_event_manager.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/node_event_manager.h @@ -52,6 +52,7 @@ class NodeEventManager void onDataSourceWrite(DataSourceWriteCallback callback); void onMethodCall(MethodCallback callback); void onDisplayNameChanged(DisplayNameChangedCallback callback); + void onDescriptionChanged(DescriptionChangedCallback callback); protected: OpcUaNodeId nodeId; diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h index eb6e2f6..c88eb66 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h @@ -87,6 +87,9 @@ class OpcUaServer final : public daq::utils::ThreadEx void setDisplayName(const OpcUaNodeId& nodeId, const std::string& text); OpcUaObject readDisplayName(const OpcUaNodeId& nodeId) const; + void setDescription(const OpcUaNodeId& nodeId, const OpcUaObject& localizedText); + void setDescription(const OpcUaNodeId& nodeId, const std::string& text); + void writeValue(const OpcUaNodeId& nodeId, const OpcUaVariant& var); OpcUaVariant readValue(const OpcUaNodeId& nodeId); OpcUaNodeId readDataType(const OpcUaNodeId& typeNodeId); diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/server_event_manager.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/server_event_manager.h index 915c71e..5092e3b 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/server_event_manager.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/server_event_manager.h @@ -25,7 +25,8 @@ class ServerEventManager; using ServerEventManagerPtr = std::shared_ptr; using CreatOptionalNodeCallback = std::function; -using DisplayNameChangedCallback = std::function& name)>; +using DisplayNameChangedCallback = std::function& name, void* context)>; +using DescriptionChangedCallback = std::function& description, void* context)>; class ServerEventManager { @@ -39,14 +40,18 @@ class ServerEventManager void onDisplayNameChanged(const OpcUaNodeId& nodeId, const DisplayNameChangedCallback& callback); void removeOnDisplayNameChanged(const OpcUaNodeId& nodeId); + void onDescriptionChanged(const OpcUaNodeId& nodeId, const DescriptionChangedCallback& callback); + void removeOnDescriptionChanged(const OpcUaNodeId& nodeId); private: OpcUaServer* server; CreatOptionalNodeCallback createOptionalNodeCallback; std::unordered_map displayNameCallbacks; + std::unordered_map descriptionCallbacks; UA_Boolean triggerCreateOptionalNode(const UA_NodeId* nodeId); - void triggerDisplayNameChanged(const UA_NodeId* nodeId, UA_LocalizedText* name); + void triggerDisplayNameChanged(const UA_NodeId* nodeId, UA_LocalizedText* name, void* context); + void triggerDescriptionChanged(const UA_NodeId* nodeId, UA_LocalizedText* description, void* context); static UA_Boolean CreateOptionalNode(UA_Server* server, const UA_NodeId* sessionId, @@ -55,7 +60,8 @@ class ServerEventManager const UA_NodeId* targetParentNodeId, const UA_NodeId* referenceTypeId); - static void DisplayNameChanged(UA_Server* server, UA_NodeId* nodeId, UA_LocalizedText* newDisplayName); + static void DisplayNameChanged(UA_Server* server, UA_NodeId* nodeId, UA_LocalizedText* newDisplayName, void* context); + static void DescriptionChanged(UA_Server* server, UA_NodeId* nodeId, UA_LocalizedText* newDescription, void* context); }; END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/src/node_event_manager.cpp b/shared/libraries/opcua/opcuaserver/src/node_event_manager.cpp index 167cbb0..e0f8995 100644 --- a/shared/libraries/opcua/opcuaserver/src/node_event_manager.cpp +++ b/shared/libraries/opcua/opcuaserver/src/node_event_manager.cpp @@ -62,6 +62,12 @@ void NodeEventManager::onDisplayNameChanged(DisplayNameChangedCallback callback) server->getEventManager()->onDisplayNameChanged(nodeId, callback); } +void NodeEventManager::onDescriptionChanged(DescriptionChangedCallback callback) +{ + server->getEventManager()->onDescriptionChanged(nodeId, callback); +} + + // c-style callback, required by open62541 interface void NodeEventManager::OnWrite(UA_Server* server, diff --git a/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp b/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp index 94cf675..0690c75 100644 --- a/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp +++ b/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp @@ -432,6 +432,18 @@ OpcUaObject OpcUaServer::readDisplayName(const OpcUaNodeId& no return localizedText; } +void OpcUaServer::setDescription(const OpcUaNodeId& nodeId, const OpcUaObject& localizedText) +{ + const auto status = UA_Server_writeDescription(server, *nodeId, *localizedText); + CheckStatusCodeException(status); +} + +void OpcUaServer::setDescription(const OpcUaNodeId& nodeId, const std::string& text) +{ + OpcUaObject localizedText = UA_LOCALIZEDTEXT_ALLOC("", text.c_str()); + setDescription(nodeId, localizedText); +} + void OpcUaServer::writeValue(const OpcUaNodeId& nodeId, const OpcUaVariant& value) { CheckStatusCodeException(UA_Server_writeValue(server, *nodeId, *value)); diff --git a/shared/libraries/opcua/opcuaserver/src/server_event_manager.cpp b/shared/libraries/opcua/opcuaserver/src/server_event_manager.cpp index 89f755a..0f32a63 100644 --- a/shared/libraries/opcua/opcuaserver/src/server_event_manager.cpp +++ b/shared/libraries/opcua/opcuaserver/src/server_event_manager.cpp @@ -19,6 +19,7 @@ void ServerEventManager::registerEvents() config->nodeLifecycle.context = this; config->displayNameChanged = DisplayNameChanged; + config->descriptionChanged = DescriptionChanged; config->nodeLifecycle.createOptionalChild = CreateOptionalNode; } @@ -31,14 +32,24 @@ UA_Boolean ServerEventManager::triggerCreateOptionalNode(const UA_NodeId* nodeId return createOptionalNodeCallback(nodeIdObj); } -void ServerEventManager::triggerDisplayNameChanged(const UA_NodeId* nodeId, UA_LocalizedText* name) +void ServerEventManager::triggerDisplayNameChanged(const UA_NodeId* nodeId, UA_LocalizedText* name, void* context) { const auto nodeIdObj = OpcUaNodeId(*nodeId); if (displayNameCallbacks.count(nodeIdObj) == 0) return; auto callback = displayNameCallbacks[nodeIdObj]; - callback(nodeIdObj, OpcUaObject(*name)); + callback(nodeIdObj, OpcUaObject(*name), context); +} + +void ServerEventManager::triggerDescriptionChanged(const UA_NodeId* nodeId, UA_LocalizedText* description, void* context) +{ + const auto nodeIdObj = OpcUaNodeId(*nodeId); + if (descriptionCallbacks.count(nodeIdObj) == 0) + return; + + auto callback = descriptionCallbacks[nodeIdObj]; + callback(nodeIdObj, OpcUaObject(*description), context); } void ServerEventManager::onCreateOptionalNode(const CreatOptionalNodeCallback& callback) @@ -51,11 +62,21 @@ void ServerEventManager::onDisplayNameChanged(const OpcUaNodeId& nodeId, const D displayNameCallbacks.insert({nodeId, callback}); } +void ServerEventManager::onDescriptionChanged(const OpcUaNodeId& nodeId, const DescriptionChangedCallback& callback) +{ + descriptionCallbacks.insert({nodeId, callback}); +} + void ServerEventManager::removeOnDisplayNameChanged(const OpcUaNodeId& nodeId) { displayNameCallbacks.erase(nodeId); } +void ServerEventManager::removeOnDescriptionChanged(const OpcUaNodeId& nodeId) +{ + descriptionCallbacks.erase(nodeId); +} + // Static callbacks UA_Boolean ServerEventManager::CreateOptionalNode(UA_Server* server, @@ -70,11 +91,18 @@ UA_Boolean ServerEventManager::CreateOptionalNode(UA_Server* server, return eventManager->triggerCreateOptionalNode(sourceNodeId); } -void ServerEventManager::DisplayNameChanged(UA_Server* server, UA_NodeId* nodeId, UA_LocalizedText* newDisplayName) +void ServerEventManager::DisplayNameChanged(UA_Server* server, UA_NodeId* nodeId, UA_LocalizedText* newDisplayName, void* context) +{ + auto& lifecycle = UA_Server_getConfig(server)->nodeLifecycle; + auto eventManager = (ServerEventManager*) lifecycle.context; + eventManager->triggerDisplayNameChanged(nodeId, newDisplayName, context); +} + +void ServerEventManager::DescriptionChanged(UA_Server* server, UA_NodeId* nodeId, UA_LocalizedText* newDescription, void* context) { auto& lifecycle = UA_Server_getConfig(server)->nodeLifecycle; auto eventManager = (ServerEventManager*) lifecycle.context; - eventManager->triggerDisplayNameChanged(nodeId, newDisplayName); + eventManager->triggerDescriptionChanged(nodeId, newDescription, context); } END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h index b923ee6..50dd219 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h @@ -30,7 +30,7 @@ class TmsClientComponentBaseImpl : public TmsClientPropertyObjectBaseImpl { public: - template = 0> + template = 0> TmsClientComponentBaseImpl(const ContextPtr& ctx, const ComponentPtr& parent, const StringPtr& localId, @@ -40,7 +40,7 @@ class TmsClientComponentBaseImpl : public TmsClientPropertyObjectBaseImpl { } - template = 0> + template = 0> TmsClientComponentBaseImpl(const ContextPtr& ctx, const ComponentPtr& parent, const StringPtr& localId, @@ -55,6 +55,10 @@ class TmsClientComponentBaseImpl : public TmsClientPropertyObjectBaseImpl ErrCode INTERFACE_FUNC getActive(Bool* active) override; ErrCode INTERFACE_FUNC setActive(Bool active) override; ErrCode INTERFACE_FUNC getTags(ITagsConfig** tags) override; + ErrCode INTERFACE_FUNC getName(IString** name) override; + ErrCode INTERFACE_FUNC setName(IString* name) override; + ErrCode INTERFACE_FUNC getDescription(IString** description) override; + ErrCode INTERFACE_FUNC setDescription(IString* description) override; }; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h index adb3a02..f518147 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h @@ -25,7 +25,7 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS -namespace detail +namespace template_utils { template using enable_if_any = std::enable_if_t<(std::is_same_v || ...), int>; @@ -44,7 +44,7 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl { public: - template = 0> + template = 0> TmsClientPropertyObjectBaseImpl(const ContextPtr& daqContext, const TmsClientContextPtr& clientContext, const opcua::OpcUaNodeId& nodeId) : TmsClientObjectImpl(daqContext, clientContext, nodeId) , Impl() @@ -53,7 +53,7 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl browseRawProperties(); } - template = 0> + template = 0> TmsClientPropertyObjectBaseImpl(const ContextPtr& daqContext, const StringPtr& protocolId, const TmsClientContextPtr& clientContext, @@ -65,7 +65,7 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl browseRawProperties(); } - template = 0> + template = 0> TmsClientPropertyObjectBaseImpl(const ContextPtr& ctx, const ComponentPtr& parent, const StringPtr& localId, @@ -78,7 +78,7 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl browseRawProperties(); } - template = 0> + template = 0> TmsClientPropertyObjectBaseImpl(const ContextPtr& ctx, const ComponentPtr& parent, const StringPtr& localId, diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h index e13e5e9..8642c6d 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h @@ -49,9 +49,6 @@ class TmsClientSignalImpl final : public TmsClientComponentBaseImpl::getTags(ITagsConfig** tags) }); } +template +ErrCode TmsClientComponentBaseImpl::getName(IString** name) +{ + OPENDAQ_PARAM_NOT_NULL(name); + + return daqTry([&] + { + StringPtr nameObj =this->client->readDisplayName(this->nodeId); + *name = nameObj.detach(); + return OPENDAQ_SUCCESS; + }); +} + +template +ErrCode TmsClientComponentBaseImpl::setName(IString* name) +{ + OPENDAQ_PARAM_NOT_NULL(name); + + try + { + StringPtr nameObj = name; + this->client->writeDisplayName(this->nodeId, nameObj); + return OPENDAQ_SUCCESS; + } + catch(...) + { + auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClientComponent"); + StringPtr nameObj; + this->getName(&nameObj); + LOG_W("Failed to set name of component \"{}\"", nameObj); + } + + return OPENDAQ_IGNORED; +} + +template +ErrCode TmsClientComponentBaseImpl::getDescription(IString** description) +{ + OPENDAQ_PARAM_NOT_NULL(description); + + return daqTry([&] + { + StringPtr descObj = this->client->readDescription(this->nodeId); + *description = descObj.detach(); + return OPENDAQ_SUCCESS; + }); +} + +template +ErrCode TmsClientComponentBaseImpl::setDescription(IString* description) +{ + OPENDAQ_PARAM_NOT_NULL(description); + + try + { + StringPtr descriptionObj = description; + this->client->writeDescription(this->nodeId, descriptionObj); + return OPENDAQ_SUCCESS; + } + catch(...) + { + auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClientComponent"); + StringPtr descObj; + this->getName(&descObj); + LOG_W("Failed to set description of component \"{}\"", descObj); + } + + return OPENDAQ_IGNORED; +} + template class TmsClientComponentBaseImpl>; template class TmsClientComponentBaseImpl>; template class TmsClientComponentBaseImpl; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp index f11d550..cf0f43d 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp @@ -137,34 +137,6 @@ ErrCode TmsClientSignalImpl::clearRelatedSignals() return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; } -ErrCode TmsClientSignalImpl::getName(IString** name) -{ - OPENDAQ_PARAM_NOT_NULL(name); - - auto objPtr = this->borrowPtr(); - - return daqTry( - [&name, &objPtr]() - { - *name = objPtr.getPropertyValue("Name").asPtr().detach(); - return OPENDAQ_SUCCESS; - }); -} - -ErrCode TmsClientSignalImpl::setName(IString* name) -{ - OPENDAQ_PARAM_NOT_NULL(name); - - auto objPtr = this->borrowPtr(); - - return daqTry( - [&name, &objPtr]() - { - objPtr.setPropertyValue("Name", name); - return OPENDAQ_SUCCESS; - }); -} - Bool TmsClientSignalImpl::onTriggerEvent(EventPacketPtr eventPacket) { // No new duplicated event packets have been created so returns true to forward original packet diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h index b0477d1..1fa4560 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h @@ -40,14 +40,18 @@ class TmsServerComponent : public TmsServerObjectBaseImpl std::string getBrowseName() override; std::string getDisplayName() override; + std::string getDescription() override; opcua::OpcUaNodeId getReferenceType() override; void bindCallbacks() override; void addChildNodes() override; protected: opcua::OpcUaNodeId getTmsTypeId() override; + void configureNodeAttributes(opcua::OpcUaObject& attr) override; std::unique_ptr tmsPropertyObject; +private: + bool selfChange; }; using namespace opcua; @@ -55,8 +59,9 @@ using namespace opcua; template TmsServerComponent::TmsServerComponent(const ComponentPtr& object, const OpcUaServerPtr& server, const ContextPtr& context) : Super(object, server, context) + , selfChange(false) { - tmsPropertyObject = std::make_unique(this->object, this->server, this->daqContext); + tmsPropertyObject = std::make_unique(this->object, this->server, this->daqContext, std::unordered_set{"Name", "Description"}); } template @@ -71,6 +76,12 @@ std::string TmsServerComponent::getDisplayName() return this->object.getName(); } +template +std::string TmsServerComponent::getDescription() +{ + return this->object.getDescription(); +} + template OpcUaNodeId TmsServerComponent::getReferenceType() { @@ -83,6 +94,16 @@ OpcUaNodeId TmsServerComponent::getTmsTypeId() return OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQCOMPONENTTYPE); } +template +void TmsServerComponent::configureNodeAttributes(opcua::OpcUaObject& attr) +{ + TmsServerObject::configureNodeAttributes(attr); + if (this->object.hasProperty("Name") && !this->object.getProperty("Name").getReadOnly()) + attr->writeMask |= UA_WRITEMASK_DISPLAYNAME; + if (this->object.hasProperty("Description") && !this->object.getProperty("Description").getReadOnly()) + attr->writeMask |= UA_WRITEMASK_DESCRIPTION; +} + template bool TmsServerComponent::createOptionalNode(const OpcUaNodeId& nodeId) { @@ -108,6 +129,64 @@ void TmsServerComponent::bindCallbacks() return UA_STATUSCODE_GOOD; }); } + + if (this->object.hasProperty("Name")) + { + this->object.getOnPropertyValueWrite("Name") += + [&](const PropertyObjectPtr& /*obj*/, const PropertyValueEventArgsPtr& args) + { + if (selfChange) + return; + + std::string name = args.getValue(); + this->server->setDisplayName(this->nodeId, name); + }; + } + + if (this->object.hasProperty("Description")) + { + this->object.getOnPropertyValueWrite("Description") += + [&](const PropertyObjectPtr& /*obj*/, const PropertyValueEventArgsPtr& args) + { + if (selfChange) + return; + + std::string description = args.getValue(); + this->server->setDescription(this->nodeId, description); + }; + } + + DisplayNameChangedCallback nameChangedCallback = + [this](const OpcUaNodeId& /*nodeId*/, const OpcUaObject& name, void* /*context*/) + { + try + { + selfChange = true; + this->object.setName(utils::ToStdString(name->text)); + } + catch(...) + { + } + + selfChange = false; + }; + this->server->getEventManager()->onDisplayNameChanged(this->nodeId, nameChangedCallback); + + DisplayNameChangedCallback descriptionChangedCallback = + [this](const OpcUaNodeId& /*nodeId*/, const OpcUaObject& description, void* /*context*/) + { + try + { + selfChange = true; + this->object.setDescription(utils::ToStdString(description->text)); + } + catch(...) + { + } + + selfChange = false; + }; + this->server->getEventManager()->onDescriptionChanged(this->nodeId, descriptionChangedCallback); } template diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h index e11cbbf..a4b6fdb 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h @@ -58,6 +58,7 @@ class TmsServerObject : public std::enable_shared_from_this virtual std::string getBrowseName(); virtual std::string getDisplayName(); + virtual std::string getDescription(); opcua::NodeEventManagerPtr addEvent(const StringPtr& nodeName); opcua::NodeEventManagerPtr addEvent(const opcua::OpcUaNodeId& nodeId); opcua::OpcUaNodeId registerOpcUaNode( diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h index 1febd4f..7a4f922 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h @@ -29,7 +29,10 @@ class TmsServerPropertyObject : public TmsServerObjectBaseImpl; - TmsServerPropertyObject(const PropertyObjectPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context); + TmsServerPropertyObject(const PropertyObjectPtr& object, + const opcua::OpcUaServerPtr& server, + const ContextPtr& context, + const std::unordered_set& ignoredProps = {}); TmsServerPropertyObject(const PropertyObjectPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, @@ -67,6 +70,7 @@ class TmsServerPropertyObject : public TmsServerObjectBaseImpl ignoredProps; }; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h index 27b87c4..f4c6dc2 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h @@ -30,8 +30,6 @@ class TmsServerSignal : public TmsServerComponent TmsServerSignal(const SignalPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context); - std::string getBrowseName() override; - std::string getDisplayName() override; opcua::OpcUaNodeId getReferenceType() override; void bindCallbacks() override; bool createOptionalNode(const opcua::OpcUaNodeId& nodeId) override; diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp index e37a533..1cb3fb5 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp @@ -37,6 +37,11 @@ std::string TmsServerObject::getDisplayName() return ""; } +std::string TmsServerObject::getDescription() +{ + return ""; +} + OpcUaNodeId TmsServerObject::getReferenceType() { return OpcUaNodeId(UA_NS0ID_HASCOMPONENT); @@ -233,6 +238,9 @@ void TmsServerObject::configureNodeAttributes(OpcUaObject& auto displayName = getDisplayName(); if (!displayName.empty()) attr->displayName = UA_LOCALIZEDTEXT_ALLOC("", displayName.c_str()); + auto description = getDescription(); + if (!description.empty()) + attr->description = UA_LOCALIZEDTEXT_ALLOC("", description.c_str()); } void TmsServerObject::addReadCallback(const std::string& nodeName, ReadVariantCallback readFunc) diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp index e444184..c9fb186 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp @@ -15,9 +15,11 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS using namespace opcua; TmsServerPropertyObject::TmsServerPropertyObject(const PropertyObjectPtr& object, - const OpcUaServerPtr& server, - const ContextPtr& context) + const OpcUaServerPtr& server, + const ContextPtr& context, + const std::unordered_set& ignoredProps) : Super(object, server, context) + , ignoredProps(ignoredProps) { } @@ -74,12 +76,18 @@ void TmsServerPropertyObject::addChildNodes() std::unordered_map propOrder; for (const auto& prop : object.getAllProperties()) { + if (ignoredProps.count(prop.getName())) + continue; + propOrder.insert(std::pair(prop.getName(), propNumber)); propNumber++; } for (const auto& prop : object.getAllProperties()) { + if (ignoredProps.count(prop.getName())) + continue; + // NOTE: ctObject types cannot be placed below ReferenceVariableType properties if (prop.getValueType() != ctObject || prop.getReferencedProperty().assigned()) { diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp index e3443ed..7353b28 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp @@ -12,20 +12,6 @@ TmsServerSignal::TmsServerSignal(const SignalPtr& object, const OpcUaServerPtr& { } -std::string TmsServerSignal::getBrowseName() -{ - return this->object.getLocalId(); -} - -std::string TmsServerSignal::getDisplayName() -{ - const auto name = object.getName(); - if (name.assigned()) - return name; - - return {}; -} - OpcUaNodeId TmsServerSignal::getReferenceType() { //TODO UA_TMSBSPID_HASSTATUSSIGNAL diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp index e2e5ed5..71abbe1 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp @@ -308,7 +308,10 @@ TEST_F(TmsSignalTest, ComponentMethods) // TODO: Support changing read-only properties over OPC UA ASSERT_NO_THROW(clientSignal.setName("new_name")); - //ASSERT_EQ(signal.getName(), clientSignal.getName()); + ASSERT_EQ(signal.getName(), clientSignal.getName()); + + ASSERT_NO_THROW(clientSignal.setDescription("new_description")); + ASSERT_EQ(signal.getDescription(), clientSignal.getDescription()); auto tags = signal.getTags(); auto clientTags = clientSignal.getTags(); From 542c8d599a959b363d79e7933dfe067311abb730 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Thu, 23 Nov 2023 14:36:04 +0100 Subject: [PATCH 022/217] Add tests for component get/set name --- .../test_tms_component.cpp | 52 +++++++++++++++++-- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_component.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_component.cpp index d76b7e6..835df30 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_component.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_component.cpp @@ -34,11 +34,14 @@ class TmsComponentTest : public TmsObjectIntegrationTest return component; } - RegisteredComponent registerTestComponent() + RegisteredComponent registerTestComponent(const ComponentPtr& customComponent = nullptr) { RegisteredComponent component{}; - - component.serverComponent = createTestComponent(); + + if (customComponent == nullptr) + component.serverComponent = createTestComponent(); + else + component.serverComponent = customComponent; component.serverObject = std::make_shared>(component.serverComponent, this->getServer(), NullContext()); auto nodeId = component.serverObject->registerOpcUaNode(); component.clientComponent = TmsClientComponent(NullContext(), nullptr, "test", clientContext, nodeId); @@ -90,3 +93,46 @@ TEST_F(TmsComponentTest, Properties) component.clientComponent.setPropertyValue("foo", "notbar"); ASSERT_EQ(component.serverComponent.getPropertyValue("foo"), component.clientComponent.getPropertyValue("foo")); } + +TEST_F(TmsComponentTest, NameAndDescription) +{ + const auto component = registerTestComponent(); + ASSERT_EQ(component.serverComponent.getName(), component.clientComponent.getName()); + ASSERT_EQ(component.serverComponent.getDescription(), component.clientComponent.getDescription()); + + component.serverComponent.setName("new_name"); + component.serverComponent.setDescription("new_description"); + + ASSERT_EQ(component.serverComponent.getName(), component.clientComponent.getName()); + ASSERT_EQ(component.serverComponent.getDescription(), component.clientComponent.getDescription()); + + component.clientComponent.setName("newer_name"); + component.clientComponent.setDescription("newer_description"); + + ASSERT_EQ(component.serverComponent.getName(), component.clientComponent.getName()); + ASSERT_EQ(component.serverComponent.getDescription(), component.clientComponent.getDescription()); +} + +TEST_F(TmsComponentTest, NameAndDescriptionReadOnly) +{ + const auto name = "read_only"; + const auto customComponent = Component(NullContext(), nullptr, name, ComponentStandardProps::AddReadOnly); + const auto component = registerTestComponent(customComponent); + + ASSERT_NO_THROW(component.clientComponent.setName("new_name")); + ASSERT_NO_THROW(component.clientComponent.setDescription("new_description")); + + ASSERT_EQ(component.clientComponent.getName(), name); +} + +TEST_F(TmsComponentTest, NameAndDescriptionSkip) +{ + const auto name = "read_only"; + const auto customComponent = Component(NullContext(), nullptr, name, ComponentStandardProps::Skip); + const auto component = registerTestComponent(customComponent); + + ASSERT_NO_THROW(component.clientComponent.setName("new_name")); + ASSERT_NO_THROW(component.clientComponent.setDescription("new_description")); + + ASSERT_EQ(component.clientComponent.getName(), name); +} \ No newline at end of file From d307e9a736e87e271f04d71f4abb96feedd5d6ce Mon Sep 17 00:00:00 2001 From: janm-dw <97100424+janm-dw@users.noreply.github.com> Date: Tue, 5 Dec 2023 09:15:34 +0100 Subject: [PATCH 023/217] Implement opcua attribute reader (openDAQ/openDAQ#54) * Implement OpcUa attribute reader --- .../include/opcuaclient/attribute_reader.h | 52 +++++ .../opcua/opcuaclient/src/CMakeLists.txt | 2 + .../opcuaclient/src/attribute_reader.cpp | 104 ++++++++++ .../opcua/opcuaclient/tests/CMakeLists.txt | 1 + .../tests/include/opcuaservertesthelper.h | 6 +- .../tests/src/opcuaservertesthelper.cpp | 17 +- .../tests/src/test_attribute_reader.cpp | 194 ++++++++++++++++++ .../include/opcuashared/opcua_attribute.h | 36 ++++ .../include/opcuashared/opcuadatavalue.h | 3 + .../opcua/opcuashared/src/CMakeLists.txt | 1 + 10 files changed, 412 insertions(+), 4 deletions(-) create mode 100644 shared/libraries/opcua/opcuaclient/include/opcuaclient/attribute_reader.h create mode 100644 shared/libraries/opcua/opcuaclient/src/attribute_reader.cpp create mode 100644 shared/libraries/opcua/opcuaclient/tests/src/test_attribute_reader.cpp create mode 100644 shared/libraries/opcua/opcuashared/include/opcuashared/opcua_attribute.h diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/attribute_reader.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/attribute_reader.h new file mode 100644 index 0000000..309ec59 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/attribute_reader.h @@ -0,0 +1,52 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class AttributeReader; +using AttributeReaderPtr = std::shared_ptr; + +class AttributeReader +{ +public: + AttributeReader(const OpcUaClientPtr& client, size_t maxBatchSize = 0); + + void addAttribute(const OpcUaAttribute& attribute); + OpcUaDataValuePtr getValue(const OpcUaNodeId& nodeId, UA_AttributeId attributeId); + OpcUaDataValuePtr getValue(const OpcUaAttribute& attribute); + void reset(); + void read(); + const std::vector>& getResponses(); + +private: + using ResultMap = std::unordered_map>; + + size_t readBatch(size_t startIndex, size_t size); + void addBatchToResultMap(size_t startIndex, const OpcUaObject& response); + + OpcUaClientPtr client; + std::vector attributes; + std::vector> responses; + ResultMap resultMap; + size_t maxBatchSize = 0; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/src/CMakeLists.txt b/shared/libraries/opcua/opcuaclient/src/CMakeLists.txt index 39ef487..296591b 100644 --- a/shared/libraries/opcua/opcuaclient/src/CMakeLists.txt +++ b/shared/libraries/opcua/opcuaclient/src/CMakeLists.txt @@ -13,6 +13,7 @@ set(SOURCE_CPPS opcuaclient.cpp browse_request.cpp reference_utils.cpp request_handler.cpp + attribute_reader.cpp ) set(SOURCE_BROWSER_CPPS browser/opcuanodevisitor.cpp @@ -34,6 +35,7 @@ set(SOURCE_HEADERS opcuaclient.h browse_request.h reference_utils.h request_handler.h + attribute_reader.h ) set(SOURCE_BROWSER_HEADERS diff --git a/shared/libraries/opcua/opcuaclient/src/attribute_reader.cpp b/shared/libraries/opcua/opcuaclient/src/attribute_reader.cpp new file mode 100644 index 0000000..1c18b0b --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/src/attribute_reader.cpp @@ -0,0 +1,104 @@ +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +AttributeReader::AttributeReader(const OpcUaClientPtr& client, size_t maxBatchSize) + : client(client) + , maxBatchSize(maxBatchSize) +{ +} + +void AttributeReader::addAttribute(const OpcUaAttribute& attribute) +{ + attributes.push_back(attribute); +} + +OpcUaDataValuePtr AttributeReader::getValue(const OpcUaNodeId& nodeId, UA_AttributeId attributeId) +{ + if (resultMap.count(nodeId) == 0 || resultMap[nodeId].count(attributeId) == 0) + throw OpcUaException(UA_STATUSCODE_BADNOTFOUND, "Attribute read result not found"); + + return resultMap[nodeId][attributeId]; +} + +OpcUaDataValuePtr AttributeReader::getValue(const OpcUaAttribute& attribute) +{ + return getValue(attribute.nodeId, attribute.attributeId); +} + +void AttributeReader::reset() +{ + attributes.clear(); + resultMap.clear(); + responses.clear(); +} + +void AttributeReader::read() +{ + resultMap.clear(); + responses.clear(); + + if (attributes.empty()) + return; + + const size_t batchSize = (maxBatchSize > 0) ? maxBatchSize : attributes.size(); + const size_t numberOfBatches = std::ceil((double) attributes.size() / batchSize); + size_t i = 0; + responses.reserve(numberOfBatches); + + while (i < attributes.size()) + i += readBatch(i, batchSize); +} + +const std::vector>& AttributeReader::getResponses() +{ + return responses; +} + +size_t AttributeReader::readBatch(size_t startIndex, size_t size) +{ + if (startIndex + size > attributes.size()) + size = attributes.size() - startIndex; + + OpcUaObject request; + request->nodesToReadSize = size; + request->nodesToRead = (UA_ReadValueId*) UA_Array_new(attributes.size(), &UA_TYPES[UA_TYPES_READVALUEID]); + + for (size_t i = 0; i < size; i++) + { + const auto& attribute = attributes[startIndex + i]; + + request->nodesToRead[i].nodeId = attribute.nodeId.copyAndGetDetachedValue(); + request->nodesToRead[i].attributeId = attribute.attributeId; + } + + responses.emplace_back(UA_Client_Service_read(client->getLockedUaClient(), *request)); + + const auto& response = responses.back(); + const auto status = response->responseHeader.serviceResult; + + if (status != UA_STATUSCODE_GOOD) + throw OpcUaException(status, "Attribute read request failed"); + + addBatchToResultMap(startIndex, response); + return size; +} + +void AttributeReader::addBatchToResultMap(size_t startIndex, const OpcUaObject& response) +{ + for (size_t i = 0; i < response->resultsSize; i++) + { + const auto& attr = attributes[startIndex + i]; + + const auto value = std::make_shared(response->results + i); + + if (resultMap.count(attr.nodeId) == 0) + resultMap[attr.nodeId] = {}; + + resultMap[attr.nodeId][attr.attributeId] = value; + } +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/tests/CMakeLists.txt b/shared/libraries/opcua/opcuaclient/tests/CMakeLists.txt index b893a20..4ef8c4e 100644 --- a/shared/libraries/opcua/opcuaclient/tests/CMakeLists.txt +++ b/shared/libraries/opcua/opcuaclient/tests/CMakeLists.txt @@ -9,6 +9,7 @@ set(SRC_Cpp main.cpp test_opcuataskprocessor.cpp test_opcuatimertaskhelper.cpp test_opcuaclient.cpp + test_attribute_reader.cpp ) set(SRC_Include opcuaservertesthelper.h diff --git a/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h b/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h index 5d05d13..aeebe0a 100644 --- a/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h +++ b/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h @@ -21,7 +21,7 @@ #include "opcuaclient/opcuaclient.h" #include "opcuashared/opcua.h" #include "opcuashared/opcuacommon.h" - +#include #include BEGIN_NAMESPACE_OPENDAQ_OPCUA @@ -31,11 +31,14 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA class OpcUaServerTestHelper final { public: + using OnConfigureCallback = std::function; + OpcUaServerTestHelper(); ~OpcUaServerTestHelper(); void setSessionTimeout(double sessionTimeoutMs); + void onConfigure(const OnConfigureCallback& callback); void startServer(); void stop(); @@ -71,6 +74,7 @@ class OpcUaServerTestHelper final std::atomic serverRunning = false; UA_UInt16 port = 4842u; + OnConfigureCallback onConfigureCallback; }; class BaseClientTest : public testing::Test diff --git a/shared/libraries/opcua/opcuaclient/tests/src/opcuaservertesthelper.cpp b/shared/libraries/opcua/opcuaclient/tests/src/opcuaservertesthelper.cpp index 26be1fe..4a0e59d 100644 --- a/shared/libraries/opcua/opcuaclient/tests/src/opcuaservertesthelper.cpp +++ b/shared/libraries/opcua/opcuaclient/tests/src/opcuaservertesthelper.cpp @@ -2,6 +2,7 @@ #include #include #include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA @@ -29,14 +30,24 @@ void OpcUaServerTestHelper::runServer() UA_Server_delete(server); } +void OpcUaServerTestHelper::onConfigure(const OnConfigureCallback& callback) +{ + onConfigureCallback = callback; +} + void OpcUaServerTestHelper::startServer() { serverRunning = true; - server = UA_Server_new(); - UA_ServerConfig* config = UA_Server_getConfig(server); + UA_ServerConfig initConfig; + std::memset(&initConfig, 0, sizeof(UA_ServerConfig)); + + if (onConfigureCallback) + onConfigureCallback(&initConfig); - UA_ServerConfig_setMinimal(config, port, nullptr); + UA_ServerConfig_setMinimal(&initConfig, port, nullptr); + server = UA_Server_newWithConfig(&initConfig); + UA_ServerConfig* config = UA_Server_getConfig(server); if (sessionTimeoutMs > 0) config->maxSessionTimeout = sessionTimeoutMs; diff --git a/shared/libraries/opcua/opcuaclient/tests/src/test_attribute_reader.cpp b/shared/libraries/opcua/opcuaclient/tests/src/test_attribute_reader.cpp new file mode 100644 index 0000000..b57c1ee --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/tests/src/test_attribute_reader.cpp @@ -0,0 +1,194 @@ +#include +#include +#include "opcuaclient/opcuaclient.h" +#include "opcuaservertesthelper.h" +#include "opcuashared/opcuacommon.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using AttributeReaderTest = BaseClientTest; + +TEST_F(AttributeReaderTest, TwoAttributes) +{ + auto client = std::make_shared(getServerUrl()); + client->connect(); + + const auto attr1 = OpcUaAttribute(OpcUaNodeId(1, ".i64"), UA_ATTRIBUTEID_VALUE); + const auto attr2 = OpcUaAttribute(OpcUaNodeId(1, ".i32"), UA_ATTRIBUTEID_VALUE); + + auto reader = AttributeReader(client); + reader.addAttribute(attr1); + reader.addAttribute(attr2); + reader.read(); + + auto i64 = reader.getValue(attr1)->getValue().toInteger(); + ASSERT_EQ(i64, 64); + + auto i32 = reader.getValue(attr2)->getValue().toInteger(); + ASSERT_EQ(i32, 41); +} + +TEST_F(AttributeReaderTest, NotRead) +{ + auto client = std::make_shared(getServerUrl()); + client->connect(); + + const auto attr = OpcUaAttribute(OpcUaNodeId(1, ".i64"), UA_ATTRIBUTEID_VALUE); + + auto reader = AttributeReader(client); + reader.addAttribute(attr); + + ASSERT_THROW(reader.getValue(attr), OpcUaException); + + reader.read(); + ASSERT_NO_THROW(reader.getValue(attr)); +} + +TEST_F(AttributeReaderTest, Missing) +{ + auto client = std::make_shared(getServerUrl()); + client->connect(); + + const auto idI64 = OpcUaNodeId(1, ".i64"); + const auto idI32 = OpcUaNodeId(1, ".i32"); + + auto reader = AttributeReader(client); + reader.addAttribute({idI64, UA_ATTRIBUTEID_VALUE}); + reader.read(); + + ASSERT_NO_THROW(reader.getValue(idI64, UA_ATTRIBUTEID_VALUE)); + ASSERT_THROW(reader.getValue(idI32, UA_ATTRIBUTEID_VALUE), OpcUaException); + ASSERT_THROW(reader.getValue(idI64, UA_ATTRIBUTEID_DISPLAYNAME), OpcUaException); +} + +TEST_F(AttributeReaderTest, NoAttributes) +{ + auto client = std::make_shared(getServerUrl()); + + auto reader = AttributeReader(client); + ASSERT_NO_THROW(reader.read()); +} + +TEST_F(AttributeReaderTest, Clear) +{ + auto client = std::make_shared(getServerUrl()); + client->connect(); + + const auto idI64 = OpcUaNodeId(1, ".i64"); + + auto reader = AttributeReader(client); + reader.addAttribute({idI64, UA_ATTRIBUTEID_VALUE}); + reader.addAttribute({idI64, UA_ATTRIBUTEID_VALUE}); + reader.read(); + + auto i64 = reader.getValue(idI64, UA_ATTRIBUTEID_VALUE)->getValue().toInteger(); + ASSERT_EQ(i64, 64); +} + +TEST_F(AttributeReaderTest, FailedRequest) +{ + auto client = std::make_shared(getServerUrl()); + ASSERT_FALSE(client->isConnected()); + + const auto idI64 = OpcUaNodeId(1, ".i64"); + + auto reader = AttributeReader(client); + reader.addAttribute({idI64, UA_ATTRIBUTEID_VALUE}); + ASSERT_THROW(reader.read(), OpcUaException); +} + +TEST_F(AttributeReaderTest, SameAttribute) +{ + auto client = std::make_shared(getServerUrl()); + client->connect(); + + const auto attr = OpcUaAttribute(OpcUaNodeId(1, ".i64"), UA_ATTRIBUTEID_VALUE); + + auto reader = AttributeReader(client); + reader.addAttribute(attr); + reader.addAttribute(attr); + reader.read(); + + auto i64 = reader.getValue(attr)->getValue().toInteger(); + ASSERT_EQ(i64, 64); +} + +TEST_F(AttributeReaderTest, MaxNodesPerRead) +{ + const size_t maxNodesPerRead = 3; + + testHelper.stop(); + testHelper.onConfigure([&](UA_ServerConfig* config) { config->maxNodesPerRead = maxNodesPerRead; }); + testHelper.startServer(); + + auto client = std::make_shared(getServerUrl()); + client->connect(); + + const size_t maxBatchSize = client->readValue(OpcUaNodeId(UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERREAD)).toInteger(); + ASSERT_EQ(maxBatchSize, maxNodesPerRead); + + const auto idI64 = OpcUaNodeId(1, ".i64"); + const auto idI32 = OpcUaNodeId(1, ".i32"); + const auto idI16 = OpcUaNodeId(1, ".i16"); + const auto idProductUri = OpcUaNodeId(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI); + + auto reader = AttributeReader(client, maxBatchSize); + reader.addAttribute({idI64, UA_ATTRIBUTEID_VALUE}); + reader.addAttribute({idI64, UA_ATTRIBUTEID_DISPLAYNAME}); + reader.addAttribute({idI32, UA_ATTRIBUTEID_VALUE}); + reader.addAttribute({idI32, UA_ATTRIBUTEID_DISPLAYNAME}); + reader.addAttribute({idProductUri, UA_ATTRIBUTEID_VALUE}); + reader.addAttribute({idProductUri, UA_ATTRIBUTEID_BROWSENAME}); + reader.addAttribute({idI16, UA_ATTRIBUTEID_VALUE}); + reader.read(); + + OpcUaVariant variant; + + variant = reader.getValue(idI64, UA_ATTRIBUTEID_VALUE)->getValue(); + ASSERT_EQ(64, variant.toInteger()); + + variant = reader.getValue(idI64, UA_ATTRIBUTEID_DISPLAYNAME)->getValue(); + ASSERT_EQ(".i64", variant.toString()); + + variant = reader.getValue(idI32, UA_ATTRIBUTEID_VALUE)->getValue(); + ASSERT_EQ(41, variant.toInteger()); + + variant = reader.getValue(idI32, UA_ATTRIBUTEID_DISPLAYNAME)->getValue(); + ASSERT_EQ(".i32", variant.toString()); + + variant = reader.getValue(idProductUri, UA_ATTRIBUTEID_VALUE)->getValue(); + ASSERT_EQ("http://open62541.org", variant.toString()); + + variant = reader.getValue(idProductUri, UA_ATTRIBUTEID_BROWSENAME)->getValue(); + ASSERT_EQ("ProductUri", variant.toString()); + + variant = reader.getValue(idI16, UA_ATTRIBUTEID_VALUE)->getValue(); + ASSERT_EQ(16, variant.toInteger()); +} + +TEST_F(AttributeReaderTest, GetResponses) +{ + auto client = std::make_shared(getServerUrl()); + client->connect(); + + const size_t maxBatchSize = 2; + const auto idI64 = OpcUaNodeId(1, ".i64"); + + auto reader = AttributeReader(client, maxBatchSize); + reader.addAttribute({idI64, UA_ATTRIBUTEID_VALUE}); + reader.addAttribute({idI64, UA_ATTRIBUTEID_DISPLAYNAME}); + reader.addAttribute({idI64, UA_ATTRIBUTEID_BROWSENAME}); + + ASSERT_EQ(reader.getResponses().size(), 0); + + reader.read(); + + const auto& responses = reader.getResponses(); + + ASSERT_EQ(responses.size(), 2); + ASSERT_EQ(responses[0]->resultsSize, 2); + ASSERT_EQ(responses[1]->resultsSize, 1); +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcua_attribute.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcua_attribute.h new file mode 100644 index 0000000..6578f98 --- /dev/null +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcua_attribute.h @@ -0,0 +1,36 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +struct OpcUaAttribute +{ + OpcUaNodeId nodeId; + UA_AttributeId attributeId; + + OpcUaAttribute(const OpcUaNodeId& nodeId, UA_AttributeId attributeId) + : nodeId(nodeId) + , attributeId(attributeId) + { + } +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatavalue.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatavalue.h index 9814259..e532872 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatavalue.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatavalue.h @@ -21,6 +21,9 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA +class OpcUaDataValue; +using OpcUaDataValuePtr = std::shared_ptr; + class OpcUaDataValue { public: diff --git a/shared/libraries/opcua/opcuashared/src/CMakeLists.txt b/shared/libraries/opcua/opcuashared/src/CMakeLists.txt index a461d08..e07798a 100644 --- a/shared/libraries/opcua/opcuashared/src/CMakeLists.txt +++ b/shared/libraries/opcua/opcuashared/src/CMakeLists.txt @@ -51,6 +51,7 @@ set(SOURCE_HEADERS opcuavariant.h opcuadatatypearraylist.h opcuavector.h opcuanodeid.h + opcua_attribute.h bcrypt.h bcrypt/crypt_blowfish.h ) From b2491b4f0721f7e4d756afe2e2fcf60d27da3493 Mon Sep 17 00:00:00 2001 From: Martin Kraner Date: Mon, 4 Dec 2023 11:00:18 +0100 Subject: [PATCH 024/217] Rework how interface inheritance and queryInterface work to hopefully prevent ICEs and out-of-heap-space errors --- .../opcuatms/tests/opcuatms_integration/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt b/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt index ed24d03..632cf50 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt @@ -41,7 +41,7 @@ endif() set(StreamingLibraries ) if (OPENDAQ_ENABLE_WEBSOCKET_STREAMING) - list(APPEND StreamingLibraries PRIVATE daq::opendaq_websocket_streaming) + list(APPEND StreamingLibraries PRIVATE daq::websocket_streaming) endif() target_link_libraries(${TEST_APP} PRIVATE daq::opcuatms_test_utils From 374bdc07f456c354dea07459a667ae394cf56390 Mon Sep 17 00:00:00 2001 From: Nikolai Shipilov Date: Tue, 28 Nov 2023 18:14:07 +0100 Subject: [PATCH 025/217] Utilize signal subscribing within the websocket streaming: * subscribe/unsubscribe client signals which connected/disconnected to/from InputPort * temporarily subscribe all available signals during streaming connection initialization --- .../test_streaming_integration.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp index b76fdd1..d355614 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp @@ -252,12 +252,7 @@ TEST_F(StreamingIntegrationTest, ByteStep) ASSERT_TRUE(packetsEqual(serverReceivedPackets, clientReceivedPackets)); } -// TODO websocket streaming does not recreate half assigned data descriptor changed event packet on client side -// both: value and domain descriptors are always assigned in event packet -// while on server side one descriptor can be assigned only -// client side always generates 2 event packets for each server side event packet: -// one for value descriptor changed and another for domain descriptor changed -TEST_F(StreamingIntegrationTest, DISABLED_ChangingSignal) +TEST_F(StreamingIntegrationTest, ChangingSignal) { const size_t packetsToGenerate = 5; const size_t initialEventPackets = 1; @@ -287,6 +282,9 @@ TEST_F(StreamingIntegrationTest, DISABLED_ChangingSignal) ASSERT_EQ(serverReceivedPackets.getCount(), packetsToRead); ASSERT_EQ(clientReceivedPackets.getCount(), packetsToRead); // TODO: this fails + // TODO websocket streaming does not recreate half assigned data descriptor changed event packet on client side + // both: value and domain descriptors are always assigned in event packet + // while on server side one descriptor can be assigned only //ASSERT_TRUE(packetsEqual(serverReceivedPackets, clientReceivedPackets)); } From a709c88cbf77d86e5d026f9ca3e1344960641a24 Mon Sep 17 00:00:00 2001 From: Nikolai Shipilov Date: Wed, 29 Nov 2023 11:48:28 +0100 Subject: [PATCH 026/217] Change timeout handling for streaming integration tests --- .../test_streaming_integration.cpp | 65 ++++++++++++------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp index d355614..649793d 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp @@ -40,6 +40,7 @@ class StreamingIntegrationTest : public testing::Test void SetUp() override { logger = Logger(); + loggerComponent = logger.getOrAddComponent("StreamingIntegrationTest"); auto clientLogger = Logger(); clientContext = Context(Scheduler(clientLogger, 1), clientLogger, nullptr, nullptr); instance = createDevice(); @@ -87,19 +88,25 @@ class StreamingIntegrationTest : public testing::Test throw NotFoundException(); } - ListPtr tryReadPackets(const PacketReaderPtr& reader, size_t packetCount, uint64_t timeoutMs = 500) + ListPtr tryReadPackets(const PacketReaderPtr& reader, + size_t packetCount, + std::chrono::seconds timeout = std::chrono::seconds(60)) { auto allPackets = List(); - auto lastPacketReceived = std::chrono::system_clock::now(); + auto startPoint = std::chrono::system_clock::now(); while (allPackets.getCount() < packetCount) { if (reader.getAvailableCount() == 0) { auto now = std::chrono::system_clock::now(); - uint64_t diffMs = (uint64_t) std::chrono::duration_cast(now - lastPacketReceived).count(); - if (diffMs > timeoutMs) + auto timeElapsed = now - startPoint; + if (timeElapsed > timeout) + { + LOG_E("Timeout expired: packets count expected {}, packets count ready {}", + packetCount, allPackets.getCount()); break; + } std::this_thread::sleep_for(std::chrono::milliseconds(20)); continue; @@ -109,8 +116,6 @@ class StreamingIntegrationTest : public testing::Test for (const auto& packet : packets) allPackets.pushBack(packet); - - lastPacketReceived = std::chrono::system_clock::now(); } return allPackets; @@ -118,16 +123,30 @@ class StreamingIntegrationTest : public testing::Test bool packetsEqual(const ListPtr& listA, const ListPtr& listB, bool compareDescriptors = true) { + bool result = true; if (listA.getCount() != listB.getCount()) - return false; + { + LOG_E("Compared packets count differs: A {}, B {}", listA.getCount(), listB.getCount()); + result = false; + } - for (SizeT i = 0; i < listA.getCount(); i++) + auto count = std::min(listA.getCount(), listB.getCount()); + + for (SizeT i = 0; i < count; i++) { + if (!compareDescriptors && + listA.getItemAt(i).getType() == PacketType::Event && + listB.getItemAt(i).getType() == PacketType::Event) + continue; if (!BaseObjectPtr::Equals(listA.getItemAt(i), listB.getItemAt(i))) - return false; + { + LOG_E("Packets at index {} differs: A - \"{}\", B - \"{}\"", + i, listA.getItemAt(i).toString(), listB.getItemAt(i).toString()); + result = false; + } } - return true; + return result; } protected: @@ -163,6 +182,7 @@ class StreamingIntegrationTest : public testing::Test } LoggerPtr logger; + LoggerComponentPtr loggerComponent; ContextPtr clientContext; InstancePtr instance; FunctionPtr createStreamingCallback; @@ -247,9 +267,9 @@ TEST_F(StreamingIntegrationTest, ByteStep) auto serverReceivedPackets = tryReadPackets(serverStepReader, packetsToRead + 1); auto clientReceivedPackets = tryReadPackets(clientStepReader, packetsToRead + 1); - ASSERT_EQ(serverReceivedPackets.getCount(), packetsToRead + 1); - ASSERT_EQ(clientReceivedPackets.getCount(), packetsToRead + 1); - ASSERT_TRUE(packetsEqual(serverReceivedPackets, clientReceivedPackets)); + EXPECT_EQ(serverReceivedPackets.getCount(), packetsToRead + 1); + EXPECT_EQ(clientReceivedPackets.getCount(), packetsToRead + 1); + EXPECT_TRUE(packetsEqual(serverReceivedPackets, clientReceivedPackets)); } TEST_F(StreamingIntegrationTest, ChangingSignal) @@ -279,13 +299,12 @@ TEST_F(StreamingIntegrationTest, ChangingSignal) auto serverReceivedPackets = tryReadPackets(serverStepReader, packetsToRead); auto clientReceivedPackets = tryReadPackets(clientStepReader, packetsToRead); - ASSERT_EQ(serverReceivedPackets.getCount(), packetsToRead); - ASSERT_EQ(clientReceivedPackets.getCount(), packetsToRead); - // TODO: this fails + EXPECT_EQ(serverReceivedPackets.getCount(), packetsToRead); + EXPECT_EQ(clientReceivedPackets.getCount(), packetsToRead); // TODO websocket streaming does not recreate half assigned data descriptor changed event packet on client side // both: value and domain descriptors are always assigned in event packet // while on server side one descriptor can be assigned only - //ASSERT_TRUE(packetsEqual(serverReceivedPackets, clientReceivedPackets)); + EXPECT_TRUE(packetsEqual(serverReceivedPackets, clientReceivedPackets, false)); } TEST_F(StreamingIntegrationTest, AllSignalsAsync) @@ -336,9 +355,9 @@ TEST_F(StreamingIntegrationTest, AllSignalsAsync) { auto sentPackets = serverFetures[i].get(); auto receivedPackets = clientFetures[i].get(); - ASSERT_EQ(sentPackets.getCount(), packetsToRead + 1); - ASSERT_EQ(receivedPackets.getCount(), packetsToRead + 1); - ASSERT_TRUE(packetsEqual(sentPackets, receivedPackets)); + EXPECT_EQ(sentPackets.getCount(), packetsToRead + 1); + EXPECT_EQ(receivedPackets.getCount(), packetsToRead + 1); + EXPECT_TRUE(packetsEqual(sentPackets, receivedPackets)); } } @@ -382,7 +401,7 @@ TEST_F(StreamingIntegrationTest, StreamingDeactivate) auto clientStepReader = createReader(clientDevice, "Sine"); - auto clientReceivedPackets = tryReadPackets(clientStepReader, packetsToRead + 1); + auto clientReceivedPackets = tryReadPackets(clientStepReader, 1); ASSERT_EQ(clientReceivedPackets.getCount(), 1u); // Single event packet only generatePackets(packetsToRead); @@ -390,11 +409,11 @@ TEST_F(StreamingIntegrationTest, StreamingDeactivate) auto serverReceivedPackets = tryReadPackets(serverStepReader, packetsToRead + 1); ASSERT_EQ(serverReceivedPackets.getCount(), packetsToRead + 1); - clientReceivedPackets = tryReadPackets(clientStepReader, packetsToRead + 1); + clientReceivedPackets = tryReadPackets(clientStepReader, packetsToRead, std::chrono::seconds(5)); ASSERT_EQ(clientReceivedPackets.getCount(), 0u); // no data packets since streaming is inactive streaming.setActive(True); - clientReceivedPackets = tryReadPackets(clientStepReader, packetsToRead + 1); + clientReceivedPackets = tryReadPackets(clientStepReader, packetsToRead, std::chrono::seconds(5)); ASSERT_EQ(clientReceivedPackets.getCount(), 0u); // still no data packets available } From 564f49651ecba98fb96546de2a52e76553f0a192 Mon Sep 17 00:00:00 2001 From: Nikolai Shipilov Date: Wed, 6 Dec 2023 17:34:53 +0100 Subject: [PATCH 027/217] Integrate subscription ack event handling into streaming tests --- .../test_streaming_integration.cpp | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp index 649793d..5d35256 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp @@ -74,6 +74,22 @@ class StreamingIntegrationTest : public testing::Test } } + SignalPtr getSignal(const DevicePtr& device, const std::string& signalName) + { + auto signals = device.getSignalsRecursive(); + + for (const auto& signal : signals) + { + const auto descriptor = signal.getDescriptor(); + if (descriptor.assigned() && descriptor.getName() == signalName) + { + return signal; + } + } + + throw NotFoundException(); + } + PacketReaderPtr createReader(const DevicePtr& device, const std::string& signalName) { auto signals = device.getSignalsRecursive(); @@ -260,8 +276,20 @@ TEST_F(StreamingIntegrationTest, ByteStep) auto clientDevice = client.connect(); setActiveStreamingSource(clientDevice); + auto mirroredSignalPtr = getSignal(clientDevice, "ByteStep").template asPtr(); + std::promise subscribeCompletePromise; + std::future subscribeCompleteFuture = subscribeCompletePromise.get_future(); + mirroredSignalPtr.getOnSubscribeComplete() += + [&subscribeCompletePromise](MirroredSignalConfigPtr& sender, SubscriptionEventArgsPtr& args) + { + subscribeCompletePromise.set_value(args.getStreamingConnectionString()); + }; + auto clientStepReader = createReader(clientDevice, "ByteStep"); + ASSERT_EQ(subscribeCompleteFuture.wait_for(std::chrono::seconds(1)), std::future_status::ready); + ASSERT_EQ(subscribeCompleteFuture.get(), mirroredSignalPtr.getActiveStreamingSource()); + generatePackets(packetsToRead); auto serverReceivedPackets = tryReadPackets(serverStepReader, packetsToRead + 1); @@ -293,8 +321,20 @@ TEST_F(StreamingIntegrationTest, ChangingSignal) auto clientDevice = client.connect(); setActiveStreamingSource(clientDevice); + auto mirroredSignalPtr = getSignal(clientDevice, "ChangingSignal").template asPtr(); + std::promise subscribeCompletePromise; + std::future subscribeCompleteFuture = subscribeCompletePromise.get_future(); + mirroredSignalPtr.getOnSubscribeComplete() += + [&subscribeCompletePromise](MirroredSignalConfigPtr& sender, SubscriptionEventArgsPtr& args) + { + subscribeCompletePromise.set_value(args.getStreamingConnectionString()); + }; + auto clientStepReader = createReader(clientDevice, "ChangingSignal"); + ASSERT_EQ(subscribeCompleteFuture.wait_for(std::chrono::seconds(1)), std::future_status::ready); + ASSERT_EQ(subscribeCompleteFuture.get(), mirroredSignalPtr.getActiveStreamingSource()); + generatePackets(packetsToGenerate); auto serverReceivedPackets = tryReadPackets(serverStepReader, packetsToRead); @@ -333,8 +373,22 @@ TEST_F(StreamingIntegrationTest, AllSignalsAsync) setActiveStreamingSource(clientDevice); for (const auto& signal : signals) + { + auto mirroredSignalPtr = getSignal(clientDevice, signal).template asPtr(); + std::promise subscribeCompletePromise; + std::future subscribeCompleteFuture = subscribeCompletePromise.get_future(); + mirroredSignalPtr.getOnSubscribeComplete() += + [&subscribeCompletePromise](MirroredSignalConfigPtr& sender, SubscriptionEventArgsPtr& args) + { + subscribeCompletePromise.set_value(args.getStreamingConnectionString()); + }; + clientReaders.insert({signal, createReader(clientDevice, signal)}); + ASSERT_EQ(subscribeCompleteFuture.wait_for(std::chrono::seconds(1)), std::future_status::ready); + ASSERT_EQ(subscribeCompleteFuture.get(), mirroredSignalPtr.getActiveStreamingSource()); + } + generatePackets(packetsToRead); std::vector>> serverFetures; From 011f7776fc5766f7faca5aaf61377b2c9ce45b8c Mon Sep 17 00:00:00 2001 From: Nils Roettger <99480819+nilsRoettgerAtBB@users.noreply.github.com> Date: Thu, 14 Dec 2023 09:12:43 +0000 Subject: [PATCH 028/217] Feature/OPC-UA Vendor Supports (openDAQ/openDAQ#67) * Renaming: TMS->DAQ In opc-ua we are also calling the spec daq. Because of this we should also not use the name TMS there. * Remove options for building daq mandatory opc-ua specs For the openDAQ SDK it makes no sense to switch the options to false, because these types need to be known, so that variables from a opc-ua server a visible on openDAQ client side. * Add Vendor Spec support for openDAQ Clients If an electronic supplier add some more definition to opc-ua based on the openDAQ specs, it is possible to add these via vendor spec defintion. For this a vendor needs to add the source of the opc-ua files, Types, nodeIds and the NodeSet2 itself. * Add cmake generation of endpoint nodeset register methods * Fix opc-ua types were not added to opc-ua server. Tests are running again. Remove specific registerCustomTypes call for HBK Spec. * Improve PR based on Feedback Create separate CMakeLists.txt for HBK vendor spec. Add compile option for the vendor spec. * Register only data types if the server supports the namespaces This is important because if all namespaces are added which are generated by the SDK it could come to namespace index missmatch. It is very importnat that only the namepsaces provided by the opc-ua server are added and in the right order. --------- Co-authored-by: Jaka Mohorko --- external/opcua_daq_types/CMakeLists.txt | 220 ++++++++++++++++++ .../opcua_daq_types/daq_opcua_nodesets.h.in | 15 ++ external/opcua_daq_types/hbk/CMakeLists.txt | 41 ++++ .../opcua/opcuaserver/src/CMakeLists.txt | 2 +- .../opcua/opcuaserver/src/opcuatmstypes.cpp | 40 ++-- .../opcua/opcuaserver/tests/CMakeLists.txt | 2 +- .../include/opcuatms/converter_maps.h | 38 +-- .../opcuatms/include/opcuatms/opcuatms.h | 4 +- .../opcuatms/include/opcuatms/type_mappings.h | 36 +-- .../opcuatms/opcuatms/src/CMakeLists.txt | 2 +- .../src/converters/argument_converter.cpp | 2 +- .../converters/data_descriptor_converter.cpp | 14 +- .../src/converters/data_rule_converter.cpp | 22 +- .../src/converters/dict_converter.cpp | 2 +- .../src/converters/dimension_converter.cpp | 4 +- .../converters/dimension_rule_converter.cpp | 18 +- .../function_block_type_converter.cpp | 6 +- .../src/converters/ratio_converter.cpp | 4 +- .../src/converters/scaling_converter.cpp | 12 +- .../src/converters/unit_converter.cpp | 6 +- .../opcuatms/src/core_types_utils.cpp | 18 +- .../objects/tms_client_folder_factory.h | 2 +- .../src/objects/tms_client_device_impl.cpp | 22 +- .../src/objects/tms_client_folder_impl.cpp | 2 +- .../tms_client_function_block_impl.cpp | 10 +- .../objects/tms_client_input_port_impl.cpp | 10 +- .../src/objects/tms_client_io_folder_impl.cpp | 6 +- .../src/objects/tms_client_property_impl.cpp | 4 +- .../tms_client_property_object_impl.cpp | 12 +- .../src/objects/tms_client_signal_impl.cpp | 6 +- .../opcuatms_client/src/tms_client.cpp | 33 ++- .../objects/tms_server_component.h | 4 +- .../objects/tms_server_object.h | 2 +- .../src/objects/tms_server_channel.cpp | 4 +- .../src/objects/tms_server_device.cpp | 4 +- .../src/objects/tms_server_eval_value.cpp | 4 +- .../src/objects/tms_server_folder.cpp | 6 +- .../src/objects/tms_server_function_block.cpp | 4 +- .../src/objects/tms_server_input_port.cpp | 10 +- .../src/objects/tms_server_object.cpp | 2 +- .../src/objects/tms_server_property.cpp | 26 +-- .../objects/tms_server_property_object.cpp | 6 +- .../src/objects/tms_server_signal.cpp | 10 +- .../opcuatms_server/tests/test_helpers.h | 12 +- .../tests/test_tms_channel.cpp | 6 +- .../opcuatms_server/tests/test_tms_device.cpp | 2 +- .../tests/test_tms_function_block.cpp | 6 +- .../tests/test_tms_input_port.cpp | 4 +- .../opcuatms_server/tests/test_tms_server.cpp | 4 +- .../opcuatms_server/tests/test_tms_signal.cpp | 6 +- .../opcuatms_integration/test_tms_channel.cpp | 4 +- .../test_tms_function_block.cpp | 4 +- .../test_tms_input_port.cpp | 2 +- .../opcuatms_integration/test_tms_signal.cpp | 6 +- .../opcuatms/tests/test_utils/CMakeLists.txt | 2 +- .../tests/test_utils/tms_object_test.cpp | 10 +- 56 files changed, 526 insertions(+), 239 deletions(-) create mode 100644 external/opcua_daq_types/CMakeLists.txt create mode 100644 external/opcua_daq_types/daq_opcua_nodesets.h.in create mode 100644 external/opcua_daq_types/hbk/CMakeLists.txt diff --git a/external/opcua_daq_types/CMakeLists.txt b/external/opcua_daq_types/CMakeLists.txt new file mode 100644 index 0000000..2d8315d --- /dev/null +++ b/external/opcua_daq_types/CMakeLists.txt @@ -0,0 +1,220 @@ +set_cmake_folder_context(TARGET_FOLDER_NAME) +project(opcua_daq_types VERSION 1.0.0 DESCRIPTION "DAQ types" LANGUAGES C) + +option(HBK_NODESET "Adds an HBK Nodeset on top of the DAQ ESP spec" ON) + +# Define empty list of nodeset dependencies +list(APPEND OPC_UA_NODESET_DEPENDENCIES) +set(OPCUA_NODESET_NAMES) +set(OPCUA_NODESET_URIS) + + +# +# Fetch the openDAQ OPC-UA Companion Specification NodeSet +# +set(daq_spec_REQUIREDVERSION "3.0.2") +get_custom_fetch_content_params(daqspec FC_PARAMS) + +FetchContent_Declare(daqspec + GIT_REPOSITORY https://github.com/openDAQ/opc-ua-companion-spec.git + GIT_TAG v${daq_spec_REQUIREDVERSION} + ${FC_PARAMS} +) +FetchContent_GetProperties(daqspec) +if(NOT daqspec_POPULATED) + message(STATUS "Fetching daq specification ${daq_spec_REQUIREDVERSION}...") + FetchContent_Populate(daqspec) + set(COMPANION_SPECIFICATIONS_DIRPREFIX "${daqspec_SOURCE_DIR}/opendaq") +endif() + +# python interpreter is required for the code genaration process +find_package(Python3 REQUIRED) +set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE}) + +set(DI_NAME_SPACE_INDEX 2) +set(NAME_SPACE_INDEX ${DI_NAME_SPACE_INDEX}) +set(GENERATE_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated/open62541") + +# Define some empty list necessary for code generation +list(APPEND OPC_UA_NODESET_COMPILE_FLAGS) +list(APPEND OPC_UA_NODESET_SOURCES) +list(APPEND OPC_UA_NODESET_HEADERS) + +# +# Generate DI nodeset +# +message(STATUS "Generating DI nodeset...") +ua_generate_nodeset_and_datatypes( + NAME "di" + TARGET_PREFIX "${PROJECT_NAME}" + IMPORT_BSD "UA_TYPES#${open62541_NODESET_DIR}/Schema/Opc.Ua.Types.bsd" + FILE_CSV "${open62541_NODESET_DIR}/DI/OpcUaDiModel.csv" + FILE_BSD "${open62541_NODESET_DIR}/DI/Opc.Ua.Di.Types.bsd" + OUTPUT_DIR "${GENERATE_OUTPUT_DIR}" + NAMESPACE_MAP "${NAME_SPACE_INDEX}:http://opcfoundation.org/UA/DI/" + FILE_NS "${open62541_NODESET_DIR}/DI/Opc.Ua.Di.NodeSet2.xml" + INTERNAL +) +list(APPEND OPC_UA_NODESET_DEPENDENCIES ${PROJECT_NAME}-ns-di) +list(APPEND OPC_UA_NODESET_SOURCES ${UA_NODESET_DI_SOURCES} ${UA_TYPES_DI_SOURCES}) +list(APPEND OPC_UA_NODESET_HEADERS ${UA_NODESET_DI_HEADERS} ${UA_TYPES_DI_HEADERS} ${GENERATE_OUTPUT_DIR}/di_nodeids.h) +list(APPEND OPC_UA_NODESET_COMPILE_FLAGS NAMESPACE_DI=${NAME_SPACE_INDEX}) +list(APPEND OPCUA_NODESET_NAMES "di") +list(APPEND OPCUA_NODESET_URIS "http://opcfoundation.org/UA/DI/") + +MATH(EXPR NAME_SPACE_INDEX "${NAME_SPACE_INDEX}+1") + + +# +# Generate DAQ Base Types (BT) nodeset if needed +# +message(STATUS "Generating DAQ BT nodeset...") +ua_generate_nodeset_and_datatypes( + NAME "daqbt" + TARGET_PREFIX "${PROJECT_NAME}" + IMPORT_BSD "UA_TYPES#${open62541_NODESET_DIR}/Schema/Opc.Ua.Types.bsd" + FILE_CSV "${COMPANION_SPECIFICATIONS_DIRPREFIX}/Opc.Ua.Daq.Bt.NodeIds.csv" + FILE_BSD "${COMPANION_SPECIFICATIONS_DIRPREFIX}/Opc.Ua.Daq.Bt.Types.bsd" + OUTPUT_DIR "${GENERATE_OUTPUT_DIR}" + NAMESPACE_MAP "${NAME_SPACE_INDEX}:https://docs.opendaq.io/specifications/opc-ua/daq/bt" + FILE_NS "${COMPANION_SPECIFICATIONS_DIRPREFIX}/Opc.Ua.Daq.Bt.NodeSet2.xml" + DEPENDS "di" + INTERNAL +) +list(APPEND OPC_UA_NODESET_DEPENDENCIES ${PROJECT_NAME}-ns-daqbt) +list(APPEND OPC_UA_NODESET_SOURCES ${UA_NODESET_DAQBT_SOURCES} ${UA_TYPES_DAQBT_SOURCES}) +list(APPEND OPC_UA_NODESET_HEADERS ${UA_NODESET_DAQBT_HEADERS} ${UA_TYPES_DAQBT_HEADERS} ${GENERATE_OUTPUT_DIR}/daqbt_nodeids.h) +list(APPEND OPC_UA_NODESET_COMPILE_FLAGS NAMESPACE_DAQBT=${NAME_SPACE_INDEX}) +list(APPEND OPCUA_NODESET_NAMES "daqbt") +list(APPEND OPCUA_NODESET_URIS "https://docs.opendaq.io/specifications/opc-ua/daq/bt") +MATH(EXPR NAME_SPACE_INDEX "${NAME_SPACE_INDEX}+1") + +# +# Generate DAQ Basic Signal Processing (BSP) nodeset if needed +# +message(STATUS "Generating DAQ BSP nodeset...") +ua_generate_nodeset_and_datatypes( + NAME "daqbsp" + TARGET_PREFIX "${PROJECT_NAME}" + IMPORT_BSD "UA_TYPES#${open62541_NODESET_DIR}/Schema/Opc.Ua.Types.bsd" + IMPORT_BSD "UA_TYPES_DAQBT#${COMPANION_SPECIFICATIONS_DIRPREFIX}/Opc.Ua.Daq.Bt.Types.bsd" + FILE_CSV "${COMPANION_SPECIFICATIONS_DIRPREFIX}/Opc.Ua.Daq.Bsp.NodeIds.csv" + FILE_BSD "${COMPANION_SPECIFICATIONS_DIRPREFIX}/Opc.Ua.Daq.Bsp.Types.bsd" + OUTPUT_DIR "${GENERATE_OUTPUT_DIR}" + NAMESPACE_MAP "${NAME_SPACE_INDEX}:https://docs.opendaq.io/specifications/opc-ua/daq/bsp" + FILE_NS "${COMPANION_SPECIFICATIONS_DIRPREFIX}/Opc.Ua.Daq.Bsp.NodeSet2.xml" + DEPENDS "daqbt" + INTERNAL +) +list(APPEND OPC_UA_NODESET_DEPENDENCIES ${PROJECT_NAME}-ns-daqbsp) +list(APPEND OPC_UA_NODESET_SOURCES ${UA_NODESET_DAQBSP_SOURCES} ${UA_TYPES_DAQBSP_SOURCES}) +list(APPEND OPC_UA_NODESET_HEADERS ${UA_NODESET_DAQBSP_HEADERS} ${UA_TYPES_DAQBSP_HEADERS} ${GENERATE_OUTPUT_DIR}/daqbsp_nodeids.h) +list(APPEND OPC_UA_NODESET_COMPILE_FLAGS NAMESPACE_DAQBSP=${NAME_SPACE_INDEX}) +list(APPEND OPCUA_NODESET_NAMES "daqbsp") +list(APPEND OPCUA_NODESET_URIS "https://docs.opendaq.io/specifications/opc-ua/daq/bsp") +MATH(EXPR NAME_SPACE_INDEX "${NAME_SPACE_INDEX}+1") + +# +# Generate DAQ Device nodeset if needed +# +message(STATUS "Generating DAQ Device nodeset...") +ua_generate_nodeset_and_datatypes( + NAME "daqdevice" + TARGET_PREFIX "${PROJECT_NAME}" + IMPORT_BSD "UA_TYPES#${open62541_NODESET_DIR}/Schema/Opc.Ua.Types.bsd" + IMPORT_BSD "UA_TYPES_DAQBT#${COMPANION_SPECIFICATIONS_DIRPREFIX}/Opc.Ua.Daq.Bt.Types.bsd" + IMPORT_BSD "UA_TYPES_DAQBSP#${COMPANION_SPECIFICATIONS_DIRPREFIX}/Opc.Ua.Daq.Bsp.Types.bsd" + FILE_CSV "${COMPANION_SPECIFICATIONS_DIRPREFIX}/Opc.Ua.Daq.Device.NodeIds.csv" + FILE_BSD "${COMPANION_SPECIFICATIONS_DIRPREFIX}/Opc.Ua.Daq.Device.Types.bsd" + OUTPUT_DIR "${GENERATE_OUTPUT_DIR}" + NAMESPACE_MAP "${NAME_SPACE_INDEX}:https://docs.opendaq.io/specifications/opc-ua/daq/device" + FILE_NS "${COMPANION_SPECIFICATIONS_DIRPREFIX}/Opc.Ua.Daq.Device.NodeSet2.xml" + DEPENDS "daqbsp" + INTERNAL +) +list(APPEND OPC_UA_NODESET_DEPENDENCIES ${PROJECT_NAME}-ns-daqdevice) +list(APPEND OPC_UA_NODESET_SOURCES ${UA_NODESET_DAQDEVICE_SOURCES} ${UA_TYPES_DAQDEVICE_SOURCES}) +list(APPEND OPC_UA_NODESET_HEADERS ${UA_NODESET_DAQDEVICE_HEADERS} ${UA_TYPES_DAQDEVICE_HEADERS} ${GENERATE_OUTPUT_DIR}/daqdevice_nodeids.h) +list(APPEND OPC_UA_NODESET_COMPILE_FLAGS NAMESPACE_DAQDEVICE=${NAME_SPACE_INDEX}) +list(APPEND OPCUA_NODESET_NAMES "daqdevice") +list(APPEND OPCUA_NODESET_URIS "https://docs.opendaq.io/specifications/opc-ua/daq/device") +MATH(EXPR NAME_SPACE_INDEX "${NAME_SPACE_INDEX}+1") + +# +# Generate DAQ ESP nodeset if needed +# +message(STATUS "Generating DAQ ESP nodeset...") +ua_generate_nodeset_and_datatypes( + NAME "daqesp" + TARGET_PREFIX "${PROJECT_NAME}" + IMPORT_BSD "UA_TYPES#${open62541_NODESET_DIR}/Schema/Opc.Ua.Types.bsd" + IMPORT_BSD "UA_TYPES_DAQBT#${COMPANION_SPECIFICATIONS_DIRPREFIX}/Opc.Ua.Daq.Bt.Types.bsd" + IMPORT_BSD "UA_TYPES_DAQBSP#${COMPANION_SPECIFICATIONS_DIRPREFIX}/Opc.Ua.Daq.Bsp.Types.bsd" + IMPORT_BSD "UA_TYPES_DAQDEVICE#${COMPANION_SPECIFICATIONS_DIRPREFIX}/Opc.Ua.Daq.Device.Types.bsd" + FILE_CSV "${COMPANION_SPECIFICATIONS_DIRPREFIX}/Opc.Ua.Daq.Esp.NodeIds.csv" + FILE_BSD "${COMPANION_SPECIFICATIONS_DIRPREFIX}/Opc.Ua.Daq.Esp.Types.bsd" + OUTPUT_DIR "${GENERATE_OUTPUT_DIR}" + NAMESPACE_MAP "${NAME_SPACE_INDEX}:https://docs.opendaq.io/specifications/opc-ua/daq/esp" + FILE_NS "${COMPANION_SPECIFICATIONS_DIRPREFIX}/Opc.Ua.Daq.Esp.NodeSet2.xml" + DEPENDS "daqdevice" + INTERNAL +) +list(APPEND OPC_UA_NODESET_DEPENDENCIES ${PROJECT_NAME}-ns-daqesp) +list(APPEND OPC_UA_NODESET_SOURCES ${UA_NODESET_DAQESP_SOURCES} ${UA_TYPES_DAQESP_SOURCES}) +list(APPEND OPC_UA_NODESET_HEADERS ${UA_NODESET_DAQESP_HEADERS} ${UA_TYPES_DAQESP_HEADERS} ${GENERATE_OUTPUT_DIR}/daqesp_nodeids.h) +list(APPEND OPC_UA_NODESET_COMPILE_FLAGS NAMESPACE_DAQESP=${NAME_SPACE_INDEX}) +list(APPEND OPCUA_NODESET_NAMES "daqesp") +list(APPEND OPCUA_NODESET_URIS "https://docs.opendaq.io/specifications/opc-ua/daq/esp") +MATH(EXPR NAME_SPACE_INDEX "${NAME_SPACE_INDEX}+1") + +# Add Vendor Specs if wanted +if(HBK_NODESET) + include(hbk/CMakeLists.txt) +endif() +# +# Create custom target that will also execute the node compilations (because of the ALL keyword below) +# +list(LENGTH OPC_UA_NODESET_DEPENDENCIES OPC_UA_NODESET_DEPENDENCY_LENGTH) + +set(OPCUA_NODESET_INCLUDES "") +set(OPCUA_ENDPOINT_REGISTRATIONS "") +set(LOOP_RUN_INDEX 0) +foreach(NODESET_NAME ${OPCUA_NODESET_NAMES}) + list(GET OPCUA_NODESET_URIS ${LOOP_RUN_INDEX} OPCUA_NODESET_URI) + set(OPCUA_NODESET_INCLUDES "${OPCUA_NODESET_INCLUDES}#include\n") + string(TOUPPER ${NODESET_NAME} OPCUA_NODESET_NAME_UPPERCASE) + if(LOOP_RUN_INDEX EQUAL 0) + set(OPCUA_ENDPOINT_REGISTRATIONS "${OPCUA_ENDPOINT_REGISTRATIONS} if(nameSpace == \"${OPCUA_NODESET_URI}\")\n endpoint.registerCustomTypes(UA_TYPES_${OPCUA_NODESET_NAME_UPPERCASE}_COUNT, UA_TYPES_${OPCUA_NODESET_NAME_UPPERCASE});\n") + else() + set(OPCUA_ENDPOINT_REGISTRATIONS "${OPCUA_ENDPOINT_REGISTRATIONS} else if(nameSpace == \"${OPCUA_NODESET_URI}\")\n endpoint.registerCustomTypes(UA_TYPES_${OPCUA_NODESET_NAME_UPPERCASE}_COUNT, UA_TYPES_${OPCUA_NODESET_NAME_UPPERCASE});\n") + endif() + MATH(EXPR LOOP_RUN_INDEX "${LOOP_RUN_INDEX}+1") +endforeach() + +message(STATUS "Generating opcua nodeset include methods at ${GENERATE_OUTPUT_DIR}/daq_opcua_nodesets.h") +configure_file("daq_opcua_nodesets.h.in" ${GENERATE_OUTPUT_DIR}/daq_opcua_nodesets.h) +list(APPEND OPC_UA_NODESET_HEADERS ${GENERATE_OUTPUT_DIR}/daq_opcua_nodesets.h) + +add_library(${PROJECT_NAME} + STATIC + ${OPC_UA_NODESET_SOURCES} + ${OPC_UA_NODESET_HEADERS} +) + +add_library(${SDK_TARGET_NAMESPACE}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) + +target_link_libraries(${PROJECT_NAME} PUBLIC $) + +# Make sure that generation is run before but don't link libraries +add_dependencies(${PROJECT_NAME} ${OPC_UA_NODESET_DEPENDENCIES}) + +target_compile_definitions(${PROJECT_NAME} PUBLIC ${OPC_UA_NODESET_COMPILE_FLAGS}) + +# Ignore warnings defined in "external/bbopen62541" +target_compile_options(${PROJECT_NAME} PRIVATE ${OPEN62541_DISABLED_WARNINGS}) + +# Let libraries linking to us know where to find the generated headers +target_include_directories(${PROJECT_NAME} INTERFACE + $ + $ +) diff --git a/external/opcua_daq_types/daq_opcua_nodesets.h.in b/external/opcua_daq_types/daq_opcua_nodesets.h.in new file mode 100644 index 0000000..e382a23 --- /dev/null +++ b/external/opcua_daq_types/daq_opcua_nodesets.h.in @@ -0,0 +1,15 @@ +#pragma once +#include +@OPCUA_NODESET_INCLUDES@ + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +static void registerDaqTypes(OpcUaEndpoint& endpoint, ListPtr nameSpaces) +{ + for (auto nameSpace : nameSpaces) + { +@OPCUA_ENDPOINT_REGISTRATIONS@ + } +} + +END_NAMESPACE_OPENDAQ_OPCUA \ No newline at end of file diff --git a/external/opcua_daq_types/hbk/CMakeLists.txt b/external/opcua_daq_types/hbk/CMakeLists.txt new file mode 100644 index 0000000..b84ba76 --- /dev/null +++ b/external/opcua_daq_types/hbk/CMakeLists.txt @@ -0,0 +1,41 @@ +set(daq_hbk_REQUIREDVERSION "3.0.12") + +get_custom_fetch_content_params(daqhbkspec FC_PARAMS) +FetchContent_Declare(daqhbkspec + GIT_REPOSITORY "https://github.com/hbkworld/opc-ua-specs.git" + GIT_TAG v${daq_hbk_REQUIREDVERSION} + ${FC_PARAMS} +) +FetchContent_GetProperties(daqhbkspec) +if(NOT daqhbkspec_POPULATED) + message(STATUS "Fetching hbk daq specification ${daq_hbk_REQUIREDVERSION}...") + FetchContent_Populate(daqhbkspec) + list(APPEND VENDOR_COMPANION_SPECIFICATION_DIRPREFIX "${daqhbkspec_SOURCE_DIR}/opendaq/hbk") +endif() + +message(STATUS "Generating DAQ Hbk nodeset...") + +ua_generate_nodeset_and_datatypes( + NAME "daqhbk" + TARGET_PREFIX "${PROJECT_NAME}" + IMPORT_BSD "UA_TYPES#${open62541_NODESET_DIR}/Schema/Opc.Ua.Types.bsd" + IMPORT_BSD "UA_TYPES_DAQBT#${COMPANION_SPECIFICATIONS_DIRPREFIX}/Opc.Ua.Daq.Bt.Types.bsd" + IMPORT_BSD "UA_TYPES_DAQBSP#${COMPANION_SPECIFICATIONS_DIRPREFIX}/Opc.Ua.Daq.Bsp.Types.bsd" + IMPORT_BSD "UA_TYPES_DAQDEVICE#${COMPANION_SPECIFICATIONS_DIRPREFIX}/Opc.Ua.Daq.Device.Types.bsd" + IMPORT_BSD "UA_TYPES_DAQESP#${COMPANION_SPECIFICATIONS_DIRPREFIX}/Opc.Ua.Daq.Esp.Types.bsd" + FILE_CSV "${VENDOR_COMPANION_SPECIFICATION_DIRPREFIX}/Opc.Ua.Daq.Vendor.Hbk.NodeIds.csv" + FILE_BSD "${VENDOR_COMPANION_SPECIFICATION_DIRPREFIX}/Opc.Ua.Daq.Vendor.Hbk.Types.bsd" + OUTPUT_DIR "${GENERATE_OUTPUT_DIR}" + NAMESPACE_MAP "${NAME_SPACE_INDEX}:https://docs.opendaq.io/specifications/opc-ua/daq/vendor/hbk" + FILE_NS "${VENDOR_COMPANION_SPECIFICATION_DIRPREFIX}/Opc.Ua.Daq.Vendor.Hbk.NodeSet2.xml" + DEPENDS "daqesp" + INTERNAL +) + +list(APPEND OPC_UA_NODESET_DEPENDENCIES ${PROJECT_NAME}-ns-daqhbk) +list(APPEND OPC_UA_NODESET_SOURCES ${UA_NODESET_DAQHBK_SOURCES} ${UA_TYPES_DAQHBK_SOURCES}) +list(APPEND OPC_UA_NODESET_HEADERS ${UA_NODESET_DAQHBK_HEADERS} ${UA_TYPES_DAQHBK_HEADERS} ${GENERATE_OUTPUT_DIR}/daqhbk_nodeids.h) +list(APPEND OPC_UA_NODESET_COMPILE_FLAGS NAMESPACE_DAQHBK=${NAME_SPACE_INDEX}) +list(APPEND OPCUA_NODESET_NAMES "daqhbk") +list(APPEND OPCUA_NODESET_URIS "https://docs.opendaq.io/specifications/opc-ua/daq/vendor/hbk") +MATH(EXPR NAME_SPACE_INDEX "${NAME_SPACE_INDEX}+1") \ No newline at end of file diff --git a/shared/libraries/opcua/opcuaserver/src/CMakeLists.txt b/shared/libraries/opcua/opcuaserver/src/CMakeLists.txt index e7723f3..67ca02c 100644 --- a/shared/libraries/opcua/opcuaserver/src/CMakeLists.txt +++ b/shared/libraries/opcua/opcuaserver/src/CMakeLists.txt @@ -45,7 +45,7 @@ target_include_directories(${MODULE_NAME} PUBLIC $ #include -#ifdef NAMESPACE_TMSBT - #include - #include +#ifdef NAMESPACE_DAQBT + #include + #include #endif -#ifdef NAMESPACE_TMSBSP - #include - #include +#ifdef NAMESPACE_DAQBSP + #include + #include #endif -#ifdef NAMESPACE_TMSDEVICE - #include - #include +#ifdef NAMESPACE_DAQDEVICE + #include + #include #endif -#ifdef NAMESPACE_TMSESP - #include - #include +#ifdef NAMESPACE_DAQESP + #include + #include #endif #include "opcuashared/opcuaexception.h" #include "opcuashared/opcualog.h" @@ -29,26 +29,26 @@ void addTmsTypes(UA_Server *server) CheckStatusCodeException(uaStatus, "Failed to add OPC-UA for devices nodeset."); LOGD << "OPC-UA for devices nodeSet was added successfully."; -#ifdef NAMESPACE_TMSBT - uaStatus = namespace_tmsbt_generated(server); +#ifdef NAMESPACE_DAQBT + uaStatus = namespace_daqbt_generated(server); CheckStatusCodeException(uaStatus, "Failed to add TMS BT nodeset."); LOGD << "TMS BT nodeset was added successfully."; #endif -#ifdef NAMESPACE_TMSBSP - uaStatus = namespace_tmsbsp_generated(server); +#ifdef NAMESPACE_DAQBSP + uaStatus = namespace_daqbsp_generated(server); CheckStatusCodeException(uaStatus, "Failed to add TMS BSP nodeset."); LOGD << "TMS BSP nodeset was added successfully."; #endif -#ifdef NAMESPACE_TMSDEVICE - uaStatus = namespace_tmsdevice_generated(server); +#ifdef NAMESPACE_DAQDEVICE + uaStatus = namespace_daqdevice_generated(server); CheckStatusCodeException(uaStatus, "Failed to add TMS DEVICE nodeset."); LOGD << "TMS DEVICE nodeset was added successfully."; #endif -#ifdef NAMESPACE_TMSESP - uaStatus = namespace_tmsesp_generated(server); +#ifdef NAMESPACE_DAQESP + uaStatus = namespace_daqesp_generated(server); CheckStatusCodeException(uaStatus, "Failed to add TMS ESP nodeset."); LOGD << "TMS ESP nodeset was added successfully."; #endif diff --git a/shared/libraries/opcua/opcuaserver/tests/CMakeLists.txt b/shared/libraries/opcua/opcuaserver/tests/CMakeLists.txt index 0602c50..022758e 100644 --- a/shared/libraries/opcua/opcuaserver/tests/CMakeLists.txt +++ b/shared/libraries/opcua/opcuaserver/tests/CMakeLists.txt @@ -16,7 +16,7 @@ target_link_libraries(${TEST_APP} PRIVATE ${SDK_TARGET_NAMESPACE}::${MODULE_NAME daq::opendaq_utils daq::test_utils daq::opcuaclient - daq::opcua_tms_types + daq::opcua_daq_types ) add_test(NAME ${TEST_APP} diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h index 458970b..982c083 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h @@ -19,12 +19,12 @@ #include "opcuatms/converters/variant_converter.h" #include "opcuatms/converters/selection_converter.h" #include "opendaq/data_descriptor_ptr.h" -#include "open62541/tmsbt_nodeids.h" -#include "open62541/tmsbsp_nodeids.h" +#include "open62541/daqbt_nodeids.h" +#include "open62541/daqbsp_nodeids.h" #include "open62541/nodeids.h" #include "opendaq/function_block_type_ptr.h" -namespace daq::opcua::tms { +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS namespace converters { @@ -176,26 +176,26 @@ namespace converters [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, {OpcUaNodeId(0, UA_NS0ID_QUALIFIEDNAME), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, - {OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_EUINFORMATIONWITHQUANTITY), + {OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_EUINFORMATIONWITHQUANTITY), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, {OpcUaNodeId(0, UA_NS0ID_EUINFORMATION), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, {OpcUaNodeId(0, UA_NS0ID_RATIONALNUMBER), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, - {OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_RATIONALNUMBER64), + {OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_RATIONALNUMBER64), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, - {OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_DATADESCRIPTORSTRUCTURE), + {OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_DATADESCRIPTORSTRUCTURE), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, - {OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_STRUCTDESCRIPTORSTRUCTURE), + {OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_STRUCTDESCRIPTORSTRUCTURE), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, - {OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_DIMENSIONDESCRIPTORSTRUCTURE), + {OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_DIMENSIONDESCRIPTORSTRUCTURE), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, - {OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_FUNCTIONBLOCKINFOSTRUCTURE), + {OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_FUNCTIONBLOCKINFOSTRUCTURE), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, - {OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_POSTSCALINGSTRUCTURE), + {OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_POSTSCALINGSTRUCTURE), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, - {OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_LINEARSCALINGDESCRIPTIONSTRUCTURE), + {OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_LINEARSCALINGDESCRIPTIONSTRUCTURE), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, {OpcUaNodeId(0, UA_NS0ID_ARGUMENT), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, @@ -232,25 +232,25 @@ namespace converters [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, {OpcUaNodeId(0, UA_NS0ID_QUALIFIEDNAME), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, - {OpcUaNodeId(NAMESPACE_TMSBT, UA_TYPES_TMSBT_EUINFORMATIONWITHQUANTITY), + {OpcUaNodeId(NAMESPACE_DAQBT, UA_TYPES_DAQBT_EUINFORMATIONWITHQUANTITY), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, {OpcUaNodeId(0, UA_TYPES_EUINFORMATION), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, {OpcUaNodeId(0, UA_NS0ID_RATIONALNUMBER), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, - {OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_RATIONALNUMBER64), + {OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_RATIONALNUMBER64), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, - {OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_DATADESCRIPTORSTRUCTURE), + {OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_DATADESCRIPTORSTRUCTURE), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, - {OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_STRUCTDESCRIPTORSTRUCTURE), + {OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_STRUCTDESCRIPTORSTRUCTURE), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, - {OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_DIMENSIONDESCRIPTORSTRUCTURE), + {OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_DIMENSIONDESCRIPTORSTRUCTURE), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, - {OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_FUNCTIONBLOCKINFOSTRUCTURE), + {OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_FUNCTIONBLOCKINFOSTRUCTURE), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, - {OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_POSTSCALINGSTRUCTURE), + {OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_POSTSCALINGSTRUCTURE), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, - {OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_LINEARSCALINGDESCRIPTIONSTRUCTURE), + {OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_LINEARSCALINGDESCRIPTIONSTRUCTURE), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, {OpcUaNodeId(0, UA_NS0ID_ARGUMENT), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h index ba49dc3..1a52c4f 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h @@ -18,8 +18,8 @@ #include #include -#include -#include +#include +#include #include #define BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS \ diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h index fa56a36..d2d1ad9 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h @@ -19,22 +19,22 @@ namespace daq::opcua { - ADD_CUSTOM_TYPE_MAPPING(UA_BaseRuleDescriptionStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_BASERULEDESCRIPTIONSTRUCTURE]) - ADD_CUSTOM_TYPE_MAPPING(UA_ExplicitDomainRuleDescriptionStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_EXPLICITDOMAINRULEDESCRIPTIONSTRUCTURE]) - ADD_CUSTOM_TYPE_MAPPING(UA_CustomRuleDescriptionStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_CUSTOMRULEDESCRIPTIONSTRUCTURE]) - ADD_CUSTOM_TYPE_MAPPING(UA_ConstantRuleDescriptionStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_CONSTANTRULEDESCRIPTIONSTRUCTURE]) - ADD_CUSTOM_TYPE_MAPPING(UA_LinearRuleDescriptionStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LINEARRULEDESCRIPTIONSTRUCTURE]) - ADD_CUSTOM_TYPE_MAPPING(UA_ListRuleDescriptionStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LISTRULEDESCRIPTIONSTRUCTURE]) - ADD_CUSTOM_TYPE_MAPPING(UA_LogRuleDescriptionStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LOGRULEDESCRIPTIONSTRUCTURE]) - ADD_CUSTOM_TYPE_MAPPING(UA_EUInformationWithQuantity, &UA_TYPES_TMSBT[UA_TYPES_TMSBT_EUINFORMATIONWITHQUANTITY]) - ADD_CUSTOM_TYPE_MAPPING(UA_DataDescriptorStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_DATADESCRIPTORSTRUCTURE]) - ADD_CUSTOM_TYPE_MAPPING(UA_StructDescriptorStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_STRUCTDESCRIPTORSTRUCTURE]) - ADD_CUSTOM_TYPE_MAPPING(UA_DimensionDescriptorStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_DIMENSIONDESCRIPTORSTRUCTURE]) - ADD_CUSTOM_TYPE_MAPPING(UA_RationalNumber64, &UA_TYPES_TMSBT[UA_TYPES_TMSBT_RATIONALNUMBER64]) - ADD_CUSTOM_TYPE_MAPPING(UA_PostScalingStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_POSTSCALINGSTRUCTURE]) - ADD_CUSTOM_TYPE_MAPPING(UA_LinearScalingDescriptionStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LINEARSCALINGDESCRIPTIONSTRUCTURE]) - ADD_CUSTOM_TYPE_MAPPING(UA_FunctionBlockInfoStructure, &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_FUNCTIONBLOCKINFOSTRUCTURE]) - ADD_CUSTOM_TYPE_MAPPING(UA_DaqKeyValuePair, &UA_TYPES_TMSBT[UA_TYPES_TMSBT_DAQKEYVALUEPAIR]) - ADD_CUSTOM_TYPE_MAPPING(UA_SelectionEntryStructure, &UA_TYPES_TMSBT[UA_TYPES_TMSBT_SELECTIONENTRYSTRUCTURE]) - ADD_CUSTOM_TYPE_MAPPING(UA_DeviceDomainStructure, &UA_TYPES_TMSDEVICE[UA_TYPES_TMSDEVICE_DEVICEDOMAINSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_BaseRuleDescriptionStructure, &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_BASERULEDESCRIPTIONSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_ExplicitDomainRuleDescriptionStructure, &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_EXPLICITDOMAINRULEDESCRIPTIONSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_CustomRuleDescriptionStructure, &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_CUSTOMRULEDESCRIPTIONSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_ConstantRuleDescriptionStructure, &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_CONSTANTRULEDESCRIPTIONSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_LinearRuleDescriptionStructure, &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_LINEARRULEDESCRIPTIONSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_ListRuleDescriptionStructure, &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_LISTRULEDESCRIPTIONSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_LogRuleDescriptionStructure, &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_LOGRULEDESCRIPTIONSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_EUInformationWithQuantity, &UA_TYPES_DAQBT[UA_TYPES_DAQBT_EUINFORMATIONWITHQUANTITY]) + ADD_CUSTOM_TYPE_MAPPING(UA_DataDescriptorStructure, &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_DATADESCRIPTORSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_StructDescriptorStructure, &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_STRUCTDESCRIPTORSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_DimensionDescriptorStructure, &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_DIMENSIONDESCRIPTORSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_RationalNumber64, &UA_TYPES_DAQBT[UA_TYPES_DAQBT_RATIONALNUMBER64]) + ADD_CUSTOM_TYPE_MAPPING(UA_PostScalingStructure, &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_POSTSCALINGSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_LinearScalingDescriptionStructure, &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_LINEARSCALINGDESCRIPTIONSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_FunctionBlockInfoStructure, &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_FUNCTIONBLOCKINFOSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_DaqKeyValuePair, &UA_TYPES_DAQBT[UA_TYPES_DAQBT_DAQKEYVALUEPAIR]) + ADD_CUSTOM_TYPE_MAPPING(UA_SelectionEntryStructure, &UA_TYPES_DAQBT[UA_TYPES_DAQBT_SELECTIONENTRYSTRUCTURE]) + ADD_CUSTOM_TYPE_MAPPING(UA_DeviceDomainStructure, &UA_TYPES_DAQDEVICE[UA_TYPES_DAQDEVICE_DEVICEDOMAINSTRUCTURE]) } diff --git a/shared/libraries/opcuatms/opcuatms/src/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms/src/CMakeLists.txt index 9b99bc7..45d56d5 100644 --- a/shared/libraries/opcuatms/opcuatms/src/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms/src/CMakeLists.txt @@ -67,7 +67,7 @@ target_include_directories(${MODULE_NAME} PUBLIC $ +#include #include #include "opcuatms/converters/struct_converter.h" #include "opcuatms/converters/variant_converter.h" @@ -271,16 +271,16 @@ OpcUaVariant VariantConverter::ToVariant(const DataDescriptorPt { auto variant = OpcUaVariant(); - if (targetType ==nullptr || targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_BASEDATADESCRIPTORSTRUCTURE]) + if (targetType ==nullptr || targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_BASEDATADESCRIPTORSTRUCTURE]) { if (object.isStructDescriptor()) variant.setScalar(*StructConverter::ToTmsType(object)); else variant.setScalar(*StructConverter::ToTmsType(object)); } - else if (targetType ==&UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_DATADESCRIPTORSTRUCTURE]) + else if (targetType ==&UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_DATADESCRIPTORSTRUCTURE]) variant.setScalar(*StructConverter::ToTmsType(object)); - else if (targetType ==&UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_STRUCTDESCRIPTORSTRUCTURE]) + else if (targetType ==&UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_STRUCTDESCRIPTORSTRUCTURE]) variant.setScalar(*StructConverter::ToTmsType(object)); else throw ConversionFailedException{}; @@ -306,11 +306,11 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr(list); - if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_DATADESCRIPTORSTRUCTURE]) + if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_DATADESCRIPTORSTRUCTURE]) return ListConversionUtils::ToArrayVariant(list); - if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_STRUCTDESCRIPTORSTRUCTURE]) + if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_STRUCTDESCRIPTORSTRUCTURE]) return ListConversionUtils::ToArrayVariant(list); throw ConversionFailedException{}; diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/data_rule_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/data_rule_converter.cpp index f3a8254..015779e 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/data_rule_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/data_rule_converter.cpp @@ -1,7 +1,7 @@ #include #include "opcuatms/converters/struct_converter.h" #include "opcuatms/converters/variant_converter.h" -#include "open62541/types_tmsbsp_generated_handling.h" +#include "open62541/types_daqbsp_generated_handling.h" #include "opcuatms/converters/list_conversion_utils.h" #include "opcuatms/core_types_utils.h" @@ -251,15 +251,15 @@ OpcUaVariant VariantConverter::ToVariant(const DataRulePtr& object, c } } } - else if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LINEARRULEDESCRIPTIONSTRUCTURE]) + else if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_LINEARRULEDESCRIPTIONSTRUCTURE]) variant.setScalar(*StructConverter::ToTmsType(object)); - else if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_CONSTANTRULEDESCRIPTIONSTRUCTURE]) + else if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_CONSTANTRULEDESCRIPTIONSTRUCTURE]) variant.setScalar(*StructConverter::ToTmsType(object)); - else if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_BASERULEDESCRIPTIONSTRUCTURE]) + else if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_BASERULEDESCRIPTIONSTRUCTURE]) variant.setScalar(*StructConverter::ToTmsType(object)); - else if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_CUSTOMRULEDESCRIPTIONSTRUCTURE]) + else if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_CUSTOMRULEDESCRIPTIONSTRUCTURE]) variant.setScalar(*StructConverter::ToTmsType(object)); - else if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_EXPLICITDOMAINRULEDESCRIPTIONSTRUCTURE]) + else if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_EXPLICITDOMAINRULEDESCRIPTIONSTRUCTURE]) variant.setScalar(*StructConverter::ToTmsType(object)); else throw ConversionFailedException{}; @@ -293,15 +293,15 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr(list); - if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LINEARRULEDESCRIPTIONSTRUCTURE]) + if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_LINEARRULEDESCRIPTIONSTRUCTURE]) return ListConversionUtils::ToArrayVariant(list); - if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_CONSTANTRULEDESCRIPTIONSTRUCTURE]) + if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_CONSTANTRULEDESCRIPTIONSTRUCTURE]) return ListConversionUtils::ToArrayVariant(list); - if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_EXPLICITDOMAINRULEDESCRIPTIONSTRUCTURE]) + if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_EXPLICITDOMAINRULEDESCRIPTIONSTRUCTURE]) return ListConversionUtils::ToArrayVariant(list); - if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_BASERULEDESCRIPTIONSTRUCTURE]) + if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_BASERULEDESCRIPTIONSTRUCTURE]) return ListConversionUtils::ToArrayVariant(list); - if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_CUSTOMRULEDESCRIPTIONSTRUCTURE]) + if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_CUSTOMRULEDESCRIPTIONSTRUCTURE]) return ListConversionUtils::ToArrayVariant(list); throw ConversionFailedException{}; } diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/dict_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/dict_converter.cpp index 9eb8e79..a1155aa 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/dict_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/dict_converter.cpp @@ -90,7 +90,7 @@ OpcUaVariant VariantConverter::ToVariant(const DictPtr::ToVariant(const DimensionPtr& object, const ContextPtr& /*context*/) { auto variant = OpcUaVariant(); - if (targetType == nullptr || targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_DIMENSIONDESCRIPTORSTRUCTURE]) + if (targetType == nullptr || targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_DIMENSIONDESCRIPTORSTRUCTURE]) variant.setScalar(*StructConverter::ToTmsType(object)); else throw ConversionFailedException{}; @@ -96,7 +96,7 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr(list); throw ConversionFailedException{}; diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/dimension_rule_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/dimension_rule_converter.cpp index 26ab7b8..bded1a7 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/dimension_rule_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/dimension_rule_converter.cpp @@ -3,7 +3,7 @@ #include "opcuatms/converters/list_conversion_utils.h" #include "opcuatms/converters/struct_converter.h" #include "opcuatms/converters/variant_converter.h" -#include "open62541/types_tmsbsp_generated_handling.h" +#include "open62541/types_daqbsp_generated_handling.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -245,13 +245,13 @@ OpcUaVariant VariantConverter::ToVariant(const DimensionRulePtr& } } } - else if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LINEARRULEDESCRIPTIONSTRUCTURE]) + else if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_LINEARRULEDESCRIPTIONSTRUCTURE]) variant.setScalar(*StructConverter::ToTmsType(object)); - else if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LOGRULEDESCRIPTIONSTRUCTURE]) + else if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_LOGRULEDESCRIPTIONSTRUCTURE]) variant.setScalar(*StructConverter::ToTmsType(object)); - else if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LISTRULEDESCRIPTIONSTRUCTURE]) + else if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_LISTRULEDESCRIPTIONSTRUCTURE]) variant.setScalar(*StructConverter::ToTmsType(object)); - else if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_CUSTOMRULEDESCRIPTIONSTRUCTURE]) + else if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_CUSTOMRULEDESCRIPTIONSTRUCTURE]) variant.setScalar(*StructConverter::ToTmsType(object)); else throw ConversionFailedException{}; @@ -283,13 +283,13 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr(list); - if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LINEARRULEDESCRIPTIONSTRUCTURE]) + if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_LINEARRULEDESCRIPTIONSTRUCTURE]) return ListConversionUtils::ToArrayVariant(list); - if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LOGRULEDESCRIPTIONSTRUCTURE]) + if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_LOGRULEDESCRIPTIONSTRUCTURE]) return ListConversionUtils::ToArrayVariant(list); - if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LISTRULEDESCRIPTIONSTRUCTURE]) + if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_LISTRULEDESCRIPTIONSTRUCTURE]) return ListConversionUtils::ToArrayVariant(list); - if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_CUSTOMRULEDESCRIPTIONSTRUCTURE]) + if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_CUSTOMRULEDESCRIPTIONSTRUCTURE]) return ListConversionUtils::ToArrayVariant(list); throw ConversionFailedException{}; diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/function_block_type_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/function_block_type_converter.cpp index 4324da5..16b5e4c 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/function_block_type_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/function_block_type_converter.cpp @@ -3,7 +3,7 @@ #include "opcuatms/converters/list_conversion_utils.h" #include "opcuatms/converters/struct_converter.h" #include "opcuatms/converters/variant_converter.h" -#include "open62541/types_tmsbsp_generated.h" +#include "open62541/types_daqbsp_generated.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -59,7 +59,7 @@ OpcUaVariant VariantConverter::ToVariant(const FunctionBlock { auto variant = OpcUaVariant(); - if (targetType == nullptr || targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_FUNCTIONBLOCKINFOSTRUCTURE]) + if (targetType == nullptr || targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_FUNCTIONBLOCKINFOSTRUCTURE]) variant.setScalar(*StructConverter::ToTmsType(object)); else throw ConversionFailedException{}; @@ -81,7 +81,7 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr< const UA_DataType* targetType, const ContextPtr& /*context*/) { - if (targetType == nullptr || targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_FUNCTIONBLOCKINFOSTRUCTURE]) + if (targetType == nullptr || targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_FUNCTIONBLOCKINFOSTRUCTURE]) return ListConversionUtils::ToArrayVariant(list); throw ConversionFailedException{}; diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/ratio_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/ratio_converter.cpp index 84255fa..d38eb88 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/ratio_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/ratio_converter.cpp @@ -77,7 +77,7 @@ OpcUaVariant VariantConverter::ToVariant(const RatioPtr& object, const U { auto variant = OpcUaVariant(); - if (targetType == nullptr || targetType == &UA_TYPES_TMSBT[UA_TYPES_TMSBT_RATIONALNUMBER64]) + if (targetType == nullptr || targetType == &UA_TYPES_DAQBT[UA_TYPES_DAQBT_RATIONALNUMBER64]) variant.setScalar(*StructConverter::ToTmsType(object)); else if (targetType == &UA_TYPES[UA_TYPES_RATIONALNUMBER]) variant.setScalar(*StructConverter::ToTmsType(object)); @@ -105,7 +105,7 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& lis const UA_DataType* targetType, const ContextPtr& /*context*/) { - if (targetType == nullptr || targetType == &UA_TYPES_TMSBT[UA_TYPES_TMSBT_RATIONALNUMBER64]) + if (targetType == nullptr || targetType == &UA_TYPES_DAQBT[UA_TYPES_DAQBT_RATIONALNUMBER64]) return ListConversionUtils::ToArrayVariant(list); if (targetType == &UA_TYPES[UA_TYPES_RATIONALNUMBER]) return ListConversionUtils::ToArrayVariant(list); diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/scaling_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/scaling_converter.cpp index 69115e4..44734cc 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/scaling_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/scaling_converter.cpp @@ -1,7 +1,7 @@ #include #include "opcuatms/converters/struct_converter.h" #include "opcuatms/converters/variant_converter.h" -#include "open62541/types_tmsbsp_generated_handling.h" +#include "open62541/types_daqbsp_generated_handling.h" #include "opcuatms/core_types_utils.h" #include "opcuatms/extension_object.h" #include "opcuatms/converters/list_conversion_utils.h" @@ -95,7 +95,7 @@ OpcUaObject StructConverteroffset = VariantConverter::ToVariant(offset).getDetachedValue(); uaPostScaling->scalingDescription.encoding = UA_EXTENSIONOBJECT_DECODED; - uaPostScaling->scalingDescription.content.decoded.type = &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LINEARSCALINGDESCRIPTIONSTRUCTURE]; + uaPostScaling->scalingDescription.content.decoded.type = &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_LINEARSCALINGDESCRIPTIONSTRUCTURE]; const auto uaLinearScalingDescriptionPtr = UA_LinearScalingDescriptionStructure_new(); *uaLinearScalingDescriptionPtr = uaLinearScalingDescription.getDetachedValue(); @@ -131,9 +131,9 @@ OpcUaVariant VariantConverter::ToVariant(const ScalingPtr& object, con { auto variant = OpcUaVariant(); - if (targetType == nullptr || targetType ==&UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_POSTSCALINGSTRUCTURE]) + if (targetType == nullptr || targetType ==&UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_POSTSCALINGSTRUCTURE]) variant.setScalar(*StructConverter::ToTmsType(object)); - else if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LINEARSCALINGDESCRIPTIONSTRUCTURE]) + else if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_LINEARSCALINGDESCRIPTIONSTRUCTURE]) variant.setScalar(*StructConverter::ToTmsType(object)); else throw ConversionFailedException{}; @@ -159,9 +159,9 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& const UA_DataType* targetType, const ContextPtr& /*context*/) { - if (targetType == nullptr || targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_POSTSCALINGSTRUCTURE]) + if (targetType == nullptr || targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_POSTSCALINGSTRUCTURE]) return ListConversionUtils::ToArrayVariant(list); - if (targetType == &UA_TYPES_TMSBSP[UA_TYPES_TMSBSP_LINEARSCALINGDESCRIPTIONSTRUCTURE]) + if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_LINEARSCALINGDESCRIPTIONSTRUCTURE]) return ListConversionUtils::ToArrayVariant(list); throw ConversionFailedException{}; diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/unit_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/unit_converter.cpp index f730768..c110ed7 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/unit_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/unit_converter.cpp @@ -3,7 +3,7 @@ #include "opcuatms/converters/list_conversion_utils.h" #include "opcuatms/converters/struct_converter.h" #include "opcuatms/converters/variant_converter.h" -#include "open62541/types_tmsbsp_generated.h" +#include "open62541/types_daqbsp_generated.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -84,7 +84,7 @@ OpcUaVariant VariantConverter::ToVariant(const UnitPtr& object, const UA_ { auto variant = OpcUaVariant(); - if (targetType == nullptr || targetType == &UA_TYPES_TMSBT[UA_TYPES_TMSBT_EUINFORMATIONWITHQUANTITY]) + if (targetType == nullptr || targetType == &UA_TYPES_DAQBT[UA_TYPES_DAQBT_EUINFORMATIONWITHQUANTITY]) variant.setScalar(*StructConverter::ToTmsType(object)); else if (targetType == &UA_TYPES[UA_TYPES_EUINFORMATION]) variant.setScalar(*StructConverter::ToTmsType(object)); @@ -112,7 +112,7 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& list, const UA_DataType* targetType, const ContextPtr& /*context*/) { - if (targetType == nullptr || targetType == &UA_TYPES_TMSBT[UA_TYPES_TMSBT_EUINFORMATIONWITHQUANTITY]) + if (targetType == nullptr || targetType == &UA_TYPES_DAQBT[UA_TYPES_DAQBT_EUINFORMATIONWITHQUANTITY]) return ListConversionUtils::ToArrayVariant(list); if (targetType == &UA_TYPES[UA_TYPES_EUINFORMATION]) return ListConversionUtils::ToArrayVariant(list); diff --git a/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp b/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp index 3ccf818..c78c191 100644 --- a/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp @@ -3,9 +3,9 @@ #include "opcuashared/opcuadatatypearraylist.h" #include "opcuatms/extension_object.h" #include "open62541/nodeids.h" -#include "open62541/tmsbt_nodeids.h" +#include "open62541/daqbt_nodeids.h" #include "open62541/types_di_generated.h" -#include "open62541/types_tmsesp_generated.h" +#include "open62541/types_daqesp_generated.h" using namespace daq::opcua; using namespace daq; @@ -29,8 +29,8 @@ namespace details {OpcUaNodeId(0, UA_NS0ID_UINT64), ctInt}, {OpcUaNodeId(0, UA_NS0ID_STRING), ctString}, {OpcUaNodeId(0, UA_NS0ID_RATIONALNUMBER), ctRatio}, - {OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_RATIONALNUMBER64), ctRatio}, - {OpcUaNodeId(0, UA_TMSBTID_RATIONALNUMBER64), ctRatio} + {OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_RATIONALNUMBER64), ctRatio}, + {OpcUaNodeId(0, UA_DAQBTID_RATIONALNUMBER64), ctRatio} }; } @@ -186,7 +186,7 @@ OpcUaNodeId CoreTypeToUANodeID(CoreType type) case ctString: return OpcUaNodeId(0, UA_NS0ID_STRING); case ctRatio: - return OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_RATIONALNUMBER64); + return OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_RATIONALNUMBER64); case ctProc: case ctList: case ctDict: @@ -239,10 +239,10 @@ const UA_DataType* GetUAStructureDataTypeByName(const std::string& structName) OpcUaDataTypeArrayList typeArr; typeArr.add(UA_TYPES_COUNT, UA_TYPES); typeArr.add(UA_TYPES_DI_COUNT, UA_TYPES_DI); - typeArr.add(UA_TYPES_TMSBT_COUNT, UA_TYPES_TMSBT); - typeArr.add(UA_TYPES_TMSBSP_COUNT, UA_TYPES_TMSBSP); - typeArr.add(UA_TYPES_TMSDEVICE_COUNT, UA_TYPES_TMSDEVICE); - typeArr.add(UA_TYPES_TMSESP_COUNT, UA_TYPES_TMSESP); + typeArr.add(UA_TYPES_DAQBT_COUNT, UA_TYPES_DAQBT); + typeArr.add(UA_TYPES_DAQBSP_COUNT, UA_TYPES_DAQBSP); + typeArr.add(UA_TYPES_DAQDEVICE_COUNT, UA_TYPES_DAQDEVICE); + typeArr.add(UA_TYPES_DAQESP_COUNT, UA_TYPES_DAQESP); const UA_DataTypeArray* dataType = typeArr.getCustomDataTypes(); while(dataType) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_factory.h index c982037..a36083e 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_factory.h @@ -18,7 +18,7 @@ #include "opcuatms_client/objects/tms_client_folder_impl.h" #include -#include "open62541/tmsdevice_nodeids.h" +#include "open62541/daqdevice_nodeids.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS inline FolderPtr TmsClientFolder(const ContextPtr& context, diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 59c45c3..937e345 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -11,10 +11,10 @@ #include "opcuatms_client/objects/tms_client_component_factory.h" #include "opcuatms_client/objects/tms_client_io_folder_factory.h" #include "opcuatms_client/objects/tms_client_streaming_info_factory.h" -#include -#include "open62541/tmsbt_nodeids.h" -#include -#include +#include +#include "open62541/daqbt_nodeids.h" +#include +#include #include #include #include "opcuatms/core_types_utils.h" @@ -82,7 +82,7 @@ void TmsClientDeviceImpl::findAndCreateSubdevices() std::map orderedDevices; std::vector unorderedDevices; - auto subdeviceNodeIds = this->getChildNodes(client, nodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQDEVICETYPE)); + auto subdeviceNodeIds = this->getChildNodes(client, nodeId, OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_DAQDEVICETYPE)); for (const auto& subdeviceNodeId : subdeviceNodeIds) { auto browseName = client->readBrowseName(subdeviceNodeId); @@ -227,7 +227,7 @@ void TmsClientDeviceImpl::findAndCreateFunctionBlocks() auto functionBlocksNodeId = getNodeId("FB"); auto functionBlockNodeIds = - this->getChildNodes(client, functionBlocksNodeId, OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_FUNCTIONBLOCKTYPE)); + this->getChildNodes(client, functionBlocksNodeId, OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_FUNCTIONBLOCKTYPE)); for (const auto& functionBlockNodeId : functionBlockNodeIds) { auto browseName = this->client->readBrowseName(functionBlockNodeId); @@ -258,7 +258,7 @@ void TmsClientDeviceImpl::findAndCreateSignals() std::vector unorderedSignals; const auto signalsNodeId = getNodeId("Sig"); - const auto signalNodeIds = this->getChildNodes(client, signalsNodeId, OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_SIGNALTYPE)); + const auto signalNodeIds = this->getChildNodes(client, signalsNodeId, OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_SIGNALTYPE)); for (const auto& signalNodeId : signalNodeIds) { auto clientSignal = FindOrCreateTmsClientSignal(context, signals, clientContext, signalNodeId); @@ -283,7 +283,7 @@ void TmsClientDeviceImpl::findAndCreateInputsOutputs() this->ioFolder.clear(); auto inputsOutputsNodeId = getNodeId("IO"); - auto channelNodeIds = this->getChildNodes(client, inputsOutputsNodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_CHANNELTYPE)); + auto channelNodeIds = this->getChildNodes(client, inputsOutputsNodeId, OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_CHANNELTYPE)); for (const auto& channelNodeId : channelNodeIds) { auto browseName = client->readBrowseName(channelNodeId); @@ -296,7 +296,7 @@ void TmsClientDeviceImpl::findAndCreateInputsOutputs() unorderedComponents.emplace_back(tmsClientChannel); } - auto folderNodeIds = this->getChildNodes(client, inputsOutputsNodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_IOCOMPONENTTYPE)); + auto folderNodeIds = this->getChildNodes(client, inputsOutputsNodeId, OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_IOCOMPONENTTYPE)); for (const auto& folderNodeId : folderNodeIds) { auto browseName = client->readBrowseName(folderNodeId); @@ -325,7 +325,7 @@ void TmsClientDeviceImpl::findAndCreateStreamingOptions() try { auto streamingOptionNodeIds = - this->getChildNodes(client, streamingOptionsNodeId, OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_VARIABLEBLOCKTYPE)); + this->getChildNodes(client, streamingOptionsNodeId, OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_VARIABLEBLOCKTYPE)); for (const auto& streamingOptionNodeId : streamingOptionNodeIds) { auto browseName = client->readBrowseName(streamingOptionNodeId); @@ -354,7 +354,7 @@ void TmsClientDeviceImpl::findAndCreateCustomComponents() std::map orderedComponents; std::vector unorderedComponents; - auto componentId = OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQCOMPONENTTYPE); + auto componentId = OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_DAQCOMPONENTTYPE); auto folderNodeIds = this->getChildNodes(client, nodeId, componentId); for (const auto& folderNodeId : folderNodeIds) { diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp index 2a3d87f..c677ac3 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp @@ -32,7 +32,7 @@ TmsClientFolderImpl::TmsClientFolderImpl(const ContextPtr& ctx, template void TmsClientFolderImpl::findAndCreateFolders(std::map& orderedComponents, std::vector& unorderedComponents) { - auto componentId = OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQCOMPONENTTYPE); + auto componentId = OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_DAQCOMPONENTTYPE); auto folderNodeIds = this->getChildNodes(this->client, this->nodeId, componentId); for (const auto& folderNodeId : folderNodeIds) { diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp index 199d681..36cff35 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp @@ -4,7 +4,7 @@ #include "opcuatms_client/objects/tms_client_signal_factory.h" #include "opcuatms_client/objects/tms_client_function_block_factory.h" #include "opcuatms_client/objects/tms_client_input_port_factory.h" -#include "open62541/tmsbsp_nodeids.h" +#include "open62541/daqbsp_nodeids.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -31,7 +31,7 @@ template tsl::ordered_set TmsClientFunctionBlockBaseImpl::getFunctionBlockNodeIds() { const OpcUaNodeId referenceTypeId(UA_NS0ID_HASCOMPONENT); - const OpcUaNodeId functionBlockType(NAMESPACE_TMSBSP, UA_TMSBSPID_FUNCTIONBLOCKTYPE); // TODO subtypes + const OpcUaNodeId functionBlockType(NAMESPACE_DAQBSP, UA_DAQBSPID_FUNCTIONBLOCKTYPE); // TODO subtypes return this->referenceUtils.getReferencedNodes(this->nodeId, referenceTypeId, true, functionBlockType); } @@ -39,7 +39,7 @@ template tsl::ordered_set TmsClientFunctionBlockBaseImpl::getOutputSignalNodeIds() { auto signalsNodeId = this->getNodeId("Sig"); - OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASVALUESIGNAL); + OpcUaNodeId referenceTypeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASVALUESIGNAL); return this->referenceUtils.getReferencedNodes(signalsNodeId, referenceTypeId, true); } @@ -107,7 +107,7 @@ template tsl::ordered_set TmsClientFunctionBlockBaseImpl::getInputPortNodeIds() { auto inputPortsNodeId = this->getNodeId("IP"); - OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASINPUTPORT); + OpcUaNodeId referenceTypeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASINPUTPORT); return this->referenceUtils.getReferencedNodes(inputPortsNodeId, referenceTypeId, true); } @@ -147,7 +147,7 @@ void TmsClientFunctionBlockBaseImpl::readFbType() template SignalPtr TmsClientFunctionBlockBaseImpl::onGetStatusSignal() { - OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASSTATUSSIGNAL); + OpcUaNodeId referenceTypeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASSTATUSSIGNAL); auto nodeIds = this->referenceUtils.getReferencedNodes(this->nodeId, referenceTypeId, true); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp index 4dfd00d..e96cbf4 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp @@ -1,4 +1,4 @@ -#include "open62541/tmsbsp_nodeids.h" +#include "open62541/daqbsp_nodeids.h" #include "opcuatms/converters/variant_converter.h" #include "opcuatms_client/objects/tms_client_input_port_impl.h" #include "opcuatms/errors.h" @@ -33,7 +33,7 @@ ErrCode TmsClientInputPortImpl::acceptsSignal(ISignal* signal, Bool* accepts) return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; //return daqTry([&]() { - // OpcUaNodeId methodId(NAMESPACE_TMSBSP, UA_TMSBSPID_INPUTPORTTYPE_ACCEPTSSIGNAL); + // OpcUaNodeId methodId(NAMESPACE_DAQBSP, UA_DAQBSPID_INPUTPORTTYPE_ACCEPTSSIGNAL); // auto signalNodeId = clientContext->getNodeId(signal); // OpcUaVariant inputArg; @@ -55,7 +55,7 @@ ErrCode TmsClientInputPortImpl::connect(ISignal* signal) { return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; //return daqTry([&]() { - // OpcUaNodeId methodId(NAMESPACE_TMSBSP, UA_TMSBSPID_INPUTPORTTYPE_CONNECTSIGNAL); + // OpcUaNodeId methodId(NAMESPACE_DAQBSP, UA_DAQBSPID_INPUTPORTTYPE_CONNECTSIGNAL); // auto signalNodeId = clientContext->getNodeId(signal); // OpcUaVariant inputArg; @@ -79,7 +79,7 @@ ErrCode TmsClientInputPortImpl::disconnect() return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; //return daqTry([&]() { - // OpcUaNodeId methodId(NAMESPACE_TMSBSP, UA_TMSBSPID_INPUTPORTTYPE_DISCONNECTSIGNAL); + // OpcUaNodeId methodId(NAMESPACE_DAQBSP, UA_DAQBSPID_INPUTPORTTYPE_DISCONNECTSIGNAL); // OpcUaCallMethodRequest callRequest(methodId, nodeId, 0, nullptr); // OpcUaObject result = client->callMethod(callRequest); @@ -104,7 +104,7 @@ ErrCode TmsClientInputPortImpl::getSignal(ISignal** signal) SignalPtr TmsClientInputPortImpl::onGetSignal() { - OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_CONNECTEDTOSIGNAL); + OpcUaNodeId referenceTypeId(NAMESPACE_DAQBSP, UA_DAQBSPID_CONNECTEDTOSIGNAL); auto nodeIds = referenceUtils.getReferencedNodes(nodeId, referenceTypeId, true); assert(nodeIds.size() <= 1); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp index d1c3ec1..33882a1 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp @@ -1,7 +1,7 @@ #include "opcuatms_client/objects/tms_client_io_folder_impl.h" #include "opcuatms_client/objects/tms_client_channel_factory.h" #include "opcuatms_client/objects/tms_client_io_folder_factory.h" -#include "open62541/tmsdevice_nodeids.h" +#include "open62541/daqdevice_nodeids.h" #include "opendaq/folder_config_ptr.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -30,7 +30,7 @@ TmsClientIoFolderImpl::TmsClientIoFolderImpl(const ContextPtr& ctx, void TmsClientIoFolderImpl::findAndCreateChannels(std::map& orderedComponents, std::vector& unorderedComponents) { - auto channelNodeIds = getChildNodes(this->client, this->nodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_CHANNELTYPE)); + auto channelNodeIds = getChildNodes(this->client, this->nodeId, OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_CHANNELTYPE)); for (const auto& channelNodeId : channelNodeIds) { auto browseName = this->client->readBrowseName(channelNodeId); @@ -47,7 +47,7 @@ void TmsClientIoFolderImpl::findAndCreateChannels(std::map& orderedComponents, std::vector& unorderedComponents) { - auto folderNodeIds = getChildNodes(this->client, this->nodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_IOCOMPONENTTYPE)); + auto folderNodeIds = getChildNodes(this->client, this->nodeId, OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_IOCOMPONENTTYPE)); for (const auto& folderNodeId : folderNodeIds) { auto browseName = this->client->readBrowseName(folderNodeId); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp index 3cd7220..ec81a8d 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp @@ -4,7 +4,7 @@ #include "coreobjects/validator_factory.h" #include "opcuatms/converters/variant_converter.h" #include "opcuatms/converters/selection_converter.h" -#include "open62541/tmsbt_nodeids.h" +#include "open62541/daqbt_nodeids.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -59,7 +59,7 @@ void TmsClientPropertyImpl::readBasicInfo() void TmsClientPropertyImpl::configurePropertyFields() { - const auto evaluationVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_EVALUATIONVARIABLETYPE); + const auto evaluationVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_EVALUATIONVARIABLETYPE); for (auto [childNodeId, ref] : referenceUtils.getReferences(nodeId)) { diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index cf2d247..4062f37 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -4,7 +4,7 @@ #include "coreobjects/property_object_factory.h" #include "opcuaclient/browser/opcuabrowser.h" #include "opcuatms_client/objects/tms_client_property_factory.h" -#include "open62541/tmsbt_nodeids.h" +#include "open62541/daqbt_nodeids.h" #include "opcuatms/converters/variant_converter.h" #include "opcuatms_client/objects/tms_client_property_object_factory.h" #include "opcuatms_client/objects/tms_client_function_factory.h" @@ -167,10 +167,10 @@ void TmsClientPropertyObjectBaseImpl::addProperties( std::map& orderedProperties, std::vector& unorderedProperties) { - const auto introspectionVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_INTROSPECTIONVARIABLETYPE); - const auto structureVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_STRUCTUREVARIABLETYPE); - const auto referenceVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_REFERENCEVARIABLETYPE); - const auto variableBlockTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_VARIABLEBLOCKTYPE); + const auto introspectionVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_INTROSPECTIONVARIABLETYPE); + const auto structureVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_STRUCTUREVARIABLETYPE); + const auto referenceVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_REFERENCEVARIABLETYPE); + const auto variableBlockTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_VARIABLEBLOCKTYPE); for (auto& [childNodeId, ref] : references) { @@ -222,7 +222,7 @@ void TmsClientPropertyObjectBaseImpl::addProperties( auto obj = TmsClientPropertyObject(daqContext, clientContext, childNodeId); auto propBuilder = ObjectPropertyBuilder(propName, obj).setDescription(String(client->readDescription(childNodeId))); - const auto evaluationVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_EVALUATIONVARIABLETYPE); + const auto evaluationVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_EVALUATIONVARIABLETYPE); const auto variableBlockRefs = referenceUtils.getReferences(childNodeId); for (auto& [variableBlockNodeId, variableBlockRef] : variableBlockRefs) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp index cf0f43d..edd4524 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp @@ -1,5 +1,5 @@ #include -#include "open62541/tmsbsp_nodeids.h" +#include "open62541/daqbsp_nodeids.h" #include "opcuashared/opcuacommon.h" #include "opcuatms/exceptions.h" #include "opcuatms_client/objects/tms_client_signal_impl.h" @@ -77,7 +77,7 @@ ErrCode TmsClientSignalImpl::getDomainSignal(ISignal** signal) SignalPtr TmsClientSignalImpl::onGetDomainSignal() { - OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASDOMAINSIGNAL); + OpcUaNodeId referenceTypeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASDOMAINSIGNAL); auto nodeIds = referenceUtils.getReferencedNodes(nodeId, referenceTypeId, true); assert(nodeIds.size() <= 1); @@ -106,7 +106,7 @@ ErrCode TmsClientSignalImpl::getRelatedSignals(IList** signals) ListPtr TmsClientSignalImpl::onGetRelatedSignals() { - OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_RELATESTOSIGNAL); + OpcUaNodeId referenceTypeId(NAMESPACE_DAQBSP, UA_DAQBSPID_RELATESTOSIGNAL); auto nodeIds = referenceUtils.getReferencedNodes(nodeId, referenceTypeId, true); ListPtr resultList = List(); for (auto signalNodeId : nodeIds) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp index 30df4f8..0e68c86 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp @@ -2,12 +2,15 @@ #include #include #include +#include #include -#include +#include #include -#include -#include -#include +#include +#include +#include +#include + #include @@ -30,17 +33,25 @@ TmsClient::TmsClient(const ContextPtr& context, daq::DevicePtr TmsClient::connect() { OpcUaEndpoint endpoint("TmsClient", opcUaUrl); - endpoint.registerCustomTypes(UA_TYPES_DI_COUNT, UA_TYPES_DI); - endpoint.registerCustomTypes(UA_TYPES_TMSBT_COUNT, UA_TYPES_TMSBT); - endpoint.registerCustomTypes(UA_TYPES_TMSBSP_COUNT, UA_TYPES_TMSBSP); - endpoint.registerCustomTypes(UA_TYPES_TMSDEVICE_COUNT, UA_TYPES_TMSDEVICE); - endpoint.registerCustomTypes(UA_TYPES_TMSESP_COUNT, UA_TYPES_TMSESP); client = std::make_shared(endpoint); if (!client->connect()) throw NotFoundException(); client->runIterate(); + // A first connect is needed to read from the server the available namespaces out from the server + auto namespaces = VariantConverter::ToDaqList(client->readValue(OpcUaNodeId(0,UA_NS0ID_SERVER_NAMESPACEARRAY))); + + client->stopIterate(); + client->disconnect(); + + // After a disconnect, we need to register the data types, but only these which are available on server side. + registerDaqTypes(endpoint, namespaces); + client = std::make_shared(endpoint); + if (!client->connect()) + throw NotFoundException(); + client->runIterate(); + tmsClientContext = std::make_shared(client); auto rootDeviceNodeId = getRootDeviceNodeId(); @@ -76,8 +87,8 @@ OpcUaNodeId TmsClient::getRootDeviceNodeId() OpcUaBrowser browser(br, client); auto results = browser.browse(); - const OpcUaNodeId daqDeviceTypeNodeId( NAMESPACE_TMSDEVICE, // TODO NAMESPACE_TMSDEVICE is server namespace id. You need - UA_TMSDEVICEID_DAQDEVICETYPE); // to map it to client. Or use namespace URI. + const OpcUaNodeId daqDeviceTypeNodeId( NAMESPACE_DAQDEVICE, // TODO NAMESPACE_DAQDEVICE is server namespace id. You need + UA_DAQDEVICEID_DAQDEVICETYPE); // to map it to client. Or use namespace URI. for (const auto& result : results) diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h index 1fa4560..37cd3cc 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h @@ -19,7 +19,7 @@ #include #include "opcuatms_server/objects/tms_server_property_object.h" #include "opcuatms/converters/variant_converter.h" -#include "open62541/tmsdevice_nodeids.h" +#include "open62541/daqdevice_nodeids.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -91,7 +91,7 @@ OpcUaNodeId TmsServerComponent::getReferenceType() template OpcUaNodeId TmsServerComponent::getTmsTypeId() { - return OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQCOMPONENTTYPE); + return OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_DAQCOMPONENTTYPE); } template diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h index a4b6fdb..de3f14a 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h @@ -40,7 +40,7 @@ struct RequestedNodeId +#include #include "opcuatms/converters/struct_converter.h" #include #include @@ -56,7 +56,7 @@ TmsServerDevice::TmsServerDevice(const DevicePtr& object, const OpcUaServerPtr& OpcUaNodeId TmsServerDevice::getTmsTypeId() { - return OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQDEVICETYPE); + return OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_DAQDEVICETYPE); } bool TmsServerDevice::createOptionalNode(const OpcUaNodeId& nodeId) diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_eval_value.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_eval_value.cpp index 55ed1b5..76e1c26 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_eval_value.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_eval_value.cpp @@ -1,7 +1,7 @@ #include "opcuatms_server/objects/tms_server_eval_value.h" #include "opcuatms/converters/variant_converter.h" #include "opcuatms/converters/selection_converter.h" -#include "open62541/tmsbt_nodeids.h" +#include "open62541/daqbt_nodeids.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -43,7 +43,7 @@ void TmsServerEvalValue::setIsSelectionType(bool isSelection) opcua::OpcUaNodeId TmsServerEvalValue::getTmsTypeId() { - return OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_EVALUATIONVARIABLETYPE); + return OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_EVALUATIONVARIABLETYPE); } void TmsServerEvalValue::configureVariableNodeAttributes(opcua::OpcUaObject& attr) diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp index d1e7e5c..723533b 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp @@ -1,7 +1,7 @@ #include "opcuatms_server/objects/tms_server_channel.h" #include "opcuatms_server/objects/tms_server_folder.h" #include "opcuatms/converters/variant_converter.h" -#include "open62541/tmsdevice_nodeids.h" +#include "open62541/daqdevice_nodeids.h" #include "opendaq/io_folder_config.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -49,8 +49,8 @@ void TmsServerFolder::addChildNodes() OpcUaNodeId TmsServerFolder::getTmsTypeId() { if (object.asPtrOrNull().assigned()) - return OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_IOCOMPONENTTYPE); - return OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQCOMPONENTTYPE); + return OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_IOCOMPONENTTYPE); + return OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_DAQCOMPONENTTYPE); } void TmsServerFolder::createNonhierarchicalReferences() diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp index 301a8e0..1dc04da 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp @@ -2,7 +2,7 @@ #include "opcuatms_server/objects/tms_server_function_block.h" #include "opcuatms/converters/variant_converter.h" #include "open62541/statuscodes.h" -#include "open62541/tmsbsp_nodeids.h" +#include "open62541/daqbsp_nodeids.h" #include "open62541/di_nodeids.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -18,7 +18,7 @@ TmsServerFunctionBlock::TmsServerFunctionBlock(const FunctionBlockPtr& object template OpcUaNodeId TmsServerFunctionBlock::getTmsTypeId() { - return OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_FUNCTIONBLOCKTYPE); + return OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_FUNCTIONBLOCKTYPE); } template diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp index 8ad41f1..db4abe7 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp @@ -2,9 +2,9 @@ #include "opcuatms_server/objects/tms_server_input_port.h" #include "opcuatms/converters/variant_converter.h" #include "open62541/statuscodes.h" -#include "open62541/tmsbsp_nodeids.h" +#include "open62541/daqbsp_nodeids.h" #include "open62541/di_nodeids.h" -#include "open62541/tmsbsp_nodeids.h" +#include "open62541/daqbsp_nodeids.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -17,12 +17,12 @@ TmsServerInputPort::TmsServerInputPort(const InputPortPtr& object, const OpcUaSe OpcUaNodeId TmsServerInputPort::getReferenceType() { - return OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASINPUTPORT); + return OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASINPUTPORT); } OpcUaNodeId TmsServerInputPort::getTmsTypeId() { - return OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_INPUTPORTTYPE); + return OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_INPUTPORTTYPE); } void TmsServerInputPort::bindCallbacks() @@ -94,7 +94,7 @@ void TmsServerInputPort::createNonhierarchicalReferences() { auto connectedSignalNodeId = findSignalNodeId(connectedSignal); if (!connectedSignalNodeId.isNull()) - addReference(connectedSignalNodeId, OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_CONNECTEDTOSIGNAL)); + addReference(connectedSignalNodeId, OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_CONNECTEDTOSIGNAL)); } } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp index 1cb3fb5..7e26335 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp @@ -4,7 +4,7 @@ #include #include "opcuatms/converters/variant_converter.h" #include "open62541/server.h" -#include "open62541/tmsbsp_nodeids.h" +#include "open62541/daqbsp_nodeids.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp index 4b558f2..bac2142 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp @@ -2,10 +2,10 @@ #include #include #include -#include -#include +#include +#include #include "opcuatms/converters/variant_converter.h" -#include "open62541/tmsbsp_nodeids.h" +#include "open62541/daqbsp_nodeids.h" #include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -99,24 +99,24 @@ void TmsServerProperty::bindCallbacks() opcua::OpcUaNodeId TmsServerProperty::getTmsTypeId() { if (objectInternal.getSelectionValuesUnresolved().assigned()) - return OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_SELECTIONVARIABLETYPE); + return OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_SELECTIONVARIABLETYPE); if (objectInternal.getReferencedPropertyUnresolved().assigned()) - return OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_REFERENCEVARIABLETYPE); + return OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_REFERENCEVARIABLETYPE); const auto type = object.getValueType(); switch (type) { case CoreType::ctInt: case CoreType::ctFloat: - return OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_NUMERICVARIABLETYPE); + return OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_NUMERICVARIABLETYPE); case CoreType::ctStruct: - return OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_STRUCTUREVARIABLETYPE); + return OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_STRUCTUREVARIABLETYPE); default: break; } - return OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_INTROSPECTIONVARIABLETYPE); + return OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_INTROSPECTIONVARIABLETYPE); } bool TmsServerProperty::createOptionalNode(const opcua::OpcUaNodeId& nodeId) @@ -169,27 +169,27 @@ void TmsServerProperty::registerEvalValueNode(const std::string& nodeName, TmsSe bool TmsServerProperty::isSelectionType() { - return getTmsTypeId() == OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_SELECTIONVARIABLETYPE); + return getTmsTypeId() == OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_SELECTIONVARIABLETYPE); } bool TmsServerProperty::isNumericType() { - return getTmsTypeId() == OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_NUMERICVARIABLETYPE); + return getTmsTypeId() == OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_NUMERICVARIABLETYPE); } bool TmsServerProperty::isIntrospectionType() { - return getTmsTypeId() == OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_INTROSPECTIONVARIABLETYPE); + return getTmsTypeId() == OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_INTROSPECTIONVARIABLETYPE); } bool TmsServerProperty::isReferenceType() { - return getTmsTypeId() == OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_REFERENCEVARIABLETYPE); + return getTmsTypeId() == OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_REFERENCEVARIABLETYPE); } bool TmsServerProperty::isStructureType() { - return getTmsTypeId() == OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_STRUCTUREVARIABLETYPE); + return getTmsTypeId() == OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_STRUCTUREVARIABLETYPE); } void TmsServerProperty::hideReferenceTypeChildren() diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp index c9fb186..2f742b2 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp @@ -7,8 +7,8 @@ #include "opcuatms_server/objects/tms_server_property.h" #include "open62541/nodeids.h" #include "open62541/statuscodes.h" -#include "open62541/tmsbsp_nodeids.h" -#include "open62541/tmsbt_nodeids.h" +#include "open62541/daqbsp_nodeids.h" +#include "open62541/daqbt_nodeids.h" #include "open62541/types_generated.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -59,7 +59,7 @@ std::string TmsServerPropertyObject::getBrowseName() OpcUaNodeId TmsServerPropertyObject::getTmsTypeId() { - return OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_VARIABLEBLOCKTYPE); + return OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_VARIABLEBLOCKTYPE); } void TmsServerPropertyObject::addChildNodes() diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp index 7353b28..922ece7 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp @@ -1,7 +1,7 @@ #include "opcuatms_server/objects/tms_server_signal.h" #include "opcuatms/converters/variant_converter.h" #include "open62541/statuscodes.h" -#include "open62541/tmsbsp_nodeids.h" +#include "open62541/daqbsp_nodeids.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -14,13 +14,13 @@ TmsServerSignal::TmsServerSignal(const SignalPtr& object, const OpcUaServerPtr& OpcUaNodeId TmsServerSignal::getReferenceType() { - //TODO UA_TMSBSPID_HASSTATUSSIGNAL - return OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASVALUESIGNAL); + //TODO UA_DAQBSPID_HASSTATUSSIGNAL + return OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASVALUESIGNAL); } OpcUaNodeId TmsServerSignal::getTmsTypeId() { - return OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_SIGNALTYPE); + return OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_SIGNALTYPE); } void TmsServerSignal::bindCallbacks() @@ -71,7 +71,7 @@ void TmsServerSignal::createNonhierarchicalReferences() { try { - addReference(domainSignalNodeId, OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASDOMAINSIGNAL)); + addReference(domainSignalNodeId, OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASDOMAINSIGNAL)); } catch (const OpcUaException& ex) { diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h b/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h index 10e7064..5f365a9 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h @@ -20,11 +20,11 @@ #include #include #include -#include +#include #include "opendaq/mock/mock_device_module.h" #include "opendaq/mock/mock_fb_module.h" #include "opendaq/mock/mock_physical_device.h" -#include "open62541/tmsbsp_nodeids.h" +#include "open62541/daqbsp_nodeids.h" namespace test_helpers { @@ -93,28 +93,28 @@ namespace test_helpers const daq::opcua::OpcUaNodeId& nodeId) { using namespace daq::opcua; - return BrowseForChildWithTypeId(client, nodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQDEVICETYPE)); + return BrowseForChildWithTypeId(client, nodeId, OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_DAQDEVICETYPE)); } inline std::vector BrowseFunctionBlocks(const daq::opcua::OpcUaClientPtr& client, const daq::opcua::OpcUaNodeId& nodeId) { using namespace daq::opcua; - return BrowseForChildWithTypeId(client, nodeId, OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_FUNCTIONBLOCKTYPE)); + return BrowseForChildWithTypeId(client, nodeId, OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_FUNCTIONBLOCKTYPE)); } inline std::vector BrowseChannels(const daq::opcua::OpcUaClientPtr& client, const daq::opcua::OpcUaNodeId& nodeId) { using namespace daq::opcua; - return BrowseForChildWithTypeId(client, nodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_CHANNELTYPE)); + return BrowseForChildWithTypeId(client, nodeId, OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_CHANNELTYPE)); } inline std::vector BrowseSignals(const daq::opcua::OpcUaClientPtr& client, const daq::opcua::OpcUaNodeId& nodeId) { using namespace daq::opcua; - return BrowseForChildWithTypeId(client, nodeId, OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_SIGNALTYPE)); + return BrowseForChildWithTypeId(client, nodeId, OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_SIGNALTYPE)); } inline daq::opcua::OpcUaNodeId GetMockPhysicalDevice(const daq::opcua::OpcUaClientPtr& client) diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_channel.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_channel.cpp index 2bfdc2b..d296dfe 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_channel.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_channel.cpp @@ -8,7 +8,7 @@ #include "opcuaclient/opcuaclient.h" #include "opcuatms_server/objects/tms_server_channel.h" #include "tms_object_test.h" -#include "open62541/tmsbsp_nodeids.h" +#include "open62541/daqbsp_nodeids.h" using namespace daq; using namespace opcua::tms; @@ -64,8 +64,8 @@ TEST_F(TmsChannelTest, BrowseSignals) auto nodeId = serverChannel.registerOpcUaNode(); OpcUaServerNode serverNodeFB(*this->getServer(), nodeId); - auto signalServerNode = serverNodeFB.getChildNode(UA_QUALIFIEDNAME_ALLOC(NAMESPACE_TMSBSP, "Sig")); - auto signalReferences = signalServerNode->browse(OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASVALUESIGNAL)); + auto signalServerNode = serverNodeFB.getChildNode(UA_QUALIFIEDNAME_ALLOC(NAMESPACE_DAQBSP, "Sig")); + auto signalReferences = signalServerNode->browse(OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASVALUESIGNAL)); ASSERT_EQ(signalReferences.size(), 10u); } diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_device.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_device.cpp index 27dbd55..8a9644c 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_device.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp index 781a21f..16ec719 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp @@ -7,7 +7,7 @@ #include "opcuaclient/opcuaclient.h" #include "opcuatms_server/objects/tms_server_function_block.h" #include "tms_object_test.h" -#include "open62541/tmsbsp_nodeids.h" +#include "open62541/daqbsp_nodeids.h" #include using namespace daq; @@ -72,8 +72,8 @@ TEST_F(TmsFunctionBlockTest, BrowseSignals) auto nodeId = serverFunctionBlock.registerOpcUaNode(); OpcUaServerNode serverNodeFB(*this->getServer(), nodeId); - auto signalServerNode = serverNodeFB.getChildNode(UA_QUALIFIEDNAME_ALLOC(NAMESPACE_TMSBSP, "Sig")); - auto signalReferences = signalServerNode->browse(OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASVALUESIGNAL)); + auto signalServerNode = serverNodeFB.getChildNode(UA_QUALIFIEDNAME_ALLOC(NAMESPACE_DAQBSP, "Sig")); + auto signalReferences = signalServerNode->browse(OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASVALUESIGNAL)); ASSERT_EQ(signalReferences.size(), 5u); } diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp index 00a5043..9170e0b 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include using namespace daq; @@ -69,7 +69,7 @@ TEST_F(TmsInputPortTest, ConnectedToReference) ASSERT_TRUE(this->getClient()->nodeExists(inputPortNodeId)); OpcUaServerNode inputPortNode(*this->getServer(), inputPortNodeId); - auto connectedToNodes = inputPortNode.browse(OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_CONNECTEDTOSIGNAL)); + auto connectedToNodes = inputPortNode.browse(OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_CONNECTEDTOSIGNAL)); ASSERT_EQ(connectedToNodes.size(), 1u); ASSERT_EQ(connectedToNodes[0]->getNodeId(), signalNodeId); } diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_server.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_server.cpp index 62a3e78..3918e0f 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_server.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_server.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include #include "test_helpers.h" @@ -80,7 +80,7 @@ TEST_F(TmsServerTest, Channels) ReferenceUtils referenceUtils(client); referenceUtils.updateReferences(byteStepSignal); - auto references = referenceUtils.getReferencedNodes(byteStepSignal, OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASDOMAINSIGNAL), true); + auto references = referenceUtils.getReferencedNodes(byteStepSignal, OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASDOMAINSIGNAL), true); ASSERT_EQ(references.size(), 1u); ASSERT_EQ(*references.begin(), timeSignal); } diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_signal.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_signal.cpp index 944160a..68d156f 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_signal.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_signal.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include #include #include @@ -59,7 +59,7 @@ TEST_F(TmsSignalTest, DomainSignalReference) ASSERT_TRUE(this->getClient()->nodeExists(domainSignalNodeId)); OpcUaServerNode signalNode(*this->getServer(), signalNodeId); - auto hasDomainNodes = signalNode.browse(OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASDOMAINSIGNAL)); + auto hasDomainNodes = signalNode.browse(OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASDOMAINSIGNAL)); ASSERT_EQ(hasDomainNodes.size(), 1u); ASSERT_EQ(hasDomainNodes[0]->getNodeId(), domainSignalNodeId); } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_channel.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_channel.cpp index 214c7ff..1241c76 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_channel.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_channel.cpp @@ -9,7 +9,7 @@ #include #include "opcuatms_client/objects/tms_client_input_port_factory.h" #include "opcuatms_client/objects/tms_client_signal_factory.h" -#include "open62541/tmsbsp_nodeids.h" +#include "open62541/daqbsp_nodeids.h" #include "tms_object_integration_test.h" #include "opendaq/mock/mock_channel_factory.h" @@ -135,7 +135,7 @@ TEST_F(TmsChannelTest, MethodGetStatusSignal) auto tmsServerSignal = TmsServerSignal(serverSignal, this->getServer(), NullContext()); auto signalNodeId = tmsServerSignal.registerOpcUaNode(); - OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASSTATUSSIGNAL); + OpcUaNodeId referenceTypeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASSTATUSSIGNAL); getServer()->addReference(channelNodeId, referenceTypeId, signalNodeId, true); ChannelPtr clientChannel = TmsClientChannel(ctx, nullptr, "ch", clientContext, channelNodeId); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp index 547a103..ebf3ff7 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp @@ -14,7 +14,7 @@ #include #include "opcuatms_client/objects/tms_client_input_port_factory.h" #include "opcuatms_client/objects/tms_client_signal_factory.h" -#include "open62541/tmsbsp_nodeids.h" +#include "open62541/daqbsp_nodeids.h" #include "tms_object_integration_test.h" #include "opendaq/folder_config_ptr.h" @@ -160,7 +160,7 @@ TEST_F(TmsFunctionBlockTest, MethodGetStatusSignal) auto tmsServerSignal = TmsServerSignal(serverSignal, this->getServer(), NullContext()); auto signalNodeId = tmsServerSignal.registerOpcUaNode(); - OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASSTATUSSIGNAL); + OpcUaNodeId referenceTypeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASSTATUSSIGNAL); getServer()->addReference(functionBlockNodeId, referenceTypeId, signalNodeId, true); FunctionBlockPtr clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, functionBlockNodeId); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp index 3211944..281df7e 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include using namespace daq; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp index 71abbe1..3157047 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp @@ -7,7 +7,7 @@ #include "opcuatms/exceptions.h" #include "opcuatms_client/objects/tms_client_signal_factory.h" #include "opcuatms_server/objects/tms_server_signal.h" -#include "open62541/tmsbsp_nodeids.h" +#include "open62541/daqbsp_nodeids.h" #include #include #include @@ -226,7 +226,7 @@ TEST_F(TmsSignalTest, AttrDomainSignal) auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), NullContext()); auto nodeId = serverSignal.registerOpcUaNode(); - OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASDOMAINSIGNAL); + OpcUaNodeId referenceTypeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASDOMAINSIGNAL); getServer()->addReference(nodeId, referenceTypeId, domainNodeId); SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); @@ -252,7 +252,7 @@ TEST_F(TmsSignalTest, AttrRelatedSignals) auto serverSignal3 = TmsServerSignal(daqServerSignal3, this->getServer(), NullContext()); auto nodeId3 = serverSignal3.registerOpcUaNode(); - OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_RELATESTOSIGNAL); + OpcUaNodeId referenceTypeId(NAMESPACE_DAQBSP, UA_DAQBSPID_RELATESTOSIGNAL); getServer()->addReference(nodeId2, referenceTypeId, nodeId1); getServer()->addReference(nodeId3, referenceTypeId, nodeId1); getServer()->addReference(nodeId3, referenceTypeId, nodeId2); diff --git a/shared/libraries/opcuatms/tests/test_utils/CMakeLists.txt b/shared/libraries/opcuatms/tests/test_utils/CMakeLists.txt index ce1ae36..e64509b 100644 --- a/shared/libraries/opcuatms/tests/test_utils/CMakeLists.txt +++ b/shared/libraries/opcuatms/tests/test_utils/CMakeLists.txt @@ -17,5 +17,5 @@ target_link_libraries(${MODULE_NAME} PUBLIC daq::test_utils daq::opcuaclient daq::opcuaserver daq::opendaq - daq::opcua_tms_types + daq::opcua_daq_types ) diff --git a/shared/libraries/opcuatms/tests/test_utils/tms_object_test.cpp b/shared/libraries/opcuatms/tests/test_utils/tms_object_test.cpp index 1768782..7cee8fa 100644 --- a/shared/libraries/opcuatms/tests/test_utils/tms_object_test.cpp +++ b/shared/libraries/opcuatms/tests/test_utils/tms_object_test.cpp @@ -1,7 +1,7 @@ #include "tms_object_test.h" #include "opcuaclient/opcuaclient.h" -#include -#include +#include +#include #include using namespace daq::opcua; @@ -92,9 +92,9 @@ daq::opcua::OpcUaClientPtr TmsObjectTest::CreateAndConnectTestClient() { OpcUaEndpoint endpoint("Test", "opc.tcp://127.0.0.1:4840"); endpoint.registerCustomTypes(UA_TYPES_DI_COUNT, UA_TYPES_DI); - endpoint.registerCustomTypes(UA_TYPES_TMSBT_COUNT, UA_TYPES_TMSBT); - endpoint.registerCustomTypes(UA_TYPES_TMSBSP_COUNT, UA_TYPES_TMSBSP); - endpoint.registerCustomTypes(UA_TYPES_TMSDEVICE_COUNT, UA_TYPES_TMSDEVICE); + endpoint.registerCustomTypes(UA_TYPES_DAQBT_COUNT, UA_TYPES_DAQBT); + endpoint.registerCustomTypes(UA_TYPES_DAQBSP_COUNT, UA_TYPES_DAQBSP); + endpoint.registerCustomTypes(UA_TYPES_DAQDEVICE_COUNT, UA_TYPES_DAQDEVICE); auto client = std::make_shared(endpoint); client->connect(); From 273526d2394fb1314079d78bae80915eb64d6c10 Mon Sep 17 00:00:00 2001 From: Martin Kraner Date: Thu, 14 Dec 2023 11:49:39 +0100 Subject: [PATCH 029/217] Fix open62541 CMake configure under aarch64 cross-compiler --- external/open62541/CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/external/open62541/CMakeLists.txt b/external/open62541/CMakeLists.txt index 768cd68..d2f3225 100644 --- a/external/open62541/CMakeLists.txt +++ b/external/open62541/CMakeLists.txt @@ -9,6 +9,10 @@ set(UA_ENABLE_TYPEDESCRIPTION ON CACHE STRING "" FORCE) set(UA_ENABLE_STATUSCODE_DESCRIPTIONS ON CACHE STRING "" FORCE) set(UA_MULTITHREADING 100 CACHE STRING "" FORCE) +if (CMAKE_COMPILER_IS_GNUCXX AND NOT DEFINED CMAKE_INTERPROCEDURAL_OPTIMIZATION) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION OFF) +endif() + set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL YES) opendaq_dependency( @@ -53,10 +57,6 @@ if (open62541_FETCHED) foreach(LIB_TARGET ${LIB_TARGETS}) set_target_properties(${LIB_TARGET} PROPERTIES FOLDER "${CMAKE_FOLDER}/lib") - - if (UNIX) - set_target_properties(${LIB_TARGET} PROPERTIES INTERPROCEDURAL_OPTIMIZATION OFF) - endif() endforeach() if (UA_ENABLE_AMALGAMATION) From 639857901946302f461e83704856bee52b26ebed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Tue, 5 Dec 2023 14:37:39 +0100 Subject: [PATCH 030/217] Add implementation of cached reference browser --- .../opcuaclient/cached_reference_browser.h | 66 +++++++ .../opcua/opcuaclient/src/CMakeLists.txt | 1 + .../src/cached_reference_browser.cpp | 183 ++++++++++++++++++ .../opcua/opcuaclient/tests/CMakeLists.txt | 1 + .../tests/include/opcuaservertesthelper.h | 7 +- .../src/test_cached_reference_browser.cpp | 152 +++++++++++++++ .../objects/tms_client_context.h | 3 + .../src/objects/tms_client_context.cpp | 6 + 8 files changed, 416 insertions(+), 3 deletions(-) create mode 100644 shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h create mode 100644 shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp create mode 100644 shared/libraries/opcua/opcuaclient/tests/src/test_cached_reference_browser.cpp diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h new file mode 100644 index 0000000..19c3c9d --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h @@ -0,0 +1,66 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +class CachedReferenceBrowser; +using CachedReferenceBrowserPtr = std::shared_ptr; + +struct CachedReferences +{ + tsl::ordered_map> byNodeId; + tsl::ordered_map> byBrowseName; +}; + +class CachedReferenceBrowser +{ +public: + CachedReferenceBrowser(const OpcUaClientPtr& client); + + const CachedReferences& browse(const OpcUaNodeId& nodeId, bool forceInvalidate = false); + void invalidate(const OpcUaNodeId& nodeId); + + bool isSubtypeOf(const OpcUaNodeId& typeId, const OpcUaNodeId& baseType); + bool hasReference(const OpcUaNodeId& nodeId, const std::string& browseName); + OpcUaNodeId getChildNodeId(const OpcUaNodeId& nodeId, const std::string& browseName); + std::vector getFilteredChildren(const OpcUaNodeId& nodeId, + const OpcUaNodeId& referenceTypeId, + bool isForward = true, + const OpcUaNodeId& typeDefinition = OpcUaNodeId()); + +private: + bool isCached(const OpcUaNodeId& nodeId); + void markAsCached(const OpcUaNodeId& nodeId); + void browseMultiple(const std::vector& nodes); + void processBrowseResults(const std::vector& nodes, UA_BrowseResult* results, size_t size, std::vector& browseNextOut); + bool getContinuationPoint(UA_BrowseResult* results, UA_ByteString* continuationPointOut); + + OpcUaClientPtr client; + std::unordered_map references; +}; + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/src/CMakeLists.txt b/shared/libraries/opcua/opcuaclient/src/CMakeLists.txt index 296591b..a35e776 100644 --- a/shared/libraries/opcua/opcuaclient/src/CMakeLists.txt +++ b/shared/libraries/opcua/opcuaclient/src/CMakeLists.txt @@ -14,6 +14,7 @@ set(SOURCE_CPPS opcuaclient.cpp reference_utils.cpp request_handler.cpp attribute_reader.cpp + cached_reference_browser.cpp ) set(SOURCE_BROWSER_CPPS browser/opcuanodevisitor.cpp diff --git a/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp b/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp new file mode 100644 index 0000000..341629c --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp @@ -0,0 +1,183 @@ +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +CachedReferenceBrowser::CachedReferenceBrowser(const OpcUaClientPtr& client) + : client(client) +{ +} + +const CachedReferences& CachedReferenceBrowser::browse(const OpcUaNodeId& nodeId, bool forceInvalidate) +{ + if (forceInvalidate) + invalidate(nodeId); + + if (!isCached(nodeId)) + browseMultiple({nodeId}); + + return references[nodeId]; +} + +void CachedReferenceBrowser::invalidate(const OpcUaNodeId& nodeId) +{ + if (!isCached(nodeId)) + return; + + const auto children = references[nodeId].byNodeId; + references.erase(nodeId); + + for (const auto& [refNodeId, ref] : children) + { + if (ref->isForward) + invalidate(refNodeId); + } +} + +bool CachedReferenceBrowser::isSubtypeOf(const OpcUaNodeId& typeId, const OpcUaNodeId& baseType) +{ + if (typeId == baseType) + return true; + + browse(baseType); + + for (const auto& [refNodeId, ref] : references[baseType].byNodeId) + { + if (OpcUaNodeId(ref->referenceTypeId) == OpcUaNodeId(UA_NS0ID_HASSUBTYPE) && isSubtypeOf(typeId, refNodeId)) + return true; + } + + return false; +} + +bool CachedReferenceBrowser::hasReference(const OpcUaNodeId& nodeId, const std::string& browseName) +{ + browse(nodeId); + return references[nodeId].byBrowseName.count(browseName) > 0; +} + +OpcUaNodeId CachedReferenceBrowser::getChildNodeId(const OpcUaNodeId& nodeId, const std::string& browseName) +{ + browse(nodeId); + const auto& node = references[nodeId].byBrowseName[browseName]; + return node->nodeId.nodeId; +} + +std::vector CachedReferenceBrowser::getFilteredChildren(const OpcUaNodeId& nodeId, + const OpcUaNodeId& referenceTypeId, + bool isForward, + const OpcUaNodeId& typeDefinition) +{ + const auto& references = browse(nodeId); + std::vector filtered; + + for (const auto& [refNodeId, ref] : references.byNodeId) + { + auto typeId = OpcUaNodeId(ref->referenceTypeId); + + if (ref->isForward == isForward && typeId == referenceTypeId && + (typeDefinition.isNull() || isSubtypeOf(ref->typeDefinition.nodeId, typeDefinition))) + { + filtered.push_back(refNodeId); + } + } + + return filtered; +} + +bool CachedReferenceBrowser::isCached(const OpcUaNodeId& nodeId) +{ + return references.count(nodeId) > 0; +} + +void CachedReferenceBrowser::markAsCached(const OpcUaNodeId& nodeId) +{ + if (references.count(nodeId) == 0) + references[nodeId] = {}; +} + +void CachedReferenceBrowser::browseMultiple(const std::vector& nodes) +{ + if (nodes.empty()) + return; + + OpcUaObject request; + request->requestedMaxReferencesPerNode = 0; + request->nodesToBrowse = (UA_BrowseDescription*) UA_Array_new(nodes.size(), &UA_TYPES[UA_TYPES_BROWSEDESCRIPTION]); + request->nodesToBrowseSize = nodes.size(); + + for (size_t i = 0; i < nodes.size(); i++) + { + const auto& nodeId = nodes[i]; + markAsCached(nodeId); + + request->nodesToBrowse[i].nodeId = nodeId.copyAndGetDetachedValue(); + request->nodesToBrowse[i].resultMask = UA_BROWSERESULTMASK_ALL; + request->nodesToBrowse[i].browseDirection = UA_BROWSEDIRECTION_FORWARD; + } + + std::vector browseNext; + UA_ByteString* continuationPoint = nullptr; + OpcUaObject response = UA_Client_Service_browse(client->getLockedUaClient(), *request); + CheckStatusCodeException(response->responseHeader.serviceResult, "Browse result error"); + + processBrowseResults(nodes, response->results, response->resultsSize, browseNext); + + while (getContinuationPoint(response->results, continuationPoint)) + { + OpcUaObject nextRequest; + nextRequest->releaseContinuationPoints = UA_FALSE; + nextRequest->continuationPointsSize = 1u; + nextRequest->continuationPoints = continuationPoint; + OpcUaObject nextResponse = UA_Client_Service_browseNext(client->getLockedUaClient(), *nextRequest); + CheckStatusCodeException(response->responseHeader.serviceResult, "Browse result error"); + + processBrowseResults(nodes, nextResponse->results, nextResponse->resultsSize, browseNext); + } + + browseMultiple(browseNext); +} + +void CachedReferenceBrowser::processBrowseResults(const std::vector& nodes, + UA_BrowseResult* results, + size_t size, + std::vector& browseNextOut) +{ + assert(size == nodes.size()); + + for (size_t i = 0; i < size; i++) + { + UA_BrowseResult& result = results[i]; + + if (result.statusCode == UA_STATUSCODE_BADUSERACCESSDENIED) + continue; + if (result.statusCode == UA_STATUSCODE_BADNODEIDUNKNOWN) + continue; + + CheckStatusCodeException(result.statusCode, "Browse result error"); + + const auto nodeId = nodes[i]; + references[nodeId] = {}; + + for (size_t j = 0; j < result.referencesSize; j++) + { + const auto& ref = result.references[j]; + const std::string browseName = utils::ToStdString(ref.browseName.name); + const auto refId = OpcUaNodeId(ref.nodeId.nodeId); + + references[nodeId].byNodeId.insert({refId, ref}); + references[nodeId].byBrowseName.insert({browseName, ref}); + + if (ref.isForward && references.count(refId) == 0) + browseNextOut.push_back(refId); + } + } +} + +bool CachedReferenceBrowser::getContinuationPoint(UA_BrowseResult* results, UA_ByteString* continuationPointOut) +{ + continuationPointOut = &results->continuationPoint; + return results->continuationPoint.length > 0; +} + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/tests/CMakeLists.txt b/shared/libraries/opcua/opcuaclient/tests/CMakeLists.txt index 4ef8c4e..e482615 100644 --- a/shared/libraries/opcua/opcuaclient/tests/CMakeLists.txt +++ b/shared/libraries/opcua/opcuaclient/tests/CMakeLists.txt @@ -10,6 +10,7 @@ set(SRC_Cpp main.cpp test_opcuatimertaskhelper.cpp test_opcuaclient.cpp test_attribute_reader.cpp + test_cached_reference_browser.cpp ) set(SRC_Include opcuaservertesthelper.h diff --git a/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h b/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h index aeebe0a..d02a8e1 100644 --- a/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h +++ b/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h @@ -44,9 +44,6 @@ class OpcUaServerTestHelper final std::string getServerUrl() const; -private: - void runServer(); - void createModel(); void publishVariable(std::string identifier, const void* value, const UA_DataType* type, @@ -54,6 +51,10 @@ class OpcUaServerTestHelper final const char* locale = "en_US", int nodeIndex = 1, size_t dimension = 1); + +private: + void runServer(); + void createModel(); void publishFolder(const char* identifier, UA_NodeId* parentNodeId, const char* locale = "en_US", int nodeIndex = 1); void publishMethod(std::string identifier, UA_NodeId* parentNodeId, const char* locale = "en_US", int nodeIndex = 1); static UA_StatusCode helloMethodCallback(UA_Server* server, diff --git a/shared/libraries/opcua/opcuaclient/tests/src/test_cached_reference_browser.cpp b/shared/libraries/opcua/opcuaclient/tests/src/test_cached_reference_browser.cpp new file mode 100644 index 0000000..236d480 --- /dev/null +++ b/shared/libraries/opcua/opcuaclient/tests/src/test_cached_reference_browser.cpp @@ -0,0 +1,152 @@ +#include "testutils/testutils.h" +#include "opcuaclient/opcuaclient.h" +#include "opcuaservertesthelper.h" +#include "opcuashared/opcua.h" +#include "opcuashared/opcuacommon.h" +#include "opcuaclient/cached_reference_browser.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA + +using CachedReferenceBrowserTest = BaseClientTest; + +TEST_F(CachedReferenceBrowserTest, ObjectsFolder) +{ + auto client = std::make_shared(getServerUrl()); + client->connect(); + + auto nodeId = OpcUaNodeId(UA_NS0ID_OBJECTSFOLDER); + + auto browser = CachedReferenceBrowser(client); + ASSERT_NO_THROW(browser.browse(nodeId)); + + auto references = browser.browse(nodeId); + ASSERT_GT(references.byNodeId.size(), 0u); + + ASSERT_NO_THROW(browser.invalidate(nodeId)); +} + +TEST_F(CachedReferenceBrowserTest, ServerStatus) +{ + auto client = std::make_shared(getServerUrl()); + client->connect(); + + auto nodeId = OpcUaNodeId(UA_NS0ID_SERVER_SERVERSTATUS); + + auto browser = CachedReferenceBrowser(client); + auto serverStatusRefs = browser.browse(OpcUaNodeId(UA_NS0ID_SERVER_SERVERSTATUS)); + + ASSERT_EQ(serverStatusRefs.byBrowseName.size(), 7u); + ASSERT_EQ(serverStatusRefs.byNodeId.size(), serverStatusRefs.byBrowseName.size()); + + auto begin = serverStatusRefs.byBrowseName.begin(); + ASSERT_EQ("ServerStatusType", (begin + 0).key()); + ASSERT_EQ("ShutdownReason", (begin + 1).key()); + ASSERT_EQ("SecondsTillShutdown", (begin + 2).key()); + ASSERT_EQ("BuildInfo", (begin + 3).key()); + ASSERT_EQ("State", (begin + 4).key()); + ASSERT_EQ("CurrentTime", (begin + 5).key()); + ASSERT_EQ("StartTime", (begin + 6).key()); + + auto buildInfoRefs = browser.browse(OpcUaNodeId(UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO)); + ASSERT_EQ(buildInfoRefs.byBrowseName.size(), 7u); + + begin = buildInfoRefs.byBrowseName.begin(); + ASSERT_EQ("BuildInfoType", (begin + 0).key()); + ASSERT_EQ("BuildDate", (begin + 1).key()); + ASSERT_EQ("BuildNumber", (begin + 2).key()); + ASSERT_EQ("SoftwareVersion", (begin + 3).key()); + ASSERT_EQ("ManufacturerName", (begin + 4).key()); + ASSERT_EQ("ProductUri", (begin + 5).key()); + ASSERT_EQ("ProductName", (begin + 6).key()); + + auto buildDateRefs = browser.browse(OpcUaNodeId(UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDDATE)); + ASSERT_EQ(buildDateRefs.byBrowseName.size(), 1u); + + begin = buildDateRefs.byBrowseName.begin(); + ASSERT_EQ("BaseDataVariableType", (begin + 0).key()); +} + +TEST_F(CachedReferenceBrowserTest, Invalidate) +{ + auto client = std::make_shared(getServerUrl()); + client->connect(); + + auto nodeObjectsFolder = OpcUaNodeId(UA_NS0ID_OBJECTSFOLDER); + auto browser = CachedReferenceBrowser(client); + auto references = browser.browse(nodeObjectsFolder); + + ASSERT_GT(references.byNodeId.size(), 0u); + + UA_Double doubleVal = 10.5; + testHelper.publishVariable(".anotherVar", &doubleVal, &UA_TYPES[UA_TYPES_DOUBLE], nodeObjectsFolder.getPtr()); + + auto referencesFromCache = browser.browse(nodeObjectsFolder); + ASSERT_EQ(references.byNodeId.size(), referencesFromCache.byNodeId.size()); + + browser.invalidate(nodeObjectsFolder); + + auto referencesAfterInvalidate = browser.browse(nodeObjectsFolder); + ASSERT_EQ(references.byNodeId.size() + 1, referencesAfterInvalidate.byNodeId.size()); +} + +TEST_F(CachedReferenceBrowserTest, IsSubtypeOf) +{ + auto client = std::make_shared(getServerUrl()); + client->connect(); + + const auto shelvedStateMachineType = OpcUaNodeId(UA_NS0ID_SHELVEDSTATEMACHINETYPE); + const auto finiteStateMachineType = OpcUaNodeId(UA_NS0ID_FINITESTATEMACHINETYPE); + const auto stateMachineType = OpcUaNodeId(UA_NS0ID_STATEMACHINETYPE); + const auto serverType = OpcUaNodeId(UA_NS0ID_SERVERTYPE); + + auto browser = CachedReferenceBrowser(client); + + ASSERT_TRUE(browser.isSubtypeOf(shelvedStateMachineType, stateMachineType)); + ASSERT_TRUE(browser.isSubtypeOf(finiteStateMachineType, stateMachineType)); + ASSERT_TRUE(browser.isSubtypeOf(finiteStateMachineType, finiteStateMachineType)); + ASSERT_FALSE(browser.isSubtypeOf(shelvedStateMachineType, serverType)); +} + +TEST_F(CachedReferenceBrowserTest, HasReference) +{ + auto client = std::make_shared(getServerUrl()); + client->connect(); + + const auto nodeObjectsFolder = OpcUaNodeId(UA_NS0ID_OBJECTSFOLDER); + auto browser = CachedReferenceBrowser(client); + + ASSERT_TRUE(browser.hasReference(nodeObjectsFolder, ".b")); + ASSERT_TRUE(browser.hasReference(nodeObjectsFolder, ".ui16")); + ASSERT_FALSE(browser.hasReference(nodeObjectsFolder, "MissingNode")); +} + +TEST_F(CachedReferenceBrowserTest, GetChildNodeId) +{ + auto client = std::make_shared(getServerUrl()); + client->connect(); + + const auto nodeObjectsFolder = OpcUaNodeId(UA_NS0ID_OBJECTSFOLDER); + auto browser = CachedReferenceBrowser(client); + + ASSERT_EQ(browser.getChildNodeId(nodeObjectsFolder, ".b"), OpcUaNodeId(1, ".b")); + ASSERT_EQ(browser.getChildNodeId(nodeObjectsFolder, ".ui16"), OpcUaNodeId(1, ".ui16")); + ASSERT_EQ(browser.getChildNodeId(nodeObjectsFolder, "Server"), OpcUaNodeId(UA_NS0ID_SERVER)); +} + +TEST_F(CachedReferenceBrowserTest, FilterChildren) +{ + auto client = std::make_shared(getServerUrl()); + client->connect(); + + const auto nodeObjectsFolder = OpcUaNodeId(UA_NS0ID_SERVER); + auto browser = CachedReferenceBrowser(client); + + const auto nodeId = OpcUaNodeId(UA_NS0ID_SERVER); + const auto refTypeId = OpcUaNodeId(UA_NS0ID_HASPROPERTY); + + auto children = browser.getFilteredChildren(nodeId, refTypeId); + ASSERT_EQ(children.size(), 4u); +} + + +END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h index 5cbc0ed..d1ac7c0 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h @@ -18,6 +18,7 @@ #include "opcuatms/opcuatms.h" #include "opcuaclient/opcuaclient.h" #include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -35,6 +36,7 @@ class TmsClientContext void unregisterObject(const opcua::OpcUaNodeId& nodeId); BaseObjectPtr getObject(const opcua::OpcUaNodeId& nodeId) const; opcua::OpcUaNodeId getNodeId(const BaseObjectPtr object) const; + CachedReferenceBrowserPtr getReferenceBrowser(); template ::SmartPtr> Ptr getObject(const opcua::OpcUaNodeId& nodeId) @@ -53,6 +55,7 @@ class TmsClientContext protected: opcua::OpcUaClientPtr client; + CachedReferenceBrowserPtr referenceBrowser; mutable std::mutex mutex; // Context should not hold objects because of cycling reference diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp index c51f2e5..fe325b1 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp @@ -6,6 +6,7 @@ using namespace opcua; TmsClientContext::TmsClientContext(const OpcUaClientPtr& client) : client(client) + , referenceBrowser(std::make_shared(client)) { } @@ -48,4 +49,9 @@ opcua::OpcUaNodeId TmsClientContext::getNodeId(const BaseObjectPtr object) const return opcua::OpcUaNodeId(); } +CachedReferenceBrowserPtr TmsClientContext::getReferenceBrowser() +{ + return referenceBrowser; +} + END_NAMESPACE_OPENDAQ_OPCUA_TMS From 303fe52eebff23d09f94345d6d592369fa4d1c6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Thu, 7 Dec 2023 10:13:06 +0100 Subject: [PATCH 031/217] Replace ReferenceUtils with CachedReferenceBrowser --- .../opcuaclient/cached_reference_browser.h | 12 +- .../include/opcuaclient/reference_utils.h | 60 --------- .../opcua/opcuaclient/src/CMakeLists.txt | 2 - .../src/cached_reference_browser.cpp | 25 ++-- .../opcua/opcuaclient/src/reference_utils.cpp | 124 ------------------ .../src/test_cached_reference_browser.cpp | 12 +- .../objects/tms_client_function_block_impl.h | 6 +- .../objects/tms_client_object_impl.h | 16 +-- .../objects/tms_client_property_object_impl.h | 11 +- .../src/objects/tms_client_device_impl.cpp | 63 +++++---- .../src/objects/tms_client_folder_impl.cpp | 14 +- .../tms_client_function_block_impl.cpp | 75 ++++++----- .../objects/tms_client_input_port_impl.cpp | 13 +- .../src/objects/tms_client_io_folder_impl.cpp | 14 +- .../src/objects/tms_client_object_impl.cpp | 45 ++----- .../src/objects/tms_client_property_impl.cpp | 17 ++- .../tms_client_property_object_impl.cpp | 90 ++++++------- .../src/objects/tms_client_signal_impl.cpp | 33 +++-- .../opcuatms_client/src/tms_client.cpp | 29 ++-- .../opcuatms_server/tests/test_tms_server.cpp | 16 ++- 20 files changed, 244 insertions(+), 433 deletions(-) delete mode 100644 shared/libraries/opcua/opcuaclient/include/opcuaclient/reference_utils.h delete mode 100644 shared/libraries/opcua/opcuaclient/src/reference_utils.cpp diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h index 19c3c9d..56920c5 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h @@ -36,6 +36,13 @@ struct CachedReferences tsl::ordered_map> byBrowseName; }; +struct BrowseFilter +{ + OpcUaNodeId referenceTypeId = OpcUaNodeId(); + OpcUaNodeId typeDefinition = OpcUaNodeId(); + UA_BrowseDirection direction = UA_BROWSEDIRECTION_BOTH; +}; + class CachedReferenceBrowser { public: @@ -47,10 +54,7 @@ class CachedReferenceBrowser bool isSubtypeOf(const OpcUaNodeId& typeId, const OpcUaNodeId& baseType); bool hasReference(const OpcUaNodeId& nodeId, const std::string& browseName); OpcUaNodeId getChildNodeId(const OpcUaNodeId& nodeId, const std::string& browseName); - std::vector getFilteredChildren(const OpcUaNodeId& nodeId, - const OpcUaNodeId& referenceTypeId, - bool isForward = true, - const OpcUaNodeId& typeDefinition = OpcUaNodeId()); + CachedReferences browseFiltered(const OpcUaNodeId& nodeId, const BrowseFilter& filter); private: bool isCached(const OpcUaNodeId& nodeId); diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/reference_utils.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/reference_utils.h deleted file mode 100644 index 73a7c27..0000000 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/reference_utils.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2022-2023 Blueberry d.o.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once -#include -#include -#include -#include - -BEGIN_NAMESPACE_OPENDAQ_OPCUA - -class ReferenceUtils; -using ReferenceUtilsPtr = std::shared_ptr; - -class ReferenceUtils -{ -public: - using ReferenceMap = tsl::ordered_map>; - - explicit ReferenceUtils(const OpcUaClientPtr& client); - - void updateReferences(const OpcUaNodeId& nodeId); - const ReferenceMap& getReferences(const OpcUaNodeId& nodeId); - tsl::ordered_set getReferencedNodes(const OpcUaNodeId& nodeId, - const OpcUaNodeId& referenceTypeId, - bool isForward, - const OpcUaNodeId& typeDefinition = OpcUaNodeId()); - bool hasReference(const OpcUaNodeId& nodeId, const std::string& browseName); - bool isInstanceOf(const OpcUaNodeId& typeInQuestion, const OpcUaNodeId& baseType); - tsl::ordered_set getVariableNodes(const OpcUaNodeId& nodeId); - OpcUaNodeId getChildNodeId(const OpcUaNodeId& nodeId, const std::string& browseName); - std::string getBrowseName(const OpcUaObject& reference); - void clearCache(); - -protected: - using BrowseNameMap = std::unordered_map; - - void browseNodeReferences(const OpcUaNodeId& nodeId); - void buildBrowseNameMap(const OpcUaNodeId& nodeId); - bool isHasSubType(const OpcUaObject& reference); - - OpcUaClientPtr client; - std::unordered_map referenceCache; - std::unordered_map browseNameCache; -}; - -END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/src/CMakeLists.txt b/shared/libraries/opcua/opcuaclient/src/CMakeLists.txt index a35e776..f0dca5f 100644 --- a/shared/libraries/opcua/opcuaclient/src/CMakeLists.txt +++ b/shared/libraries/opcua/opcuaclient/src/CMakeLists.txt @@ -11,7 +11,6 @@ set(SOURCE_CPPS opcuaclient.cpp monitored_item_create_request.cpp event_filter.cpp browse_request.cpp - reference_utils.cpp request_handler.cpp attribute_reader.cpp cached_reference_browser.cpp @@ -34,7 +33,6 @@ set(SOURCE_HEADERS opcuaclient.h monitored_item_create_request.h event_filter.h browse_request.h - reference_utils.h request_handler.h attribute_reader.h ) diff --git a/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp b/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp index 341629c..a34f4a0 100644 --- a/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp +++ b/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp @@ -63,23 +63,26 @@ OpcUaNodeId CachedReferenceBrowser::getChildNodeId(const OpcUaNodeId& nodeId, co return node->nodeId.nodeId; } -std::vector CachedReferenceBrowser::getFilteredChildren(const OpcUaNodeId& nodeId, - const OpcUaNodeId& referenceTypeId, - bool isForward, - const OpcUaNodeId& typeDefinition) +CachedReferences CachedReferenceBrowser::browseFiltered(const OpcUaNodeId& nodeId, const BrowseFilter& filter) { const auto& references = browse(nodeId); - std::vector filtered; + CachedReferences filtered; - for (const auto& [refNodeId, ref] : references.byNodeId) + for (const auto& [browseName, ref] : references.byBrowseName) { auto typeId = OpcUaNodeId(ref->referenceTypeId); - if (ref->isForward == isForward && typeId == referenceTypeId && - (typeDefinition.isNull() || isSubtypeOf(ref->typeDefinition.nodeId, typeDefinition))) - { - filtered.push_back(refNodeId); - } + if (!filter.referenceTypeId.isNull() && filter.referenceTypeId != typeId) + continue; + if (!filter.typeDefinition.isNull() && !isSubtypeOf(ref->typeDefinition.nodeId, filter.typeDefinition)) + continue; + if (filter.direction == UA_BROWSEDIRECTION_FORWARD && !ref->isForward) + continue; + if (filter.direction == UA_BROWSEDIRECTION_INVERSE && ref->isForward) + continue; + + filtered.byNodeId.insert({ref->nodeId.nodeId, ref}); + filtered.byBrowseName.insert({browseName, ref}); } return filtered; diff --git a/shared/libraries/opcua/opcuaclient/src/reference_utils.cpp b/shared/libraries/opcua/opcuaclient/src/reference_utils.cpp deleted file mode 100644 index c688e5d..0000000 --- a/shared/libraries/opcua/opcuaclient/src/reference_utils.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include "opcuaclient/reference_utils.h" -#include "opcuaclient/browser/opcuabrowser.h" -#include - -BEGIN_NAMESPACE_OPENDAQ_OPCUA - -ReferenceUtils::ReferenceUtils(const OpcUaClientPtr& client) - : client(client) -{ -} - -const ReferenceUtils::ReferenceMap& ReferenceUtils::getReferences(const OpcUaNodeId& nodeId) -{ - browseNodeReferences(nodeId); - return referenceCache[nodeId]; -} - -tsl::ordered_set ReferenceUtils::getReferencedNodes(const OpcUaNodeId& nodeId, - const OpcUaNodeId& referenceTypeId, - bool isForward, - const OpcUaNodeId& typeDefinition) -{ - browseNodeReferences(nodeId); - tsl::ordered_set nodeIds; - const auto& references = referenceCache[nodeId]; - for (const auto& [refNodeId, ref] : references) - { - auto refId = OpcUaNodeId(ref->referenceTypeId); - if (ref->isForward == isForward && refId == referenceTypeId && - (typeDefinition.isNull() || isInstanceOf(ref->typeDefinition.nodeId, typeDefinition))) - nodeIds.insert(OpcUaNodeId(ref->nodeId.nodeId)); - } - return nodeIds; -} - -bool ReferenceUtils::hasReference(const OpcUaNodeId& nodeId, const std::string& browseName) -{ - browseNodeReferences(nodeId); - return browseNameCache[nodeId].count(browseName) > 0; -} - -bool ReferenceUtils::isInstanceOf(const OpcUaNodeId& typeInQuestion, const OpcUaNodeId& baseType) -{ - if (typeInQuestion == baseType) - return true; - - browseNodeReferences(baseType); - if (referenceCache[baseType].count(typeInQuestion) > 0) - { - const auto& ref = referenceCache[baseType][typeInQuestion]; - return isHasSubType(ref); - } - - return false; -} - -tsl::ordered_set ReferenceUtils::getVariableNodes(const OpcUaNodeId& nodeId) -{ - browseNodeReferences(nodeId); - tsl::ordered_set variableNodes; - - const auto& references = referenceCache[nodeId]; - for (const auto& [refNodeId, ref] : references) - { - if (ref->nodeClass == UA_NODECLASS_VARIABLE) - variableNodes.insert(refNodeId); - } - - return variableNodes; -} - -OpcUaNodeId ReferenceUtils::getChildNodeId(const OpcUaNodeId& nodeId, const std::string& browseName) -{ - browseNodeReferences(nodeId); - return browseNameCache[nodeId][browseName]; -} - -void ReferenceUtils::clearCache() -{ - referenceCache.clear(); - browseNameCache.clear(); -} - -void ReferenceUtils::updateReferences(const OpcUaNodeId& nodeId) -{ - auto browser = OpcUaBrowser(nodeId, client); - auto references = browser.browse(); - referenceCache[nodeId] = browser.referencesByNodeId(); - buildBrowseNameMap(nodeId); -} - -void ReferenceUtils::browseNodeReferences(const OpcUaNodeId& nodeId) -{ - if (referenceCache.count(nodeId) > 0) - return; - - updateReferences(nodeId); -} - -void ReferenceUtils::buildBrowseNameMap(const OpcUaNodeId& nodeId) -{ - const auto& referenceMap = referenceCache[nodeId]; - BrowseNameMap browseNameMap; - - for (const auto& [refNodeId, ref] : referenceMap) - { - const auto browseName = getBrowseName(ref); - browseNameMap.insert({browseName, refNodeId}); - } - - browseNameCache.insert({nodeId, browseNameMap}); -} - -std::string ReferenceUtils::getBrowseName(const OpcUaObject& reference) -{ - return utils::ToStdString(reference->browseName.name); -} - -bool ReferenceUtils::isHasSubType(const OpcUaObject& reference) -{ - return OpcUaNodeId(reference->referenceTypeId) == OpcUaNodeId(UA_NS0ID_HASSUBTYPE); -} - -END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/tests/src/test_cached_reference_browser.cpp b/shared/libraries/opcua/opcuaclient/tests/src/test_cached_reference_browser.cpp index 236d480..61185de 100644 --- a/shared/libraries/opcua/opcuaclient/tests/src/test_cached_reference_browser.cpp +++ b/shared/libraries/opcua/opcuaclient/tests/src/test_cached_reference_browser.cpp @@ -133,19 +133,21 @@ TEST_F(CachedReferenceBrowserTest, GetChildNodeId) ASSERT_EQ(browser.getChildNodeId(nodeObjectsFolder, "Server"), OpcUaNodeId(UA_NS0ID_SERVER)); } -TEST_F(CachedReferenceBrowserTest, FilterChildren) +TEST_F(CachedReferenceBrowserTest, BrowseFiltered) { auto client = std::make_shared(getServerUrl()); client->connect(); - const auto nodeObjectsFolder = OpcUaNodeId(UA_NS0ID_SERVER); auto browser = CachedReferenceBrowser(client); const auto nodeId = OpcUaNodeId(UA_NS0ID_SERVER); - const auto refTypeId = OpcUaNodeId(UA_NS0ID_HASPROPERTY); - auto children = browser.getFilteredChildren(nodeId, refTypeId); - ASSERT_EQ(children.size(), 4u); + BrowseFilter filter; + filter.referenceTypeId = OpcUaNodeId(UA_NS0ID_HASPROPERTY); + filter.direction = UA_BROWSEDIRECTION_FORWARD; + + const auto& children = browser.browseFiltered(nodeId, filter); + ASSERT_EQ(children.byNodeId.size(), 4u); } diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h index d3df713..45f80ce 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h @@ -42,9 +42,9 @@ class TmsClientFunctionBlockBaseImpl : public TmsClientComponentBaseImpl void findAndCreateSignals(); void findAndCreateInputPorts(); void readFbType(); - tsl::ordered_set getFunctionBlockNodeIds(); - tsl::ordered_set getOutputSignalNodeIds(); - tsl::ordered_set getInputPortNodeIds(); + CachedReferences getFunctionBlockReferences(); + CachedReferences getOutputSignalReferences(); + CachedReferences getInputPortBlockReferences(); }; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h index 79f0eaf..010512d 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h @@ -19,7 +19,6 @@ #include "opcuaclient/opcuaclient.h" #include "opcuatms/converters/variant_converter.h" #include "opcuatms/opcuatms.h" -#include "opcuaclient/reference_utils.h" #include #include @@ -43,19 +42,7 @@ class TmsClientObjectImpl virtual void subscriptionStatusChangeCallback(UA_StatusChangeNotification* notification); uint32_t tryReadChildNumberInList(const std::string& nodeName); uint32_t tryReadChildNumberInList(const opcua::OpcUaNodeId& nodeId); - - /*! - * @brief Returns child nodes of a specific type. By default it returns also the nodes which are a - * a subtype of the specific type. It can be disabled. - * @param client The opc-ua client - * @param nodeId The root nodeId - * @param typeId The type of child nodes to return - * @param subTypeEnabled Allows also that nodes of the sub types of the request type are returned. - */ - std::vector getChildNodes(const opcua::OpcUaClientPtr& client, - const opcua::OpcUaNodeId& nodeId, - const opcua::OpcUaNodeId& typeId, - const bool subTypeEnabled = true); + CachedReferences getChildReferencesOfType(const opcua::OpcUaNodeId& nodeId, const opcua::OpcUaNodeId& typeId); opcua::MonitoredItem* monitoredItemsCreateEvent( const opcua::EventMonitoredItemCreateRequest& item, @@ -89,7 +76,6 @@ class TmsClientObjectImpl opcua::OpcUaClientPtr client; opcua::OpcUaNodeId nodeId; - opcua::ReferenceUtils referenceUtils; ContextPtr daqContext; private: diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h index f518147..1d47871 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h @@ -19,7 +19,6 @@ #include "opcuaclient/opcuaclient.h" #include "opcuatms/opcuatms.h" #include "opcuatms_client/objects/tms_client_object_impl.h" -#include "opcuaclient/reference_utils.h" #include "opendaq/channel_impl.h" #include "opendaq/streaming_info_impl.h" @@ -48,7 +47,6 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl TmsClientPropertyObjectBaseImpl(const ContextPtr& daqContext, const TmsClientContextPtr& clientContext, const opcua::OpcUaNodeId& nodeId) : TmsClientObjectImpl(daqContext, clientContext, nodeId) , Impl() - , referenceUtils(client) { browseRawProperties(); } @@ -60,7 +58,6 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl const opcua::OpcUaNodeId& nodeId) : TmsClientObjectImpl(daqContext, clientContext, nodeId) , Impl(protocolId) - , referenceUtils(client) { browseRawProperties(); } @@ -73,7 +70,6 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl const opcua::OpcUaNodeId& nodeId) : TmsClientObjectImpl(ctx, clientContext, nodeId) , Impl(ctx, parent, localId, nullptr, ComponentStandardProps::Skip) - , referenceUtils(client) { browseRawProperties(); } @@ -87,7 +83,6 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl const FunctionBlockTypePtr& type) : TmsClientObjectImpl(ctx, clientContext, nodeId) , Impl(type, ctx, parent, localId, nullptr, ComponentStandardProps::Skip) - , referenceUtils(client) { browseRawProperties(); } @@ -108,17 +103,15 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl ErrCode INTERFACE_FUNC setPropertyOrder(IList* orderedPropertyNames) override; protected: - opcua::ReferenceUtils referenceUtils; std::unordered_map introspectionVariableIdMap; std::unordered_map referenceVariableIdMap; std::unordered_map objectTypeIdMap; opcua::OpcUaNodeId methodParentNodeId; - void addProperties(const tsl::ordered_map>& references, + void addProperties(const OpcUaNodeId& parentId, std::map& orderedProperties, std::vector& unorderedProperties); - void addMethodProperties(const tsl::ordered_map>& references, - const opcua::OpcUaNodeId& parentNodeId, + void addMethodProperties(const opcua::OpcUaNodeId& parentNodeId, std::map& orderedProperties, std::vector& unorderedProperties, std::unordered_map& functionPropValues); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 937e345..fbcee7b 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -82,10 +82,11 @@ void TmsClientDeviceImpl::findAndCreateSubdevices() std::map orderedDevices; std::vector unorderedDevices; - auto subdeviceNodeIds = this->getChildNodes(client, nodeId, OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_DAQDEVICETYPE)); - for (const auto& subdeviceNodeId : subdeviceNodeIds) + const auto& references = getChildReferencesOfType(nodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQDEVICETYPE)); + + for (const auto& [browseName, ref] : references.byBrowseName) { - auto browseName = client->readBrowseName(subdeviceNodeId); + auto subdeviceNodeId = OpcUaNodeId(ref->nodeId.nodeId); auto clientSubdevice = TmsClientDevice(context, devices, browseName, clientContext, subdeviceNodeId, createStreamingCallback); auto numberInList = this->tryReadChildNumberInList(subdeviceNodeId); @@ -226,11 +227,12 @@ void TmsClientDeviceImpl::findAndCreateFunctionBlocks() std::vector unorderedFunctionBlocks; auto functionBlocksNodeId = getNodeId("FB"); - auto functionBlockNodeIds = - this->getChildNodes(client, functionBlocksNodeId, OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_FUNCTIONBLOCKTYPE)); - for (const auto& functionBlockNodeId : functionBlockNodeIds) + const auto& references = getChildReferencesOfType(functionBlocksNodeId, OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_FUNCTIONBLOCKTYPE)); + + for (const auto& [browseName, ref] : references.byBrowseName) { - auto browseName = this->client->readBrowseName(functionBlockNodeId); + const auto functionBlockNodeId = OpcUaNodeId(ref->nodeId.nodeId); + try { auto clientFunctionBlock = TmsClientFunctionBlock(context, this->functionBlocks, browseName, clientContext, functionBlockNodeId); @@ -258,8 +260,9 @@ void TmsClientDeviceImpl::findAndCreateSignals() std::vector unorderedSignals; const auto signalsNodeId = getNodeId("Sig"); - const auto signalNodeIds = this->getChildNodes(client, signalsNodeId, OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_SIGNALTYPE)); - for (const auto& signalNodeId : signalNodeIds) + const auto& references = getChildReferencesOfType(signalsNodeId, OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_SIGNALTYPE)); + + for (const auto& [signalNodeId, ref] : references.byNodeId) { auto clientSignal = FindOrCreateTmsClientSignal(context, signals, clientContext, signalNodeId); const auto numberInList = this->tryReadChildNumberInList(signalNodeId); @@ -282,11 +285,11 @@ void TmsClientDeviceImpl::findAndCreateInputsOutputs() this->ioFolder.clear(); auto inputsOutputsNodeId = getNodeId("IO"); + const auto& channelreferences = getChildReferencesOfType(inputsOutputsNodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_CHANNELTYPE)); - auto channelNodeIds = this->getChildNodes(client, inputsOutputsNodeId, OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_CHANNELTYPE)); - for (const auto& channelNodeId : channelNodeIds) + for (const auto& [browseName, ref] : channelreferences.byBrowseName) { - auto browseName = client->readBrowseName(channelNodeId); + const auto channelNodeId = OpcUaNodeId(ref->nodeId.nodeId); auto tmsClientChannel = TmsClientChannel(context, this->ioFolder, browseName, clientContext, channelNodeId); auto numberInList = this->tryReadChildNumberInList(channelNodeId); @@ -296,10 +299,11 @@ void TmsClientDeviceImpl::findAndCreateInputsOutputs() unorderedComponents.emplace_back(tmsClientChannel); } - auto folderNodeIds = this->getChildNodes(client, inputsOutputsNodeId, OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_IOCOMPONENTTYPE)); - for (const auto& folderNodeId : folderNodeIds) + const auto& folderReferences = getChildReferencesOfType(inputsOutputsNodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_IOCOMPONENTTYPE)); + + for (const auto& [browseName, ref] : folderReferences.byBrowseName) { - auto browseName = client->readBrowseName(folderNodeId); + const auto folderNodeId = OpcUaNodeId(ref->nodeId.nodeId); auto tmsClientFolder = TmsClientIoFolder(context, this->ioFolder, browseName, clientContext, folderNodeId); auto numberInList = this->tryReadChildNumberInList(folderNodeId); @@ -322,16 +326,18 @@ void TmsClientDeviceImpl::findAndCreateStreamingOptions() this->streamingOptions.clear(); auto streamingOptionsNodeId = getNodeId("StreamingOptions"); + try { - auto streamingOptionNodeIds = - this->getChildNodes(client, streamingOptionsNodeId, OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_VARIABLEBLOCKTYPE)); - for (const auto& streamingOptionNodeId : streamingOptionNodeIds) + const auto& streamingOptionsReferences = + getChildReferencesOfType(streamingOptionsNodeId, OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_VARIABLEBLOCKTYPE)); + + for (const auto& [browseName, ref] : streamingOptionsReferences.byBrowseName) { - auto browseName = client->readBrowseName(streamingOptionNodeId); - auto clientStreamingInfo = TmsClientStreamingInfo(daqContext, browseName, clientContext, streamingOptionNodeId); + const auto optionNodeId = OpcUaNodeId(ref->nodeId.nodeId); + auto clientStreamingInfo = TmsClientStreamingInfo(daqContext, browseName, clientContext, optionNodeId); - auto numberInList = this->tryReadChildNumberInList(streamingOptionNodeId); + auto numberInList = this->tryReadChildNumberInList(optionNodeId); if (numberInList != std::numeric_limits::max()) orderedStreamings.insert(std::pair(numberInList, clientStreamingInfo)); else @@ -354,17 +360,20 @@ void TmsClientDeviceImpl::findAndCreateCustomComponents() std::map orderedComponents; std::vector unorderedComponents; - auto componentId = OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_DAQCOMPONENTTYPE); - auto folderNodeIds = this->getChildNodes(client, nodeId, componentId); - for (const auto& folderNodeId : folderNodeIds) + auto componentId = OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQCOMPONENTTYPE); + const auto& folderReferences = getChildReferencesOfType(nodeId, componentId); + + for (const auto& [browseName, ref] : folderReferences.byBrowseName) { - auto browseName = client->readBrowseName(folderNodeId); + const auto folderNodeId = OpcUaNodeId(ref->nodeId.nodeId); + if (detail::defaultComponents.count(browseName)) continue; - auto childComponents = this->getChildNodes(client, folderNodeId, componentId); + const auto& componentReferences = getChildReferencesOfType(folderNodeId, componentId); + ComponentPtr child; - if (childComponents.size()) + if (!componentReferences.byNodeId.empty()) child = TmsClientFolder(context, this->thisPtr(), browseName, clientContext, folderNodeId); else child = TmsClientComponent(context, this->thisPtr(), browseName, clientContext, folderNodeId); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp index c677ac3..bf298cc 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp @@ -32,16 +32,18 @@ TmsClientFolderImpl::TmsClientFolderImpl(const ContextPtr& ctx, template void TmsClientFolderImpl::findAndCreateFolders(std::map& orderedComponents, std::vector& unorderedComponents) { - auto componentId = OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_DAQCOMPONENTTYPE); - auto folderNodeIds = this->getChildNodes(this->client, this->nodeId, componentId); - for (const auto& folderNodeId : folderNodeIds) + auto componentId = OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQCOMPONENTTYPE); + const auto& folderReferences = this->getChildReferencesOfType(this->nodeId, componentId); + + for (const auto& [browseName, ref] : folderReferences.byBrowseName) { - auto browseName = this->client->readBrowseName(folderNodeId); + const auto folderNodeId = OpcUaNodeId(ref->nodeId.nodeId); auto thisPtr = this->template borrowPtr(); - auto childComponents = this->getChildNodes(this->client, folderNodeId, componentId); + const auto& childComponentsReferences = getChildReferencesOfType(folderNodeId, componentId); + ComponentPtr child; - if (childComponents.size()) + if (!childComponentsReferences.byNodeId.empty()) child = TmsClientFolder(this->context, thisPtr, browseName, this->clientContext, folderNodeId); else child = TmsClientComponent(this->context, thisPtr, browseName, this->clientContext, folderNodeId); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp index 36cff35..606d9c0 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp @@ -28,20 +28,13 @@ TmsClientFunctionBlockBaseImpl::TmsClientFunctionBlockBaseImpl( } template -tsl::ordered_set TmsClientFunctionBlockBaseImpl::getFunctionBlockNodeIds() +CachedReferences TmsClientFunctionBlockBaseImpl::getFunctionBlockReferences() { - const OpcUaNodeId referenceTypeId(UA_NS0ID_HASCOMPONENT); - const OpcUaNodeId functionBlockType(NAMESPACE_DAQBSP, UA_DAQBSPID_FUNCTIONBLOCKTYPE); // TODO subtypes - return this->referenceUtils.getReferencedNodes(this->nodeId, referenceTypeId, true, functionBlockType); -} - -template -tsl::ordered_set TmsClientFunctionBlockBaseImpl::getOutputSignalNodeIds() -{ - auto signalsNodeId = this->getNodeId("Sig"); - OpcUaNodeId referenceTypeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASVALUESIGNAL); - - return this->referenceUtils.getReferencedNodes(signalsNodeId, referenceTypeId, true); + auto filter = BrowseFilter(); + filter.referenceTypeId = OpcUaNodeId(UA_NS0ID_HASCOMPONENT); + filter.typeDefinition = OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_FUNCTIONBLOCKTYPE); + filter.direction = UA_BROWSEDIRECTION_FORWARD; + return this->clientContext->getReferenceBrowser()->browseFiltered(this->nodeId, filter); } template @@ -50,10 +43,11 @@ void TmsClientFunctionBlockBaseImpl::findAndCreateFunctionBlocks() std::map orderedFunctionBlocks; std::vector unorderedFunctionBlocks; - auto functionBlockNodeIds = getFunctionBlockNodeIds(); - for (const auto& functionBlockNodeId : functionBlockNodeIds) + const auto& references = getFunctionBlockReferences(); + for (const auto& [browseName, ref] : references.byBrowseName) { - auto browseName = this->client->readBrowseName(functionBlockNodeId); + const auto functionBlockNodeId = OpcUaNodeId(ref->nodeId.nodeId); + try { // TODO: If there is no access to the nodes within a function blocks an exeption @@ -86,8 +80,9 @@ void TmsClientFunctionBlockBaseImpl::findAndCreateSignals() std::map orderedSignals; std::vector unorderedSignals; - auto signalNodeIds = getOutputSignalNodeIds(); - for (const auto& signalNodeId : signalNodeIds) + const auto& references = getOutputSignalReferences(); + + for (const auto& [signalNodeId, ref] : references.byNodeId) { auto clientSignal = FindOrCreateTmsClientSignal(this->context, this->signals, this->clientContext, signalNodeId); const auto numberInList = this->tryReadChildNumberInList(signalNodeId); @@ -103,13 +98,28 @@ void TmsClientFunctionBlockBaseImpl::findAndCreateSignals() this->addSignal(val); } -template -tsl::ordered_set TmsClientFunctionBlockBaseImpl::getInputPortNodeIds() +template +CachedReferences TmsClientFunctionBlockBaseImpl::getOutputSignalReferences() { + auto filter = BrowseFilter(); + filter.referenceTypeId = OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASVALUESIGNAL); + filter.direction = UA_BROWSEDIRECTION_FORWARD; + + auto signalsNodeId = this->getNodeId("Sig"); + + return clientContext->getReferenceBrowser()->browseFiltered(signalsNodeId, filter); +} + +template +CachedReferences TmsClientFunctionBlockBaseImpl::getInputPortBlockReferences() +{ + auto filter = BrowseFilter(); + filter.referenceTypeId = OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASINPUTPORT); + filter.direction = UA_BROWSEDIRECTION_FORWARD; + auto inputPortsNodeId = this->getNodeId("IP"); - OpcUaNodeId referenceTypeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASINPUTPORT); - return this->referenceUtils.getReferencedNodes(inputPortsNodeId, referenceTypeId, true); + return clientContext->getReferenceBrowser()->browseFiltered(inputPortsNodeId, filter); } template @@ -118,10 +128,12 @@ void TmsClientFunctionBlockBaseImpl::findAndCreateInputPorts() std::map orderedInputPorts; std::vector unorderedInputPorts; - auto inputPortNodeIds = getInputPortNodeIds(); - for (const auto& inputPortNodeId : inputPortNodeIds) + const auto& references = getInputPortBlockReferences(); + + for (const auto& [browseName, ref] : references.byBrowseName) { - auto browseName = this->client->readBrowseName(inputPortNodeId); + const auto inputPortNodeId = OpcUaNodeId(ref->nodeId.nodeId); + auto clientInputPort = TmsClientInputPort(this->context, this->inputPorts, browseName, this->clientContext, inputPortNodeId); const auto numberInList = this->tryReadChildNumberInList(inputPortNodeId); @@ -147,18 +159,19 @@ void TmsClientFunctionBlockBaseImpl::readFbType() template SignalPtr TmsClientFunctionBlockBaseImpl::onGetStatusSignal() { - OpcUaNodeId referenceTypeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASSTATUSSIGNAL); + auto filter = BrowseFilter(); + filter.referenceTypeId = OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASSTATUSSIGNAL); + filter.direction = UA_BROWSEDIRECTION_FORWARD; - auto nodeIds = this->referenceUtils.getReferencedNodes(this->nodeId, referenceTypeId, true); + const auto& references = clientContext->getReferenceBrowser()->browseFiltered(nodeId, filter); + assert(references.byNodeId.size() <= 1); - assert(nodeIds.size() <= 1); - if (!nodeIds.empty()) + if (!references.byNodeId.empty()) { - auto signalNodeId = *nodeIds.begin(); + auto signalNodeId = references.byNodeId.begin().key(); return this->findSignal(signalNodeId); } - // Not Found return nullptr; } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp index e96cbf4..5789f63 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp @@ -104,13 +104,16 @@ ErrCode TmsClientInputPortImpl::getSignal(ISignal** signal) SignalPtr TmsClientInputPortImpl::onGetSignal() { - OpcUaNodeId referenceTypeId(NAMESPACE_DAQBSP, UA_DAQBSPID_CONNECTEDTOSIGNAL); - auto nodeIds = referenceUtils.getReferencedNodes(nodeId, referenceTypeId, true); - assert(nodeIds.size() <= 1); + auto filter = BrowseFilter(); + filter.referenceTypeId = OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_CONNECTEDTOSIGNAL); + filter.direction = UA_BROWSEDIRECTION_FORWARD; - if (!nodeIds.empty()) + const auto& references = clientContext->getReferenceBrowser()->browseFiltered(nodeId, filter); + assert(references.byNodeId.size() <= 1); + + if (!references.byNodeId.empty()) { - auto connectedSignalNodeId = *nodeIds.begin(); + auto connectedSignalNodeId = references.byNodeId.begin().key(); return findSignal(connectedSignalNodeId); } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp index 33882a1..d7e8b22 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp @@ -30,10 +30,11 @@ TmsClientIoFolderImpl::TmsClientIoFolderImpl(const ContextPtr& ctx, void TmsClientIoFolderImpl::findAndCreateChannels(std::map& orderedComponents, std::vector& unorderedComponents) { - auto channelNodeIds = getChildNodes(this->client, this->nodeId, OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_CHANNELTYPE)); - for (const auto& channelNodeId : channelNodeIds) + const auto& references = getChildReferencesOfType(this->nodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_CHANNELTYPE)); + + for (const auto& [browseName, ref] : references.byBrowseName) { - auto browseName = this->client->readBrowseName(channelNodeId); + const auto channelNodeId = OpcUaNodeId(ref->nodeId.nodeId); auto thisPtr = this->borrowPtr(); auto tmsClientChannel = TmsClientChannel(this->context, thisPtr, browseName, this->clientContext, channelNodeId); @@ -47,10 +48,11 @@ void TmsClientIoFolderImpl::findAndCreateChannels(std::map& orderedComponents, std::vector& unorderedComponents) { - auto folderNodeIds = getChildNodes(this->client, this->nodeId, OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_IOCOMPONENTTYPE)); - for (const auto& folderNodeId : folderNodeIds) + const auto& folderReferences = getChildReferencesOfType(this->nodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_IOCOMPONENTTYPE)); + + for (const auto& [browseName, ref] : folderReferences.byBrowseName) { - auto browseName = this->client->readBrowseName(folderNodeId); + const auto folderNodeId = OpcUaNodeId(ref->nodeId.nodeId); auto thisPtr = this->template borrowPtr(); auto tmsClientFolder = TmsClientIoFolder(this->context, thisPtr, browseName, this->clientContext, folderNodeId); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_object_impl.cpp index 69ef9b1..8a8e642 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_object_impl.cpp @@ -11,7 +11,6 @@ TmsClientObjectImpl::TmsClientObjectImpl(const ContextPtr& daqContext, const Tms : clientContext(clientContext) , client(clientContext->getClient()) , nodeId(nodeId) - , referenceUtils(client) , daqContext(daqContext) { } @@ -33,12 +32,12 @@ SignalPtr TmsClientObjectImpl::findSignal(const opcua::OpcUaNodeId& nodeId) cons bool TmsClientObjectImpl::hasReference(const std::string& name) { - return referenceUtils.hasReference(nodeId, name); + return clientContext->getReferenceBrowser()->hasReference(nodeId, name); } OpcUaNodeId TmsClientObjectImpl::getNodeId(const std::string& nodeName) { - return referenceUtils.getChildNodeId(nodeId, nodeName); + return clientContext->getReferenceBrowser()->getChildNodeId(nodeId, nodeName); } void TmsClientObjectImpl::writeValue(const std::string& nodeName, const OpcUaVariant& value) @@ -96,14 +95,8 @@ uint32_t TmsClientObjectImpl::tryReadChildNumberInList(const opcua::OpcUaNodeId& { try { - const auto& childReferences = referenceUtils.getReferences(nodeId); - for (auto& [addedPropChildId, addedPropChildRef] : childReferences) - { - if (client->readBrowseName(addedPropChildId) == "NumberInList") - { - return VariantConverter::ToDaqObject(client->readValue(addedPropChildId)); - } - } + const auto numberInListId = clientContext->getReferenceBrowser()->getChildNodeId(nodeId, "NumberInList"); + return VariantConverter::ToDaqObject(client->readValue(numberInListId)); } catch(...) { @@ -112,33 +105,11 @@ uint32_t TmsClientObjectImpl::tryReadChildNumberInList(const opcua::OpcUaNodeId& return std::numeric_limits::max(); } -std::vector TmsClientObjectImpl::getChildNodes(const opcua::OpcUaClientPtr& client, - const opcua::OpcUaNodeId& nodeId, - const opcua::OpcUaNodeId& typeId, - const bool subTypeEnabled) +CachedReferences TmsClientObjectImpl::getChildReferencesOfType(const opcua::OpcUaNodeId& nodeId, const opcua::OpcUaNodeId& typeId) { - using namespace daq::opcua; - ReferenceUtils referenceUtilities(client); - std::vector results; - BrowseRequest request(nodeId, OpcUaNodeClass::Object); - OpcUaBrowser browser(request, client); - auto browseResult = browser.browse(); - - for (const UA_ReferenceDescription& reference : browseResult) - { - if (OpcUaNodeId(reference.typeDefinition.nodeId) == typeId) - results.push_back(OpcUaNodeId(reference.nodeId.nodeId)); - else - { - if (subTypeEnabled) - { - if (referenceUtilities.isInstanceOf(reference.typeDefinition.nodeId, typeId)) - results.push_back(OpcUaNodeId(reference.nodeId.nodeId)); - } - } - } - - return results; + BrowseFilter filter; + filter.typeDefinition = typeId; + return clientContext->getReferenceBrowser()->browseFiltered(nodeId, filter); } END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp index ec81a8d..90d88f6 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp @@ -59,22 +59,25 @@ void TmsClientPropertyImpl::readBasicInfo() void TmsClientPropertyImpl::configurePropertyFields() { - const auto evaluationVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_EVALUATIONVARIABLETYPE); + const auto evaluationVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_EVALUATIONVARIABLETYPE); + const auto& references = clientContext->getReferenceBrowser()->browse(nodeId); - for (auto [childNodeId, ref] : referenceUtils.getReferences(nodeId)) + for (auto [browseName, ref] : references.byBrowseName) { - if (referenceUtils.getBrowseName(ref) == "CoercionExpression") + const auto childNodeId = OpcUaNodeId(ref->nodeId.nodeId); + + if (browseName == "CoercionExpression") { this->coercer = Coercer(VariantConverter::ToDaqObject(client->readValue(childNodeId))); } - else if (referenceUtils.getBrowseName(ref) == "ValidationExpression") + else if (browseName == "ValidationExpression") { this->validator = Validator(VariantConverter::ToDaqObject(client->readValue(childNodeId))); } - else if (referenceUtils.isInstanceOf(ref->typeDefinition.nodeId, evaluationVariableTypeId)) + else if (clientContext->getReferenceBrowser()->isSubtypeOf(ref->typeDefinition.nodeId, evaluationVariableTypeId)) { - auto evalId = referenceUtils.getChildNodeId(childNodeId, "EvaluationExpression"); - const auto browseName = referenceUtils.getBrowseName(ref); + auto evalId = clientContext->getReferenceBrowser()->getChildNodeId(childNodeId, "EvaluationExpression"); + StringPtr evalStr = VariantConverter::ToDaqObject(client->readValue(evalId)); if (details::stringToPropertyFieldEnum.count(browseName)) { diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index 4062f37..71da288 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -161,25 +161,27 @@ ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::setPropertyOrder(I return OPENDAQ_ERR_INVALID_OPERATION; } -template -void TmsClientPropertyObjectBaseImpl::addProperties( - const tsl::ordered_map>& references, - std::map& orderedProperties, - std::vector& unorderedProperties) +template +void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& parentId, + std::map& orderedProperties, + std::vector& unorderedProperties) { - const auto introspectionVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_INTROSPECTIONVARIABLETYPE); - const auto structureVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_STRUCTUREVARIABLETYPE); - const auto referenceVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_REFERENCEVARIABLETYPE); - const auto variableBlockTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_VARIABLEBLOCKTYPE); + const auto& references = clientContext->getReferenceBrowser()->browse(parentId); - for (auto& [childNodeId, ref] : references) + const auto introspectionVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_INTROSPECTIONVARIABLETYPE); + const auto structureVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_STRUCTUREVARIABLETYPE); + const auto referenceVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_REFERENCEVARIABLETYPE); + const auto variableBlockTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_VARIABLEBLOCKTYPE); + + for (auto& [childNodeId, ref] : references.byNodeId) { const auto typeId = OpcUaNodeId(ref->typeDefinition.nodeId); - auto propName = String(client->readBrowseName(childNodeId)); + const auto propName = String(utils::ToStdString(ref->browseName.name)); + Bool hasProp; daq::checkErrorInfo(Impl::hasProperty(propName, &hasProp)); PropertyPtr prop; - if (referenceUtils.isInstanceOf(typeId, referenceVariableTypeId)) + if (clientContext->getReferenceBrowser()->isSubtypeOf(typeId, referenceVariableTypeId)) { try { @@ -190,8 +192,7 @@ void TmsClientPropertyObjectBaseImpl::addProperties( } referenceVariableIdMap.insert(std::pair(propName, childNodeId)); - const auto& refPropReferences = referenceUtils.getReferences(childNodeId); - addProperties(refPropReferences, orderedProperties, unorderedProperties); + addProperties(childNodeId, orderedProperties, unorderedProperties); } catch(...) { @@ -199,8 +200,8 @@ void TmsClientPropertyObjectBaseImpl::addProperties( continue; } } - else if (referenceUtils.isInstanceOf(typeId, introspectionVariableTypeId) || - referenceUtils.isInstanceOf(typeId, structureVariableTypeId)) + else if (clientContext->getReferenceBrowser()->isSubtypeOf(typeId, introspectionVariableTypeId) || + clientContext->getReferenceBrowser()->isSubtypeOf(typeId, structureVariableTypeId)) { try { @@ -215,22 +216,23 @@ void TmsClientPropertyObjectBaseImpl::addProperties( continue; } } - else if (referenceUtils.isInstanceOf(typeId, variableBlockTypeId)) + else if (clientContext->getReferenceBrowser()->isSubtypeOf(typeId, variableBlockTypeId)) { if (!hasProp) { auto obj = TmsClientPropertyObject(daqContext, clientContext, childNodeId); auto propBuilder = ObjectPropertyBuilder(propName, obj).setDescription(String(client->readDescription(childNodeId))); - const auto evaluationVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_EVALUATIONVARIABLETYPE); - const auto variableBlockRefs = referenceUtils.getReferences(childNodeId); + const auto evaluationVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_EVALUATIONVARIABLETYPE); + const auto variableBlockRefs = clientContext->getReferenceBrowser()->browse(childNodeId); - for (auto& [variableBlockNodeId, variableBlockRef] : variableBlockRefs) + for (auto& [browseName, variableBlockRef] : variableBlockRefs.byBrowseName) { - const auto browseName = referenceUtils.getBrowseName(variableBlockRef); - if (referenceUtils.isInstanceOf(variableBlockRef->typeDefinition.nodeId, evaluationVariableTypeId)) + const auto variableBlockNodeId = OpcUaNodeId(variableBlockRef->nodeId.nodeId); + + if (clientContext->getReferenceBrowser()->isSubtypeOf(variableBlockRef->typeDefinition.nodeId, evaluationVariableTypeId)) { - auto evalId = referenceUtils.getChildNodeId(variableBlockNodeId, "EvaluationExpression"); + auto evalId = clientContext->getReferenceBrowser()->getChildNodeId(variableBlockNodeId, "EvaluationExpression"); StringPtr evalStr = VariantConverter::ToDaqObject(client->readValue(evalId)); @@ -269,19 +271,19 @@ void TmsClientPropertyObjectBaseImpl::addProperties( } template -void TmsClientPropertyObjectBaseImpl::addMethodProperties( - const tsl::ordered_map>& references, - const OpcUaNodeId& parentNodeId, - std::map& orderedProperties, - std::vector& unorderedProperties, - std::unordered_map& functionPropValues) +void TmsClientPropertyObjectBaseImpl::addMethodProperties(const OpcUaNodeId& parentNodeId, + std::map& orderedProperties, + std::vector& unorderedProperties, + std::unordered_map& functionPropValues) { + const auto& references = clientContext->getReferenceBrowser()->browse(parentNodeId); const auto methodTypeId = OpcUaNodeId(0, UA_NS0ID_METHODNODE); - for (auto& [childNodeId, ref] : references) + for (auto& [childNodeId, ref] : references.byNodeId) { const auto typeId = OpcUaNodeId(ref->typeDefinition.nodeId); - auto propName = String(client->readBrowseName(childNodeId)); + const auto propName = String(utils::ToStdString(ref->browseName.name)); + Bool hasProp; daq::checkErrorInfo(Impl::hasProperty(propName, &hasProp)); @@ -295,14 +297,17 @@ void TmsClientPropertyObjectBaseImpl::addMethodProperties( try { - if (referenceUtils.hasReference(childNodeId, "InputArguments")) - inputArgs = VariantConverter::ToDaqList(client->readValue(referenceUtils.getChildNodeId(childNodeId, "InputArguments"))); + if (clientContext->getReferenceBrowser()->hasReference(childNodeId, "InputArguments")) + inputArgs = VariantConverter::ToDaqList( + client->readValue(clientContext->getReferenceBrowser()->getChildNodeId(childNodeId, "InputArguments"))); - if (referenceUtils.hasReference(childNodeId, "OutputArguments")) - outputArgs = VariantConverter::ToDaqList(client->readValue(referenceUtils.getChildNodeId(childNodeId, "OutputArguments"))); + if (clientContext->getReferenceBrowser()->hasReference(childNodeId, "OutputArguments")) + outputArgs = VariantConverter::ToDaqList( + client->readValue(clientContext->getReferenceBrowser()->getChildNodeId(childNodeId, "OutputArguments"))); - if (referenceUtils.hasReference(childNodeId, "NumberInList")) - numberInList = VariantConverter::ToDaqObject(client->readValue(referenceUtils.getChildNodeId(childNodeId, "NumberInList"))); + if (clientContext->getReferenceBrowser()->hasReference(childNodeId, "NumberInList")) + numberInList = VariantConverter::ToDaqObject( + client->readValue(clientContext->getReferenceBrowser()->getChildNodeId(childNodeId, "NumberInList"))); } catch(...) { @@ -338,24 +343,21 @@ void TmsClientPropertyObjectBaseImpl::addMethodProperties( template void TmsClientPropertyObjectBaseImpl::browseRawProperties() { - const auto& references = referenceUtils.getReferences(nodeId); - std::map orderedProperties; std::vector unorderedProperties; std::unordered_map functionPropValues; - addProperties(references, orderedProperties, unorderedProperties); + addProperties(nodeId, orderedProperties, unorderedProperties); // TODO: Make sure that this is a DeviceType node if (hasReference("MethodSet")) { - const auto methodNodeId = referenceUtils.getChildNodeId(nodeId, "MethodSet"); - const auto& methodReferences = referenceUtils.getReferences(methodNodeId); - addMethodProperties(methodReferences, methodNodeId, orderedProperties, unorderedProperties, functionPropValues); + const auto methodNodeId = clientContext->getReferenceBrowser()->getChildNodeId(nodeId, "MethodSet"); + addMethodProperties(methodNodeId, orderedProperties, unorderedProperties, functionPropValues); } else { - addMethodProperties(references, nodeId, orderedProperties, unorderedProperties, functionPropValues); + addMethodProperties(nodeId, orderedProperties, unorderedProperties, functionPropValues); } for (const auto& val : orderedProperties) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp index edd4524..8717b77 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp @@ -23,8 +23,12 @@ TmsClientSignalImpl::TmsClientSignalImpl( { deviceSignalId = nodeId.getIdentifier(); - if (referenceUtils.hasReference(nodeId, "Value")) - descriptorNodeId = std::make_unique(referenceUtils.getChildNodeId(referenceUtils.getChildNodeId(nodeId, "Value"), "DataDescriptor")); + if (hasReference("Value")) + { + const auto valueNodeId = clientContext->getReferenceBrowser()->getChildNodeId(nodeId, "Value"); + const auto dataDescriptorNodeId = clientContext->getReferenceBrowser()->getChildNodeId(valueNodeId, "DataDescriptor"); + descriptorNodeId = std::make_unique(dataDescriptorNodeId); + } registerObject(this->borrowPtr()); } @@ -77,13 +81,16 @@ ErrCode TmsClientSignalImpl::getDomainSignal(ISignal** signal) SignalPtr TmsClientSignalImpl::onGetDomainSignal() { - OpcUaNodeId referenceTypeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASDOMAINSIGNAL); - auto nodeIds = referenceUtils.getReferencedNodes(nodeId, referenceTypeId, true); - assert(nodeIds.size() <= 1); + auto filter = BrowseFilter(); + filter.referenceTypeId = OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASDOMAINSIGNAL); + filter.direction = UA_BROWSEDIRECTION_FORWARD; - if (!nodeIds.empty()) + const auto& references = clientContext->getReferenceBrowser()->browseFiltered(nodeId, filter); + assert(references.byNodeId.size() <= 1); + + if (!references.byNodeId.empty()) { - auto domainSignalNodeId = *nodeIds.begin(); + auto domainSignalNodeId = references.byNodeId.begin().key(); return findSignal(domainSignalNodeId); } @@ -106,14 +113,20 @@ ErrCode TmsClientSignalImpl::getRelatedSignals(IList** signals) ListPtr TmsClientSignalImpl::onGetRelatedSignals() { - OpcUaNodeId referenceTypeId(NAMESPACE_DAQBSP, UA_DAQBSPID_RELATESTOSIGNAL); - auto nodeIds = referenceUtils.getReferencedNodes(nodeId, referenceTypeId, true); + auto filter = BrowseFilter(); + filter.referenceTypeId = OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_RELATESTOSIGNAL); + filter.direction = UA_BROWSEDIRECTION_FORWARD; + + const auto& references = clientContext->getReferenceBrowser()->browseFiltered(nodeId, filter); + ListPtr resultList = List(); - for (auto signalNodeId : nodeIds) + + for (const auto& [signalNodeId, ref] : references.byNodeId) { auto signal = findSignal(signalNodeId); resultList.pushBack(signal); } + return resultList.detach(); } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp index 0e68c86..efff825 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp @@ -82,28 +82,17 @@ daq::DevicePtr TmsClient::connect() OpcUaNodeId TmsClient::getRootDeviceNodeId() { const OpcUaNodeId rootNodeId(NAMESPACE_DI, UA_DIID_DEVICESET); - BrowseRequest br(rootNodeId, OpcUaNodeClass::Object, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT)); - OpcUaBrowser browser(br, client); - auto results = browser.browse(); + auto filter = BrowseFilter(); + filter.referenceTypeId = OpcUaNodeId(0, UA_NS0ID_HASCOMPONENT); + filter.typeDefinition = OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQDEVICETYPE); - const OpcUaNodeId daqDeviceTypeNodeId( NAMESPACE_DAQDEVICE, // TODO NAMESPACE_DAQDEVICE is server namespace id. You need - UA_DAQDEVICEID_DAQDEVICETYPE); // to map it to client. Or use namespace URI. - - - for (const auto& result : results) - { - ReferenceUtils referenceUtilities(client); - if (daqDeviceTypeNodeId == result.typeDefinition.nodeId) - return result.nodeId.nodeId; - else - { - // Else check if this is a subtype of the openDAQ device. - if (referenceUtilities.isInstanceOf(result.typeDefinition.nodeId, daqDeviceTypeNodeId)) - return result.nodeId.nodeId; - } - } - throw NotFoundException(); + const auto& references = tmsClientContext->getReferenceBrowser()->browseFiltered(rootNodeId, filter); + + if (references.byNodeId.empty()) + throw NotFoundException(); + + return references.byNodeId.begin().key(); } StringPtr TmsClient::getUniqueLocalId(const StringPtr& localId, int iteration) diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_server.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_server.cpp index 3918e0f..0ca7e43 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_server.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_server.cpp @@ -1,10 +1,10 @@ #include #include #include -#include -#include +#include #include #include "test_helpers.h" +#include using TmsServerTest = testing::Test; @@ -60,6 +60,7 @@ TEST_F(TmsServerTest, Channels) server.start(); auto client = TmsObjectTest::CreateAndConnectTestClient(); + auto referenceBrowser = CachedReferenceBrowser(client); auto mockPhysicalDevice = GetMockPhysicalDevice(client); auto inputsOutputsFolder = BrowseForChild(client, mockPhysicalDevice, "IO"); @@ -77,10 +78,11 @@ TEST_F(TmsServerTest, Channels) auto byteStepSignal = BrowseForChild(client, signalsNode, "ByteStep"); auto timeSignal = BrowseForChild(client, signalsNode, "Time"); - ReferenceUtils referenceUtils(client); - referenceUtils.updateReferences(byteStepSignal); + auto filter = BrowseFilter(); + filter.referenceTypeId = OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASDOMAINSIGNAL); + filter.direction = UA_BROWSEDIRECTION_FORWARD; - auto references = referenceUtils.getReferencedNodes(byteStepSignal, OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASDOMAINSIGNAL), true); - ASSERT_EQ(references.size(), 1u); - ASSERT_EQ(*references.begin(), timeSignal); + auto references = referenceBrowser.browseFiltered(byteStepSignal, filter); + ASSERT_EQ(references.byNodeId.size(), 1u); + ASSERT_EQ(references.byNodeId.begin().key(), timeSignal); } From bbea9714343e73552ae0693819db8479a962c08c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Thu, 7 Dec 2023 12:20:15 +0100 Subject: [PATCH 032/217] Add support for max nodes per browse to reference browser --- .../opcuaclient/cached_reference_browser.h | 11 ++++- .../opcuaclient/src/attribute_reader.cpp | 4 +- .../src/cached_reference_browser.cpp | 41 +++++++++++++------ .../src/test_cached_reference_browser.cpp | 22 ++++++++++ .../objects/tms_client_context.h | 3 +- .../src/objects/tms_client_context.cpp | 20 ++++++++- 6 files changed, 83 insertions(+), 18 deletions(-) diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h index 56920c5..3aeff26 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h @@ -46,7 +46,7 @@ struct BrowseFilter class CachedReferenceBrowser { public: - CachedReferenceBrowser(const OpcUaClientPtr& client); + CachedReferenceBrowser(const OpcUaClientPtr& client, size_t maxNodesPerBrowse = 0); const CachedReferences& browse(const OpcUaNodeId& nodeId, bool forceInvalidate = false); void invalidate(const OpcUaNodeId& nodeId); @@ -60,10 +60,17 @@ class CachedReferenceBrowser bool isCached(const OpcUaNodeId& nodeId); void markAsCached(const OpcUaNodeId& nodeId); void browseMultiple(const std::vector& nodes); - void processBrowseResults(const std::vector& nodes, UA_BrowseResult* results, size_t size, std::vector& browseNextOut); + size_t browseBatch(const std::vector& nodes, size_t startIndex, size_t size); + void processBrowseResults(const std::vector& nodes, + size_t startIndex, + size_t requestedSize, + UA_BrowseResult* results, + size_t resultSize, + std::vector& browseNextOut); bool getContinuationPoint(UA_BrowseResult* results, UA_ByteString* continuationPointOut); OpcUaClientPtr client; + size_t maxNodesPerBrowse; std::unordered_map references; }; diff --git a/shared/libraries/opcua/opcuaclient/src/attribute_reader.cpp b/shared/libraries/opcua/opcuaclient/src/attribute_reader.cpp index 1c18b0b..cf76df4 100644 --- a/shared/libraries/opcua/opcuaclient/src/attribute_reader.cpp +++ b/shared/libraries/opcua/opcuaclient/src/attribute_reader.cpp @@ -59,9 +59,11 @@ const std::vector>& AttributeReader::getResponses() size_t AttributeReader::readBatch(size_t startIndex, size_t size) { - if (startIndex + size > attributes.size()) + if ((startIndex + size) > attributes.size()) size = attributes.size() - startIndex; + assert(size > 0); + OpcUaObject request; request->nodesToReadSize = size; request->nodesToRead = (UA_ReadValueId*) UA_Array_new(attributes.size(), &UA_TYPES[UA_TYPES_READVALUEID]); diff --git a/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp b/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp index a34f4a0..8561f42 100644 --- a/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp +++ b/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp @@ -3,8 +3,9 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA -CachedReferenceBrowser::CachedReferenceBrowser(const OpcUaClientPtr& client) +CachedReferenceBrowser::CachedReferenceBrowser(const OpcUaClientPtr& client, size_t maxNodesPerBrowse) : client(client) + , maxNodesPerBrowse(maxNodesPerBrowse) { } @@ -101,17 +102,28 @@ void CachedReferenceBrowser::markAsCached(const OpcUaNodeId& nodeId) void CachedReferenceBrowser::browseMultiple(const std::vector& nodes) { - if (nodes.empty()) - return; + const size_t batchSize = (maxNodesPerBrowse > 0) ? maxNodesPerBrowse : nodes.size(); + size_t i = 0; + + while (i < nodes.size()) + i += browseBatch(nodes, i, batchSize); +} + +size_t CachedReferenceBrowser::browseBatch(const std::vector& nodes, size_t startIndex, size_t size) +{ + if ((startIndex + size) > nodes.size()) + size = nodes.size() - startIndex; + + assert(size > 0); OpcUaObject request; request->requestedMaxReferencesPerNode = 0; - request->nodesToBrowse = (UA_BrowseDescription*) UA_Array_new(nodes.size(), &UA_TYPES[UA_TYPES_BROWSEDESCRIPTION]); - request->nodesToBrowseSize = nodes.size(); + request->nodesToBrowse = (UA_BrowseDescription*) UA_Array_new(size, &UA_TYPES[UA_TYPES_BROWSEDESCRIPTION]); + request->nodesToBrowseSize = size; - for (size_t i = 0; i < nodes.size(); i++) + for (size_t i = 0; i < size; i++) { - const auto& nodeId = nodes[i]; + const auto& nodeId = nodes[startIndex + i]; markAsCached(nodeId); request->nodesToBrowse[i].nodeId = nodeId.copyAndGetDetachedValue(); @@ -124,7 +136,7 @@ void CachedReferenceBrowser::browseMultiple(const std::vector& node OpcUaObject response = UA_Client_Service_browse(client->getLockedUaClient(), *request); CheckStatusCodeException(response->responseHeader.serviceResult, "Browse result error"); - processBrowseResults(nodes, response->results, response->resultsSize, browseNext); + processBrowseResults(nodes, startIndex, size, response->results, response->resultsSize, browseNext); while (getContinuationPoint(response->results, continuationPoint)) { @@ -135,20 +147,23 @@ void CachedReferenceBrowser::browseMultiple(const std::vector& node OpcUaObject nextResponse = UA_Client_Service_browseNext(client->getLockedUaClient(), *nextRequest); CheckStatusCodeException(response->responseHeader.serviceResult, "Browse result error"); - processBrowseResults(nodes, nextResponse->results, nextResponse->resultsSize, browseNext); + processBrowseResults(nodes, startIndex, size, nextResponse->results, nextResponse->resultsSize, browseNext); } browseMultiple(browseNext); + return size; } void CachedReferenceBrowser::processBrowseResults(const std::vector& nodes, + size_t startIndex, + size_t requestedSize, UA_BrowseResult* results, - size_t size, + size_t resultSize, std::vector& browseNextOut) { - assert(size == nodes.size()); + assert(requestedSize == resultSize); - for (size_t i = 0; i < size; i++) + for (size_t i = 0; i < resultSize; i++) { UA_BrowseResult& result = results[i]; @@ -159,7 +174,7 @@ void CachedReferenceBrowser::processBrowseResults(const std::vector CheckStatusCodeException(result.statusCode, "Browse result error"); - const auto nodeId = nodes[i]; + const auto nodeId = nodes[startIndex + i]; references[nodeId] = {}; for (size_t j = 0; j < result.referencesSize; j++) diff --git a/shared/libraries/opcua/opcuaclient/tests/src/test_cached_reference_browser.cpp b/shared/libraries/opcua/opcuaclient/tests/src/test_cached_reference_browser.cpp index 61185de..fe11899 100644 --- a/shared/libraries/opcua/opcuaclient/tests/src/test_cached_reference_browser.cpp +++ b/shared/libraries/opcua/opcuaclient/tests/src/test_cached_reference_browser.cpp @@ -150,5 +150,27 @@ TEST_F(CachedReferenceBrowserTest, BrowseFiltered) ASSERT_EQ(children.byNodeId.size(), 4u); } +TEST_F(CachedReferenceBrowserTest, MaxNodesPerBrowse) +{ + testHelper.stop(); + testHelper.onConfigure([&](UA_ServerConfig* config) { config->maxNodesPerBrowse = 5; }); + testHelper.startServer(); + + auto client = std::make_shared(getServerUrl()); + client->connect(); + + const auto nodeId = OpcUaNodeId(UA_NS0ID_OBJECTSFOLDER); + const auto maxNodesPerBrowseId = OpcUaNodeId(UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERBROWSE); + const auto maxNodesPerBrowse = client->readValue(maxNodesPerBrowseId).toInteger(); + ASSERT_GT(maxNodesPerBrowse, 0); + + auto browser = CachedReferenceBrowser(client, maxNodesPerBrowse); + const auto& references = browser.browse(nodeId); + ASSERT_FALSE(references.byNodeId.empty()); + + auto missconfiguredBrowser = CachedReferenceBrowser(client); + ASSERT_THROW(missconfiguredBrowser.browse(nodeId), OpcUaException); +} + END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h index d1ac7c0..87d4f7e 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h @@ -57,9 +57,10 @@ class TmsClientContext opcua::OpcUaClientPtr client; CachedReferenceBrowserPtr referenceBrowser; mutable std::mutex mutex; - // Context should not hold objects because of cycling reference std::unordered_map objects; + + void initReferenceBrowser(); }; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp index fe325b1..0f5a767 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp @@ -1,4 +1,5 @@ #include "opcuatms_client/objects/tms_client_context.h" +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -6,8 +7,8 @@ using namespace opcua; TmsClientContext::TmsClientContext(const OpcUaClientPtr& client) : client(client) - , referenceBrowser(std::make_shared(client)) { + initReferenceBrowser(); } const opcua::OpcUaClientPtr& TmsClientContext::getClient() const @@ -54,4 +55,21 @@ CachedReferenceBrowserPtr TmsClientContext::getReferenceBrowser() return referenceBrowser; } +void TmsClientContext::initReferenceBrowser() +{ + size_t maxNodesPerBrowse = 0; + + try + { + const auto maxNodesPerBrowseId = OpcUaNodeId(UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERBROWSE); + maxNodesPerBrowse = client->readValue(maxNodesPerBrowseId).toInteger(); + } + catch (const std::exception& e) + { + LOGW << "Failed to read maxNodesPerBrowse variable: " << e.what(); + } + + referenceBrowser = std::make_shared(client, maxNodesPerBrowse); +} + END_NAMESPACE_OPENDAQ_OPCUA_TMS From e44a85f52f45856d69a6f175634b0b37e033972a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Fri, 8 Dec 2023 10:51:08 +0100 Subject: [PATCH 033/217] Pass continuation point by reference --- .../include/opcuaclient/cached_reference_browser.h | 2 +- .../opcua/opcuaclient/src/cached_reference_browser.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h index 3aeff26..a3241d7 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h @@ -67,7 +67,7 @@ class CachedReferenceBrowser UA_BrowseResult* results, size_t resultSize, std::vector& browseNextOut); - bool getContinuationPoint(UA_BrowseResult* results, UA_ByteString* continuationPointOut); + bool getContinuationPoint(UA_BrowseResult* results, UA_ByteString** continuationPointOut); OpcUaClientPtr client; size_t maxNodesPerBrowse; diff --git a/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp b/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp index 8561f42..59b7827 100644 --- a/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp +++ b/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp @@ -138,7 +138,7 @@ size_t CachedReferenceBrowser::browseBatch(const std::vector& nodes processBrowseResults(nodes, startIndex, size, response->results, response->resultsSize, browseNext); - while (getContinuationPoint(response->results, continuationPoint)) + while (getContinuationPoint(response->results, &continuationPoint)) { OpcUaObject nextRequest; nextRequest->releaseContinuationPoints = UA_FALSE; @@ -192,9 +192,9 @@ void CachedReferenceBrowser::processBrowseResults(const std::vector } } -bool CachedReferenceBrowser::getContinuationPoint(UA_BrowseResult* results, UA_ByteString* continuationPointOut) +bool CachedReferenceBrowser::getContinuationPoint(UA_BrowseResult* results, UA_ByteString** continuationPointOut) { - continuationPointOut = &results->continuationPoint; + *continuationPointOut = &results->continuationPoint; return results->continuationPoint.length > 0; } From c3d8ab9e3bdfeb342daea6f598689d57648f6032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Fri, 8 Dec 2023 15:12:05 +0100 Subject: [PATCH 034/217] Fix build errors --- .../src/objects/tms_client_function_block_impl.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp index 606d9c0..f97e6d7 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp @@ -107,7 +107,7 @@ CachedReferences TmsClientFunctionBlockBaseImpl::getOutputSignalReferences auto signalsNodeId = this->getNodeId("Sig"); - return clientContext->getReferenceBrowser()->browseFiltered(signalsNodeId, filter); + return this->clientContext->getReferenceBrowser()->browseFiltered(signalsNodeId, filter); } template @@ -119,7 +119,7 @@ CachedReferences TmsClientFunctionBlockBaseImpl::getInputPortBlockReferenc auto inputPortsNodeId = this->getNodeId("IP"); - return clientContext->getReferenceBrowser()->browseFiltered(inputPortsNodeId, filter); + return this->clientContext->getReferenceBrowser()->browseFiltered(inputPortsNodeId, filter); } template @@ -163,7 +163,7 @@ SignalPtr TmsClientFunctionBlockBaseImpl::onGetStatusSignal() filter.referenceTypeId = OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASSTATUSSIGNAL); filter.direction = UA_BROWSEDIRECTION_FORWARD; - const auto& references = clientContext->getReferenceBrowser()->browseFiltered(nodeId, filter); + const auto& references = this->clientContext->getReferenceBrowser()->browseFiltered(nodeId, filter); assert(references.byNodeId.size() <= 1); if (!references.byNodeId.empty()) From ef840c14964c15fd91796e41198e2db284a164e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Mon, 11 Dec 2023 08:54:03 +0100 Subject: [PATCH 035/217] Fix build errors --- .../src/objects/tms_client_function_block_impl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp index f97e6d7..3840108 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp @@ -163,7 +163,7 @@ SignalPtr TmsClientFunctionBlockBaseImpl::onGetStatusSignal() filter.referenceTypeId = OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASSTATUSSIGNAL); filter.direction = UA_BROWSEDIRECTION_FORWARD; - const auto& references = this->clientContext->getReferenceBrowser()->browseFiltered(nodeId, filter); + const auto& references = this->clientContext->getReferenceBrowser()->browseFiltered(this->nodeId, filter); assert(references.byNodeId.size() <= 1); if (!references.byNodeId.empty()) From 46f865575fa7dc9721b15445ed1801931614580b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Mon, 11 Dec 2023 13:31:30 +0100 Subject: [PATCH 036/217] Fix linux build errors --- .../opcuatms_client/src/objects/tms_client_folder_impl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp index bf298cc..6b9c458 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp @@ -40,7 +40,7 @@ void TmsClientFolderImpl::findAndCreateFolders(std::mapnodeId.nodeId); auto thisPtr = this->template borrowPtr(); - const auto& childComponentsReferences = getChildReferencesOfType(folderNodeId, componentId); + const auto& childComponentsReferences = this->getChildReferencesOfType(folderNodeId, componentId); ComponentPtr child; if (!childComponentsReferences.byNodeId.empty()) From 17cf3b5121067d5133b13bef402d216f258faa53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Wed, 27 Dec 2023 10:46:31 +0100 Subject: [PATCH 037/217] Fix merge conflicts --- .../src/objects/tms_client_device_impl.cpp | 14 +++++++------- .../src/objects/tms_client_folder_impl.cpp | 2 +- .../src/objects/tms_client_function_block_impl.cpp | 8 ++++---- .../src/objects/tms_client_input_port_impl.cpp | 2 +- .../src/objects/tms_client_io_folder_impl.cpp | 4 ++-- .../src/objects/tms_client_property_impl.cpp | 2 +- .../objects/tms_client_property_object_impl.cpp | 12 ++++++------ .../src/objects/tms_client_signal_impl.cpp | 4 ++-- .../opcuatms/opcuatms_client/src/tms_client.cpp | 2 +- .../opcuatms_server/tests/test_tms_server.cpp | 4 ++-- 10 files changed, 27 insertions(+), 27 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index fbcee7b..bc38453 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -82,7 +82,7 @@ void TmsClientDeviceImpl::findAndCreateSubdevices() std::map orderedDevices; std::vector unorderedDevices; - const auto& references = getChildReferencesOfType(nodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQDEVICETYPE)); + const auto& references = getChildReferencesOfType(nodeId, OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_DAQDEVICETYPE)); for (const auto& [browseName, ref] : references.byBrowseName) { @@ -227,7 +227,7 @@ void TmsClientDeviceImpl::findAndCreateFunctionBlocks() std::vector unorderedFunctionBlocks; auto functionBlocksNodeId = getNodeId("FB"); - const auto& references = getChildReferencesOfType(functionBlocksNodeId, OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_FUNCTIONBLOCKTYPE)); + const auto& references = getChildReferencesOfType(functionBlocksNodeId, OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_FUNCTIONBLOCKTYPE)); for (const auto& [browseName, ref] : references.byBrowseName) { @@ -260,7 +260,7 @@ void TmsClientDeviceImpl::findAndCreateSignals() std::vector unorderedSignals; const auto signalsNodeId = getNodeId("Sig"); - const auto& references = getChildReferencesOfType(signalsNodeId, OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_SIGNALTYPE)); + const auto& references = getChildReferencesOfType(signalsNodeId, OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_SIGNALTYPE)); for (const auto& [signalNodeId, ref] : references.byNodeId) { @@ -285,7 +285,7 @@ void TmsClientDeviceImpl::findAndCreateInputsOutputs() this->ioFolder.clear(); auto inputsOutputsNodeId = getNodeId("IO"); - const auto& channelreferences = getChildReferencesOfType(inputsOutputsNodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_CHANNELTYPE)); + const auto& channelreferences = getChildReferencesOfType(inputsOutputsNodeId, OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_CHANNELTYPE)); for (const auto& [browseName, ref] : channelreferences.byBrowseName) { @@ -299,7 +299,7 @@ void TmsClientDeviceImpl::findAndCreateInputsOutputs() unorderedComponents.emplace_back(tmsClientChannel); } - const auto& folderReferences = getChildReferencesOfType(inputsOutputsNodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_IOCOMPONENTTYPE)); + const auto& folderReferences = getChildReferencesOfType(inputsOutputsNodeId, OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_IOCOMPONENTTYPE)); for (const auto& [browseName, ref] : folderReferences.byBrowseName) { @@ -330,7 +330,7 @@ void TmsClientDeviceImpl::findAndCreateStreamingOptions() try { const auto& streamingOptionsReferences = - getChildReferencesOfType(streamingOptionsNodeId, OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_VARIABLEBLOCKTYPE)); + getChildReferencesOfType(streamingOptionsNodeId, OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_VARIABLEBLOCKTYPE)); for (const auto& [browseName, ref] : streamingOptionsReferences.byBrowseName) { @@ -360,7 +360,7 @@ void TmsClientDeviceImpl::findAndCreateCustomComponents() std::map orderedComponents; std::vector unorderedComponents; - auto componentId = OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQCOMPONENTTYPE); + auto componentId = OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_DAQCOMPONENTTYPE); const auto& folderReferences = getChildReferencesOfType(nodeId, componentId); for (const auto& [browseName, ref] : folderReferences.byBrowseName) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp index 6b9c458..f6c310a 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp @@ -32,7 +32,7 @@ TmsClientFolderImpl::TmsClientFolderImpl(const ContextPtr& ctx, template void TmsClientFolderImpl::findAndCreateFolders(std::map& orderedComponents, std::vector& unorderedComponents) { - auto componentId = OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQCOMPONENTTYPE); + auto componentId = OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_DAQCOMPONENTTYPE); const auto& folderReferences = this->getChildReferencesOfType(this->nodeId, componentId); for (const auto& [browseName, ref] : folderReferences.byBrowseName) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp index 3840108..557e6f8 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp @@ -32,7 +32,7 @@ CachedReferences TmsClientFunctionBlockBaseImpl::getFunctionBlockReference { auto filter = BrowseFilter(); filter.referenceTypeId = OpcUaNodeId(UA_NS0ID_HASCOMPONENT); - filter.typeDefinition = OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_FUNCTIONBLOCKTYPE); + filter.typeDefinition = OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_FUNCTIONBLOCKTYPE); filter.direction = UA_BROWSEDIRECTION_FORWARD; return this->clientContext->getReferenceBrowser()->browseFiltered(this->nodeId, filter); } @@ -102,7 +102,7 @@ template CachedReferences TmsClientFunctionBlockBaseImpl::getOutputSignalReferences() { auto filter = BrowseFilter(); - filter.referenceTypeId = OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASVALUESIGNAL); + filter.referenceTypeId = OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASVALUESIGNAL); filter.direction = UA_BROWSEDIRECTION_FORWARD; auto signalsNodeId = this->getNodeId("Sig"); @@ -114,7 +114,7 @@ template CachedReferences TmsClientFunctionBlockBaseImpl::getInputPortBlockReferences() { auto filter = BrowseFilter(); - filter.referenceTypeId = OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASINPUTPORT); + filter.referenceTypeId = OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASINPUTPORT); filter.direction = UA_BROWSEDIRECTION_FORWARD; auto inputPortsNodeId = this->getNodeId("IP"); @@ -160,7 +160,7 @@ template SignalPtr TmsClientFunctionBlockBaseImpl::onGetStatusSignal() { auto filter = BrowseFilter(); - filter.referenceTypeId = OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASSTATUSSIGNAL); + filter.referenceTypeId = OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASSTATUSSIGNAL); filter.direction = UA_BROWSEDIRECTION_FORWARD; const auto& references = this->clientContext->getReferenceBrowser()->browseFiltered(this->nodeId, filter); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp index 5789f63..a52752e 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp @@ -105,7 +105,7 @@ ErrCode TmsClientInputPortImpl::getSignal(ISignal** signal) SignalPtr TmsClientInputPortImpl::onGetSignal() { auto filter = BrowseFilter(); - filter.referenceTypeId = OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_CONNECTEDTOSIGNAL); + filter.referenceTypeId = OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_CONNECTEDTOSIGNAL); filter.direction = UA_BROWSEDIRECTION_FORWARD; const auto& references = clientContext->getReferenceBrowser()->browseFiltered(nodeId, filter); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp index d7e8b22..7e9b6e6 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp @@ -30,7 +30,7 @@ TmsClientIoFolderImpl::TmsClientIoFolderImpl(const ContextPtr& ctx, void TmsClientIoFolderImpl::findAndCreateChannels(std::map& orderedComponents, std::vector& unorderedComponents) { - const auto& references = getChildReferencesOfType(this->nodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_CHANNELTYPE)); + const auto& references = getChildReferencesOfType(this->nodeId, OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_CHANNELTYPE)); for (const auto& [browseName, ref] : references.byBrowseName) { @@ -48,7 +48,7 @@ void TmsClientIoFolderImpl::findAndCreateChannels(std::map& orderedComponents, std::vector& unorderedComponents) { - const auto& folderReferences = getChildReferencesOfType(this->nodeId, OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_IOCOMPONENTTYPE)); + const auto& folderReferences = getChildReferencesOfType(this->nodeId, OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_IOCOMPONENTTYPE)); for (const auto& [browseName, ref] : folderReferences.byBrowseName) { diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp index 90d88f6..bc215dc 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp @@ -59,7 +59,7 @@ void TmsClientPropertyImpl::readBasicInfo() void TmsClientPropertyImpl::configurePropertyFields() { - const auto evaluationVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_EVALUATIONVARIABLETYPE); + const auto evaluationVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_EVALUATIONVARIABLETYPE); const auto& references = clientContext->getReferenceBrowser()->browse(nodeId); for (auto [browseName, ref] : references.byBrowseName) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index 71da288..24509d5 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -166,12 +166,12 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par std::map& orderedProperties, std::vector& unorderedProperties) { - const auto& references = clientContext->getReferenceBrowser()->browse(parentId); + const auto introspectionVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_INTROSPECTIONVARIABLETYPE); + const auto structureVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_STRUCTUREVARIABLETYPE); + const auto referenceVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_REFERENCEVARIABLETYPE); + const auto variableBlockTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_VARIABLEBLOCKTYPE); - const auto introspectionVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_INTROSPECTIONVARIABLETYPE); - const auto structureVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_STRUCTUREVARIABLETYPE); - const auto referenceVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_REFERENCEVARIABLETYPE); - const auto variableBlockTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_VARIABLEBLOCKTYPE); + const auto& references = clientContext->getReferenceBrowser()->browse(parentId); for (auto& [childNodeId, ref] : references.byNodeId) { @@ -223,7 +223,7 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par auto obj = TmsClientPropertyObject(daqContext, clientContext, childNodeId); auto propBuilder = ObjectPropertyBuilder(propName, obj).setDescription(String(client->readDescription(childNodeId))); - const auto evaluationVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_EVALUATIONVARIABLETYPE); + const auto evaluationVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_EVALUATIONVARIABLETYPE); const auto variableBlockRefs = clientContext->getReferenceBrowser()->browse(childNodeId); for (auto& [browseName, variableBlockRef] : variableBlockRefs.byBrowseName) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp index 8717b77..43db9b6 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp @@ -82,7 +82,7 @@ ErrCode TmsClientSignalImpl::getDomainSignal(ISignal** signal) SignalPtr TmsClientSignalImpl::onGetDomainSignal() { auto filter = BrowseFilter(); - filter.referenceTypeId = OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASDOMAINSIGNAL); + filter.referenceTypeId = OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASDOMAINSIGNAL); filter.direction = UA_BROWSEDIRECTION_FORWARD; const auto& references = clientContext->getReferenceBrowser()->browseFiltered(nodeId, filter); @@ -114,7 +114,7 @@ ErrCode TmsClientSignalImpl::getRelatedSignals(IList** signals) ListPtr TmsClientSignalImpl::onGetRelatedSignals() { auto filter = BrowseFilter(); - filter.referenceTypeId = OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_RELATESTOSIGNAL); + filter.referenceTypeId = OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_RELATESTOSIGNAL); filter.direction = UA_BROWSEDIRECTION_FORWARD; const auto& references = clientContext->getReferenceBrowser()->browseFiltered(nodeId, filter); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp index efff825..5ac2bc6 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp @@ -85,7 +85,7 @@ OpcUaNodeId TmsClient::getRootDeviceNodeId() auto filter = BrowseFilter(); filter.referenceTypeId = OpcUaNodeId(0, UA_NS0ID_HASCOMPONENT); - filter.typeDefinition = OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQDEVICETYPE); + filter.typeDefinition = OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_DAQDEVICETYPE); const auto& references = tmsClientContext->getReferenceBrowser()->browseFiltered(rootNodeId, filter); diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_server.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_server.cpp index 0ca7e43..bd9a6a8 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_server.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_server.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include "test_helpers.h" #include @@ -79,7 +79,7 @@ TEST_F(TmsServerTest, Channels) auto timeSignal = BrowseForChild(client, signalsNode, "Time"); auto filter = BrowseFilter(); - filter.referenceTypeId = OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_HASDOMAINSIGNAL); + filter.referenceTypeId = OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASDOMAINSIGNAL); filter.direction = UA_BROWSEDIRECTION_FORWARD; auto references = referenceBrowser.browseFiltered(byteStepSignal, filter); From 498fcff683c3df63bf8dd0822fe2264e8eae97b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Thu, 7 Dec 2023 10:13:06 +0100 Subject: [PATCH 038/217] Replace ReferenceUtils with CachedReferenceBrowser --- .../src/objects/tms_client_property_object_impl.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index 24509d5..45ad234 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -166,10 +166,10 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par std::map& orderedProperties, std::vector& unorderedProperties) { - const auto introspectionVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_INTROSPECTIONVARIABLETYPE); - const auto structureVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_STRUCTUREVARIABLETYPE); - const auto referenceVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_REFERENCEVARIABLETYPE); - const auto variableBlockTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_VARIABLEBLOCKTYPE); + const auto introspectionVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_INTROSPECTIONVARIABLETYPE); + const auto structureVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_STRUCTUREVARIABLETYPE); + const auto referenceVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_REFERENCEVARIABLETYPE); + const auto variableBlockTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_VARIABLEBLOCKTYPE); const auto& references = clientContext->getReferenceBrowser()->browse(parentId); From 749e29d215f7f4173063d0e111a30746e44d4820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Thu, 21 Dec 2023 12:51:28 +0100 Subject: [PATCH 039/217] Implement opcua attribute collector --- .../include/opcuaclient/attribute_reader.h | 20 +- .../opcuaclient/cached_reference_browser.h | 1 + .../opcuaclient/src/attribute_reader.cpp | 78 ++--- .../src/cached_reference_browser.cpp | 19 +- .../tests/src/test_attribute_reader.cpp | 77 +++-- .../include/opcuashared/opcua_attribute.h | 18 ++ .../src/converters/base_object_converter.cpp | 5 +- .../tests/test_variant_list_converter.cpp | 23 +- .../objects/tms_client_component_impl.h | 2 + .../objects/tms_client_context.h | 15 +- .../objects/tms_client_object_impl.h | 4 +- .../objects/tms_client_property_object_impl.h | 11 +- .../objects/tms_client_signal_factory.h | 2 +- .../opcuatms_client/tms_attribute_collector.h | 67 +++++ .../include/opcuatms_client/tms_client.h | 2 +- .../opcuatms_client/src/CMakeLists.txt | 2 + .../src/objects/tms_client_context.cpp | 56 +++- .../src/objects/tms_client_device_impl.cpp | 73 +++-- .../src/objects/tms_client_folder_impl.cpp | 2 +- .../tms_client_function_block_impl.cpp | 11 +- .../src/objects/tms_client_io_folder_impl.cpp | 4 +- .../src/objects/tms_client_object_impl.cpp | 29 +- .../src/objects/tms_client_property_impl.cpp | 34 ++- .../tms_client_property_object_impl.cpp | 59 ++-- .../src/tms_attribute_collector.cpp | 284 ++++++++++++++++++ .../opcuatms_client/src/tms_client.cpp | 17 +- .../tests/test_client_context.cpp | 19 +- .../tests/test_tms_property_object.cpp | 24 ++ .../tms_object_integration_test.cpp | 5 +- .../tms_object_integration_test.h | 1 + 30 files changed, 773 insertions(+), 191 deletions(-) create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_attribute_collector.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/src/tms_attribute_collector.cpp diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/attribute_reader.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/attribute_reader.h index 309ec59..8a408ee 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/attribute_reader.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/attribute_reader.h @@ -18,6 +18,7 @@ #include #include #include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA @@ -29,22 +30,23 @@ class AttributeReader public: AttributeReader(const OpcUaClientPtr& client, size_t maxBatchSize = 0); + void setAttibutes(const tsl::ordered_set& attributes); void addAttribute(const OpcUaAttribute& attribute); - OpcUaDataValuePtr getValue(const OpcUaNodeId& nodeId, UA_AttributeId attributeId); - OpcUaDataValuePtr getValue(const OpcUaAttribute& attribute); - void reset(); + OpcUaVariant getValue(const OpcUaNodeId& nodeId, UA_AttributeId attributeId); + OpcUaVariant getValue(const OpcUaAttribute& attribute); + bool hasAnyValue(const OpcUaNodeId& nodeId); + void clearResults(); + void clearAttributes(); void read(); - const std::vector>& getResponses(); private: - using ResultMap = std::unordered_map>; + using ResultMap = std::unordered_map>; - size_t readBatch(size_t startIndex, size_t size); - void addBatchToResultMap(size_t startIndex, const OpcUaObject& response); + void readBatch(tsl::ordered_set::iterator& attrIterator, size_t size); + void addBatchToResultMap(tsl::ordered_set::iterator attrIterator, const OpcUaObject& response); OpcUaClientPtr client; - std::vector attributes; - std::vector> responses; + tsl::ordered_set attributes; ResultMap resultMap; size_t maxBatchSize = 0; }; diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h index a3241d7..64c4e41 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h @@ -52,6 +52,7 @@ class CachedReferenceBrowser void invalidate(const OpcUaNodeId& nodeId); bool isSubtypeOf(const OpcUaNodeId& typeId, const OpcUaNodeId& baseType); + OpcUaNodeId getTypeDefinition(const OpcUaNodeId& nodeId); bool hasReference(const OpcUaNodeId& nodeId, const std::string& browseName); OpcUaNodeId getChildNodeId(const OpcUaNodeId& nodeId, const std::string& browseName); CachedReferences browseFiltered(const OpcUaNodeId& nodeId, const BrowseFilter& filter); diff --git a/shared/libraries/opcua/opcuaclient/src/attribute_reader.cpp b/shared/libraries/opcua/opcuaclient/src/attribute_reader.cpp index cf76df4..9b88575 100644 --- a/shared/libraries/opcua/opcuaclient/src/attribute_reader.cpp +++ b/shared/libraries/opcua/opcuaclient/src/attribute_reader.cpp @@ -1,6 +1,7 @@ #include #include #include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA @@ -10,12 +11,17 @@ AttributeReader::AttributeReader(const OpcUaClientPtr& client, size_t maxBatchSi { } +void AttributeReader::setAttibutes(const tsl::ordered_set& attributes) +{ + this->attributes = attributes; +} + void AttributeReader::addAttribute(const OpcUaAttribute& attribute) { - attributes.push_back(attribute); + attributes.insert(attribute); } -OpcUaDataValuePtr AttributeReader::getValue(const OpcUaNodeId& nodeId, UA_AttributeId attributeId) +OpcUaVariant AttributeReader::getValue(const OpcUaNodeId& nodeId, UA_AttributeId attributeId) { if (resultMap.count(nodeId) == 0 || resultMap[nodeId].count(attributeId) == 0) throw OpcUaException(UA_STATUSCODE_BADNOTFOUND, "Attribute read result not found"); @@ -23,46 +29,51 @@ OpcUaDataValuePtr AttributeReader::getValue(const OpcUaNodeId& nodeId, UA_Attrib return resultMap[nodeId][attributeId]; } -OpcUaDataValuePtr AttributeReader::getValue(const OpcUaAttribute& attribute) +OpcUaVariant AttributeReader::getValue(const OpcUaAttribute& attribute) { return getValue(attribute.nodeId, attribute.attributeId); } -void AttributeReader::reset() +bool AttributeReader::hasAnyValue(const OpcUaNodeId& nodeId) { - attributes.clear(); - resultMap.clear(); - responses.clear(); + return resultMap.count(nodeId) > 0; } -void AttributeReader::read() +void AttributeReader::clearResults() { resultMap.clear(); - responses.clear(); +} + +void AttributeReader::clearAttributes() +{ + attributes.clear(); +} +void AttributeReader::read() +{ if (attributes.empty()) return; const size_t batchSize = (maxBatchSize > 0) ? maxBatchSize : attributes.size(); - const size_t numberOfBatches = std::ceil((double) attributes.size() / batchSize); - size_t i = 0; - responses.reserve(numberOfBatches); + size_t read = 0; + size_t toRead = batchSize; + auto attrIterator = attributes.begin(); - while (i < attributes.size()) - i += readBatch(i, batchSize); -} + while (read < attributes.size()) + { + toRead = batchSize; + if (read + toRead > attributes.size()) + toRead = attributes.size() - read; -const std::vector>& AttributeReader::getResponses() -{ - return responses; + readBatch(attrIterator, toRead); + read += toRead; + } } -size_t AttributeReader::readBatch(size_t startIndex, size_t size) +void AttributeReader::readBatch(tsl::ordered_set::iterator& attrIterator, size_t size) { - if ((startIndex + size) > attributes.size()) - size = attributes.size() - startIndex; - assert(size > 0); + auto batchStartIterator = attrIterator; OpcUaObject request; request->nodesToReadSize = size; @@ -70,36 +81,35 @@ size_t AttributeReader::readBatch(size_t startIndex, size_t size) for (size_t i = 0; i < size; i++) { - const auto& attribute = attributes[startIndex + i]; - + const auto& attribute = *attrIterator; request->nodesToRead[i].nodeId = attribute.nodeId.copyAndGetDetachedValue(); request->nodesToRead[i].attributeId = attribute.attributeId; + attrIterator++; } - responses.emplace_back(UA_Client_Service_read(client->getLockedUaClient(), *request)); - - const auto& response = responses.back(); + OpcUaObject response = UA_Client_Service_read(client->getLockedUaClient(), *request); const auto status = response->responseHeader.serviceResult; if (status != UA_STATUSCODE_GOOD) throw OpcUaException(status, "Attribute read request failed"); + if (response->resultsSize != size) + throw OpcUaException(UA_STATUSCODE_BADINVALIDSTATE, "Read request returned incorrect number of results"); - addBatchToResultMap(startIndex, response); - return size; + addBatchToResultMap(batchStartIterator, response); } -void AttributeReader::addBatchToResultMap(size_t startIndex, const OpcUaObject& response) +void AttributeReader::addBatchToResultMap(tsl::ordered_set::iterator attrIterator, + const OpcUaObject& response) { for (size_t i = 0; i < response->resultsSize; i++) { - const auto& attr = attributes[startIndex + i]; - - const auto value = std::make_shared(response->results + i); + const auto& attr = *attrIterator; if (resultMap.count(attr.nodeId) == 0) resultMap[attr.nodeId] = {}; - resultMap[attr.nodeId][attr.attributeId] = value; + resultMap[attr.nodeId][attr.attributeId] = OpcUaVariant(response->results[i].value); + attrIterator++; } } diff --git a/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp b/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp index 59b7827..dae3882 100644 --- a/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp +++ b/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp @@ -39,10 +39,12 @@ bool CachedReferenceBrowser::isSubtypeOf(const OpcUaNodeId& typeId, const OpcUaN { if (typeId == baseType) return true; + if (typeId.isNull()) + return false; - browse(baseType); + const auto& references = browse(baseType); - for (const auto& [refNodeId, ref] : references[baseType].byNodeId) + for (const auto& [refNodeId, ref] : references.byNodeId) { if (OpcUaNodeId(ref->referenceTypeId) == OpcUaNodeId(UA_NS0ID_HASSUBTYPE) && isSubtypeOf(typeId, refNodeId)) return true; @@ -51,6 +53,19 @@ bool CachedReferenceBrowser::isSubtypeOf(const OpcUaNodeId& typeId, const OpcUaN return false; } +OpcUaNodeId CachedReferenceBrowser::getTypeDefinition(const OpcUaNodeId& nodeId) +{ + const auto& references = browse(nodeId); + + for (const auto& [refNodeId, ref] : references.byNodeId) + { + if (OpcUaNodeId(ref->referenceTypeId) == OpcUaNodeId(UA_NS0ID_HASTYPEDEFINITION)) + return ref->nodeId.nodeId; + } + + return OpcUaNodeId(); +} + bool CachedReferenceBrowser::hasReference(const OpcUaNodeId& nodeId, const std::string& browseName) { browse(nodeId); diff --git a/shared/libraries/opcua/opcuaclient/tests/src/test_attribute_reader.cpp b/shared/libraries/opcua/opcuaclient/tests/src/test_attribute_reader.cpp index b57c1ee..bf62196 100644 --- a/shared/libraries/opcua/opcuaclient/tests/src/test_attribute_reader.cpp +++ b/shared/libraries/opcua/opcuaclient/tests/src/test_attribute_reader.cpp @@ -22,10 +22,10 @@ TEST_F(AttributeReaderTest, TwoAttributes) reader.addAttribute(attr2); reader.read(); - auto i64 = reader.getValue(attr1)->getValue().toInteger(); + auto i64 = reader.getValue(attr1).toInteger(); ASSERT_EQ(i64, 64); - auto i32 = reader.getValue(attr2)->getValue().toInteger(); + auto i32 = reader.getValue(attr2).toInteger(); ASSERT_EQ(i32, 41); } @@ -82,7 +82,7 @@ TEST_F(AttributeReaderTest, Clear) reader.addAttribute({idI64, UA_ATTRIBUTEID_VALUE}); reader.read(); - auto i64 = reader.getValue(idI64, UA_ATTRIBUTEID_VALUE)->getValue().toInteger(); + auto i64 = reader.getValue(idI64, UA_ATTRIBUTEID_VALUE).toInteger(); ASSERT_EQ(i64, 64); } @@ -110,7 +110,7 @@ TEST_F(AttributeReaderTest, SameAttribute) reader.addAttribute(attr); reader.read(); - auto i64 = reader.getValue(attr)->getValue().toInteger(); + auto i64 = reader.getValue(attr).toInteger(); ASSERT_EQ(i64, 64); } @@ -145,50 +145,87 @@ TEST_F(AttributeReaderTest, MaxNodesPerRead) OpcUaVariant variant; - variant = reader.getValue(idI64, UA_ATTRIBUTEID_VALUE)->getValue(); + variant = reader.getValue(idI64, UA_ATTRIBUTEID_VALUE); ASSERT_EQ(64, variant.toInteger()); - variant = reader.getValue(idI64, UA_ATTRIBUTEID_DISPLAYNAME)->getValue(); + variant = reader.getValue(idI64, UA_ATTRIBUTEID_DISPLAYNAME); ASSERT_EQ(".i64", variant.toString()); - variant = reader.getValue(idI32, UA_ATTRIBUTEID_VALUE)->getValue(); + variant = reader.getValue(idI32, UA_ATTRIBUTEID_VALUE); ASSERT_EQ(41, variant.toInteger()); - variant = reader.getValue(idI32, UA_ATTRIBUTEID_DISPLAYNAME)->getValue(); + variant = reader.getValue(idI32, UA_ATTRIBUTEID_DISPLAYNAME); ASSERT_EQ(".i32", variant.toString()); - variant = reader.getValue(idProductUri, UA_ATTRIBUTEID_VALUE)->getValue(); + variant = reader.getValue(idProductUri, UA_ATTRIBUTEID_VALUE); ASSERT_EQ("http://open62541.org", variant.toString()); - variant = reader.getValue(idProductUri, UA_ATTRIBUTEID_BROWSENAME)->getValue(); + variant = reader.getValue(idProductUri, UA_ATTRIBUTEID_BROWSENAME); ASSERT_EQ("ProductUri", variant.toString()); - variant = reader.getValue(idI16, UA_ATTRIBUTEID_VALUE)->getValue(); + variant = reader.getValue(idI16, UA_ATTRIBUTEID_VALUE); ASSERT_EQ(16, variant.toInteger()); } -TEST_F(AttributeReaderTest, GetResponses) +TEST_F(AttributeReaderTest, MultipleReads) { auto client = std::make_shared(getServerUrl()); client->connect(); - const size_t maxBatchSize = 2; const auto idI64 = OpcUaNodeId(1, ".i64"); + const auto idI32 = OpcUaNodeId(1, ".i32"); - auto reader = AttributeReader(client, maxBatchSize); + auto reader = AttributeReader(client); reader.addAttribute({idI64, UA_ATTRIBUTEID_VALUE}); - reader.addAttribute({idI64, UA_ATTRIBUTEID_DISPLAYNAME}); reader.addAttribute({idI64, UA_ATTRIBUTEID_BROWSENAME}); + reader.read(); - ASSERT_EQ(reader.getResponses().size(), 0); + reader.addAttribute({idI32, UA_ATTRIBUTEID_VALUE}); + reader.addAttribute({idI32, UA_ATTRIBUTEID_BROWSENAME}); + reader.read(); + + ASSERT_NO_THROW(reader.getValue({idI64, UA_ATTRIBUTEID_VALUE})); + ASSERT_NO_THROW(reader.getValue({idI64, UA_ATTRIBUTEID_BROWSENAME})); + ASSERT_NO_THROW(reader.getValue({idI32, UA_ATTRIBUTEID_VALUE})); + ASSERT_NO_THROW(reader.getValue({idI32, UA_ATTRIBUTEID_BROWSENAME})); +} +TEST_F(AttributeReaderTest, ClearAttributes) +{ + auto client = std::make_shared(getServerUrl()); + client->connect(); + + const auto idI64 = OpcUaNodeId(1, ".i64"); + const auto idI32 = OpcUaNodeId(1, ".i32"); + + auto reader = AttributeReader(client); + reader.addAttribute({idI64, UA_ATTRIBUTEID_VALUE}); + reader.clearAttributes(); + reader.addAttribute({idI64, UA_ATTRIBUTEID_BROWSENAME}); reader.read(); - const auto& responses = reader.getResponses(); + ASSERT_NO_THROW(reader.getValue({idI64, UA_ATTRIBUTEID_BROWSENAME})); + ASSERT_THROW(reader.getValue({idI64, UA_ATTRIBUTEID_VALUE}), OpcUaException); +} - ASSERT_EQ(responses.size(), 2); - ASSERT_EQ(responses[0]->resultsSize, 2); - ASSERT_EQ(responses[1]->resultsSize, 1); +TEST_F(AttributeReaderTest, ClearResults) +{ + auto client = std::make_shared(getServerUrl()); + client->connect(); + + const auto idI64 = OpcUaNodeId(1, ".i64"); + const auto idI32 = OpcUaNodeId(1, ".i32"); + + auto reader = AttributeReader(client); + reader.addAttribute({idI64, UA_ATTRIBUTEID_VALUE}); + reader.clearAttributes(); + reader.addAttribute({idI64, UA_ATTRIBUTEID_BROWSENAME}); + reader.read(); + + ASSERT_NO_THROW(reader.getValue({idI64, UA_ATTRIBUTEID_BROWSENAME})); + ASSERT_THROW(reader.getValue({idI64, UA_ATTRIBUTEID_VALUE}), OpcUaException); } + + END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcua_attribute.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcua_attribute.h index 6578f98..4bbefac 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcua_attribute.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcua_attribute.h @@ -31,6 +31,24 @@ struct OpcUaAttribute , attributeId(attributeId) { } + + bool operator==(const OpcUaAttribute& other) const + { + return nodeId == other.nodeId && attributeId == other.attributeId; + } }; END_NAMESPACE_OPENDAQ_OPCUA + +namespace std +{ + template <> + struct hash + { + size_t operator()(const daq::opcua::OpcUaAttribute& attr) const noexcept + { + size_t hash = UA_NodeId_hash(attr.nodeId.get()); + return UA_ByteString_hash(hash, (const UA_Byte*) &attr.attributeId, sizeof(UA_AttributeId)); + } + }; +} diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp index acd1c2a..198e8fb 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp @@ -113,14 +113,15 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtrgetElementInterfaceId(&elementId); - if (IntfID::Compare(elementId, IUnknown::Id) && list.getCount() > 0) + bool idUnknown = IntfID::Compare(elementId, IUnknown::Id) || IntfID::Compare(elementId, IBaseObject::Id); + if (idUnknown && list.getCount() > 0) elementId = list[0].asPtr().getInterfaceIds()[0]; auto var = converters::convertToArrayVariant(elementId, list, targetType, context); if (!var.isNull()) return var; - return ListConversionUtils::ToExtensionObjectArrayVariant(list, context); + return ListConversionUtils::ToVariantTypeArrayVariant(list, context); } template <> diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_variant_list_converter.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_variant_list_converter.cpp index dbedf28..8aafd73 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/test_variant_list_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/tests/test_variant_list_converter.cpp @@ -148,8 +148,10 @@ TEST_F(VariantListConverterTest, String) ASSERT_TRUE(eq); } -TEST_F(VariantListConverterTest, BaseObject) +TEST_F(VariantListConverterTest, DISABLED_MixedBaseObject) { + // disabled: only homogeneous lists are allowed for now + auto list = List(); list.pushBack(nullptr); list.pushBack(true); @@ -165,6 +167,21 @@ TEST_F(VariantListConverterTest, BaseObject) ASSERT_TRUE(eq); } +TEST_F(VariantListConverterTest, BaseObject) +{ + auto list = List(); + list.pushBack(1.5); + list.pushBack(2.5); + list.pushBack(3.5); + + const auto variant = VariantConverter::ToArrayVariant(list); + const auto listOut = VariantConverter::ToDaqList(variant); + + Bool eq{false}; + listOut->equals(list, &eq); + ASSERT_TRUE(eq); +} + TEST_F(VariantListConverterTest, DataDescriptor) { auto id = DataDescriptorBuilder().setSampleType(SampleType::Int32).setName("id").build(); @@ -267,8 +284,10 @@ TEST_F(VariantListConverterTest, Scaling) ASSERT_TRUE(eq); } -TEST_F(VariantListConverterTest, NonExtensionObjectTest) +TEST_F(VariantListConverterTest, DISABLED_NonExtensionObjectTest) { + // disabled: only homogeneous lists are allowed for now + constexpr size_t listSize = 3; auto list = List(); diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h index 50dd219..dbef6e8 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h @@ -38,6 +38,7 @@ class TmsClientComponentBaseImpl : public TmsClientPropertyObjectBaseImpl const opcua::OpcUaNodeId& nodeId) : TmsClientPropertyObjectBaseImpl(ctx, parent, localId, clientContext, nodeId) { + clientContext->readObjectAttributes(nodeId); } template = 0> @@ -49,6 +50,7 @@ class TmsClientComponentBaseImpl : public TmsClientPropertyObjectBaseImpl const FunctionBlockTypePtr& type) : TmsClientPropertyObjectBaseImpl(ctx, parent, localId, clientContext, nodeId, type) { + clientContext->readObjectAttributes(nodeId); } // Component overrides diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h index 87d4f7e..9f98f39 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h @@ -19,6 +19,9 @@ #include "opcuaclient/opcuaclient.h" #include #include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -28,7 +31,7 @@ using TmsClientContextPtr = std::shared_ptr; class TmsClientContext { public: - explicit TmsClientContext(const opcua::OpcUaClientPtr& client); + explicit TmsClientContext(const opcua::OpcUaClientPtr& client, const ContextPtr& context); const opcua::OpcUaClientPtr& getClient() const; @@ -37,6 +40,10 @@ class TmsClientContext BaseObjectPtr getObject(const opcua::OpcUaNodeId& nodeId) const; opcua::OpcUaNodeId getNodeId(const BaseObjectPtr object) const; CachedReferenceBrowserPtr getReferenceBrowser(); + AttributeReaderPtr getAttributeReader(); + void readObjectAttributes(const OpcUaNodeId& nodeId, bool forceRead = false); + size_t getMaxNodesPerBrowse(); + size_t getMaxNodesPerRead(); template ::SmartPtr> Ptr getObject(const opcua::OpcUaNodeId& nodeId) @@ -55,12 +62,18 @@ class TmsClientContext protected: opcua::OpcUaClientPtr client; + ContextPtr context; + LoggerComponentPtr loggerComponent; CachedReferenceBrowserPtr referenceBrowser; + AttributeReaderPtr attributeReader; mutable std::mutex mutex; // Context should not hold objects because of cycling reference std::unordered_map objects; + size_t maxNodesPerBrowse = 0; + size_t maxNodesPerRead = 0; void initReferenceBrowser(); + void initAttributeReader(); }; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h index 010512d..cb43ebf 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h @@ -40,8 +40,8 @@ class TmsClientObjectImpl void writeValue(const std::string& nodeName, const opcua::OpcUaVariant& value); opcua::OpcUaVariant readValue(const std::string& nodeName); virtual void subscriptionStatusChangeCallback(UA_StatusChangeNotification* notification); - uint32_t tryReadChildNumberInList(const std::string& nodeName); - uint32_t tryReadChildNumberInList(const opcua::OpcUaNodeId& nodeId); + uint32_t readChildNumberInList(const std::string& nodeName); + uint32_t readChildNumberInList(const opcua::OpcUaNodeId& nodeId); CachedReferences getChildReferencesOfType(const opcua::OpcUaNodeId& nodeId, const opcua::OpcUaNodeId& typeId); opcua::MonitoredItem* monitoredItemsCreateEvent( diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h index 1d47871..29a8ab4 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h @@ -48,7 +48,7 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl : TmsClientObjectImpl(daqContext, clientContext, nodeId) , Impl() { - browseRawProperties(); + init(); } template = 0> @@ -59,7 +59,7 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl : TmsClientObjectImpl(daqContext, clientContext, nodeId) , Impl(protocolId) { - browseRawProperties(); + init(); } template = 0> @@ -71,7 +71,7 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl : TmsClientObjectImpl(ctx, clientContext, nodeId) , Impl(ctx, parent, localId, nullptr, ComponentStandardProps::Skip) { - browseRawProperties(); + init(); } template = 0> @@ -84,9 +84,11 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl : TmsClientObjectImpl(ctx, clientContext, nodeId) , Impl(type, ctx, parent, localId, nullptr, ComponentStandardProps::Skip) { - browseRawProperties(); + init(); } + void init(); + ErrCode INTERFACE_FUNC setPropertyValue(IString* propertyName, IBaseObject* value) override; ErrCode INTERFACE_FUNC setProtectedPropertyValue(IString* propertyName, IBaseObject* value) override; ErrCode INTERFACE_FUNC getPropertyValue(IString* propertyName, IBaseObject** value) override; @@ -107,6 +109,7 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl std::unordered_map referenceVariableIdMap; std::unordered_map objectTypeIdMap; opcua::OpcUaNodeId methodParentNodeId; + LoggerComponentPtr loggerComponent; void addProperties(const OpcUaNodeId& parentId, std::map& orderedProperties, diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_factory.h index 26ca65a..3614dbf 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_factory.h @@ -50,7 +50,7 @@ inline SignalPtr FindOrCreateTmsClientSignal(const ContextPtr& ctx, SignalPtr clientSignal = clientContext->getObject(nodeId); if (!clientSignal.assigned()) { - auto localId = clientContext->getClient()->readBrowseName(nodeId); + auto localId = clientContext->getAttributeReader()->getValue(nodeId, UA_ATTRIBUTEID_BROWSENAME).toString(); clientSignal = TmsClientSignal(ctx, parent, localId, clientContext, nodeId); // TODO current client implementation limitation: The order of populating signals is important. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_attribute_collector.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_attribute_collector.h new file mode 100644 index 0000000..e3458a6 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_attribute_collector.h @@ -0,0 +1,67 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class TmsAttributeCollector +{ +public: + TmsAttributeCollector(const CachedReferenceBrowserPtr& browser); + + tsl::ordered_set collectAttributes(const OpcUaNodeId& nodeId); + +private: + void collectDeviceAttributes(const OpcUaNodeId& nodeId); + void collectFunctionBlockAttributes(const OpcUaNodeId& nodeId); + void collectInputPortAttributes(const OpcUaNodeId& nodeId); + void collectSignalAttributes(const OpcUaNodeId& nodeId); + void collectComponentAttributes(const OpcUaNodeId& nodeId); + void collectPropertyObjectAttributes(const OpcUaNodeId& nodeId); + void collectPropertyAttributes(const OpcUaNodeId& nodeId); + void collectEvaluationPropertyAttributes(const OpcUaNodeId& nodeId); + void collectBaseObjectAttributes(const OpcUaNodeId& nodeId); + void collectMethodAttributes(const OpcUaNodeId& nodeId); + + void collectIoNode(const OpcUaNodeId& nodeId); + void collectInputPortNode(const OpcUaNodeId& nodeId); + void collectFunctionBlockNode(const OpcUaNodeId& nodeId); + void collectSignalsNode(const OpcUaNodeId& nodeId); + void collectStreamingOptionsNode(const OpcUaNodeId& nodeId); + void collectMethodSetNode(const OpcUaNodeId& nodeId); + + bool isSubtypeOf(const OpcUaNodeId& typeId, const OpcUaNodeId& baseType); + bool typeEquals(const OpcUaNodeId& typeId, const OpcUaNodeId& baseType); + + CachedReferenceBrowserPtr browser; + tsl::ordered_set attributes; + + static const OpcUaNodeId NodeIdBaseObjectType; + static const OpcUaNodeId NodeIdBaseVariableType; + static const OpcUaNodeId NodeIdDeviceType; + static const OpcUaNodeId NodeIdFunctionBlockType; + static const OpcUaNodeId NodeIdComponentType; + static const OpcUaNodeId NodeIdSignalType; + static const OpcUaNodeId NodeIdInputPortType; + static const OpcUaNodeId NodeIdEvaluationVariableType; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h index 922ab5d..f6c6b74 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h @@ -35,7 +35,7 @@ class TmsClient final daq::DevicePtr connect(); protected: - daq::opcua::OpcUaNodeId getRootDeviceNodeId(); + void getRootDeviceNodeAttributes(OpcUaNodeId& nodeIdOut, std::string& browseNameOut); tms::TmsClientContextPtr tmsClientContext; ContextPtr context; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt index bb0cf40..f7e1bf1 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt @@ -1,12 +1,14 @@ set(LIB_NAME opcuatms_client) set(SRC_Cpp tms_client.cpp + tms_attribute_collector.cpp ) set(SRC_PublicHeaders ) set(SRC_PrivateHeaders tms_client.h + tms_attribute_collector.h ) # objects diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp index 0f5a767..001e212 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp @@ -1,14 +1,20 @@ #include "opcuatms_client/objects/tms_client_context.h" -#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS +using namespace daq; using namespace opcua; -TmsClientContext::TmsClientContext(const OpcUaClientPtr& client) +TmsClientContext::TmsClientContext(const opcua::OpcUaClientPtr& client, const ContextPtr& context) : client(client) + , context(context) + , loggerComponent(context.getLogger().assigned() ? context.getLogger().getOrAddComponent("TmsClientContext") + : throw ArgumentNullException("Logger must not be null")) { initReferenceBrowser(); + initAttributeReader(); } const opcua::OpcUaClientPtr& TmsClientContext::getClient() const @@ -55,10 +61,35 @@ CachedReferenceBrowserPtr TmsClientContext::getReferenceBrowser() return referenceBrowser; } -void TmsClientContext::initReferenceBrowser() +AttributeReaderPtr TmsClientContext::getAttributeReader() +{ + return attributeReader; +} + +void TmsClientContext::readObjectAttributes(const OpcUaNodeId& nodeId, bool forceRead) { - size_t maxNodesPerBrowse = 0; + if (!forceRead && attributeReader->hasAnyValue(nodeId)) + return; + + auto collector = TmsAttributeCollector(referenceBrowser); + auto attributes = collector.collectAttributes(nodeId); + + attributeReader->setAttibutes(attributes); + attributeReader->read(); +} + +size_t TmsClientContext::getMaxNodesPerBrowse() +{ + return maxNodesPerBrowse; +} + +size_t TmsClientContext::getMaxNodesPerRead() +{ + return maxNodesPerRead; +} +void TmsClientContext::initReferenceBrowser() +{ try { const auto maxNodesPerBrowseId = OpcUaNodeId(UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERBROWSE); @@ -66,10 +97,25 @@ void TmsClientContext::initReferenceBrowser() } catch (const std::exception& e) { - LOGW << "Failed to read maxNodesPerBrowse variable: " << e.what(); + LOG_W("Failed to read maxNodesPerBrowse variable: {}", e.what()); } referenceBrowser = std::make_shared(client, maxNodesPerBrowse); } +void TmsClientContext::initAttributeReader() +{ + try + { + const auto maxNodesPerReadId = OpcUaNodeId(UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERREAD); + maxNodesPerRead = client->readValue(maxNodesPerReadId).toInteger(); + } + catch (const std::exception& e) + { + LOG_W("Failed to read maxNodesPerRead variable: {}", e.what()); + } + + attributeReader = std::make_shared(client, maxNodesPerRead); +} + END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index bc38453..e3ba15e 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -66,6 +66,8 @@ TmsClientDeviceImpl::TmsClientDeviceImpl(const ContextPtr& ctx, ? this->logger.getOrAddComponent("TmsClientDevice") : throw ArgumentNullException("Logger must not be null")) { + clientContext->readObjectAttributes(nodeId); + findAndCreateSubdevices(); findAndCreateFunctionBlocks(); findAndCreateSignals(); @@ -89,7 +91,7 @@ void TmsClientDeviceImpl::findAndCreateSubdevices() auto subdeviceNodeId = OpcUaNodeId(ref->nodeId.nodeId); auto clientSubdevice = TmsClientDevice(context, devices, browseName, clientContext, subdeviceNodeId, createStreamingCallback); - auto numberInList = this->tryReadChildNumberInList(subdeviceNodeId); + auto numberInList = this->readChildNumberInList(subdeviceNodeId); if (numberInList != std::numeric_limits::max() && !orderedDevices.count(numberInList)) orderedDevices.insert(std::pair(numberInList, clientSubdevice)); else @@ -119,37 +121,46 @@ DeviceInfoPtr TmsClientDeviceImpl::onGetInfo() deviceInfo = DeviceInfo(""); - BrowseRequest request(nodeId, OpcUaNodeClass::Variable); - OpcUaBrowser browser(request, client); - const auto& browseResult = browser.browse(); + const auto& references = clientContext->getReferenceBrowser()->browse(nodeId); + auto reader = AttributeReader(client, clientContext->getMaxNodesPerRead()); + + for (const auto& [browseName, ref] : references.byBrowseName) + reader.addAttribute({ref->nodeId.nodeId, UA_ATTRIBUTEID_VALUE}); - for (const UA_ReferenceDescription& reference : browseResult) + reader.read(); + + for (const auto& [browseName, ref] : references.byBrowseName) { - std::string browseName = daq::opcua::utils::ToStdString(reference.browseName.name); + const auto refNodeId = OpcUaNodeId(ref->nodeId.nodeId); + const auto value = reader.getValue(refNodeId, UA_ATTRIBUTEID_VALUE); + if (detail::deviceInfoSetterMap.count(browseName)) - detail::deviceInfoSetterMap[browseName](deviceInfo, client->readValue(OpcUaNodeId(reference.nodeId.nodeId))); - else if (browseName != "NumberInList") { - // TODO: Group requests for data type and scalar/array checks and only read required values - try - { - auto value = client->readValue(OpcUaNodeId(reference.nodeId.nodeId)); - if (value.isScalar()) - { - if (value.isString()) - deviceInfo.addProperty(StringProperty(browseName, value.toString())); - else if(value.isBool()) - deviceInfo.addProperty(BoolProperty(browseName, value.toBool())); - else if(value.isDouble()) - deviceInfo.addProperty(FloatProperty(browseName, value.toDouble())); - else if(value.isInteger()) - deviceInfo.addProperty(IntProperty(browseName, value.toInteger())); - } - } - catch(...) + detail::deviceInfoSetterMap[browseName](deviceInfo, value); + continue; + } + + if (browseName == "NumberInList") + continue; + + try + { + if (value.isScalar()) { + if (value.isString()) + deviceInfo.addProperty(StringProperty(browseName, value.toString())); + else if (value.isBool()) + deviceInfo.addProperty(BoolProperty(browseName, value.toBool())); + else if (value.isDouble()) + deviceInfo.addProperty(FloatProperty(browseName, value.toDouble())); + else if (value.isInteger()) + deviceInfo.addProperty(IntProperty(browseName, value.toInteger())); } } + catch (const std::exception& e) + { + LOG_D("Failed to read device info attribute: {}", e.what()); + } } deviceInfo.freeze(); @@ -236,7 +247,7 @@ void TmsClientDeviceImpl::findAndCreateFunctionBlocks() try { auto clientFunctionBlock = TmsClientFunctionBlock(context, this->functionBlocks, browseName, clientContext, functionBlockNodeId); - const auto numberInList = this->tryReadChildNumberInList(functionBlockNodeId); + const auto numberInList = this->readChildNumberInList(functionBlockNodeId); if (numberInList != std::numeric_limits::max() && !orderedFunctionBlocks.count(numberInList)) orderedFunctionBlocks.insert(std::pair(numberInList, clientFunctionBlock)); else @@ -265,7 +276,7 @@ void TmsClientDeviceImpl::findAndCreateSignals() for (const auto& [signalNodeId, ref] : references.byNodeId) { auto clientSignal = FindOrCreateTmsClientSignal(context, signals, clientContext, signalNodeId); - const auto numberInList = this->tryReadChildNumberInList(signalNodeId); + const auto numberInList = this->readChildNumberInList(signalNodeId); if (numberInList != std::numeric_limits::max() && !orderedSignals.count(numberInList)) orderedSignals.insert(std::pair(numberInList, clientSignal)); else @@ -292,7 +303,7 @@ void TmsClientDeviceImpl::findAndCreateInputsOutputs() const auto channelNodeId = OpcUaNodeId(ref->nodeId.nodeId); auto tmsClientChannel = TmsClientChannel(context, this->ioFolder, browseName, clientContext, channelNodeId); - auto numberInList = this->tryReadChildNumberInList(channelNodeId); + auto numberInList = this->readChildNumberInList(channelNodeId); if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) orderedComponents.insert(std::pair(numberInList, tmsClientChannel)); else @@ -306,7 +317,7 @@ void TmsClientDeviceImpl::findAndCreateInputsOutputs() const auto folderNodeId = OpcUaNodeId(ref->nodeId.nodeId); auto tmsClientFolder = TmsClientIoFolder(context, this->ioFolder, browseName, clientContext, folderNodeId); - auto numberInList = this->tryReadChildNumberInList(folderNodeId); + auto numberInList = this->readChildNumberInList(folderNodeId); if (numberInList != std::numeric_limits::max()) orderedComponents.insert(std::pair(numberInList, tmsClientFolder)); else @@ -337,7 +348,7 @@ void TmsClientDeviceImpl::findAndCreateStreamingOptions() const auto optionNodeId = OpcUaNodeId(ref->nodeId.nodeId); auto clientStreamingInfo = TmsClientStreamingInfo(daqContext, browseName, clientContext, optionNodeId); - auto numberInList = this->tryReadChildNumberInList(optionNodeId); + auto numberInList = this->readChildNumberInList(optionNodeId); if (numberInList != std::numeric_limits::max()) orderedStreamings.insert(std::pair(numberInList, clientStreamingInfo)); else @@ -378,7 +389,7 @@ void TmsClientDeviceImpl::findAndCreateCustomComponents() else child = TmsClientComponent(context, this->thisPtr(), browseName, clientContext, folderNodeId); - auto numberInList = this->tryReadChildNumberInList(folderNodeId); + auto numberInList = this->readChildNumberInList(folderNodeId); if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) orderedComponents.insert(std::pair(numberInList, child)); else diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp index f6c310a..58089fd 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp @@ -48,7 +48,7 @@ void TmsClientFolderImpl::findAndCreateFolders(std::mapcontext, thisPtr, browseName, this->clientContext, folderNodeId); - auto numberInList = this->tryReadChildNumberInList(folderNodeId); + auto numberInList = this->readChildNumberInList(folderNodeId); if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) orderedComponents.insert(std::pair(numberInList, child)); else diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp index 557e6f8..22b4da3 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp @@ -21,6 +21,8 @@ TmsClientFunctionBlockBaseImpl::TmsClientFunctionBlockBaseImpl( ) : TmsClientComponentBaseImpl(context, parent, localId, clientContext, nodeId, nullptr) { + clientContext->readObjectAttributes(nodeId); + readFbType(); findAndCreateFunctionBlocks(); findAndCreateSignals(); @@ -55,7 +57,7 @@ void TmsClientFunctionBlockBaseImpl::findAndCreateFunctionBlocks() // just be ignored. It is not an error at all. auto clientFunctionBlock = TmsClientFunctionBlock(this->context, this->functionBlocks, browseName, this->clientContext, functionBlockNodeId); - const auto numberInList = this->tryReadChildNumberInList(functionBlockNodeId); + const auto numberInList = this->readChildNumberInList(functionBlockNodeId); if (numberInList != std::numeric_limits::max() && !orderedFunctionBlocks.count(numberInList)) orderedFunctionBlocks.insert(std::pair(numberInList, clientFunctionBlock)); else @@ -85,7 +87,7 @@ void TmsClientFunctionBlockBaseImpl::findAndCreateSignals() for (const auto& [signalNodeId, ref] : references.byNodeId) { auto clientSignal = FindOrCreateTmsClientSignal(this->context, this->signals, this->clientContext, signalNodeId); - const auto numberInList = this->tryReadChildNumberInList(signalNodeId); + const auto numberInList = this->readChildNumberInList(signalNodeId); if (numberInList != std::numeric_limits::max() && !orderedSignals.count(numberInList)) orderedSignals.insert(std::pair(numberInList, clientSignal)); else @@ -136,7 +138,7 @@ void TmsClientFunctionBlockBaseImpl::findAndCreateInputPorts() auto clientInputPort = TmsClientInputPort(this->context, this->inputPorts, browseName, this->clientContext, inputPortNodeId); - const auto numberInList = this->tryReadChildNumberInList(inputPortNodeId); + const auto numberInList = this->readChildNumberInList(inputPortNodeId); if (numberInList != std::numeric_limits::max() && !orderedInputPorts.count(numberInList)) orderedInputPorts.insert(std::pair(numberInList, clientInputPort)); else @@ -152,7 +154,8 @@ void TmsClientFunctionBlockBaseImpl::findAndCreateInputPorts() template void TmsClientFunctionBlockBaseImpl::readFbType() { - auto variant = this->readValue("FunctionBlockInfo"); + auto infoNodeId = this->getNodeId("FunctionBlockInfo"); + auto variant = this->clientContext->getAttributeReader()->getValue(infoNodeId, UA_ATTRIBUTEID_VALUE); this->type = VariantConverter::ToDaqObject(variant).detach(); } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp index 7e9b6e6..ac9aadc 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp @@ -38,7 +38,7 @@ void TmsClientIoFolderImpl::findAndCreateChannels(std::mapborrowPtr(); auto tmsClientChannel = TmsClientChannel(this->context, thisPtr, browseName, this->clientContext, channelNodeId); - auto numberInList = this->tryReadChildNumberInList(channelNodeId); + auto numberInList = this->readChildNumberInList(channelNodeId); if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) orderedComponents.insert(std::pair(numberInList, tmsClientChannel)); else @@ -56,7 +56,7 @@ void TmsClientIoFolderImpl::findAndCreateIoFolders(std::maptemplate borrowPtr(); auto tmsClientFolder = TmsClientIoFolder(this->context, thisPtr, browseName, this->clientContext, folderNodeId); - auto numberInList = this->tryReadChildNumberInList(folderNodeId); + auto numberInList = this->readChildNumberInList(folderNodeId); if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) orderedComponents.insert(std::pair(numberInList, tmsClientFolder)); else diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_object_impl.cpp index 8a8e642..a581b6c 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_object_impl.cpp @@ -77,32 +77,17 @@ void TmsClientObjectImpl::subscriptionStatusChangeCallback(UA_StatusChangeNotifi //TODO report on disconnect } -uint32_t TmsClientObjectImpl::tryReadChildNumberInList(const std::string& nodeName) +uint32_t TmsClientObjectImpl::readChildNumberInList(const std::string& nodeName) { - try - { - const auto childId = this->getNodeId(nodeName); - return tryReadChildNumberInList(childId); - } - catch(...) - { - } - - return std::numeric_limits::max(); + const auto childId = this->getNodeId(nodeName); + return readChildNumberInList(childId); } -uint32_t TmsClientObjectImpl::tryReadChildNumberInList(const opcua::OpcUaNodeId& nodeId) +uint32_t TmsClientObjectImpl::readChildNumberInList(const opcua::OpcUaNodeId& nodeId) { - try - { - const auto numberInListId = clientContext->getReferenceBrowser()->getChildNodeId(nodeId, "NumberInList"); - return VariantConverter::ToDaqObject(client->readValue(numberInListId)); - } - catch(...) - { - } - - return std::numeric_limits::max(); + const auto numberInListId = clientContext->getReferenceBrowser()->getChildNodeId(nodeId, "NumberInList"); + const auto variant = clientContext->getAttributeReader()->getValue(numberInListId, UA_ATTRIBUTEID_VALUE); + return VariantConverter::ToDaqObject(variant); } CachedReferences TmsClientObjectImpl::getChildReferencesOfType(const opcua::OpcUaNodeId& nodeId, const opcua::OpcUaNodeId& typeId) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp index bc215dc..12c2c43 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp @@ -43,24 +43,28 @@ namespace details TmsClientPropertyImpl::TmsClientPropertyImpl(const ContextPtr& daqContext, const TmsClientContextPtr& ctx, const opcua::OpcUaNodeId& nodeId) : TmsClientObjectImpl(daqContext, ctx, nodeId) { + clientContext->readObjectAttributes(nodeId); + readBasicInfo(); configurePropertyFields(); } void TmsClientPropertyImpl::readBasicInfo() { - const auto variant = client->readValue(nodeId); + auto reader = clientContext->getAttributeReader(); + const auto variant = reader->getValue(nodeId, UA_ATTRIBUTEID_VALUE); const auto object = VariantConverter::ToDaqObject(variant, daqContext); this->valueType = object.getCoreType(); - this->name = String(client->readDisplayName(nodeId)); - this->description = String(client->readDescription(nodeId)); + this->name = String(reader->getValue(nodeId, UA_ATTRIBUTEID_DISPLAYNAME).toString()); + this->description = String(reader->getValue(nodeId, UA_ATTRIBUTEID_DESCRIPTION).toString()); } void TmsClientPropertyImpl::configurePropertyFields() { const auto evaluationVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_EVALUATIONVARIABLETYPE); const auto& references = clientContext->getReferenceBrowser()->browse(nodeId); + const auto reader = clientContext->getAttributeReader(); for (auto [browseName, ref] : references.byBrowseName) { @@ -68,17 +72,17 @@ void TmsClientPropertyImpl::configurePropertyFields() if (browseName == "CoercionExpression") { - this->coercer = Coercer(VariantConverter::ToDaqObject(client->readValue(childNodeId))); + this->coercer = Coercer(VariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE))); } else if (browseName == "ValidationExpression") { - this->validator = Validator(VariantConverter::ToDaqObject(client->readValue(childNodeId))); + this->validator = Validator(VariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE))); } else if (clientContext->getReferenceBrowser()->isSubtypeOf(ref->typeDefinition.nodeId, evaluationVariableTypeId)) { auto evalId = clientContext->getReferenceBrowser()->getChildNodeId(childNodeId, "EvaluationExpression"); - StringPtr evalStr = VariantConverter::ToDaqObject(client->readValue(evalId)); + StringPtr evalStr = VariantConverter::ToDaqObject(reader->getValue(evalId, UA_ATTRIBUTEID_VALUE)); if (details::stringToPropertyFieldEnum.count(browseName)) { bool strHasValue = false; @@ -134,39 +138,41 @@ void TmsClientPropertyImpl::configurePropertyFields() switch (propertyField) { case details::PropertyField::DefaultValue: - this->defaultValue = VariantConverter::ToDaqObject(client->readValue(childNodeId), daqContext); + this->defaultValue = + VariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE), daqContext); if (this->defaultValue.assigned() && this->defaultValue.asPtrOrNull().assigned()) this->defaultValue.freeze(); break; case details::PropertyField::IsReadOnly: - this->readOnly = VariantConverter::ToDaqObject(client->readValue(childNodeId)); + this->readOnly = VariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE)); break; case details::PropertyField::IsVisible: - this->visible = VariantConverter::ToDaqObject(client->readValue(childNodeId)); + this->visible = VariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE)); break; case details::PropertyField::Unit: - this->unit = VariantConverter::ToDaqObject(client->readValue(childNodeId)); + this->unit = VariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE)); break; case details::PropertyField::MaxValue: - this->maxValue = VariantConverter::ToDaqObject(client->readValue(childNodeId)); + this->maxValue = VariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE)); break; case details::PropertyField::MinValue: - this->minValue = VariantConverter::ToDaqObject(client->readValue(childNodeId)); + this->minValue = VariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE)); break; case details::PropertyField::SuggestedValues: - this->suggestedValues = VariantConverter::ToDaqList(client->readValue(childNodeId), daqContext); + this->suggestedValues = + VariantConverter::ToDaqList(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE), daqContext); if (this->suggestedValues.assigned() && this->suggestedValues.asPtrOrNull().assigned()) this->suggestedValues.freeze(); break; case details::PropertyField::SelectionValues: - this->selectionValues = SelectionVariantConverter::ToDaqObject(client->readValue(childNodeId)); + this->selectionValues = SelectionVariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE)); if (this->selectionValues.assigned() && this->selectionValues.asPtrOrNull().assigned()) this->selectionValues.freeze(); break; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index 45ad234..d3c4aef 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -56,6 +56,17 @@ ErrCode TmsClientPropertyObjectBaseImpl::setPropertyValueInternal(IString* }); } +template +void TmsClientPropertyObjectBaseImpl::init() +{ + if (!this->daqContext.getLogger().assigned()) + throw ArgumentNullException("Logger must not be null"); + + this->loggerComponent = this->daqContext.getLogger().getOrAddComponent("TmsClientPropertyObject"); + clientContext->readObjectAttributes(nodeId); + browseRawProperties(); +} + template ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::setPropertyValue(IString* propertyName, IBaseObject* value) { @@ -187,7 +198,7 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par { if (!hasProp) { - StringPtr refPropEval = VariantConverter::ToDaqObject(client->readValue(childNodeId)); + StringPtr refPropEval = VariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE)); prop = ReferenceProperty(propName, EvalValue(refPropEval)); } @@ -210,7 +221,7 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par introspectionVariableIdMap.insert(std::pair(propName, childNodeId)); } - catch(...) + catch(const std::exception& e) { // TODO: Log failure to add function/procedure. continue; @@ -221,7 +232,8 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par if (!hasProp) { auto obj = TmsClientPropertyObject(daqContext, clientContext, childNodeId); - auto propBuilder = ObjectPropertyBuilder(propName, obj).setDescription(String(client->readDescription(childNodeId))); + const auto description = reader->getValue(childNodeId, UA_ATTRIBUTEID_DESCRIPTION).toString(); + auto propBuilder = ObjectPropertyBuilder(propName, obj).setDescription(String(description)); const auto evaluationVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_EVALUATIONVARIABLETYPE); const auto variableBlockRefs = clientContext->getReferenceBrowser()->browse(childNodeId); @@ -234,21 +246,21 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par { auto evalId = clientContext->getReferenceBrowser()->getChildNodeId(variableBlockNodeId, "EvaluationExpression"); - StringPtr evalStr = VariantConverter::ToDaqObject(client->readValue(evalId)); + StringPtr evalStr = VariantConverter::ToDaqObject(reader->getValue(evalId, UA_ATTRIBUTEID_VALUE)); if (browseName == "IsReadOnly") { if (evalStr.assigned()) propBuilder.setReadOnly(EvalValue(evalStr).asPtr()); else - propBuilder.setReadOnly(VariantConverter::ToDaqObject(client->readValue(variableBlockNodeId))); + propBuilder.setReadOnly(VariantConverter::ToDaqObject(reader->getValue(variableBlockNodeId, UA_ATTRIBUTEID_VALUE))); } else if (browseName == "IsVisible") { if (evalStr.assigned()) propBuilder.setVisible(EvalValue(evalStr).asPtr()); else - propBuilder.setVisible(VariantConverter::ToDaqObject(client->readValue(variableBlockNodeId))); + propBuilder.setVisible(VariantConverter::ToDaqObject(reader->getValue(variableBlockNodeId, UA_ATTRIBUTEID_VALUE))); } } } @@ -261,7 +273,7 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par if (prop.assigned()) { - auto numberInList = tryReadChildNumberInList(childNodeId); + auto numberInList = readChildNumberInList(childNodeId); if (numberInList != std::numeric_limits::max() && !orderedProperties.count(numberInList)) orderedProperties.insert(std::pair(numberInList, prop)); else @@ -276,7 +288,10 @@ void TmsClientPropertyObjectBaseImpl::addMethodProperties(const OpcUaNodeI std::vector& unorderedProperties, std::unordered_map& functionPropValues) { - const auto& references = clientContext->getReferenceBrowser()->browse(parentNodeId); + auto browser = clientContext->getReferenceBrowser(); + auto reader = clientContext->getAttributeReader(); + + const auto& references = browser->browse(parentNodeId); const auto methodTypeId = OpcUaNodeId(0, UA_NS0ID_METHODNODE); for (auto& [childNodeId, ref] : references.byNodeId) @@ -297,21 +312,27 @@ void TmsClientPropertyObjectBaseImpl::addMethodProperties(const OpcUaNodeI try { - if (clientContext->getReferenceBrowser()->hasReference(childNodeId, "InputArguments")) - inputArgs = VariantConverter::ToDaqList( - client->readValue(clientContext->getReferenceBrowser()->getChildNodeId(childNodeId, "InputArguments"))); + if (browser->hasReference(childNodeId, "InputArguments")) + { + const auto inputArgsId = browser->getChildNodeId(childNodeId, "InputArguments"); + inputArgs = VariantConverter::ToDaqList(reader->getValue(inputArgsId, UA_ATTRIBUTEID_VALUE)); + } - if (clientContext->getReferenceBrowser()->hasReference(childNodeId, "OutputArguments")) - outputArgs = VariantConverter::ToDaqList( - client->readValue(clientContext->getReferenceBrowser()->getChildNodeId(childNodeId, "OutputArguments"))); + if (browser->hasReference(childNodeId, "OutputArguments")) + { + const auto outputArgsId = browser->getChildNodeId(childNodeId, "OutputArguments"); + outputArgs = VariantConverter::ToDaqList(reader->getValue(outputArgsId, UA_ATTRIBUTEID_VALUE)); + } - if (clientContext->getReferenceBrowser()->hasReference(childNodeId, "NumberInList")) - numberInList = VariantConverter::ToDaqObject( - client->readValue(clientContext->getReferenceBrowser()->getChildNodeId(childNodeId, "NumberInList"))); + if (browser->hasReference(childNodeId, "NumberInList")) + { + const auto numberInListId = browser->getChildNodeId(childNodeId, "NumberInList"); + numberInList = VariantConverter::ToDaqObject(reader->getValue(numberInListId, UA_ATTRIBUTEID_VALUE)); + } } - catch(...) + catch(const std::exception& e) { - // TODO: Log failure to add function/procedure. + LOG_W("Failed to parse method properties {}", e.what()); continue; } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_attribute_collector.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_attribute_collector.cpp new file mode 100644 index 0000000..f26f48b --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_attribute_collector.cpp @@ -0,0 +1,284 @@ +#include +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +// Node ids + +const OpcUaNodeId TmsAttributeCollector::NodeIdBaseObjectType = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_DAQBASEOBJECTTYPE); +const OpcUaNodeId TmsAttributeCollector::NodeIdBaseVariableType = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_DAQBASEVARIABLETYPE); +const OpcUaNodeId TmsAttributeCollector::NodeIdDeviceType = OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQDEVICETYPE); +const OpcUaNodeId TmsAttributeCollector::NodeIdFunctionBlockType = OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_BASEFUNCTIONBLOCKTYPE); +const OpcUaNodeId TmsAttributeCollector::NodeIdComponentType = OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQCOMPONENTTYPE); +const OpcUaNodeId TmsAttributeCollector::NodeIdSignalType = OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_SIGNALTYPE); +const OpcUaNodeId TmsAttributeCollector::NodeIdInputPortType = OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_INPUTPORTTYPE); +const OpcUaNodeId TmsAttributeCollector::NodeIdEvaluationVariableType = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_EVALUATIONVARIABLETYPE); + +// TmsAttributeCollector + +TmsAttributeCollector::TmsAttributeCollector(const CachedReferenceBrowserPtr& browser) + : browser(browser) +{ +} + + +tsl::ordered_set TmsAttributeCollector::collectAttributes(const OpcUaNodeId& nodeId) +{ + attributes.clear(); + + const auto typeDefinition = browser->getTypeDefinition(nodeId); + + if (typeDefinition.isNull()) + return attributes; + + if (typeEquals(typeDefinition, NodeIdDeviceType)) + collectDeviceAttributes(nodeId); + else if (isSubtypeOf(typeDefinition, NodeIdFunctionBlockType)) + collectFunctionBlockAttributes(nodeId); + else if (typeEquals(typeDefinition, NodeIdSignalType)) + collectSignalAttributes(nodeId); + else if (typeEquals(typeDefinition, NodeIdInputPortType)) + collectInputPortAttributes(nodeId); + else if (isSubtypeOf(typeDefinition, NodeIdComponentType)) + collectComponentAttributes(nodeId); + else if (isSubtypeOf(typeDefinition, NodeIdBaseObjectType)) + collectPropertyObjectAttributes(nodeId); + else if (isSubtypeOf(typeDefinition, NodeIdBaseVariableType)) + collectPropertyAttributes(nodeId); + + return attributes; +} + +void TmsAttributeCollector::collectDeviceAttributes(const OpcUaNodeId& nodeId) +{ + collectPropertyObjectAttributes(nodeId); + + const auto& references = browser->browse(nodeId); + + for (const auto& [refNodeId, ref] : references.byNodeId) + { + if (typeEquals(ref->typeDefinition.nodeId, NodeIdDeviceType)) + collectDeviceAttributes(refNodeId); + else if (isSubtypeOf(ref->typeDefinition.nodeId, NodeIdComponentType)) + collectComponentAttributes(refNodeId); + } + + const auto ioNodeId = browser->getChildNodeId(nodeId, "IO"); + collectIoNode(ioNodeId); + + const auto fbNodeId = browser->getChildNodeId(nodeId, "FB"); + collectFunctionBlockNode(fbNodeId); + + const auto signalsNodeId = browser->getChildNodeId(nodeId, "Sig"); + collectSignalsNode(signalsNodeId); + + const auto inputPortsNodeId = browser->getChildNodeId(nodeId, "IP"); + collectInputPortNode(inputPortsNodeId); + + const auto streamingOptionsNodeId = browser->getChildNodeId(nodeId, "StreamingOptions"); + collectStreamingOptionsNode(streamingOptionsNodeId); + + const auto methodSetId = browser->getChildNodeId(nodeId, "MethodSet"); + collectMethodSetNode(methodSetId); +} + +void TmsAttributeCollector::collectFunctionBlockAttributes(const OpcUaNodeId& nodeId) +{ + collectPropertyObjectAttributes(nodeId); + + const auto fbInfoId = browser->getChildNodeId(nodeId, "FunctionBlockInfo"); + attributes.insert({fbInfoId, UA_ATTRIBUTEID_VALUE}); + + const auto& references = browser->browse(nodeId); + + for (const auto& [refNodeId, ref] : references.byNodeId) + { + if (isSubtypeOf(ref->typeDefinition.nodeId, NodeIdFunctionBlockType)) + collectFunctionBlockAttributes(refNodeId); + } + + const auto signalsNodeId = browser->getChildNodeId(nodeId, "Sig"); + collectSignalsNode(signalsNodeId); + + const auto inputPortsNodeId = browser->getChildNodeId(nodeId, "IP"); + collectInputPortNode(inputPortsNodeId); +} + +void TmsAttributeCollector::collectInputPortAttributes(const OpcUaNodeId& nodeId) +{ + collectBaseObjectAttributes(nodeId); +} + +void TmsAttributeCollector::collectSignalAttributes(const OpcUaNodeId& nodeId) +{ + collectBaseObjectAttributes(nodeId); + attributes.insert({nodeId, UA_ATTRIBUTEID_BROWSENAME}); +} + +void TmsAttributeCollector::collectComponentAttributes(const OpcUaNodeId& nodeId) +{ + collectPropertyObjectAttributes(nodeId); + + const auto& references = browser->browse(nodeId); + + for (const auto& [refNodeId, ref] : references.byNodeId) + { + if (isSubtypeOf(ref->typeDefinition.nodeId, NodeIdFunctionBlockType)) + collectFunctionBlockAttributes(refNodeId); + else if (isSubtypeOf(ref->typeDefinition.nodeId, NodeIdComponentType)) + collectComponentAttributes(refNodeId); + } +} + +void TmsAttributeCollector::collectPropertyObjectAttributes(const OpcUaNodeId& nodeId) +{ + collectBaseObjectAttributes(nodeId); + + attributes.insert({nodeId, UA_ATTRIBUTEID_DESCRIPTION}); + + const auto& references = browser->browse(nodeId); + + for (const auto& [refNodeId, ref] : references.byNodeId) + { + if (ref->nodeClass == UA_NODECLASS_METHOD) + collectMethodAttributes(refNodeId); + else if (typeEquals(ref->typeDefinition.nodeId, NodeIdEvaluationVariableType)) + collectEvaluationPropertyAttributes(refNodeId); + else if (isSubtypeOf(ref->typeDefinition.nodeId, NodeIdBaseObjectType)) + collectPropertyObjectAttributes(refNodeId); + else if (isSubtypeOf(ref->typeDefinition.nodeId, NodeIdBaseVariableType)) + collectPropertyAttributes(refNodeId); + } +} + +void TmsAttributeCollector::collectPropertyAttributes(const OpcUaNodeId& nodeId) +{ + collectBaseObjectAttributes(nodeId); + + attributes.insert({nodeId, UA_ATTRIBUTEID_VALUE}); + attributes.insert({nodeId, UA_ATTRIBUTEID_DISPLAYNAME}); + attributes.insert({nodeId, UA_ATTRIBUTEID_DESCRIPTION}); + + if (browser->hasReference(nodeId, "ValidationExpression")) + attributes.insert({browser->getChildNodeId(nodeId, "ValidationExpression"), UA_ATTRIBUTEID_VALUE}); + if (browser->hasReference(nodeId, "CoercionExpression")) + attributes.insert({browser->getChildNodeId(nodeId, "CoercionExpression"), UA_ATTRIBUTEID_VALUE}); + + const auto& references = browser->browse(nodeId); + + for (const auto& [refNodeId, ref] : references.byNodeId) + { + if (typeEquals(ref->typeDefinition.nodeId, NodeIdEvaluationVariableType)) + collectEvaluationPropertyAttributes(refNodeId); + else if (isSubtypeOf(ref->typeDefinition.nodeId, NodeIdBaseVariableType)) + collectPropertyAttributes(refNodeId); + } +} + +void TmsAttributeCollector::collectEvaluationPropertyAttributes(const OpcUaNodeId& nodeId) +{ + attributes.insert({nodeId, UA_ATTRIBUTEID_VALUE}); + + const auto evalValueId = browser->getChildNodeId(nodeId, "EvaluationExpression"); + attributes.insert({evalValueId, UA_ATTRIBUTEID_VALUE}); +} + +void TmsAttributeCollector::collectBaseObjectAttributes(const OpcUaNodeId& nodeId) +{ + attributes.insert({nodeId, UA_ATTRIBUTEID_NODECLASS}); + + const auto numberInListId = browser->getChildNodeId(nodeId, "NumberInList"); + attributes.insert({numberInListId, UA_ATTRIBUTEID_VALUE}); +} + +void TmsAttributeCollector::collectMethodAttributes(const OpcUaNodeId& nodeId) +{ + if (browser->hasReference(nodeId, "InputArguments")) + attributes.insert({browser->getChildNodeId(nodeId, "InputArguments"), UA_ATTRIBUTEID_VALUE}); + if (browser->hasReference(nodeId, "OutputArguments")) + attributes.insert({browser->getChildNodeId(nodeId, "OutputArguments"), UA_ATTRIBUTEID_VALUE}); + if (browser->hasReference(nodeId, "NumberInList")) + attributes.insert({browser->getChildNodeId(nodeId, "NumberInList"), UA_ATTRIBUTEID_VALUE}); +} + +void TmsAttributeCollector::collectIoNode(const OpcUaNodeId& nodeId) +{ + const auto& references = browser->browse(nodeId); + + for (const auto& [refNodeId, ref] : references.byNodeId) + { + if (isSubtypeOf(ref->typeDefinition.nodeId, NodeIdFunctionBlockType)) + collectFunctionBlockAttributes(refNodeId); + else if (isSubtypeOf(ref->typeDefinition.nodeId, NodeIdComponentType)) + collectComponentAttributes(refNodeId); + } +} + +void TmsAttributeCollector::collectInputPortNode(const OpcUaNodeId& nodeId) +{ + const auto& references = browser->browse(nodeId); + + for (const auto& [refNodeId, ref] : references.byNodeId) + { + if (typeEquals(ref->typeDefinition.nodeId, NodeIdInputPortType)) + collectInputPortAttributes(refNodeId); + } +} + +void TmsAttributeCollector::collectFunctionBlockNode(const OpcUaNodeId& nodeId) +{ + const auto& references = browser->browse(nodeId); + + for (const auto& [refNodeId, ref] : references.byNodeId) + { + if (isSubtypeOf(ref->typeDefinition.nodeId, NodeIdFunctionBlockType)) + collectFunctionBlockAttributes(refNodeId); + } +} + +void TmsAttributeCollector::collectSignalsNode(const OpcUaNodeId& nodeId) +{ + const auto& signalReferences = browser->browse(nodeId); + + for (const auto& [refNodeId, ref] : signalReferences.byNodeId) + { + if (typeEquals(ref->typeDefinition.nodeId, NodeIdSignalType)) + collectSignalAttributes(refNodeId); + } +} + +void TmsAttributeCollector::collectStreamingOptionsNode(const OpcUaNodeId& nodeId) +{ + const auto& references = browser->browse(nodeId); + + for (const auto& [refNodeId, ref] : references.byNodeId) + { + if (isSubtypeOf(ref->typeDefinition.nodeId, NodeIdBaseVariableType)) + collectPropertyAttributes(refNodeId); + } +} + +void TmsAttributeCollector::collectMethodSetNode(const OpcUaNodeId& nodeId) +{ + const auto& references = browser->browse(nodeId); + + for (const auto& [refNodeId, ref] : references.byNodeId) + { + if (ref->nodeClass == UA_NODECLASS_METHOD) + collectMethodAttributes(refNodeId); + } +} + +bool TmsAttributeCollector::isSubtypeOf(const OpcUaNodeId& typeId, const OpcUaNodeId& baseType) +{ + return browser->isSubtypeOf(typeId, baseType); +} + +bool TmsAttributeCollector::typeEquals(const OpcUaNodeId& typeId, const OpcUaNodeId& baseType) +{ + return typeId == baseType; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp index 5ac2bc6..47c5041 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -13,6 +12,7 @@ #include +#include using namespace daq::opcua; using namespace daq::opcua::tms; @@ -52,13 +52,13 @@ daq::DevicePtr TmsClient::connect() throw NotFoundException(); client->runIterate(); - tmsClientContext = std::make_shared(client); + tmsClientContext = std::make_shared(client, context); - auto rootDeviceNodeId = getRootDeviceNodeId(); - - BrowseRequest request(rootDeviceNodeId, OpcUaNodeClass::Variable); - auto localId = getUniqueLocalId(client->readBrowseName(rootDeviceNodeId)); + OpcUaNodeId rootDeviceNodeId; + std::string rootDeviceBrowseName; + getRootDeviceNodeAttributes(rootDeviceNodeId, rootDeviceBrowseName); + const auto localId = getUniqueLocalId(rootDeviceBrowseName); auto device = TmsClientRootDevice(context, parent, localId, tmsClientContext, rootDeviceNodeId, createStreamingCallback); const auto deviceInfo = device.getInfo(); @@ -79,7 +79,7 @@ daq::DevicePtr TmsClient::connect() return device; } -OpcUaNodeId TmsClient::getRootDeviceNodeId() +void TmsClient::getRootDeviceNodeAttributes(OpcUaNodeId& nodeIdOut, std::string& browseNameOut) { const OpcUaNodeId rootNodeId(NAMESPACE_DI, UA_DIID_DEVICESET); @@ -92,7 +92,8 @@ OpcUaNodeId TmsClient::getRootDeviceNodeId() if (references.byNodeId.empty()) throw NotFoundException(); - return references.byNodeId.begin().key(); + nodeIdOut = OpcUaNodeId(references.byBrowseName.begin().value()->nodeId.nodeId); + browseNameOut = references.byBrowseName.begin().key(); } StringPtr TmsClient::getUniqueLocalId(const StringPtr& localId, int iteration) diff --git a/shared/libraries/opcuatms/opcuatms_client/tests/test_client_context.cpp b/shared/libraries/opcuatms/opcuatms_client/tests/test_client_context.cpp index 2cd1aaf..feafa12 100644 --- a/shared/libraries/opcuatms/opcuatms_client/tests/test_client_context.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/tests/test_client_context.cpp @@ -1,5 +1,6 @@ #include #include +#include using namespace daq::opcua; using namespace daq::opcua::tms; @@ -15,13 +16,15 @@ static OpcUaClientPtr CreateClient() TEST_F(ClientContextTest, Create) { auto client = CreateClient(); - ASSERT_NO_THROW(TmsClientContext clientContext(client)); + auto context = NullContext(); + ASSERT_NO_THROW(TmsClientContext clientContext(client, context)); } TEST_F(ClientContextTest, RegisterObject) { auto client = CreateClient(); - TmsClientContext clientContext(client); + auto context = NullContext(); + TmsClientContext clientContext(client, context); StringPtr str = "TestStrObject"; ASSERT_NO_THROW(clientContext.registerObject(OpcUaNodeId(1, 1), str)); @@ -30,7 +33,8 @@ TEST_F(ClientContextTest, RegisterObject) TEST_F(ClientContextTest, ContextGetObject) { auto client = CreateClient(); - TmsClientContext clientContext(client); + auto context = NullContext(); + TmsClientContext clientContext(client, context); BaseObjectPtr baseObj; ASSERT_NO_THROW(baseObj = clientContext.getObject(OpcUaNodeId(1, 1))); @@ -47,7 +51,8 @@ TEST_F(ClientContextTest, ContextGetObject) TEST_F(ClientContextTest, ContextGetObjectTemplate) { auto client = CreateClient(); - TmsClientContext clientContext(client); + auto context = NullContext(); + TmsClientContext clientContext(client, context); StringPtr strObj; ASSERT_NO_THROW(strObj = clientContext.getObject(OpcUaNodeId(1, 1))); @@ -68,7 +73,8 @@ TEST_F(ClientContextTest, ContextGetObjectTemplate) TEST_F(ClientContextTest, UnregisterObject) { auto client = CreateClient(); - TmsClientContext clientContext(client); + auto context = NullContext(); + TmsClientContext clientContext(client, context); ASSERT_NO_THROW(clientContext.unregisterObject(OpcUaNodeId(1, 1))); @@ -90,7 +96,8 @@ TEST_F(ClientContextTest, TestRefCount) }; auto client = CreateClient(); - TmsClientContext clientContext(client); + auto context = NullContext(); + TmsClientContext clientContext(client, context); StringPtr str = "TestStrObject"; ASSERT_EQ(getRefCount(str), 1); diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_property_object.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_property_object.cpp index 71128e3..45be290 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_property_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_property_object.cpp @@ -36,6 +36,30 @@ TEST_F(TmsPropertyObjectTest, Create) auto tmsPropertyObject = TmsServerPropertyObject(propertyObject, this->getServer(), NullContext()); } +TEST_F(TmsPropertyObjectTest, BaseObjectList) +{ + GenericPropertyObjectPtr object = PropertyObject(); + + auto list = List(); + list.pushBack(1.0); + list.pushBack(2.0); + list.pushBack(3.0); + object.addProperty(ListProperty("ListProp", list)); + + auto tmsPropertyObject = TmsServerPropertyObject(object, this->getServer(), NullContext()); + auto nodeId = tmsPropertyObject.registerOpcUaNode(); + + OpcUaObject request; + request->nodesToReadSize = 1; + request->nodesToRead = (UA_ReadValueId*) UA_Array_new(1, &UA_TYPES[UA_TYPES_READVALUEID]); + request->nodesToRead[0].nodeId = nodeId.getDetachedValue(); + request->nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE; + + OpcUaObject response = UA_Client_Service_read(client->getLockedUaClient(), *request); + const auto status = response->responseHeader.serviceResult; + ASSERT_TRUE(status == UA_STATUSCODE_GOOD); +} + TEST_F(TmsPropertyObjectTest, Register) { PropertyObjectPtr propertyObject = createPropertyObject(); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp index 799f298..d025837 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp @@ -1,5 +1,7 @@ #include "tms_object_integration_test.h" +#include +using namespace daq; using namespace daq::opcua; using namespace daq::opcua::tms; @@ -12,7 +14,8 @@ void TmsObjectIntegrationTest::SetUp() { TmsObjectTest::SetUp(); - clientContext = std::make_shared(client); + context = NullContext(); + clientContext = std::make_shared(client, context); } void TmsObjectIntegrationTest::TearDown() diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h index ec9c450..46ff4e3 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h @@ -27,5 +27,6 @@ class TmsObjectIntegrationTest : public TmsObjectTest void TearDown() override; protected: + daq::ContextPtr context; daq::opcua::tms::TmsClientContextPtr clientContext; }; From 4edca722cfd8db476e83ba3315589ea153eee365 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Wed, 27 Dec 2023 13:49:09 +0100 Subject: [PATCH 040/217] Fix merge conflicts --- .../tms_client_property_object_impl.cpp | 9 ++++---- .../src/tms_attribute_collector.cpp | 22 +++++++++---------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index d3c4aef..d47a938 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -177,11 +177,12 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par std::map& orderedProperties, std::vector& unorderedProperties) { - const auto introspectionVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_INTROSPECTIONVARIABLETYPE); - const auto structureVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_STRUCTUREVARIABLETYPE); - const auto referenceVariableTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_REFERENCEVARIABLETYPE); - const auto variableBlockTypeId = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_VARIABLEBLOCKTYPE); + const auto introspectionVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_INTROSPECTIONVARIABLETYPE); + const auto structureVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_STRUCTUREVARIABLETYPE); + const auto referenceVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_REFERENCEVARIABLETYPE); + const auto variableBlockTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_VARIABLEBLOCKTYPE); + auto reader = clientContext->getAttributeReader(); const auto& references = clientContext->getReferenceBrowser()->browse(parentId); for (auto& [childNodeId, ref] : references.byNodeId) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_attribute_collector.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_attribute_collector.cpp index f26f48b..0a205df 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_attribute_collector.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_attribute_collector.cpp @@ -1,20 +1,20 @@ #include -#include -#include -#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS // Node ids -const OpcUaNodeId TmsAttributeCollector::NodeIdBaseObjectType = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_DAQBASEOBJECTTYPE); -const OpcUaNodeId TmsAttributeCollector::NodeIdBaseVariableType = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_DAQBASEVARIABLETYPE); -const OpcUaNodeId TmsAttributeCollector::NodeIdDeviceType = OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQDEVICETYPE); -const OpcUaNodeId TmsAttributeCollector::NodeIdFunctionBlockType = OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_BASEFUNCTIONBLOCKTYPE); -const OpcUaNodeId TmsAttributeCollector::NodeIdComponentType = OpcUaNodeId(NAMESPACE_TMSDEVICE, UA_TMSDEVICEID_DAQCOMPONENTTYPE); -const OpcUaNodeId TmsAttributeCollector::NodeIdSignalType = OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_SIGNALTYPE); -const OpcUaNodeId TmsAttributeCollector::NodeIdInputPortType = OpcUaNodeId(NAMESPACE_TMSBSP, UA_TMSBSPID_INPUTPORTTYPE); -const OpcUaNodeId TmsAttributeCollector::NodeIdEvaluationVariableType = OpcUaNodeId(NAMESPACE_TMSBT, UA_TMSBTID_EVALUATIONVARIABLETYPE); +const OpcUaNodeId TmsAttributeCollector::NodeIdBaseObjectType = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_DAQBASEOBJECTTYPE); +const OpcUaNodeId TmsAttributeCollector::NodeIdBaseVariableType = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_DAQBASEVARIABLETYPE); +const OpcUaNodeId TmsAttributeCollector::NodeIdDeviceType = OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_DAQDEVICETYPE); +const OpcUaNodeId TmsAttributeCollector::NodeIdFunctionBlockType = OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_BASEFUNCTIONBLOCKTYPE); +const OpcUaNodeId TmsAttributeCollector::NodeIdComponentType = OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_DAQCOMPONENTTYPE); +const OpcUaNodeId TmsAttributeCollector::NodeIdSignalType = OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_SIGNALTYPE); +const OpcUaNodeId TmsAttributeCollector::NodeIdInputPortType = OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_INPUTPORTTYPE); +const OpcUaNodeId TmsAttributeCollector::NodeIdEvaluationVariableType = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_EVALUATIONVARIABLETYPE); // TmsAttributeCollector From 886ba48dcdf9f848adef2cc0cc09266ba38f221f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Wed, 27 Dec 2023 15:10:10 +0100 Subject: [PATCH 041/217] Raise log level --- .../opcuatms_client/src/objects/tms_client_device_impl.cpp | 2 +- .../src/objects/tms_client_property_object_impl.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index e3ba15e..a44ba9c 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -159,7 +159,7 @@ DeviceInfoPtr TmsClientDeviceImpl::onGetInfo() } catch (const std::exception& e) { - LOG_D("Failed to read device info attribute: {}", e.what()); + LOG_W("Failed to read device info attribute: {}", e.what()); } } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index d47a938..50a48c5 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -206,9 +206,9 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par referenceVariableIdMap.insert(std::pair(propName, childNodeId)); addProperties(childNodeId, orderedProperties, unorderedProperties); } - catch(...) + catch(const std::exception& e) { - // TODO: Log failure to add function/procedure. + LOG_W("Failed to add reference property {}", e.what()); continue; } } @@ -224,7 +224,7 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par } catch(const std::exception& e) { - // TODO: Log failure to add function/procedure. + LOG_W("Failed to add property {}", e.what()); continue; } } From 9b1fc8f720f1c485448d33ae5b8ee48c08b1899a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Thu, 28 Dec 2023 13:08:53 +0100 Subject: [PATCH 042/217] Batch nodes across multiple browse requests --- .../include/opcuaclient/cached_reference_browser.h | 2 +- .../opcuaclient/src/cached_reference_browser.cpp | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h index 64c4e41..75592bc 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h @@ -61,7 +61,7 @@ class CachedReferenceBrowser bool isCached(const OpcUaNodeId& nodeId); void markAsCached(const OpcUaNodeId& nodeId); void browseMultiple(const std::vector& nodes); - size_t browseBatch(const std::vector& nodes, size_t startIndex, size_t size); + size_t browseBatch(const std::vector& nodes, size_t startIndex, size_t size, std::vector& browseNext); void processBrowseResults(const std::vector& nodes, size_t startIndex, size_t requestedSize, diff --git a/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp b/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp index dae3882..83ec792 100644 --- a/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp +++ b/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp @@ -118,13 +118,20 @@ void CachedReferenceBrowser::markAsCached(const OpcUaNodeId& nodeId) void CachedReferenceBrowser::browseMultiple(const std::vector& nodes) { const size_t batchSize = (maxNodesPerBrowse > 0) ? maxNodesPerBrowse : nodes.size(); + std::vector browseNext; size_t i = 0; while (i < nodes.size()) - i += browseBatch(nodes, i, batchSize); + i += browseBatch(nodes, i, batchSize, browseNext); + + if (!browseNext.empty()) + browseMultiple(browseNext); } -size_t CachedReferenceBrowser::browseBatch(const std::vector& nodes, size_t startIndex, size_t size) +size_t CachedReferenceBrowser::browseBatch(const std::vector& nodes, + size_t startIndex, + size_t size, + std::vector& browseNext) { if ((startIndex + size) > nodes.size()) size = nodes.size() - startIndex; @@ -146,7 +153,6 @@ size_t CachedReferenceBrowser::browseBatch(const std::vector& nodes request->nodesToBrowse[i].browseDirection = UA_BROWSEDIRECTION_FORWARD; } - std::vector browseNext; UA_ByteString* continuationPoint = nullptr; OpcUaObject response = UA_Client_Service_browse(client->getLockedUaClient(), *request); CheckStatusCodeException(response->responseHeader.serviceResult, "Browse result error"); @@ -165,7 +171,6 @@ size_t CachedReferenceBrowser::browseBatch(const std::vector& nodes processBrowseResults(nodes, startIndex, size, nextResponse->results, nextResponse->resultsSize, browseNext); } - browseMultiple(browseNext); return size; } From 29366b482a27fe9eb19d14b69fade4e80b57d0f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Wed, 3 Jan 2024 14:42:06 +0100 Subject: [PATCH 043/217] Correctly browse StreamingOptions node --- .../include/opcuatms_client/tms_attribute_collector.h | 2 ++ .../opcuatms_client/src/tms_attribute_collector.cpp | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_attribute_collector.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_attribute_collector.h index e3458a6..b0eb085 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_attribute_collector.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_attribute_collector.h @@ -40,6 +40,7 @@ class TmsAttributeCollector void collectEvaluationPropertyAttributes(const OpcUaNodeId& nodeId); void collectBaseObjectAttributes(const OpcUaNodeId& nodeId); void collectMethodAttributes(const OpcUaNodeId& nodeId); + void collectVariableBlockAttributes(const OpcUaNodeId& nodeId); void collectIoNode(const OpcUaNodeId& nodeId); void collectInputPortNode(const OpcUaNodeId& nodeId); @@ -62,6 +63,7 @@ class TmsAttributeCollector static const OpcUaNodeId NodeIdSignalType; static const OpcUaNodeId NodeIdInputPortType; static const OpcUaNodeId NodeIdEvaluationVariableType; + static const OpcUaNodeId NodeIdVariableBlockType; }; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_attribute_collector.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_attribute_collector.cpp index 0a205df..04c95ae 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_attribute_collector.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_attribute_collector.cpp @@ -15,6 +15,7 @@ const OpcUaNodeId TmsAttributeCollector::NodeIdComponentType = OpcUaNodeId(NAMES const OpcUaNodeId TmsAttributeCollector::NodeIdSignalType = OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_SIGNALTYPE); const OpcUaNodeId TmsAttributeCollector::NodeIdInputPortType = OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_INPUTPORTTYPE); const OpcUaNodeId TmsAttributeCollector::NodeIdEvaluationVariableType = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_EVALUATIONVARIABLETYPE); +const OpcUaNodeId TmsAttributeCollector::NodeIdVariableBlockType = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_VARIABLEBLOCKTYPE); // TmsAttributeCollector @@ -203,6 +204,11 @@ void TmsAttributeCollector::collectMethodAttributes(const OpcUaNodeId& nodeId) attributes.insert({browser->getChildNodeId(nodeId, "NumberInList"), UA_ATTRIBUTEID_VALUE}); } +void TmsAttributeCollector::collectVariableBlockAttributes(const OpcUaNodeId& nodeId) +{ + collectPropertyObjectAttributes(nodeId); +} + void TmsAttributeCollector::collectIoNode(const OpcUaNodeId& nodeId) { const auto& references = browser->browse(nodeId); @@ -255,8 +261,8 @@ void TmsAttributeCollector::collectStreamingOptionsNode(const OpcUaNodeId& nodeI for (const auto& [refNodeId, ref] : references.byNodeId) { - if (isSubtypeOf(ref->typeDefinition.nodeId, NodeIdBaseVariableType)) - collectPropertyAttributes(refNodeId); + if (typeEquals(ref->typeDefinition.nodeId, NodeIdVariableBlockType)) + collectVariableBlockAttributes(refNodeId); } } From 4df95ee9174de4adfce34dec4a837c34707965e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Fri, 5 Jan 2024 10:55:56 +0100 Subject: [PATCH 044/217] Add try statement when reading number in list --- .../objects/tms_client_object_impl.h | 4 ++-- .../src/objects/tms_client_device_impl.cpp | 14 ++++++------- .../src/objects/tms_client_folder_impl.cpp | 2 +- .../tms_client_function_block_impl.cpp | 6 +++--- .../src/objects/tms_client_io_folder_impl.cpp | 4 ++-- .../src/objects/tms_client_object_impl.cpp | 20 +++++++++++++------ .../tms_client_property_object_impl.cpp | 2 +- 7 files changed, 30 insertions(+), 22 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h index cb43ebf..010512d 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h @@ -40,8 +40,8 @@ class TmsClientObjectImpl void writeValue(const std::string& nodeName, const opcua::OpcUaVariant& value); opcua::OpcUaVariant readValue(const std::string& nodeName); virtual void subscriptionStatusChangeCallback(UA_StatusChangeNotification* notification); - uint32_t readChildNumberInList(const std::string& nodeName); - uint32_t readChildNumberInList(const opcua::OpcUaNodeId& nodeId); + uint32_t tryReadChildNumberInList(const std::string& nodeName); + uint32_t tryReadChildNumberInList(const opcua::OpcUaNodeId& nodeId); CachedReferences getChildReferencesOfType(const opcua::OpcUaNodeId& nodeId, const opcua::OpcUaNodeId& typeId); opcua::MonitoredItem* monitoredItemsCreateEvent( diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index a44ba9c..14671c5 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -91,7 +91,7 @@ void TmsClientDeviceImpl::findAndCreateSubdevices() auto subdeviceNodeId = OpcUaNodeId(ref->nodeId.nodeId); auto clientSubdevice = TmsClientDevice(context, devices, browseName, clientContext, subdeviceNodeId, createStreamingCallback); - auto numberInList = this->readChildNumberInList(subdeviceNodeId); + auto numberInList = this->tryReadChildNumberInList(subdeviceNodeId); if (numberInList != std::numeric_limits::max() && !orderedDevices.count(numberInList)) orderedDevices.insert(std::pair(numberInList, clientSubdevice)); else @@ -247,7 +247,7 @@ void TmsClientDeviceImpl::findAndCreateFunctionBlocks() try { auto clientFunctionBlock = TmsClientFunctionBlock(context, this->functionBlocks, browseName, clientContext, functionBlockNodeId); - const auto numberInList = this->readChildNumberInList(functionBlockNodeId); + const auto numberInList = this->tryReadChildNumberInList(functionBlockNodeId); if (numberInList != std::numeric_limits::max() && !orderedFunctionBlocks.count(numberInList)) orderedFunctionBlocks.insert(std::pair(numberInList, clientFunctionBlock)); else @@ -276,7 +276,7 @@ void TmsClientDeviceImpl::findAndCreateSignals() for (const auto& [signalNodeId, ref] : references.byNodeId) { auto clientSignal = FindOrCreateTmsClientSignal(context, signals, clientContext, signalNodeId); - const auto numberInList = this->readChildNumberInList(signalNodeId); + const auto numberInList = this->tryReadChildNumberInList(signalNodeId); if (numberInList != std::numeric_limits::max() && !orderedSignals.count(numberInList)) orderedSignals.insert(std::pair(numberInList, clientSignal)); else @@ -303,7 +303,7 @@ void TmsClientDeviceImpl::findAndCreateInputsOutputs() const auto channelNodeId = OpcUaNodeId(ref->nodeId.nodeId); auto tmsClientChannel = TmsClientChannel(context, this->ioFolder, browseName, clientContext, channelNodeId); - auto numberInList = this->readChildNumberInList(channelNodeId); + auto numberInList = this->tryReadChildNumberInList(channelNodeId); if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) orderedComponents.insert(std::pair(numberInList, tmsClientChannel)); else @@ -317,7 +317,7 @@ void TmsClientDeviceImpl::findAndCreateInputsOutputs() const auto folderNodeId = OpcUaNodeId(ref->nodeId.nodeId); auto tmsClientFolder = TmsClientIoFolder(context, this->ioFolder, browseName, clientContext, folderNodeId); - auto numberInList = this->readChildNumberInList(folderNodeId); + auto numberInList = this->tryReadChildNumberInList(folderNodeId); if (numberInList != std::numeric_limits::max()) orderedComponents.insert(std::pair(numberInList, tmsClientFolder)); else @@ -348,7 +348,7 @@ void TmsClientDeviceImpl::findAndCreateStreamingOptions() const auto optionNodeId = OpcUaNodeId(ref->nodeId.nodeId); auto clientStreamingInfo = TmsClientStreamingInfo(daqContext, browseName, clientContext, optionNodeId); - auto numberInList = this->readChildNumberInList(optionNodeId); + auto numberInList = this->tryReadChildNumberInList(optionNodeId); if (numberInList != std::numeric_limits::max()) orderedStreamings.insert(std::pair(numberInList, clientStreamingInfo)); else @@ -389,7 +389,7 @@ void TmsClientDeviceImpl::findAndCreateCustomComponents() else child = TmsClientComponent(context, this->thisPtr(), browseName, clientContext, folderNodeId); - auto numberInList = this->readChildNumberInList(folderNodeId); + auto numberInList = this->tryReadChildNumberInList(folderNodeId); if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) orderedComponents.insert(std::pair(numberInList, child)); else diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp index 58089fd..f6c310a 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp @@ -48,7 +48,7 @@ void TmsClientFolderImpl::findAndCreateFolders(std::mapcontext, thisPtr, browseName, this->clientContext, folderNodeId); - auto numberInList = this->readChildNumberInList(folderNodeId); + auto numberInList = this->tryReadChildNumberInList(folderNodeId); if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) orderedComponents.insert(std::pair(numberInList, child)); else diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp index 22b4da3..e4929df 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp @@ -57,7 +57,7 @@ void TmsClientFunctionBlockBaseImpl::findAndCreateFunctionBlocks() // just be ignored. It is not an error at all. auto clientFunctionBlock = TmsClientFunctionBlock(this->context, this->functionBlocks, browseName, this->clientContext, functionBlockNodeId); - const auto numberInList = this->readChildNumberInList(functionBlockNodeId); + const auto numberInList = this->tryReadChildNumberInList(functionBlockNodeId); if (numberInList != std::numeric_limits::max() && !orderedFunctionBlocks.count(numberInList)) orderedFunctionBlocks.insert(std::pair(numberInList, clientFunctionBlock)); else @@ -87,7 +87,7 @@ void TmsClientFunctionBlockBaseImpl::findAndCreateSignals() for (const auto& [signalNodeId, ref] : references.byNodeId) { auto clientSignal = FindOrCreateTmsClientSignal(this->context, this->signals, this->clientContext, signalNodeId); - const auto numberInList = this->readChildNumberInList(signalNodeId); + const auto numberInList = this->tryReadChildNumberInList(signalNodeId); if (numberInList != std::numeric_limits::max() && !orderedSignals.count(numberInList)) orderedSignals.insert(std::pair(numberInList, clientSignal)); else @@ -138,7 +138,7 @@ void TmsClientFunctionBlockBaseImpl::findAndCreateInputPorts() auto clientInputPort = TmsClientInputPort(this->context, this->inputPorts, browseName, this->clientContext, inputPortNodeId); - const auto numberInList = this->readChildNumberInList(inputPortNodeId); + const auto numberInList = this->tryReadChildNumberInList(inputPortNodeId); if (numberInList != std::numeric_limits::max() && !orderedInputPorts.count(numberInList)) orderedInputPorts.insert(std::pair(numberInList, clientInputPort)); else diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp index ac9aadc..7e9b6e6 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp @@ -38,7 +38,7 @@ void TmsClientIoFolderImpl::findAndCreateChannels(std::mapborrowPtr(); auto tmsClientChannel = TmsClientChannel(this->context, thisPtr, browseName, this->clientContext, channelNodeId); - auto numberInList = this->readChildNumberInList(channelNodeId); + auto numberInList = this->tryReadChildNumberInList(channelNodeId); if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) orderedComponents.insert(std::pair(numberInList, tmsClientChannel)); else @@ -56,7 +56,7 @@ void TmsClientIoFolderImpl::findAndCreateIoFolders(std::maptemplate borrowPtr(); auto tmsClientFolder = TmsClientIoFolder(this->context, thisPtr, browseName, this->clientContext, folderNodeId); - auto numberInList = this->readChildNumberInList(folderNodeId); + auto numberInList = this->tryReadChildNumberInList(folderNodeId); if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) orderedComponents.insert(std::pair(numberInList, tmsClientFolder)); else diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_object_impl.cpp index a581b6c..0430f9e 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_object_impl.cpp @@ -77,17 +77,25 @@ void TmsClientObjectImpl::subscriptionStatusChangeCallback(UA_StatusChangeNotifi //TODO report on disconnect } -uint32_t TmsClientObjectImpl::readChildNumberInList(const std::string& nodeName) +uint32_t TmsClientObjectImpl::tryReadChildNumberInList(const std::string& nodeName) { const auto childId = this->getNodeId(nodeName); - return readChildNumberInList(childId); + return tryReadChildNumberInList(childId); } -uint32_t TmsClientObjectImpl::readChildNumberInList(const opcua::OpcUaNodeId& nodeId) +uint32_t TmsClientObjectImpl::tryReadChildNumberInList(const opcua::OpcUaNodeId& nodeId) { - const auto numberInListId = clientContext->getReferenceBrowser()->getChildNodeId(nodeId, "NumberInList"); - const auto variant = clientContext->getAttributeReader()->getValue(numberInListId, UA_ATTRIBUTEID_VALUE); - return VariantConverter::ToDaqObject(variant); + try + { + const auto numberInListId = clientContext->getReferenceBrowser()->getChildNodeId(nodeId, "NumberInList"); + const auto variant = clientContext->getAttributeReader()->getValue(numberInListId, UA_ATTRIBUTEID_VALUE); + return VariantConverter::ToDaqObject(variant); + } + catch (...) + { + } + + return std::numeric_limits::max(); } CachedReferences TmsClientObjectImpl::getChildReferencesOfType(const opcua::OpcUaNodeId& nodeId, const opcua::OpcUaNodeId& typeId) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index 50a48c5..ef0503c 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -274,7 +274,7 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par if (prop.assigned()) { - auto numberInList = readChildNumberInList(childNodeId); + auto numberInList = tryReadChildNumberInList(childNodeId); if (numberInList != std::numeric_limits::max() && !orderedProperties.count(numberInList)) orderedProperties.insert(std::pair(numberInList, prop)); else From f1423cad9a174dc9a03641a5808c59e760b7ca45 Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Thu, 11 Jan 2024 11:43:17 +0100 Subject: [PATCH 045/217] [TBBAS-1058] Add method getLastValue() in ISignal class - add method getLastValue in ISignal - support Value & AnalogValue in opcua client and server - add tests - update changelog --- .../objects/tms_client_signal_impl.h | 1 + .../src/objects/tms_client_signal_impl.cpp | 26 +++++++ .../src/objects/tms_server_signal.cpp | 23 ++++++ .../opcuatms_integration/test_tms_signal.cpp | 74 +++++++++++++++++++ 4 files changed, 124 insertions(+) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h index 8642c6d..bdba54b 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h @@ -48,6 +48,7 @@ class TmsClientSignalImpl final : public TmsClientComponentBaseImplgetReferenceBrowser()->getChildNodeId(nodeId, nodeName); + OpcUaVariant opcUaVariant = client->readValue(*valueNodeId); + if (!opcUaVariant.isNull()) + { + BaseObjectPtr valuePtr = VariantConverter::ToDaqObject(opcUaVariant); + *value = valuePtr.addRefAndReturn(); + return OPENDAQ_SUCCESS; + } + return OPENDAQ_IGNORED; + }; + + if (descriptorNodeId && readValueFunction(value, "Value") == OPENDAQ_SUCCESS) + return OPENDAQ_SUCCESS; + + if (hasReference("AnalogValue")) + return readValueFunction(value, "AnalogValue"); + + return OPENDAQ_IGNORED; +} + END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp index 922ece7..3a3bf0e 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp @@ -48,6 +48,27 @@ void TmsServerSignal::bindCallbacks() } } + addReadCallback(valueId, [this]() { + ObjectPtr lastValue = object.getLastValue(); + if (lastValue != nullptr) + return VariantConverter::ToVariant(lastValue, nullptr, daqContext); + + return OpcUaVariant(); + }); + + auto analogValueId = getChildNodeId("AnalogValue"); + addReadCallback(analogValueId, [this]() { + SampleType type = object.getDescriptor().getSampleType(); + if (type != SampleType::Float64 && type != SampleType::Int64) + return OpcUaVariant(); + + ObjectPtr lastValue = object.getLastValue(); + if (lastValue != nullptr) + return VariantConverter::ToVariant(lastValue, nullptr, daqContext); + + return OpcUaVariant(); + }); + // TODO: Value, AnalogValue, Status Super::bindCallbacks(); } @@ -57,6 +78,8 @@ bool TmsServerSignal::createOptionalNode(const opcua::OpcUaNodeId& nodeId) const auto name = server->readBrowseNameString(nodeId); if (name == "Value") return true; + if (name == "AnalogValue") + return true; return Super::createOptionalNode(nodeId); } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp index 3157047..0c5862a 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp @@ -12,6 +12,7 @@ #include #include #include "tms_object_integration_test.h" +#include using namespace daq; using namespace opcua::tms; @@ -329,3 +330,76 @@ TEST_F(TmsSignalTest, ExplicitDomainRuleDescriptor) ASSERT_EQ(signal.getDescriptor().getRule(), clientSignal.getDescriptor().getRule()); } + +TEST_F(TmsSignalTest, GetNoValue) +{ + auto domainDescriptor = DataDescriptorBuilder() + .setName("domain stub") + .setSampleType(SampleType::UInt64) + .setOrigin("2024-01-08T00:02:03+00:00") + .setTickResolution(Ratio(1, 1000000)) + .setRule(LinearDataRule(1000, 0)) + .setUnit(Unit("s", -1, "seconds", "time")) + .build(); + const auto domainSignal = SignalWithDescriptor(NullContext(), domainDescriptor, nullptr, "domainSig"); + + auto dataDescriptor = DataDescriptorBuilder().setName("stub").setSampleType(SampleType::Float64).build(); + const auto signal = SignalWithDescriptor(NullContext(), dataDescriptor, nullptr, "sig"); + + auto serverSignal = TmsServerSignal(signal, this->getServer(), NullContext()); + auto nodeId = serverSignal.registerOpcUaNode(); + + SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); + ASSERT_TRUE(clientSignal.assigned()); + ASSERT_FALSE(clientSignal.getLastValue().assigned()); +} + +template +static void sendValueToSignal(const SignalConfigPtr& signal, const T& value) +{ + if (!signal.assigned()) + return; + + DataPacketPtr packet; + + if (signal.getDomainSignal().assigned()) + { + auto domainPacket = DataPacket(signal.getDomainSignal().getDescriptor(), 1); + packet = DataPacketWithDomain(domainPacket, signal.getDescriptor(), 1); + } + else + { + packet = DataPacket(signal.getDescriptor(), 1); + } + + auto dst = static_cast(packet.getData()); + *dst = value; + signal.sendPacket(packet); +} + +TEST_F(TmsSignalTest, GetValue) +{ + auto domainDescriptor = DataDescriptorBuilder() + .setName("domain stub") + .setSampleType(SampleType::UInt64) + .setOrigin("2024-01-08T00:02:03+00:00") + .setTickResolution(Ratio(1, 1000000)) + .setRule(LinearDataRule(1000, 0)) + .setUnit(Unit("s", -1, "seconds", "time")) + .build(); + const auto domainSignal = SignalWithDescriptor(NullContext(), domainDescriptor, nullptr, "domainSig"); + + auto dataDescriptor = DataDescriptorBuilder().setName("stub").setSampleType(SampleType::Float64).build(); + const auto signal = SignalWithDescriptor(NullContext(), dataDescriptor, nullptr, "sig"); + + auto serverSignal = TmsServerSignal(signal, this->getServer(), NullContext()); + auto nodeId = serverSignal.registerOpcUaNode(); + + SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); + ASSERT_TRUE(clientSignal.assigned()); + + sendValueToSignal(signal, 1.0); + sendValueToSignal(signal, 10.0); + + ASSERT_EQ(clientSignal.getLastValue(), 10.0); +} From f7c2520531d088b8a48e68962254d6d85bd73c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Wed, 10 Jan 2024 14:27:03 +0100 Subject: [PATCH 046/217] Correctly collect attributes on objects under OutputSignals node --- .../opcuatms/opcuatms_client/src/tms_attribute_collector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_attribute_collector.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_attribute_collector.cpp index 04c95ae..f0392b4 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_attribute_collector.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_attribute_collector.cpp @@ -250,7 +250,7 @@ void TmsAttributeCollector::collectSignalsNode(const OpcUaNodeId& nodeId) for (const auto& [refNodeId, ref] : signalReferences.byNodeId) { - if (typeEquals(ref->typeDefinition.nodeId, NodeIdSignalType)) + if (isSubtypeOf(ref->typeDefinition.nodeId, NodeIdSignalType)) collectSignalAttributes(refNodeId); } } From 9d5d368afde3d2aee73acc474c49f1f44f625dcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Mon, 15 Jan 2024 10:01:05 +0100 Subject: [PATCH 047/217] Fix fusion device connection issues --- .../include/opcuaclient/cached_reference_browser.h | 1 + shared/libraries/opcua/opcuaclient/src/attribute_reader.cpp | 5 ++++- .../opcua/opcuaclient/src/cached_reference_browser.cpp | 2 ++ .../opcuatms_client/src/objects/tms_client_device_impl.cpp | 5 ++++- .../src/objects/tms_client_property_object_impl.cpp | 3 +++ 5 files changed, 14 insertions(+), 2 deletions(-) diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h index 75592bc..9672928 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h @@ -41,6 +41,7 @@ struct BrowseFilter OpcUaNodeId referenceTypeId = OpcUaNodeId(); OpcUaNodeId typeDefinition = OpcUaNodeId(); UA_BrowseDirection direction = UA_BROWSEDIRECTION_BOTH; + UA_NodeClass nodeClass = UA_NODECLASS_UNSPECIFIED; }; class CachedReferenceBrowser diff --git a/shared/libraries/opcua/opcuaclient/src/attribute_reader.cpp b/shared/libraries/opcua/opcuaclient/src/attribute_reader.cpp index 9b88575..544d5eb 100644 --- a/shared/libraries/opcua/opcuaclient/src/attribute_reader.cpp +++ b/shared/libraries/opcua/opcuaclient/src/attribute_reader.cpp @@ -104,11 +104,14 @@ void AttributeReader::addBatchToResultMap(tsl::ordered_set::iter for (size_t i = 0; i < response->resultsSize; i++) { const auto& attr = *attrIterator; + const auto& result = response->results[i]; if (resultMap.count(attr.nodeId) == 0) resultMap[attr.nodeId] = {}; - resultMap[attr.nodeId][attr.attributeId] = OpcUaVariant(response->results[i].value); + if (result.status == UA_STATUSCODE_GOOD) + resultMap[attr.nodeId][attr.attributeId] = OpcUaVariant(result.value); + attrIterator++; } } diff --git a/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp b/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp index 83ec792..f75fa50 100644 --- a/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp +++ b/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp @@ -96,6 +96,8 @@ CachedReferences CachedReferenceBrowser::browseFiltered(const OpcUaNodeId& nodeI continue; if (filter.direction == UA_BROWSEDIRECTION_INVERSE && ref->isForward) continue; + if (filter.nodeClass != UA_NODECLASS_UNSPECIFIED && filter.nodeClass != ref->nodeClass) + continue; filtered.byNodeId.insert({ref->nodeId.nodeId, ref}); filtered.byBrowseName.insert({browseName, ref}); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 14671c5..a14d562 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -121,7 +121,10 @@ DeviceInfoPtr TmsClientDeviceImpl::onGetInfo() deviceInfo = DeviceInfo(""); - const auto& references = clientContext->getReferenceBrowser()->browse(nodeId); + auto browseFilter = BrowseFilter(); + browseFilter.nodeClass = UA_NODECLASS_VARIABLE; + const auto& references = clientContext->getReferenceBrowser()->browseFiltered(nodeId, browseFilter); + auto reader = AttributeReader(client, clientContext->getMaxNodesPerRead()); for (const auto& [browseName, ref] : references.byBrowseName) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index ef0503c..eecb617 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -190,6 +190,9 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par const auto typeId = OpcUaNodeId(ref->typeDefinition.nodeId); const auto propName = String(utils::ToStdString(ref->browseName.name)); + if (!clientContext->getAttributeReader()->hasAnyValue(childNodeId)) + continue; + Bool hasProp; daq::checkErrorInfo(Impl::hasProperty(propName, &hasProp)); PropertyPtr prop; From 0f20c316275b11c3c98609975b2c55c9220a88b9 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Wed, 29 Nov 2023 16:14:21 +0100 Subject: [PATCH 048/217] Add SearchFilter, Visible flag, rework Component attributes Search filters, visible flag, component attributes - Add SearchFilter that allows for more granular component search on tree traversal methods (getItems, getSignals...) - Add visible flag to Component - Default component getters were modified to return only components with visible==true - PropertyChanged event packets were removed - ComponentModified core event was changed to AttributeModified - Attribute lock was added to components preventing changes to locked attributes - Name and Description are no longer properties, but component attributes - Add per-component core event triggers --- .../src/opcua_client_module_impl.cpp | 3 +- .../objects/tms_client_component_impl.h | 8 +- .../objects/tms_client_property_object_impl.h | 4 +- .../src/objects/tms_client_component_impl.cpp | 62 +++++++-- .../src/objects/tms_client_device_impl.cpp | 2 +- .../src/objects/tms_client_signal_impl.cpp | 1 + .../objects/tms_server_channel.h | 2 +- .../objects/tms_server_component.h | 125 +++++++++++++----- .../objects/tms_server_device.h | 2 +- .../objects/tms_server_eval_value.h | 4 +- .../objects/tms_server_folder.h | 2 +- .../objects/tms_server_function_block.h | 2 +- .../objects/tms_server_input_port.h | 2 +- .../objects/tms_server_object.h | 16 ++- .../objects/tms_server_property.h | 5 +- .../objects/tms_server_property_object.h | 3 + .../objects/tms_server_signal.h | 2 +- .../objects/tms_server_variable.h | 2 +- .../include/opcuatms_server/tms_server.h | 3 + .../opcuatms_server/tms_server_context.h | 40 ++++++ .../opcuatms_server/src/CMakeLists.txt | 2 + .../src/objects/tms_server_channel.cpp | 4 +- .../src/objects/tms_server_device.cpp | 15 ++- .../src/objects/tms_server_eval_value.cpp | 8 +- .../src/objects/tms_server_folder.cpp | 7 +- .../src/objects/tms_server_function_block.cpp | 11 +- .../src/objects/tms_server_input_port.cpp | 4 +- .../src/objects/tms_server_object.cpp | 12 +- .../src/objects/tms_server_property.cpp | 15 ++- .../objects/tms_server_property_object.cpp | 18 ++- .../src/objects/tms_server_signal.cpp | 4 +- .../src/objects/tms_server_variable.cpp | 4 +- .../opcuatms_server/src/tms_server.cpp | 5 +- .../src/tms_server_context.cpp | 28 ++++ .../opcuatms_server/tests/CMakeLists.txt | 2 + .../tests/test_tms_channel.cpp | 17 ++- .../opcuatms_server/tests/test_tms_device.cpp | 16 +-- .../tests/test_tms_function_block.cpp | 20 ++- .../tests/test_tms_input_port.cpp | 14 +- .../tests/test_tms_property_object.cpp | 12 +- .../opcuatms_server/tests/test_tms_signal.cpp | 21 ++- .../opcuatms_server/tests/tms_server_test.cpp | 17 +++ .../opcuatms_server/tests/tms_server_test.h | 30 +++++ .../test_property_object_advanced.cpp | 5 +- .../test_streaming_integration.cpp | 6 +- .../test_tms_amplifier.cpp | 7 +- .../opcuatms_integration/test_tms_channel.cpp | 17 ++- .../test_tms_component.cpp | 34 ++--- .../opcuatms_integration/test_tms_device.cpp | 43 +++--- .../opcuatms_integration/test_tms_folder.cpp | 4 +- .../test_tms_function_block.cpp | 30 ++--- .../test_tms_function_property.cpp | 2 +- .../test_tms_input_port.cpp | 24 ++-- .../test_tms_integration.cpp | 10 +- .../test_tms_property.cpp | 4 +- .../test_tms_property_object.cpp | 4 +- .../opcuatms_integration/test_tms_signal.cpp | 55 +++++--- .../tms_object_integration_test.cpp | 12 +- .../tms_object_integration_test.h | 5 +- .../tests/test_utils/tms_object_test.h | 4 +- 60 files changed, 563 insertions(+), 279 deletions(-) create mode 100644 shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server_context.h create mode 100644 shared/libraries/opcuatms/opcuatms_server/src/tms_server_context.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.h diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index d163687..3036f13 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include BEGIN_NAMESPACE_OPENDAQ_OPCUA_CLIENT_MODULE @@ -212,7 +213,7 @@ void OpcUaClientModule::configureStreamingSources(const PropertyObjectPtr& devic const StringPtr primaryStreamingProtocol = deviceConfig.getPropertyValue("PrimaryStreamingProtocol"); const ListPtr allowedStreamingProtocols = deviceConfig.getPropertyValue("AllowedStreamingProtocols"); - for (const auto& signal : device.getSignalsRecursive()) + for (const auto& signal : device.getSignals(search::Recursive(search::Any()))) { MirroredSignalConfigPtr mirroredSignalConfigPtr = signal.template asPtr(); diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h index dbef6e8..5befca1 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h @@ -38,6 +38,7 @@ class TmsClientComponentBaseImpl : public TmsClientPropertyObjectBaseImpl const opcua::OpcUaNodeId& nodeId) : TmsClientPropertyObjectBaseImpl(ctx, parent, localId, clientContext, nodeId) { + initComponent(); clientContext->readObjectAttributes(nodeId); } @@ -50,17 +51,22 @@ class TmsClientComponentBaseImpl : public TmsClientPropertyObjectBaseImpl const FunctionBlockTypePtr& type) : TmsClientPropertyObjectBaseImpl(ctx, parent, localId, clientContext, nodeId, type) { + initComponent(); clientContext->readObjectAttributes(nodeId); } // Component overrides ErrCode INTERFACE_FUNC getActive(Bool* active) override; ErrCode INTERFACE_FUNC setActive(Bool active) override; - ErrCode INTERFACE_FUNC getTags(ITagsConfig** tags) override; ErrCode INTERFACE_FUNC getName(IString** name) override; ErrCode INTERFACE_FUNC setName(IString* name) override; ErrCode INTERFACE_FUNC getDescription(IString** description) override; ErrCode INTERFACE_FUNC setDescription(IString* description) override; + ErrCode INTERFACE_FUNC getVisible(Bool* visible) override; + ErrCode INTERFACE_FUNC setVisible(Bool visible) override; + +private: + void initComponent(); }; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h index 29a8ab4..7b0b4eb 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h @@ -69,7 +69,7 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl const TmsClientContextPtr& clientContext, const opcua::OpcUaNodeId& nodeId) : TmsClientObjectImpl(ctx, clientContext, nodeId) - , Impl(ctx, parent, localId, nullptr, ComponentStandardProps::Skip) + , Impl(ctx, parent, localId, nullptr) { init(); } @@ -82,7 +82,7 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl const opcua::OpcUaNodeId& nodeId, const FunctionBlockTypePtr& type) : TmsClientObjectImpl(ctx, clientContext, nodeId) - , Impl(type, ctx, parent, localId, nullptr, ComponentStandardProps::Skip) + , Impl(type, ctx, parent, localId, nullptr) { init(); } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp index 4ac9e0a..357e075 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp @@ -28,17 +28,27 @@ ErrCode TmsClientComponentBaseImpl::setActive(Bool active) } template -ErrCode TmsClientComponentBaseImpl::getTags(ITagsConfig** tags) +void TmsClientComponentBaseImpl::initComponent() { - return daqTry([&]() { + try + { ListPtr tagValues = this->template readList("Tags"); auto tagsObj = Tags(); for (auto tag : tagValues) tagsObj.add(tag); tagsObj.freeze(); - *tags = tagsObj.detach(); - return OPENDAQ_SUCCESS; - }); + this->tags = tagsObj.detach(); + } + catch([[maybe_unused]] const std::exception& e) + { + const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClient"); + LOG_D("OPC UA Component {} failed to fetch tags: {}", this->localId, e.what()); + } + catch(...) + { + const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClient"); + LOG_D("OPC UA Component {} failed to fetch tags.", this->localId); + } } template @@ -68,9 +78,7 @@ ErrCode TmsClientComponentBaseImpl::setName(IString* name) catch(...) { auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClientComponent"); - StringPtr nameObj; - this->getName(&nameObj); - LOG_W("Failed to set name of component \"{}\"", nameObj); + LOG_W("Failed to set name of component \"{}\"", this->localId); } return OPENDAQ_IGNORED; @@ -103,9 +111,41 @@ ErrCode TmsClientComponentBaseImpl::setDescription(IString* description) catch(...) { auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClientComponent"); - StringPtr descObj; - this->getName(&descObj); - LOG_W("Failed to set description of component \"{}\"", descObj); + LOG_W("Failed to set description of component \"{}\"", this->localId); + } + + return OPENDAQ_IGNORED; +} + +template +ErrCode TmsClientComponentBaseImpl::getVisible(Bool* visible) +{ + try + { + *visible = this->template readValue("Visible"); + } + catch(...) + { + *visible = true; + const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClient"); + LOG_D("OPC UA Component {} failed to fetch \"Visible\" state.", this->localId); + } + + return OPENDAQ_SUCCESS; +} + +template +ErrCode TmsClientComponentBaseImpl::setVisible(Bool visible) +{ + try + { + this->template writeValue("Visible", visible); + return OPENDAQ_SUCCESS; + } + catch (...) + { + const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClient"); + LOG_D("OPC UA Component {} failed to set \"Active\" state.", this->localId); } return OPENDAQ_IGNORED; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index a14d562..24a44f2 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -418,7 +418,7 @@ void TmsClientDeviceImpl::onRemoveFunctionBlock(const FunctionBlockPtr& /*functi void TmsClientDeviceImpl::setUpStreamings() { auto self = this->borrowPtr(); - const auto signals = self.getSignalsRecursive(); + const auto signals = self.getSignals(search::Recursive(search::Any())); LOG_I("Device \"{}\" has established {} streaming connections", globalId, streamings.size()); for (const auto& streaming : streamings) { diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp index a8e3ae7..36f4697 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp @@ -156,6 +156,7 @@ Bool TmsClientSignalImpl::onTriggerEvent(EventPacketPtr eventPacket) return True; } + StringPtr TmsClientSignalImpl::onGetRemoteId() const { return String(deviceSignalId); diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_channel.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_channel.h index de91570..83d0dff 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_channel.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_channel.h @@ -29,7 +29,7 @@ class TmsServerChannel : public TmsServerFunctionBlock public: using Super = TmsServerFunctionBlock; - TmsServerChannel(const ChannelPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context); + TmsServerChannel(const ChannelPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext); protected: opcua::OpcUaNodeId getTmsTypeId() override; diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h index 37cd3cc..3ac7f2a 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h @@ -17,8 +17,11 @@ #pragma once #include #include +#include +#include #include "opcuatms_server/objects/tms_server_property_object.h" #include "opcuatms/converters/variant_converter.h" +#include "opcuatms_server/tms_server_context.h" #include "open62541/daqdevice_nodeids.h" @@ -34,7 +37,7 @@ class TmsServerComponent : public TmsServerObjectBaseImpl public: using Super = TmsServerObjectBaseImpl; - TmsServerComponent(const ComponentPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context); + TmsServerComponent(const ComponentPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext); bool createOptionalNode(const opcua::OpcUaNodeId& nodeId) override; @@ -43,13 +46,16 @@ class TmsServerComponent : public TmsServerObjectBaseImpl std::string getDescription() override; opcua::OpcUaNodeId getReferenceType() override; void bindCallbacks() override; + void registerToTmsServerContext() override; void addChildNodes() override; + void onCoreEvent(const CoreEventArgsPtr& args) override; protected: opcua::OpcUaNodeId getTmsTypeId() override; void configureNodeAttributes(opcua::OpcUaObject& attr) override; std::unique_ptr tmsPropertyObject; + private: bool selfChange; }; @@ -57,11 +63,11 @@ class TmsServerComponent : public TmsServerObjectBaseImpl using namespace opcua; template -TmsServerComponent::TmsServerComponent(const ComponentPtr& object, const OpcUaServerPtr& server, const ContextPtr& context) - : Super(object, server, context) +TmsServerComponent::TmsServerComponent(const ComponentPtr& object, const OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext) + : Super(object, server, context, tmsContext) , selfChange(false) { - tmsPropertyObject = std::make_unique(this->object, this->server, this->daqContext, std::unordered_set{"Name", "Description"}); + tmsPropertyObject = std::make_unique(this->object, this->server, this->daqContext, this->tmsContext, std::unordered_set{"Name", "Description"}); } template @@ -98,9 +104,13 @@ template void TmsServerComponent::configureNodeAttributes(opcua::OpcUaObject& attr) { TmsServerObject::configureNodeAttributes(attr); - if (this->object.hasProperty("Name") && !this->object.getProperty("Name").getReadOnly()) + std::unordered_set lockedAttrs; + for (const auto& str : this->object.getLockedAttributes()) + lockedAttrs.insert(str); + + if (!lockedAttrs.count("Name")) attr->writeMask |= UA_WRITEMASK_DISPLAYNAME; - if (this->object.hasProperty("Description") && !this->object.getProperty("Description").getReadOnly()) + if (!lockedAttrs.count("Description")) attr->writeMask |= UA_WRITEMASK_DESCRIPTION; } @@ -130,42 +140,36 @@ void TmsServerComponent::bindCallbacks() }); } - if (this->object.hasProperty("Name")) - { - this->object.getOnPropertyValueWrite("Name") += - [&](const PropertyObjectPtr& /*obj*/, const PropertyValueEventArgsPtr& args) - { - if (selfChange) - return; + this->addReadCallback("Visible", [this]() { return VariantConverter::ToVariant( this->object.getVisible()); }); - std::string name = args.getValue(); - this->server->setDisplayName(this->nodeId, name); - }; - } - - if (this->object.hasProperty("Description")) + if (!this->object.template asPtrOrNull().assigned() || !this->object.isFrozen()) { - this->object.getOnPropertyValueWrite("Description") += - [&](const PropertyObjectPtr& /*obj*/, const PropertyValueEventArgsPtr& args) - { - if (selfChange) - return; - - std::string description = args.getValue(); - this->server->setDescription(this->nodeId, description); - }; + this->addWriteCallback("Visible", [this](const OpcUaVariant& variant){ + this->object.setVisible(VariantConverter::ToDaqObject(variant)); + return UA_STATUSCODE_GOOD; + }); } DisplayNameChangedCallback nameChangedCallback = [this](const OpcUaNodeId& /*nodeId*/, const OpcUaObject& name, void* /*context*/) { + if (selfChange) + return; + try { selfChange = true; this->object.setName(utils::ToStdString(name->text)); } - catch(...) + catch ([[maybe_unused]] const std::exception& e) + { + const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClient"); + LOG_D("OPC UA Component {} failed to set component name: {}", this->object.getLocalId(), e.what()); + } + catch (...) { + const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClient"); + LOG_D("OPC UA Component {} failed to set component name.", this->object.getLocalId()); } selfChange = false; @@ -175,13 +179,23 @@ void TmsServerComponent::bindCallbacks() DisplayNameChangedCallback descriptionChangedCallback = [this](const OpcUaNodeId& /*nodeId*/, const OpcUaObject& description, void* /*context*/) { + if (selfChange) + return; + try { selfChange = true; this->object.setDescription(utils::ToStdString(description->text)); } - catch(...) + catch ([[maybe_unused]] const std::exception& e) + { + const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClient"); + LOG_D("OPC UA Component {} failed to set component description: {}", this->object.getLocalId(), e.what()); + } + catch (...) { + const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClient"); + LOG_D("OPC UA Component {} failed to set component description.", this->object.getLocalId()); } selfChange = false; @@ -189,10 +203,61 @@ void TmsServerComponent::bindCallbacks() this->server->getEventManager()->onDescriptionChanged(this->nodeId, descriptionChangedCallback); } +template +void TmsServerComponent::registerToTmsServerContext() +{ + Super::registerToTmsServerContext(); + this->tmsContext->registerComponent(this->object, *this); +} + template void TmsServerComponent::addChildNodes() { + OpcUaNodeId newNodeId(0); + AddVariableNodeParams params(newNodeId, this->nodeId); + params.setBrowseName("Visible"); + params.setDataType(OpcUaNodeId(UA_TYPES[UA_TYPES_BOOLEAN].typeId)); + params.typeDefinition = OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE)); + + OpcUaObject attr = UA_VariableAttributes_default; + attr->accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; + params.attr = attr; + + this->server->addVariableNode(params); + tmsPropertyObject->registerToExistingOpcUaNode(this->nodeId); } +template +void TmsServerComponent::onCoreEvent(const CoreEventArgsPtr& args) +{ + Super::onCoreEvent(args); + + if (!selfChange && args.getEventId() == core_event_ids::AttributeChanged) + { + const StringPtr attrName = args.getParameters().get("AttributeName"); + + try + { + selfChange = true; + if (attrName == "Name") + this->server->setDisplayName(this->nodeId, args.getParameters().get("Name")); + else if (attrName == "Description") + this->server->setDescription(this->nodeId, args.getParameters().get("Description")); + } + catch ([[maybe_unused]] const std::exception& e) + { + const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClient"); + LOG_D("OPC UA Component {} failed to set node attribute \"{}\": {}", this->object.getLocalId(), attrName, e.what()); + } + catch (...) + { + const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClient"); + LOG_D("OPC UA Component {} failed to set node attribute \"{}\".", this->object.getLocalId(), attrName); + } + + selfChange = false; + } +} + END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h index 3235f84..ea56f6d 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h @@ -33,7 +33,7 @@ class TmsServerDevice : public TmsServerComponent public: using Super = TmsServerComponent; - TmsServerDevice(const DevicePtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context); + TmsServerDevice(const DevicePtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext); bool createOptionalNode(const opcua::OpcUaNodeId& nodeId) override; diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_eval_value.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_eval_value.h index 6934f8d..4984bc7 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_eval_value.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_eval_value.h @@ -32,8 +32,8 @@ class TmsServerEvalValue : public TmsServerVariable using ReadCallback = std::function; using WriteCallback = std::function; - TmsServerEvalValue(const EvalValuePtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context); - TmsServerEvalValue(const opcua::OpcUaServerPtr& server, const ContextPtr& context); + TmsServerEvalValue(const EvalValuePtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext); + TmsServerEvalValue(const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext); std::string getBrowseName() override; void setReadCallback(ReadCallback readCallback); void setWriteCallback(WriteCallback writeCallback); diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_folder.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_folder.h index cd988ba..a7d4cee 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_folder.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_folder.h @@ -28,7 +28,7 @@ class TmsServerFolder : public TmsServerComponent public: using Super = TmsServerComponent; - TmsServerFolder(const FolderPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context); + TmsServerFolder(const FolderPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext); void createNonhierarchicalReferences() override; void addChildNodes() override; diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block.h index f4fa9f6..3f2f10c 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block.h @@ -34,7 +34,7 @@ class TmsServerFunctionBlock : public TmsServerComponent public: using Super = TmsServerComponent; - TmsServerFunctionBlock(const FunctionBlockPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context); + TmsServerFunctionBlock(const FunctionBlockPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext); bool createOptionalNode(const opcua::OpcUaNodeId& nodeId) override; void bindCallbacks() override; diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h index 5ff3a0f..6ba393a 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h @@ -28,7 +28,7 @@ class TmsServerInputPort : public TmsServerComponent public: using Super = TmsServerComponent; - TmsServerInputPort(const InputPortPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context); + TmsServerInputPort(const InputPortPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext); opcua::OpcUaNodeId getReferenceType() override; void bindCallbacks() override; diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h index de3f14a..1654234 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h @@ -22,8 +22,6 @@ #include "opcuaserver/opcuaserver.h" #include "opcuatms/opcuatms.h" -#include - BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS template @@ -47,13 +45,16 @@ struct RequestedNodeId; +class TmsServerContext; +using TmsServerContextPtr = std::shared_ptr; + class TmsServerObject : public std::enable_shared_from_this { public: using ReadVariantCallback = std::function; using WriteVariantCallback = std::function; - TmsServerObject(const opcua::OpcUaServerPtr& server, const ContextPtr& context); + TmsServerObject(const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext); virtual ~TmsServerObject(); virtual std::string getBrowseName(); @@ -69,6 +70,7 @@ class TmsServerObject : public std::enable_shared_from_this void addHierarchicalReference(const opcua::OpcUaNodeId& parent); virtual void createNonhierarchicalReferences(); + virtual void onCoreEvent(const CoreEventArgsPtr& eventArgs); protected: virtual void validate(); @@ -79,6 +81,7 @@ class TmsServerObject : public std::enable_shared_from_this virtual opcua::OpcUaNodeId createNode(const opcua::OpcUaNodeId& parentNodeId); virtual void addChildNodes(); virtual void bindCallbacks(); + virtual void registerToTmsServerContext(); virtual int64_t getCurrentClock(); std::string readTypeBrowseName(); virtual bool createOptionalNode(const opcua::OpcUaNodeId& nodeId); @@ -127,7 +130,7 @@ class TmsServerObject : public std::enable_shared_from_this } else { - auto tmsObject = std::make_shared(daqObject, this->server, daqContext, std::forward(params)...); + auto tmsObject = std::make_shared(daqObject, this->server, daqContext, tmsContext, std::forward(params)...); tmsObject->registerOpcUaNode(parentNodeId); if(numberInList != std::numeric_limits::max()) tmsObject->setNumberInList(numberInList); @@ -141,6 +144,7 @@ class TmsServerObject : public std::enable_shared_from_this opcua::OpcUaNodeId nodeId; ContextPtr daqContext; uint32_t numberInList; + TmsServerContextPtr tmsContext; private: void bindCallbacksInternal(); @@ -155,8 +159,8 @@ template class TmsServerObjectBaseImpl : public TmsServerObject { public: - TmsServerObjectBaseImpl(const BaseObjectPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context) - : TmsServerObject(server, context) + TmsServerObjectBaseImpl(const BaseObjectPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext) + : TmsServerObject(server, context, tmsContext) , object(object) { } diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h index a658072..126bb32 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h @@ -33,14 +33,17 @@ class TmsServerProperty : public TmsServerVariable TmsServerProperty(const PropertyPtr& object, const opcua::OpcUaServerPtr& server, - const ContextPtr& context); + const ContextPtr& context, + const TmsServerContextPtr& tmsContext); TmsServerProperty(const PropertyPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, + const TmsServerContextPtr& tmsContext, const std::unordered_map& propOrder); TmsServerProperty(const PropertyPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, + const TmsServerContextPtr& tmsContext, const PropertyObjectPtr& parent, const std::unordered_map& propOrder); diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h index 7a4f922..7205d00 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h @@ -32,14 +32,17 @@ class TmsServerPropertyObject : public TmsServerObjectBaseImpl& ignoredProps = {}); TmsServerPropertyObject(const PropertyObjectPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, + const TmsServerContextPtr& tmsContext, const StringPtr& name); TmsServerPropertyObject(const PropertyObjectPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, + const TmsServerContextPtr& tmsContext, const StringPtr& name, const PropertyPtr& objProp); ~TmsServerPropertyObject(); diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h index f4c6dc2..c8e8050 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h @@ -28,7 +28,7 @@ class TmsServerSignal : public TmsServerComponent public: using Super = TmsServerComponent; - TmsServerSignal(const SignalPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context); + TmsServerSignal(const SignalPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext); opcua::OpcUaNodeId getReferenceType() override; void bindCallbacks() override; diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h index 16a1e47..10d106c 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h @@ -25,7 +25,7 @@ class TmsServerVariable : public TmsServerObjectBaseImpl public: using Super = TmsServerObjectBaseImpl; - TmsServerVariable(const CoreType& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context); + TmsServerVariable(const CoreType& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext); opcua::OpcUaNodeId createNode(const opcua::OpcUaNodeId& parentNodeId) override; diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h index 043d48c..b509d53 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h @@ -20,6 +20,7 @@ #include #include "opcuaserver/opcuaserver.h" #include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA @@ -39,9 +40,11 @@ class TmsServer DevicePtr device; ContextPtr context; std::unique_ptr tmsDevice; + std::shared_ptr tmsContext; daq::opcua::OpcUaServerPtr server; uint16_t opcUaPort = 4840; std::string versionStr = ""; + }; END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server_context.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server_context.h new file mode 100644 index 0000000..0912971 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server_context.h @@ -0,0 +1,40 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class TmsServerContext : public std::enable_shared_from_this +{ +public: + TmsServerContext(const ContextPtr& context); + ~TmsServerContext(); + void registerComponent(const ComponentPtr& component, TmsServerObject& obj); + +private: + ContextPtr context; + + std::unordered_map> idToObjMap; + void coreEventCallback(ComponentPtr& component, CoreEventArgsPtr& eventArgs); +}; + +using TmsServerContextPtr = std::shared_ptr; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_server/src/CMakeLists.txt index 5a7646b..00568a4 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_server/src/CMakeLists.txt @@ -1,12 +1,14 @@ set(LIB_NAME opcuatms_server) set(SRC_Cpp tms_server.cpp + tms_server_context.cpp ) set(SRC_PublicHeaders ) set(SRC_PrivateHeaders tms_server.h + tms_server_context.h ) # objects diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_channel.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_channel.cpp index e7ab43e..04978d5 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_channel.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_channel.cpp @@ -7,8 +7,8 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS using namespace opcua; -TmsServerChannel::TmsServerChannel(const ChannelPtr& object, const OpcUaServerPtr& server, const ContextPtr& context) - : Super(object, server, context) +TmsServerChannel::TmsServerChannel(const ChannelPtr& object, const OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext) + : Super(object, server, context, tmsContext) { } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index c25d719..a98ec04 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -10,6 +10,7 @@ #include #include #include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -49,8 +50,8 @@ namespace detail }; } -TmsServerDevice::TmsServerDevice(const DevicePtr& object, const OpcUaServerPtr& server, const ContextPtr& context) - : Super(object, server, context) +TmsServerDevice::TmsServerDevice(const DevicePtr& object, const OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext) + : Super(object, server, context, tmsContext) { } @@ -237,7 +238,7 @@ void TmsServerDevice::addChildNodes() tmsPropertyObject->setMethodParentNodeId(methodSetNodeId); uint32_t numberInList = 0; - for (const auto& device : object.getDevices()) + for (const auto& device : object.getDevices(search::Any())) { auto tmsDevice = registerTmsObjectOrAddReference(nodeId, device, numberInList++); devices.push_back(std::move(tmsDevice)); @@ -246,7 +247,7 @@ void TmsServerDevice::addChildNodes() auto functionBlockNodeId = getChildNodeId("FB"); assert(!functionBlockNodeId.isNull()); numberInList = 0; - for (const auto& functionBlock : object.getFunctionBlocks()) + for (const auto& functionBlock : object.getFunctionBlocks(search::Any())) { auto tmsFunctionBlock = registerTmsObjectOrAddReference>(functionBlockNodeId, functionBlock, numberInList++); functionBlocks.push_back(std::move(tmsFunctionBlock)); @@ -255,7 +256,7 @@ void TmsServerDevice::addChildNodes() auto signalsNodeId = getChildNodeId("Sig"); assert(!signalsNodeId.isNull()); numberInList = 0; - for (const auto& signal : object.getSignals()) + for (const auto& signal : object.getSignals(search::Any())) { auto tmsSignal = registerTmsObjectOrAddReference(signalsNodeId, signal, numberInList++); signals.push_back(std::move(tmsSignal)); @@ -265,12 +266,12 @@ void TmsServerDevice::addChildNodes() assert(!inputsOutputsNodeId.isNull()); auto topFolder = object.getInputsOutputsFolder(); - auto inputsOutputsNode = std::make_unique(topFolder, server, daqContext); + auto inputsOutputsNode = std::make_unique(topFolder, server, daqContext, tmsContext); inputsOutputsNode->registerToExistingOpcUaNode(inputsOutputsNodeId); folders.push_back(std::move(inputsOutputsNode)); numberInList = 0; - for (auto component : object.getItems()) + for (auto component : object.getItems(search::Any())) { auto id = component.getLocalId(); if (id == "Dev" || id == "FB" || id == "IO" || id == "Sig") diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_eval_value.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_eval_value.cpp index 76e1c26..5d1ffe2 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_eval_value.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_eval_value.cpp @@ -9,15 +9,15 @@ using namespace opcua; // TmsServerEvalValue -TmsServerEvalValue::TmsServerEvalValue(const EvalValuePtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context) - : Super(nullptr, server, context) +TmsServerEvalValue::TmsServerEvalValue(const EvalValuePtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext) + : Super(nullptr, server, context, tmsContext) { this->readCallback = [this, object]() { return object; }; this->writeCallback = [](const BaseObjectPtr& object) { return UA_STATUSCODE_BADNOTWRITABLE; }; } -TmsServerEvalValue::TmsServerEvalValue(const opcua::OpcUaServerPtr& server, const ContextPtr& context) - : TmsServerEvalValue(nullptr, server, context) +TmsServerEvalValue::TmsServerEvalValue(const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext) + : TmsServerEvalValue(nullptr, server, context, tmsContext) { } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp index 723533b..7904819 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp @@ -3,20 +3,21 @@ #include "opcuatms/converters/variant_converter.h" #include "open62541/daqdevice_nodeids.h" #include "opendaq/io_folder_config.h" +#include "opendaq/search_filter_factory.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS using namespace opcua; -TmsServerFolder::TmsServerFolder(const FolderPtr& object, const OpcUaServerPtr& server, const ContextPtr& context) - : Super(object, server, context) +TmsServerFolder::TmsServerFolder(const FolderPtr& object, const OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext) + : Super(object, server, context, tmsContext) { } void TmsServerFolder::addChildNodes() { uint32_t numberInList = 0; - for (auto item : object.getItems()) + for (auto item : object.getItems(search::Any())) { auto folder = item.asPtrOrNull(); auto channel = item.asPtrOrNull(); diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp index 1dc04da..2c4b49d 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp @@ -4,14 +4,15 @@ #include "open62541/statuscodes.h" #include "open62541/daqbsp_nodeids.h" #include "open62541/di_nodeids.h" +#include "opendaq/search_filter_factory.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS using namespace opcua; template -TmsServerFunctionBlock::TmsServerFunctionBlock(const FunctionBlockPtr& object, const OpcUaServerPtr& server, const ContextPtr& context) - : Super(object, server, context) +TmsServerFunctionBlock::TmsServerFunctionBlock(const FunctionBlockPtr& object, const OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext) + : Super(object, server, context, tmsContext) { } @@ -50,7 +51,7 @@ void TmsServerFunctionBlock::addChildNodes() assert(!signalsNodeId.isNull()); uint32_t numberInList = 0; - for (const auto& signal : this->object.getSignals()) + for (const auto& signal : this->object.getSignals(search::Any())) { auto tmsSignal = this->template registerTmsObjectOrAddReference(signalsNodeId, signal, numberInList++); signals.push_back(std::move(tmsSignal)); @@ -60,14 +61,14 @@ void TmsServerFunctionBlock::addChildNodes() assert(!inputPortsNodeId.isNull()); numberInList = 0; - for (const auto& inputPort : this->object.getInputPorts()) + for (const auto& inputPort : this->object.getInputPorts(search::Any())) { auto tmsInputPort = this->template registerTmsObjectOrAddReference(inputPortsNodeId, inputPort, numberInList++); inputPorts.push_back(std::move(tmsInputPort)); } numberInList = 0; - for (const auto& fb : this->object.getFunctionBlocks()) + for (const auto& fb : this->object.getFunctionBlocks(search::Any())) { auto tmsFunctionBlock = this->template registerTmsObjectOrAddReference>(this->nodeId, fb, numberInList++); functionBlocks.push_back(std::move(tmsFunctionBlock)); diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp index db4abe7..85615fd 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp @@ -10,8 +10,8 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS using namespace opcua; -TmsServerInputPort::TmsServerInputPort(const InputPortPtr& object, const OpcUaServerPtr& server, const ContextPtr& context) - : Super(object, server, context) +TmsServerInputPort::TmsServerInputPort(const InputPortPtr& object, const OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext) + : Super(object, server, context, tmsContext) { } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp index 7e26335..95148e4 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp @@ -11,10 +11,11 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS using namespace opcua; namespace opcua_utils = opcua::utils; -TmsServerObject::TmsServerObject(const OpcUaServerPtr& server, const ContextPtr& context) +TmsServerObject::TmsServerObject(const OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext) : server(server) , daqContext(context) , numberInList(0) + , tmsContext(tmsContext) { } @@ -65,6 +66,7 @@ OpcUaNodeId TmsServerObject::registerToExistingOpcUaNode(const OpcUaNodeId& node browseReferences(); bindCallbacksInternal(); bindCallbacks(); + registerToTmsServerContext(); bindReadWriteCallbacks(); return this->nodeId; } @@ -88,6 +90,10 @@ void TmsServerObject::createNonhierarchicalReferences() { } +void TmsServerObject::onCoreEvent(const CoreEventArgsPtr& /*eventArgs*/) +{ +} + NodeEventManagerPtr TmsServerObject::addEvent(const StringPtr& nodeName) { auto nodeId = getChildNodeId(nodeName); @@ -168,6 +174,10 @@ void TmsServerObject::bindCallbacks() { } +void TmsServerObject::registerToTmsServerContext() +{ +} + void TmsServerObject::bindReadWriteCallbacks() { for (const auto& entry : readCallbacks) diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp index bac2142..efc4c76 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp @@ -12,8 +12,11 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS using namespace opcua; -TmsServerProperty::TmsServerProperty(const PropertyPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context) - : Super(object, server, context) +TmsServerProperty::TmsServerProperty(const PropertyPtr& object, + const opcua::OpcUaServerPtr& server, + const ContextPtr& context, + const TmsServerContextPtr& tmsContext) + : Super(object, server, context, tmsContext) { objectInternal = object.asPtr(false); if (isReferenceType()) @@ -31,8 +34,9 @@ TmsServerProperty::TmsServerProperty(const PropertyPtr& object, const opcua::Opc TmsServerProperty::TmsServerProperty(const PropertyPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, + const TmsServerContextPtr& tmsContext, const std::unordered_map& propOrder) - : TmsServerProperty(object, server, context) + : TmsServerProperty(object, server, context, tmsContext) { this->propOrder = propOrder; this->numberInList = propOrder.at(object.getName()); @@ -41,9 +45,10 @@ TmsServerProperty::TmsServerProperty(const PropertyPtr& object, TmsServerProperty::TmsServerProperty(const PropertyPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, + const TmsServerContextPtr& tmsContext, const PropertyObjectPtr& parent, const std::unordered_map& propOrder) - : TmsServerProperty(object, server, context, propOrder) + : TmsServerProperty(object, server, context, tmsContext, propOrder) { this->parent = parent; } @@ -159,7 +164,7 @@ void TmsServerProperty::validate() void TmsServerProperty::registerEvalValueNode(const std::string& nodeName, TmsServerEvalValue::ReadCallback readCallback, bool isSelection) { auto nodeId = getChildNodeId(nodeName); - auto serverObject = std::make_shared(server, daqContext); + auto serverObject = std::make_shared(server, daqContext, tmsContext); serverObject->setReadCallback(std::move(readCallback)); serverObject->setIsSelectionType(isSelection); auto childNodeId = serverObject->registerToExistingOpcUaNode(nodeId); diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp index 2f742b2..dd72c65 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp @@ -12,22 +12,25 @@ #include "open62541/types_generated.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS - using namespace opcua; + +using namespace opcua; TmsServerPropertyObject::TmsServerPropertyObject(const PropertyObjectPtr& object, const OpcUaServerPtr& server, const ContextPtr& context, + const TmsServerContextPtr& tmsContext, const std::unordered_set& ignoredProps) - : Super(object, server, context) - , ignoredProps(ignoredProps) + : Super(object, server, context, tmsContext) + , ignoredProps(ignoredProps) { } TmsServerPropertyObject::TmsServerPropertyObject(const PropertyObjectPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, + const TmsServerContextPtr& tmsContext, const StringPtr& name) - : TmsServerPropertyObject(object, server, context) + : TmsServerPropertyObject(object, server, context, tmsContext) { this->name = name; } @@ -35,9 +38,10 @@ TmsServerPropertyObject::TmsServerPropertyObject(const PropertyObjectPtr& object TmsServerPropertyObject::TmsServerPropertyObject(const PropertyObjectPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, + const TmsServerContextPtr& tmsContext, const StringPtr& name, const PropertyPtr& objProp) - : TmsServerPropertyObject(object, server, context, name) + : TmsServerPropertyObject(object, server, context, tmsContext, name) { this->objProp = objProp; } @@ -104,7 +108,7 @@ void TmsServerPropertyObject::addChildNodes() const auto propName = prop.getName(); if (hasChildNode(propName)) { - serverInfo = std::make_shared(prop, server, daqContext, object, propOrder); + serverInfo = std::make_shared(prop, server, daqContext, tmsContext, object, propOrder); childNodeId = serverInfo->registerToExistingOpcUaNode(nodeId); } else @@ -186,7 +190,7 @@ void TmsServerPropertyObject::setMethodParentNodeId(const OpcUaNodeId& methodPar void TmsServerPropertyObject::registerEvalValueNode(const std::string& nodeName, TmsServerEvalValue::ReadCallback readCallback) { auto nodeId = getChildNodeId(nodeName); - auto serverObject = std::make_shared(server, daqContext); + auto serverObject = std::make_shared(server, daqContext, tmsContext); serverObject->setReadCallback(std::move(readCallback)); auto childNodeId = serverObject->registerToExistingOpcUaNode(nodeId); diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp index 3a3bf0e..c5d542a 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp @@ -7,8 +7,8 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS using namespace opcua; -TmsServerSignal::TmsServerSignal(const SignalPtr& object, const OpcUaServerPtr& server, const ContextPtr& context) - : Super(object, server, context) +TmsServerSignal::TmsServerSignal(const SignalPtr& object, const OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext) + : Super(object, server, context, tmsContext) { } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp index e702bf1..97b3375 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp @@ -7,8 +7,8 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS using namespace daq::opcua; template -TmsServerVariable::TmsServerVariable(const CoreType& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context) - : Super(object, server, context) +TmsServerVariable::TmsServerVariable(const CoreType& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext) + : Super(object, server, context, tmsContext) { } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp index 9c5864f..65af638 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp @@ -11,6 +11,7 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA TmsServer::~TmsServer() { + tmsContext = nullptr; stop(); } @@ -46,7 +47,9 @@ void TmsServer::start() server->setPort(opcUaPort); server->prepare(); - tmsDevice = std::make_unique(device, server, context); + tmsContext = std::make_shared(context); + + tmsDevice = std::make_unique(device, server, context, tmsContext); tmsDevice->registerOpcUaNode(OpcUaNodeId(NAMESPACE_DI, UA_DIID_DEVICESET)); if (!versionStr.empty()) { diff --git a/shared/libraries/opcuatms/opcuatms_server/src/tms_server_context.cpp b/shared/libraries/opcuatms/opcuatms_server/src/tms_server_context.cpp new file mode 100644 index 0000000..fd82fe6 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/src/tms_server_context.cpp @@ -0,0 +1,28 @@ +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +TmsServerContext::TmsServerContext(const ContextPtr& context) + : context(context) +{ + this->context.getOnCoreEvent() += event(this, &TmsServerContext::coreEventCallback); +} + +TmsServerContext::~TmsServerContext() +{ + this->context.getOnCoreEvent() -= event(this, &TmsServerContext::coreEventCallback); +} + +void TmsServerContext::registerComponent(const ComponentPtr& component, tms::TmsServerObject& obj) +{ + idToObjMap.insert(std::make_pair(component.getGlobalId(), obj.weak_from_this())); +} + +void TmsServerContext::coreEventCallback(ComponentPtr& component, CoreEventArgsPtr& eventArgs) +{ + if (const auto it = idToObjMap.find(component.getGlobalId()); it != idToObjMap.end()) + if (const std::shared_ptr spt = it->second.lock()) + spt->onCoreEvent(eventArgs); +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt index 8bc5883..84a0f9b 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt @@ -9,6 +9,8 @@ set(TEST_SOURCES test_helpers.h test_tms_input_port.cpp test_tms_property_object.cpp test_tms_server.cpp + tms_server_test.h + tms_server_test.cpp ) add_executable(${TEST_APP} testapp.cpp diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_channel.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_channel.cpp index d296dfe..2ac6bf9 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_channel.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_channel.cpp @@ -7,7 +7,7 @@ #include "opendaq/mock/mock_channel_factory.h" #include "opcuaclient/opcuaclient.h" #include "opcuatms_server/objects/tms_server_channel.h" -#include "tms_object_test.h" +#include "tms_server_test.h" #include "open62541/daqbsp_nodeids.h" using namespace daq; @@ -15,26 +15,25 @@ using namespace opcua::tms; using namespace opcua; using namespace daq::opcua::utils; -class TmsChannelTest : public TmsObjectTest +class TmsChannelTest : public TmsServerObjectTest { public: ChannelPtr createChannel() { - const auto context = NullContext(); - return MockChannel(context, nullptr, "mockch"); + return MockChannel(ctx, nullptr, "mockch"); } }; TEST_F(TmsChannelTest, Create) { ChannelPtr channel = createChannel(); - auto tmsChannel = TmsServerChannel(channel, this->getServer(), NullContext()); + auto tmsChannel = TmsServerChannel(channel, this->getServer(), ctx, tmsCtx); } TEST_F(TmsChannelTest, Register) { ChannelPtr channel = createChannel(); - auto serverChannel = TmsServerChannel(channel, this->getServer(), NullContext()); + auto serverChannel = TmsServerChannel(channel, this->getServer(), ctx, tmsCtx); auto nodeId = serverChannel.registerOpcUaNode(); ASSERT_TRUE(this->getClient()->nodeExists(nodeId)); @@ -43,7 +42,7 @@ TEST_F(TmsChannelTest, Register) TEST_F(TmsChannelTest, AttrFunctionBlockType) { ChannelPtr channel = createChannel(); - auto serverChannel = TmsServerChannel(channel, this->getServer(), NullContext()); + auto serverChannel = TmsServerChannel(channel, this->getServer(), ctx, tmsCtx); auto nodeId = serverChannel.registerOpcUaNode(); @@ -60,7 +59,7 @@ TEST_F(TmsChannelTest, AttrFunctionBlockType) TEST_F(TmsChannelTest, BrowseSignals) { ChannelPtr channel = createChannel(); - auto serverChannel = TmsServerChannel(channel, this->getServer(), NullContext()); + auto serverChannel = TmsServerChannel(channel, this->getServer(), ctx, tmsCtx); auto nodeId = serverChannel.registerOpcUaNode(); OpcUaServerNode serverNodeFB(*this->getServer(), nodeId); @@ -79,7 +78,7 @@ TEST_F(TmsChannelTest, Property) serverChannel.addProperty(sampleRateProp); - auto tmsServerChannel = TmsServerChannel(serverChannel, this->getServer(), NullContext()); + auto tmsServerChannel = TmsServerChannel(serverChannel, this->getServer(), ctx, tmsCtx); auto nodeId = tmsServerChannel.registerOpcUaNode(); auto sampleRateNodeId = this->getChildNodeId(nodeId, "SampleRate"); diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_device.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_device.cpp index 8a9644c..50a7fc0 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_device.cpp @@ -9,25 +9,25 @@ #include "opcuaclient/opcuaclient.h" #include "opcuatms_server/objects/tms_server_device.h" #include "test_helpers.h" -#include "tms_object_test.h" +#include "tms_server_test.h" using namespace daq; using namespace opcua::tms; using namespace opcua; using namespace std::chrono_literals; -using TmsDeviceTest = TmsObjectTest; +using TmsDeviceTest = TmsServerObjectTest; TEST_F(TmsDeviceTest, Create) { DevicePtr device = test_helpers::SetupInstance(); - auto tmsDevice = TmsServerDevice(device, this->getServer(), NullContext()); + auto tmsDevice = TmsServerDevice(device, this->getServer(), ctx, tmsCtx); } TEST_F(TmsDeviceTest, Register) { DevicePtr device = test_helpers::SetupInstance(); - auto tmsDevice = TmsServerDevice(device, this->getServer(), NullContext()); + auto tmsDevice = TmsServerDevice(device, this->getServer(), ctx, tmsCtx); auto nodeId = tmsDevice.registerOpcUaNode(); ASSERT_TRUE(this->getClient()->nodeExists(nodeId)); @@ -36,7 +36,7 @@ TEST_F(TmsDeviceTest, Register) TEST_F(TmsDeviceTest, SubDevices) { DevicePtr device = test_helpers::SetupInstance(); - auto tmsDevice = TmsServerDevice(device, this->getServer(), NullContext()); + auto tmsDevice = TmsServerDevice(device, this->getServer(), ctx, tmsCtx); auto nodeId = tmsDevice.registerOpcUaNode(); ASSERT_EQ(test_helpers::BrowseSubDevices(client, nodeId).size(), 2u); @@ -45,7 +45,7 @@ TEST_F(TmsDeviceTest, SubDevices) TEST_F(TmsDeviceTest, FunctionBlock) { DevicePtr device = test_helpers::SetupInstance(); - auto tmsDevice = TmsServerDevice(device, this->getServer(), NullContext()); + auto tmsDevice = TmsServerDevice(device, this->getServer(), ctx, tmsCtx); auto nodeId = tmsDevice.registerOpcUaNode(); auto functionBlockNodeId = getChildNodeId(nodeId, "FB"); @@ -61,7 +61,7 @@ TEST_F(TmsDeviceTest, Property) device.addProperty(sampleRateProp); - auto tmsDevice = TmsServerDevice(device, this->getServer(), NullContext()); + auto tmsDevice = TmsServerDevice(device, this->getServer(), ctx, tmsCtx); auto nodeId = tmsDevice.registerOpcUaNode(); auto sampleRateNodeId = this->getChildNodeId(nodeId, "SampleRate"); @@ -87,7 +87,7 @@ TEST_F(TmsDeviceTest, Property) TEST_F(TmsDeviceTest, Components) { DevicePtr device = test_helpers::SetupInstance(); - auto tmsDevice = TmsServerDevice(device, this->getServer(), NullContext()); + auto tmsDevice = TmsServerDevice(device, this->getServer(), ctx, tmsCtx); auto nodeId = tmsDevice.registerOpcUaNode(); auto devices = test_helpers::BrowseSubDevices(client, nodeId); diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp index 16ec719..d12f318 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp @@ -6,7 +6,7 @@ #include #include "opcuaclient/opcuaclient.h" #include "opcuatms_server/objects/tms_server_function_block.h" -#include "tms_object_test.h" +#include "tms_server_test.h" #include "open62541/daqbsp_nodeids.h" #include @@ -15,28 +15,26 @@ using namespace opcua::tms; using namespace opcua; using namespace daq::opcua::utils; -class TmsFunctionBlockTest : public TmsObjectTest +class TmsFunctionBlockTest : public TmsServerObjectTest { public: FunctionBlockPtr createFunctionBlock(const FunctionBlockTypePtr& type = FunctionBlockType("uid", "name", "desc")) { - const auto context = NullContext(); - - return MockFunctionBlock(type, context, nullptr, "mockfb"); + return MockFunctionBlock(type, ctx, nullptr, "mockfb"); } }; TEST_F(TmsFunctionBlockTest, Create) { FunctionBlockPtr functionBlock = createFunctionBlock(); - auto tmsFunctionBlock = TmsServerFunctionBlock(functionBlock, this->getServer(), NullContext()); + auto tmsFunctionBlock = TmsServerFunctionBlock(functionBlock, this->getServer(), ctx, tmsCtx); } TEST_F(TmsFunctionBlockTest, Register) { FunctionBlockPtr functionBlock = createFunctionBlock(); - auto serverFunctionBlock = TmsServerFunctionBlock(functionBlock, this->getServer(), NullContext()); + auto serverFunctionBlock = TmsServerFunctionBlock(functionBlock, this->getServer(), ctx, tmsCtx); auto nodeId = serverFunctionBlock.registerOpcUaNode(); ASSERT_TRUE(this->getClient()->nodeExists(nodeId)); @@ -52,7 +50,7 @@ TEST_F(TmsFunctionBlockTest, AttrFunctionBlockType) ASSERT_EQ(serverFunctionBlock.getFunctionBlockType(), type); - auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), ctx, tmsCtx); auto nodeId = tmsServerFunctionBlock.registerOpcUaNode(); auto variant = readChildNode(nodeId, "FunctionBlockInfo"); @@ -68,7 +66,7 @@ TEST_F(TmsFunctionBlockTest, AttrFunctionBlockType) TEST_F(TmsFunctionBlockTest, BrowseSignals) { FunctionBlockPtr functionBlock = createFunctionBlock(); - auto serverFunctionBlock = TmsServerFunctionBlock(functionBlock, this->getServer(), NullContext()); + auto serverFunctionBlock = TmsServerFunctionBlock(functionBlock, this->getServer(), ctx, tmsCtx); auto nodeId = serverFunctionBlock.registerOpcUaNode(); OpcUaServerNode serverNodeFB(*this->getServer(), nodeId); @@ -91,7 +89,7 @@ TEST_F(TmsFunctionBlockTest, DISABLED_Property) serverFunctionBlock.addProperty(sampleRateProp); - auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), ctx, tmsCtx); auto nodeId = tmsServerFunctionBlock.registerOpcUaNode(); auto sampleRateNodeId = this->getChildNodeId(nodeId, "SampleRate"); @@ -118,7 +116,7 @@ TEST_F(TmsFunctionBlockTest, NestedFunctionBlocks) { FunctionBlockPtr functionBlock = createFunctionBlock(); - auto serverFunctionBlock = TmsServerFunctionBlock(functionBlock, this->getServer(), NullContext()); + auto serverFunctionBlock = TmsServerFunctionBlock(functionBlock, this->getServer(), ctx, tmsCtx); auto nodeId = serverFunctionBlock.registerOpcUaNode(); auto firstFB = functionBlock.getFunctionBlocks()[0]; diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp index 9170e0b..f792238 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp @@ -5,7 +5,7 @@ #include "opcuaclient/opcuaclient.h" #include "opcuatms_server/objects/tms_server_input_port.h" #include "opcuatms_server/objects/tms_server_signal.h" -#include "tms_object_test.h" +#include "tms_server_test.h" #include #include #include @@ -17,12 +17,12 @@ using namespace daq; using namespace opcua::tms; using namespace opcua; -class TmsInputPortTest : public TmsObjectTest +class TmsInputPortTest : public TmsServerObjectTest { public: InputPortPtr createInputPort() { - auto port = InputPort(NullContext(), nullptr, "port"); + auto port = InputPort(ctx, nullptr, "port"); port.getTags().add("port"); return port; } @@ -31,13 +31,13 @@ class TmsInputPortTest : public TmsObjectTest TEST_F(TmsInputPortTest, Create) { InputPortPtr inputPort = createInputPort(); - auto tmsInputPort = TmsServerInputPort(inputPort, this->getServer(), NullContext()); + auto tmsInputPort = TmsServerInputPort(inputPort, this->getServer(), ctx, tmsCtx); } TEST_F(TmsInputPortTest, Register) { InputPortPtr inputPort = createInputPort(); - auto serverInputPort = TmsServerInputPort(inputPort, this->getServer(), NullContext()); + auto serverInputPort = TmsServerInputPort(inputPort, this->getServer(), ctx, tmsCtx); auto nodeId = serverInputPort.registerOpcUaNode(); ASSERT_TRUE(this->getClient()->nodeExists(nodeId)); @@ -51,7 +51,7 @@ TEST_F(TmsInputPortTest, ConnectedToReference) SignalPtr signal = Signal(context, nullptr, "sig"); - auto serverSignal = TmsServerSignal(signal, this->getServer(), NullContext()); + auto serverSignal = TmsServerSignal(signal, this->getServer(), ctx, tmsCtx); auto signalNodeId = serverSignal.registerOpcUaNode(); InputPortNotificationsPtr inputPortNotification = TestInputPortNotifications(); @@ -60,7 +60,7 @@ TEST_F(TmsInputPortTest, ConnectedToReference) inputPort.setListener(inputPortNotification); inputPort.connect(signal); - auto serverInputPort = TmsServerInputPort(inputPort, this->getServer(), NullContext()); + auto serverInputPort = TmsServerInputPort(inputPort, this->getServer(), ctx, tmsCtx); auto inputPortNodeId = serverInputPort.registerOpcUaNode(); ASSERT_NO_THROW(serverInputPort.createNonhierarchicalReferences()); diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_property_object.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_property_object.cpp index 45be290..269a20e 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_property_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_property_object.cpp @@ -6,7 +6,7 @@ #include #include "coreobjects/property_object_class_ptr.h" #include "opcuatms_server/objects/tms_server_property_object.h" -#include "tms_object_test.h" +#include "tms_server_test.h" #include #include #include "opendaq/context_factory.h" @@ -16,7 +16,7 @@ using namespace opcua::tms; using namespace opcua; using namespace std::chrono_literals; -class TmsPropertyObjectTest : public TmsObjectTest +class TmsPropertyObjectTest : public TmsServerObjectTest { public: PropertyObjectPtr createPropertyObject() @@ -33,7 +33,7 @@ class TmsPropertyObjectTest : public TmsObjectTest TEST_F(TmsPropertyObjectTest, Create) { PropertyObjectPtr propertyObject = createPropertyObject(); - auto tmsPropertyObject = TmsServerPropertyObject(propertyObject, this->getServer(), NullContext()); + auto tmsPropertyObject = TmsServerPropertyObject(propertyObject, this->getServer(), ctx, tmsCtx); } TEST_F(TmsPropertyObjectTest, BaseObjectList) @@ -46,7 +46,7 @@ TEST_F(TmsPropertyObjectTest, BaseObjectList) list.pushBack(3.0); object.addProperty(ListProperty("ListProp", list)); - auto tmsPropertyObject = TmsServerPropertyObject(object, this->getServer(), NullContext()); + auto tmsPropertyObject = TmsServerPropertyObject(object, this->getServer(), ctx, tmsCtx); auto nodeId = tmsPropertyObject.registerOpcUaNode(); OpcUaObject request; @@ -64,7 +64,7 @@ TEST_F(TmsPropertyObjectTest, Register) { PropertyObjectPtr propertyObject = createPropertyObject(); - auto tmsPropertyObject = TmsServerPropertyObject(propertyObject, this->getServer(), NullContext()); + auto tmsPropertyObject = TmsServerPropertyObject(propertyObject, this->getServer(), ctx, tmsCtx); auto nodeId = tmsPropertyObject.registerOpcUaNode(); ASSERT_TRUE(this->getClient()->nodeExists(nodeId)); @@ -74,7 +74,7 @@ TEST_F(TmsPropertyObjectTest, OnPropertyValueChangeEvent) { PropertyObjectPtr propertyObject = createPropertyObject(); - auto tmsPropertyObject = TmsServerPropertyObject(propertyObject, this->getServer(), NullContext()); + auto tmsPropertyObject = TmsServerPropertyObject(propertyObject, this->getServer(), ctx, tmsCtx); auto nodeId = tmsPropertyObject.registerOpcUaNode(); OpcUaObject request = UA_CreateSubscriptionRequest_default(); diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_signal.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_signal.cpp index 68d156f..b795f30 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_signal.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_signal.cpp @@ -8,14 +8,13 @@ #include "opcuaclient/opcuaclient.h" #include "opcuatms_server/objects/tms_server_input_port.h" #include "opcuatms_server/objects/tms_server_signal.h" -#include "tms_object_test.h" -#include +#include "tms_server_test.h" using namespace daq; using namespace opcua::tms; using namespace opcua; -class TmsSignalTest : public TmsObjectTest +class TmsSignalTest : public TmsServerObjectTest { public: SignalPtr createSignal(const ContextPtr& context, const StringPtr& localId = "sig") @@ -28,14 +27,14 @@ class TmsSignalTest : public TmsObjectTest TEST_F(TmsSignalTest, Create) { - SignalPtr signal = Signal(NullContext(), nullptr, "sig"); - auto tmsSignal = TmsServerSignal(signal, this->getServer(), NullContext()); + SignalPtr signal = Signal(ctx, nullptr, "sig"); + auto tmsSignal = TmsServerSignal(signal, this->getServer(), ctx, tmsCtx); } TEST_F(TmsSignalTest, Register) { - SignalPtr signal = Signal(NullContext(), nullptr, "sig"); - auto serverSignal = TmsServerSignal(signal, this->getServer(), NullContext()); + SignalPtr signal = Signal(ctx, nullptr, "sig"); + auto serverSignal = TmsServerSignal(signal, this->getServer(), ctx, tmsCtx); auto nodeId = serverSignal.registerOpcUaNode(); ASSERT_TRUE(this->getClient()->nodeExists(nodeId)); @@ -43,14 +42,14 @@ TEST_F(TmsSignalTest, Register) TEST_F(TmsSignalTest, DomainSignalReference) { - SignalPtr signal = createSignal(NullContext(), "signal"); - SignalPtr domainSignal = createSignal(NullContext(), "time signal"); + SignalPtr signal = createSignal(ctx, "signal"); + SignalPtr domainSignal = createSignal(ctx, "time signal"); signal.asPtr(true).setDomainSignal(domainSignal); - auto serverSignal = TmsServerSignal(signal, this->getServer(), NullContext()); + auto serverSignal = TmsServerSignal(signal, this->getServer(), ctx, tmsCtx); auto signalNodeId = serverSignal.registerOpcUaNode(); - auto serverDomainSignal = TmsServerSignal(domainSignal, this->getServer(), NullContext()); + auto serverDomainSignal = TmsServerSignal(domainSignal, this->getServer(), ctx, tmsCtx); auto domainSignalNodeId = serverDomainSignal.registerOpcUaNode(); ASSERT_NO_THROW(serverSignal.createNonhierarchicalReferences()); diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.cpp new file mode 100644 index 0000000..6b56cb7 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.cpp @@ -0,0 +1,17 @@ +#include "tms_server_test.h" + +void TmsServerObjectTest::SetUp() +{ + TmsObjectTest::SetUp(); + + ctx = daq::NullContext(); + tmsCtx = std::make_shared(ctx); +} + +void TmsServerObjectTest::TearDown() +{ + ctx = nullptr; + tmsCtx = nullptr; + + TmsObjectTest::TearDown(); +} diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.h b/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.h new file mode 100644 index 0000000..8f1eb46 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.h @@ -0,0 +1,30 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "tms_object_test.h" +#include +#include "opcuatms_server/tms_server_context.h" + +class TmsServerObjectTest : public TmsObjectTest +{ +public: + void SetUp() override; + void TearDown() override; + + daq::ContextPtr ctx; + daq::opcua::tms::TmsServerContextPtr tmsCtx; +}; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp index 4287f97..a252116 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp @@ -174,8 +174,9 @@ class TmsPropertyObjectAdvancedTest : public TmsObjectIntegrationTest RegisteredPropertyObject registerPropertyObject(const PropertyObjectPtr& prop) { const auto logger = Logger(); + const auto context = Context(nullptr, logger, manager, nullptr); const auto serverProp = - std::make_shared(prop, server, Context(nullptr, logger, manager, nullptr)); + std::make_shared(prop, server, context, std::make_shared(context)); const auto nodeId = serverProp->registerOpcUaNode(); const auto clientProp = TmsClientPropertyObject(Context(nullptr, logger, manager,nullptr), clientContext, nodeId); return {serverProp, clientProp}; @@ -190,7 +191,7 @@ TEST_F(TmsPropertyObjectAdvancedTest, SetUpServer) { const auto obj = PropertyObject(manager, "TestClass"); - const auto serverProp = std::make_shared(obj, server, NullContext()); + const auto serverProp = std::make_shared(obj, server, ctx, serverContext); const auto nodeId = serverProp->registerOpcUaNode(); } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp index 5d35256..52d1fc5 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp @@ -12,7 +12,7 @@ #include "stream/WebsocketClientStream.hpp" #include #include - +#include #include #include #include @@ -92,7 +92,7 @@ class StreamingIntegrationTest : public testing::Test PacketReaderPtr createReader(const DevicePtr& device, const std::string& signalName) { - auto signals = device.getSignalsRecursive(); + auto signals = device.getSignals(search::Recursive(search::Visible())); for (const auto& signal : signals) { @@ -190,7 +190,7 @@ class StreamingIntegrationTest : public testing::Test void setActiveStreamingSource(const DevicePtr& device) { - for (const auto& signal : device.getSignalsRecursive()) + for (const auto& signal : device.getSignals(search::Recursive(search::Visible()))) { auto mirroredSignalConfigPtr = signal.template asPtr(); mirroredSignalConfigPtr.setActiveStreamingSource(STREAMING_URL); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp index 53d0e00..1b39f54 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp @@ -282,8 +282,9 @@ class TMSAmplifierTest : public TmsObjectIntegrationTest RegisteredPropertyObject registerPropertyObject(const PropertyObjectPtr& prop) { const auto logger = Logger(); + const auto context = Context(nullptr, logger, TypeManager(), nullptr); const auto serverProp = - std::make_shared(prop, server, Context(nullptr, logger, TypeManager(), nullptr)); + std::make_shared(prop, server, context, std::make_shared(context)); const auto nodeId = serverProp->registerOpcUaNode(); const auto clientProp = TmsClientPropertyObject(Context(nullptr, logger, TypeManager(), nullptr), clientContext, nodeId); return {serverProp, clientProp}; @@ -294,7 +295,7 @@ TEST_F(TMSAmplifierTest, SetUpServerLv) { const auto obj = PropertyObject(objManager, "LvAmp"); - const auto serverProp = std::make_shared(obj, server, NullContext()); + const auto serverProp = std::make_shared(obj, server, ctx, serverContext); const auto nodeId = serverProp->registerOpcUaNode(); } @@ -302,7 +303,7 @@ TEST_F(TMSAmplifierTest, SetUpServerStg) { const auto obj = PropertyObject(objManager, "StgAmp"); - const auto serverProp = std::make_shared(obj, server, NullContext()); + const auto serverProp = std::make_shared(obj, server, ctx, serverContext); const auto nodeId = serverProp->registerOpcUaNode(); } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_channel.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_channel.cpp index 1241c76..34919ed 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_channel.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_channel.cpp @@ -28,16 +28,15 @@ class TmsChannelTest : public TmsObjectIntegrationTest TEST_F(TmsChannelTest, Create) { - auto ctx = NullContext(); ChannelPtr channel = createChannel(ctx); - auto tmsChannel = TmsServerChannel(channel, this->getServer(), NullContext()); + auto tmsChannel = TmsServerChannel(channel, this->getServer(), ctx, serverContext); } TEST_F(TmsChannelTest, Register) { auto ctx = NullContext(); ChannelPtr channel = createChannel(ctx); - auto serverChannel = TmsServerChannel(channel, this->getServer(), NullContext()); // Not possible either + auto serverChannel = TmsServerChannel(channel, this->getServer(), ctx, serverContext); // Not possible either auto nodeId = serverChannel.registerOpcUaNode(); ChannelPtr clientChannel = TmsClientChannel(ctx, nullptr, "ch", clientContext, nodeId); @@ -49,7 +48,7 @@ TEST_F(TmsChannelTest, BrowseName) auto ctx = NullContext(); ChannelPtr serverChannel = createChannel(ctx); - auto tmsServerChannel = TmsServerChannel(serverChannel, this->getServer(), NullContext()); + auto tmsServerChannel = TmsServerChannel(serverChannel, this->getServer(), ctx, serverContext); auto nodeId = tmsServerChannel.registerOpcUaNode(); ChannelPtr clientChannel = TmsClientChannel(ctx, nullptr, "ch", clientContext, nodeId); @@ -66,7 +65,7 @@ TEST_F(TmsChannelTest, AttrFunctionBlockType) auto ctx = NullContext(); ChannelPtr serverChannel = createChannel(ctx); - auto tmsServerChannel = TmsServerChannel(serverChannel, this->getServer(), NullContext()); + auto tmsServerChannel = TmsServerChannel(serverChannel, this->getServer(), ctx, serverContext); auto nodeId = tmsServerChannel.registerOpcUaNode(); ChannelPtr clientChannel = TmsClientChannel(ctx, nullptr, "ch", clientContext, nodeId); @@ -82,7 +81,7 @@ TEST_F(TmsChannelTest, MethodGetInputPorts) auto ctx = NullContext(); ChannelPtr serverChannel = createChannel(ctx); - auto tmsServerChannel = TmsServerChannel(serverChannel, this->getServer(), NullContext()); + auto tmsServerChannel = TmsServerChannel(serverChannel, this->getServer(), ctx, serverContext); auto channelNodeId = tmsServerChannel.registerOpcUaNode(); ChannelPtr clientChannel = TmsClientChannel(ctx, nullptr, "ch", clientContext, channelNodeId); @@ -101,7 +100,7 @@ TEST_F(TmsChannelTest, MethodGetSignals) auto ctx = NullContext(); ChannelPtr serverChannel = createChannel(ctx); - auto tmsServerChannel = TmsServerChannel(serverChannel, this->getServer(), NullContext()); + auto tmsServerChannel = TmsServerChannel(serverChannel, this->getServer(), ctx, serverContext); auto channelNodeId = tmsServerChannel.registerOpcUaNode(); auto clientChannel = TmsClientChannel(ctx, nullptr, "ch", clientContext, channelNodeId); @@ -128,11 +127,11 @@ TEST_F(TmsChannelTest, MethodGetStatusSignal) auto ctx = NullContext(); ChannelPtr serverChannel = createChannel(ctx); - auto tmsServerChannel = TmsServerChannel(serverChannel, this->getServer(), NullContext()); + auto tmsServerChannel = TmsServerChannel(serverChannel, this->getServer(), ctx, serverContext); auto channelNodeId = tmsServerChannel.registerOpcUaNode(); SignalPtr serverSignal = Signal(ctx, nullptr, "sig"); - auto tmsServerSignal = TmsServerSignal(serverSignal, this->getServer(), NullContext()); + auto tmsServerSignal = TmsServerSignal(serverSignal, this->getServer(), ctx, serverContext); auto signalNodeId = tmsServerSignal.registerOpcUaNode(); OpcUaNodeId referenceTypeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASSTATUSSIGNAL); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_component.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_component.cpp index 835df30..716e998 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_component.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_component.cpp @@ -21,7 +21,7 @@ class TmsComponentTest : public TmsObjectIntegrationTest public: ComponentPtr createTestComponent() { - auto component = Component(NullContext(), nullptr, "test"); + auto component = Component(ctx, nullptr, "test"); component.addProperty(StringProperty("foo", "bar")); auto obj = PropertyObject(); @@ -30,6 +30,7 @@ class TmsComponentTest : public TmsObjectIntegrationTest component.getTags().add("tag1"); component.getTags().add("tag2"); + return component; } @@ -42,7 +43,9 @@ class TmsComponentTest : public TmsObjectIntegrationTest component.serverComponent = createTestComponent(); else component.serverComponent = customComponent; - component.serverObject = std::make_shared>(component.serverComponent, this->getServer(), NullContext()); + + component.serverComponent.asPtr().enableCoreEventTrigger(); + component.serverObject = std::make_shared>(component.serverComponent, this->getServer(), ctx, serverContext); auto nodeId = component.serverObject->registerOpcUaNode(); component.clientComponent = TmsClientComponent(NullContext(), nullptr, "test", clientContext, nodeId); return component; @@ -52,7 +55,7 @@ class TmsComponentTest : public TmsObjectIntegrationTest TEST_F(TmsComponentTest, Create) { auto component = createTestComponent(); - auto serverComponent = TmsServerComponent(component, this->getServer(), NullContext()); + auto serverComponent = TmsServerComponent(component, this->getServer(), ctx, serverContext); } TEST_F(TmsComponentTest, Register) @@ -109,14 +112,17 @@ TEST_F(TmsComponentTest, NameAndDescription) component.clientComponent.setName("newer_name"); component.clientComponent.setDescription("newer_description"); - ASSERT_EQ(component.serverComponent.getName(), component.clientComponent.getName()); - ASSERT_EQ(component.serverComponent.getDescription(), component.clientComponent.getDescription()); + ASSERT_EQ(component.serverComponent.getName(), "newer_name"); + ASSERT_EQ(component.clientComponent.getName(), "newer_name"); + ASSERT_EQ(component.serverComponent.getDescription(), "newer_description"); + ASSERT_EQ(component.clientComponent.getDescription(), "newer_description"); } -TEST_F(TmsComponentTest, NameAndDescriptionReadOnly) +TEST_F(TmsComponentTest, NameAndDescriptionLocked) { - const auto name = "read_only"; - const auto customComponent = Component(NullContext(), nullptr, name, ComponentStandardProps::AddReadOnly); + const auto name = "locked"; + const auto customComponent = Component(NullContext(), nullptr, name); + customComponent.asPtr().lockAttributes(List("Name", "Description")); const auto component = registerTestComponent(customComponent); ASSERT_NO_THROW(component.clientComponent.setName("new_name")); @@ -124,15 +130,3 @@ TEST_F(TmsComponentTest, NameAndDescriptionReadOnly) ASSERT_EQ(component.clientComponent.getName(), name); } - -TEST_F(TmsComponentTest, NameAndDescriptionSkip) -{ - const auto name = "read_only"; - const auto customComponent = Component(NullContext(), nullptr, name, ComponentStandardProps::Skip); - const auto component = registerTestComponent(customComponent); - - ASSERT_NO_THROW(component.clientComponent.setName("new_name")); - ASSERT_NO_THROW(component.clientComponent.setDescription("new_description")); - - ASSERT_EQ(component.clientComponent.getName(), name); -} \ No newline at end of file diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp index 0a59368..d603568 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp @@ -10,6 +10,7 @@ #include "opcuatms/exceptions.h" #include #include +#include #include "tms_object_integration_test.h" using namespace daq; @@ -43,7 +44,7 @@ TEST_F(TmsDeviceTest, CreateClientDevice) { DevicePtr serverDevice = createDevice(); - auto tmsPropertyObject = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto tmsPropertyObject = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = tmsPropertyObject.registerOpcUaNode(); auto ctx = NullContext(); ASSERT_NO_THROW(TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr)); @@ -53,7 +54,7 @@ TEST_F(TmsDeviceTest, SubDevices) { DevicePtr serverDevice = createDevice(); - auto tmsPropertyObject = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto tmsPropertyObject = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = tmsPropertyObject.registerOpcUaNode(); auto ctx = NullContext(); @@ -66,7 +67,7 @@ TEST_F(TmsDeviceTest, FunctionBlocks) auto ctx = NullContext(); DevicePtr serverDevice = createDevice(); - auto tmsPropertyObject = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto tmsPropertyObject = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = tmsPropertyObject.registerOpcUaNode(); auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); @@ -82,7 +83,7 @@ TEST_F(TmsDeviceTest, GetSignals) { DevicePtr serverDevice = createDevice(); - auto tmsPropertyObject = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto tmsPropertyObject = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = tmsPropertyObject.registerOpcUaNode(); auto ctx = NullContext(); @@ -103,15 +104,15 @@ TEST_F(TmsDeviceTest, GetSignals) ASSERT_EQ(signals.getCount(), 0u); } - ASSERT_NO_THROW(signals = clientDevice.getSignalsRecursive()); - ASSERT_EQ(signals.getCount(), serverDevice.getSignalsRecursive().getCount()); + ASSERT_NO_THROW(signals = clientDevice.getSignals(search::Recursive(search::Visible()))); + ASSERT_EQ(signals.getCount(), serverDevice.getSignals(search::Recursive(search::Visible())).getCount()); } TEST_F(TmsDeviceTest, GetChannels) { DevicePtr serverDevice = createDevice(); - auto tmsPropertyObject = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto tmsPropertyObject = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = tmsPropertyObject.registerOpcUaNode(); auto ctx = NullContext(); @@ -120,8 +121,8 @@ TEST_F(TmsDeviceTest, GetChannels) ASSERT_NO_THROW(channels = clientDevice.getChannels()); ASSERT_EQ(channels.getCount(), serverDevice.getChannels().getCount()); - ASSERT_NO_THROW(channels = clientDevice.getChannelsRecursive()); - ASSERT_EQ(channels.getCount(), serverDevice.getChannelsRecursive().getCount()); + ASSERT_NO_THROW(channels = clientDevice.getChannels(search::Recursive(search::Visible()))); + ASSERT_EQ(channels.getCount(), serverDevice.getChannels(search::Recursive(search::Visible())).getCount()); } // TODO: Enable once name and description are no longer props @@ -133,7 +134,7 @@ TEST_F(TmsDeviceTest, DISABLED_Property) serverDevice.addProperty(sampleRateProp); - auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = serverTmsDevice.registerOpcUaNode(); auto ctx = NullContext(); @@ -164,7 +165,7 @@ TEST_F(TmsDeviceTest, DeviceInfo) auto ctx = NullContext(); DevicePtr serverDevice = createDevice(); - auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = serverTmsDevice.registerOpcUaNode(); auto serverSubDevices = serverDevice.getDevices(); @@ -222,7 +223,7 @@ TEST_F(TmsDeviceTest, DeviceDomain) auto ctx = NullContext(); DevicePtr serverDevice = createDevice(); - auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = serverTmsDevice.registerOpcUaNode(); auto serverSubDevices = serverDevice.getDevices(); @@ -261,7 +262,7 @@ TEST_F(TmsDeviceTest, CustomComponents) auto ctx = NullContext(); DevicePtr serverDevice = createDevice(); - auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = serverTmsDevice.registerOpcUaNode(); auto serverSubDevice = serverDevice.getDevices()[1]; @@ -283,7 +284,7 @@ TEST_F(TmsDeviceTest, CustomComponentsProperties) auto ctx = NullContext(); DevicePtr serverDevice = createDevice(); - auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = serverTmsDevice.registerOpcUaNode(); auto serverSubDevice = serverDevice.getDevices()[1]; @@ -306,7 +307,7 @@ TEST_F(TmsDeviceTest, ComponentMethods) auto ctx = NullContext(); DevicePtr serverDevice = createDevice(); - auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = serverTmsDevice.registerOpcUaNode(); auto serverSubDevice = serverDevice.getDevices()[1]; @@ -333,7 +334,7 @@ TEST_F(TmsDeviceTest, DeviceProcedureProperty) auto ctx = NullContext(); DevicePtr serverDevice = createDevice(); - auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = serverTmsDevice.registerOpcUaNode(); auto clientDevice = TmsClientRootDevice(ctx, nullptr, "Dev", clientContext, nodeId, nullptr); auto clientSubDevice = clientDevice.getDevices()[1]; @@ -352,7 +353,7 @@ TEST_F(TmsDeviceTest, SignalOrder) for (int i = 0; i < 100; ++i) folder.addItem(Signal(NullContext(), folder, "sig_" + std::to_string(i))); - auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = tmsServerDevice.registerOpcUaNode(); DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "Dev", clientContext, nodeId, nullptr); @@ -370,7 +371,7 @@ TEST_F(TmsDeviceTest, DeviceOrder) for (int i = 0; i < 100; ++i) folder.addItem(DefaultDevice(NullContext(), folder, "dev_" + std::to_string(i))); - auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = tmsServerDevice.registerOpcUaNode(); DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "Dev", clientContext, nodeId, nullptr); @@ -388,7 +389,7 @@ TEST_F(TmsDeviceTest, FunctionBlockOrder) for (int i = 0; i < 100; ++i) folder.addItem(DefaultFunctionBlock(NullContext(), folder, "fb_" + std::to_string(i))); - auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = tmsServerDevice.registerOpcUaNode(); DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "Dev", clientContext, nodeId, nullptr); @@ -409,7 +410,7 @@ TEST_F(TmsDeviceTest, IOFolderOrder) folder.addItem(DefaultChannel(NullContext(), folder, "ch_" + std::to_string(i))); } - auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = tmsServerDevice.registerOpcUaNode(); DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "Dev", clientContext, nodeId, nullptr); @@ -427,7 +428,7 @@ TEST_F(TmsDeviceTest, CustomComponentOrder) for (int i = 0; i < 100; ++i) folder->addCustomComponent(Component(NullContext(), folder, "cmp_" + std::to_string(i))); - auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), NullContext()); + auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = tmsServerDevice.registerOpcUaNode(); DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "Dev", clientContext, nodeId, nullptr); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp index f87e0d6..62b38bf 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp @@ -56,7 +56,7 @@ class TmsFolderTest : public TmsObjectIntegrationTest RegisteredFolder folder{}; folder.serverFolder = testFolder; - folder.serverObject = std::make_shared(folder.serverFolder, this->getServer(), NullContext()); + folder.serverObject = std::make_shared(folder.serverFolder, this->getServer(), ctx, serverContext); auto nodeId = folder.serverObject->registerOpcUaNode(); if (testFolder.asPtrOrNull().assigned()) folder.clientFolder = TmsClientIoFolder(NullContext(), nullptr, "test", clientContext, nodeId); @@ -70,7 +70,7 @@ class TmsFolderTest : public TmsObjectIntegrationTest TEST_F(TmsFolderTest, Create) { auto folder = createTestFolder(); - auto serverFolder = TmsServerFolder(folder, this->getServer(), NullContext()); + auto serverFolder = TmsServerFolder(folder, this->getServer(), ctx, serverContext); } TEST_F(TmsFolderTest, Register) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp index ebf3ff7..434eae9 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp @@ -38,13 +38,13 @@ class TmsFunctionBlockTest : public TmsObjectIntegrationTest TEST_F(TmsFunctionBlockTest, Create) { FunctionBlockPtr functionBlock = createFunctionBlock(); - auto tmsFunctionBlock = TmsServerFunctionBlock(functionBlock, this->getServer(), NullContext()); + auto tmsFunctionBlock = TmsServerFunctionBlock(functionBlock, this->getServer(), ctx, serverContext); } TEST_F(TmsFunctionBlockTest, Register) { FunctionBlockPtr functionBlock = createFunctionBlock(); - auto serverFunctionBlock = TmsServerFunctionBlock(functionBlock, this->getServer(), NullContext()); // Not possible either + auto serverFunctionBlock = TmsServerFunctionBlock(functionBlock, this->getServer(), ctx, serverContext); // Not possible either auto nodeId = serverFunctionBlock.registerOpcUaNode(); FunctionBlockPtr clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, nodeId); @@ -61,7 +61,7 @@ TEST_F(TmsFunctionBlockTest, BrowseName) ASSERT_EQ(serverFunctionBlock.getFunctionBlockType(), type); - auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), ctx, serverContext); auto nodeId = tmsServerFunctionBlock.registerOpcUaNode(); FunctionBlockPtr clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, nodeId); @@ -83,7 +83,7 @@ TEST_F(TmsFunctionBlockTest, AttrFunctionBlockType) ASSERT_EQ(serverFunctionBlock.getFunctionBlockType(), type); - auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), ctx, serverContext); auto nodeId = tmsServerFunctionBlock.registerOpcUaNode(); FunctionBlockPtr clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, nodeId); @@ -98,7 +98,7 @@ TEST_F(TmsFunctionBlockTest, MethodGetInputPorts) { const FunctionBlockTypePtr type = FunctionBlockType("UNIQUE ID", "NAME", "DESCRIPTION"); auto serverFunctionBlock = createFunctionBlock(type); - auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), ctx, serverContext); auto functionBlockNodeId = tmsServerFunctionBlock.registerOpcUaNode(); FunctionBlockPtr clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, functionBlockNodeId); @@ -115,7 +115,7 @@ TEST_F(TmsFunctionBlockTest, MethodGetSignals) { const FunctionBlockTypePtr type = FunctionBlockType("UNIQUE ID", "NAME", "DESCRIPTION"); auto serverFunctionBlock = createFunctionBlock(type); - auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), ctx, serverContext); auto functionBlockNodeId = tmsServerFunctionBlock.registerOpcUaNode(); auto clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, functionBlockNodeId); @@ -137,7 +137,7 @@ TEST_F(TmsFunctionBlockTest, SignalCheckGlobalId) { const FunctionBlockTypePtr type = FunctionBlockType("UNIQUE ID", "NAME", "DESCRIPTION"); auto serverFunctionBlock = createFunctionBlock(type); - auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), ctx, serverContext); auto functionBlockNodeId = tmsServerFunctionBlock.registerOpcUaNode(); auto clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, serverFunctionBlock.getLocalId(), clientContext, functionBlockNodeId); @@ -153,11 +153,11 @@ TEST_F(TmsFunctionBlockTest, MethodGetStatusSignal) { const FunctionBlockTypePtr type = FunctionBlockType("UNIQUE ID", "NAME", "DESCRIPTION"); auto serverFunctionBlock = createFunctionBlock(type); - auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), ctx, serverContext); auto functionBlockNodeId = tmsServerFunctionBlock.registerOpcUaNode(); SignalPtr serverSignal = Signal(NullContext(), nullptr, "sig"); - auto tmsServerSignal = TmsServerSignal(serverSignal, this->getServer(), NullContext()); + auto tmsServerSignal = TmsServerSignal(serverSignal, this->getServer(), ctx, serverContext); auto signalNodeId = tmsServerSignal.registerOpcUaNode(); OpcUaNodeId referenceTypeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASSTATUSSIGNAL); @@ -179,7 +179,7 @@ TEST_F(TmsFunctionBlockTest, Property) serverFunctionBlock.addProperty(sampleRateProp); - auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), ctx, serverContext); auto nodeId = tmsServerFunctionBlock.registerOpcUaNode(); auto clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, nodeId); @@ -203,7 +203,7 @@ TEST_F(TmsFunctionBlockTest, Property) TEST_F(TmsFunctionBlockTest, NestedFunctionBlocks) { auto serverFunctionBlock = createFunctionBlock(); - auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), ctx, serverContext); auto functionBlockNodeId = tmsServerFunctionBlock.registerOpcUaNode(); FunctionBlockPtr clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, functionBlockNodeId); @@ -215,7 +215,7 @@ TEST_F(TmsFunctionBlockTest, NestedFunctionBlocks) TEST_F(TmsFunctionBlockTest, ComponentMethods) { auto serverFunctionBlock = createFunctionBlock(); - auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), ctx, serverContext); auto functionBlockNodeId = tmsServerFunctionBlock.registerOpcUaNode(); FunctionBlockPtr clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, functionBlockNodeId); @@ -242,7 +242,7 @@ TEST_F(TmsFunctionBlockTest, SignalOrder) for (int i = 0; i < 100; ++i) folder.addItem(Signal(NullContext(), folder, "sig_" + std::to_string(i))); - auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), ctx, serverContext); auto functionBlockNodeId = tmsServerFunctionBlock.registerOpcUaNode(); FunctionBlockPtr clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, functionBlockNodeId); @@ -260,7 +260,7 @@ TEST_F(TmsFunctionBlockTest, InputPortOrder) for (int i = 0; i < 100; ++i) folder.addItem(InputPort(NullContext(), folder, "ip_" + std::to_string(i))); - auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), ctx, serverContext); auto functionBlockNodeId = tmsServerFunctionBlock.registerOpcUaNode(); FunctionBlockPtr clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, functionBlockNodeId); @@ -278,7 +278,7 @@ TEST_F(TmsFunctionBlockTest, FunctionBlockOrder) for (int i = 0; i < 40; ++i) folder.addItem(DefaultFunctionBlock(NullContext(), folder, "fb_" + std::to_string(i))); - auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), NullContext()); + auto tmsServerFunctionBlock = TmsServerFunctionBlock(serverFunctionBlock, this->getServer(), ctx, serverContext); auto functionBlockNodeId = tmsServerFunctionBlock.registerOpcUaNode(); FunctionBlockPtr clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, functionBlockNodeId); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_property.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_property.cpp index ab76f86..8c53564 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_property.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_property.cpp @@ -24,7 +24,7 @@ class TmsFunctionTest: public TmsObjectIntegrationTest public: RegisteredPropertyObject registerPropertyObject(const PropertyObjectPtr& obj) { - const auto serverProp = std::make_shared(obj, server, NullContext()); + const auto serverProp = std::make_shared(obj, server, ctx, serverContext); const auto nodeId = serverProp->registerOpcUaNode(); const auto clientProp = TmsClientPropertyObject(NullContext(), clientContext, nodeId); return {serverProp, clientProp}; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp index 281df7e..bb30c03 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp @@ -36,14 +36,14 @@ class TmsInputPortTest : public TmsObjectIntegrationTest TEST_F(TmsInputPortTest, Create) { InputPortPtr inputPort = createInputPort("The Name", false); - auto tmsInputPort = TmsServerInputPort(inputPort, this->getServer(), NullContext()); + auto tmsInputPort = TmsServerInputPort(inputPort, this->getServer(), ctx, serverContext); } TEST_F(TmsInputPortTest, Register) { const std::string name{"Some Name"}; InputPortPtr daqServerInputPort = createInputPort(name, false); - auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), NullContext()); + auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), ctx, serverContext); auto nodeId = serverInputPort.registerOpcUaNode(); InputPortPtr clientInputPort = TmsClientInputPort(NullContext(), nullptr, "inputPort", clientContext, nodeId); @@ -54,7 +54,7 @@ TEST_F(TmsInputPortTest, BrowseName) { const std::string name{"Some Name"}; InputPortPtr daqServerInputPort = createInputPort(name, false); - auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), NullContext()); + auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), ctx, serverContext); auto nodeId = serverInputPort.registerOpcUaNode(); auto browseName = client->readBrowseName(nodeId); @@ -68,7 +68,7 @@ TEST_F(TmsInputPortTest, AttrName) ASSERT_FALSE(daqServerInputPort.getRequiresSignal()); ASSERT_EQ(daqServerInputPort.getLocalId(), name); - auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), NullContext()); + auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), ctx, serverContext); auto nodeId = serverInputPort.registerOpcUaNode(); auto browseName = clientContext->getClient()->readBrowseName(nodeId); @@ -81,7 +81,7 @@ TEST_F(TmsInputPortTest, AttrName) TEST_F(TmsInputPortTest, AttrRequiresSignalFalse) { InputPortPtr daqServerInputPort = createInputPort("The Name", false); - auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), NullContext()); + auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), ctx, serverContext); auto nodeId = serverInputPort.registerOpcUaNode(); InputPortPtr clientInputPort = TmsClientInputPort(NullContext(), nullptr, "inputPort", clientContext, nodeId); @@ -93,7 +93,7 @@ TEST_F(TmsInputPortTest, AttrRequiresSignalFalse) TEST_F(TmsInputPortTest, AttrRequiresSignalTrue) { InputPortPtr daqServerInputPort = createInputPort("The Name", true); - auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), NullContext()); + auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), ctx, serverContext); auto nodeId = serverInputPort.registerOpcUaNode(); InputPortPtr clientInputPort = TmsClientInputPort(NullContext(), nullptr, "inputPort", clientContext, nodeId); @@ -106,7 +106,7 @@ TEST_F(TmsInputPortTest, MethodAcceptsSignal) { SignalPtr signal = Signal(NullContext(), nullptr, "sig"); InputPortPtr daqServerInputPort = createInputPort("The Name", true); - auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), NullContext()); + auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), ctx, serverContext); auto nodeId = serverInputPort.registerOpcUaNode(); InputPortPtr clientInputPort = TmsClientInputPort(NullContext(), nullptr, "inputPort", clientContext, nodeId); @@ -120,7 +120,7 @@ TEST_F(TmsInputPortTest, MethodConnectSignal) SignalPtr signal = Signal(NullContext(), nullptr, "sig"); InputPortPtr daqServerInputPort = createInputPort("The Name", true); - auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), NullContext()); + auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), ctx, serverContext); auto nodeId = serverInputPort.registerOpcUaNode(); InputPortPtr clientInputPort = TmsClientInputPort(NullContext(), nullptr, "inputPort", clientContext, nodeId); @@ -132,7 +132,7 @@ TEST_F(TmsInputPortTest, MethodConnectSignal) TEST_F(TmsInputPortTest, MethodDisconnectSignal) { InputPortPtr daqServerInputPort = createInputPort("The Name", true); - auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), NullContext()); + auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), ctx, serverContext); auto nodeId = serverInputPort.registerOpcUaNode(); InputPortPtr clientInputPort = TmsClientInputPort(NullContext(), nullptr, "inputPort", clientContext, nodeId); @@ -161,7 +161,7 @@ TEST_F(TmsInputPortTest, ConnectedToReference) SignalPtr signal = Signal(context, nullptr, "sig"); - auto serverSignal = TmsServerSignal(signal, this->getServer(), NullContext()); + auto serverSignal = TmsServerSignal(signal, this->getServer(), ctx, serverContext); auto signalNodeId = serverSignal.registerOpcUaNode(); InputPortNotificationsPtr inputPortNotification = TestInputPortNotifications(); @@ -170,7 +170,7 @@ TEST_F(TmsInputPortTest, ConnectedToReference) inputPort.setListener(inputPortNotification); inputPort.connect(signal); - auto serverInputPort = TmsServerInputPort(inputPort, this->getServer(), NullContext()); + auto serverInputPort = TmsServerInputPort(inputPort, this->getServer(), ctx, serverContext); auto inputPortNodeId = serverInputPort.registerOpcUaNode(); ASSERT_NO_THROW(serverInputPort.createNonhierarchicalReferences()); @@ -187,7 +187,7 @@ TEST_F(TmsInputPortTest, ComponentMethods) { const std::string name{"inputPort"}; InputPortPtr daqServerInputPort = createInputPort(name, false); - auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), NullContext()); + auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), ctx, serverContext); auto nodeId = serverInputPort.registerOpcUaNode(); InputPortPtr clientInputPort = TmsClientInputPort(NullContext(), nullptr, "inputPort", clientContext, nodeId); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index d59db45..7b6020d 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -4,7 +4,7 @@ #include #include #include - +#include #include #include @@ -127,8 +127,8 @@ TEST_F(TmsIntegrationTest, GetSignals) DevicePtr clientDevice = tmsClient.connect(); ListPtr signals; - ASSERT_NO_THROW(signals = clientDevice.getSignalsRecursive()); - ASSERT_EQ(signals.getCount(), device.getSignalsRecursive().getCount()); + ASSERT_NO_THROW(signals = clientDevice.getSignals(search::Recursive(search::Visible()))); + ASSERT_EQ(signals.getCount(), device.getSignals(search::Recursive(search::Visible())).getCount()); ASSERT_NO_THROW(signals = clientDevice.getSignals()); ASSERT_EQ(signals.getCount(), 0u); @@ -146,7 +146,7 @@ TEST_F(TmsIntegrationTest, GetChannels) auto device2 = devices.getItemAt(1); ASSERT_EQ(device2.getChannels().getCount(), 4u); - ASSERT_EQ(instance.getChannelsRecursive().getCount(), 4u); + ASSERT_EQ(instance.getChannels(search::Recursive(search::Visible())).getCount(), 4u); ASSERT_EQ(instance.getChannels().getCount(), 0u); } TEST_F(TmsIntegrationTest, InputsOutputs) @@ -227,7 +227,7 @@ TEST_F(TmsIntegrationTest, GetDomainSignal) clientDevice = tmsClient.connect(); } - ListPtr signals = clientDevice.getSignalsRecursive(); + ListPtr signals = clientDevice.getSignals(search::Recursive(search::Visible())); auto byteStepSignal = *std::find_if( signals.begin(), signals.end(), [](const SignalPtr& signal) { return signal.getDescriptor().getName() == "ByteStep"; }); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property.cpp index b891434..908ca91 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property.cpp @@ -64,7 +64,7 @@ class TmsPropertyTest : public TmsObjectIntegrationTest RegisteredProperty registerProperty(const PropertyPtr& prop) { - auto serverProp = std::make_shared(prop, server, NullContext()); + auto serverProp = std::make_shared(prop, server, ctx, serverContext); auto nodeId = serverProp->registerOpcUaNode(); auto clientProp = TmsClientProperty(NullContext(), clientContext, nodeId); return {serverProp, clientProp}; @@ -75,7 +75,7 @@ TEST_F(TmsPropertyTest, Create) { auto prop = createIntProperty(); - auto serverProp = TmsServerProperty(prop, server, NullContext()); + auto serverProp = TmsServerProperty(prop, server, ctx, serverContext); auto nodeId = serverProp.registerOpcUaNode(); ASSERT_TRUE(server->nodeExists(nodeId)); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp index d7c9c5c..1f3e0fc 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp @@ -66,7 +66,7 @@ class TmsPropertyObjectTest : public TmsObjectIntegrationTest RegisteredPropertyObject registerPropertyObject(const PropertyObjectPtr& prop) { - auto serverProp = std::make_shared(prop, server, NullContext()); + auto serverProp = std::make_shared(prop, server, ctx, serverContext); auto nodeId = serverProp->registerOpcUaNode(); auto clientProp = TmsClientPropertyObject(NullContext(), clientContext, nodeId); return {serverProp, clientProp}; @@ -77,7 +77,7 @@ TEST_F(TmsPropertyObjectTest, Create) { auto prop = createPropertyObject(); - auto serverProp = TmsServerPropertyObject(prop, server, NullContext()); + auto serverProp = TmsServerPropertyObject(prop, server, ctx, serverContext); auto nodeId = serverProp.registerOpcUaNode(); ASSERT_TRUE(server->nodeExists(nodeId)); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp index 0c5862a..5ec9329 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp @@ -62,13 +62,14 @@ class TmsSignalTest : public TmsObjectIntegrationTest TEST_F(TmsSignalTest, Create) { SignalPtr signal = Signal(NullContext(), nullptr, "sig"); - auto tmsSignal = TmsServerSignal(signal, this->getServer(), NullContext()); + auto tmsSignal = TmsServerSignal(signal, this->getServer(), ctx, serverContext); + } TEST_F(TmsSignalTest, Register) { SignalPtr signal = createSignal("id"); - auto serverSignal = TmsServerSignal(signal, this->getServer(), NullContext()); + auto serverSignal = TmsServerSignal(signal, this->getServer(), ctx, serverContext); auto nodeId = serverSignal.registerOpcUaNode(); SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); @@ -80,7 +81,7 @@ TEST_F(TmsSignalTest, AttrUniqueId) SignalPtr daqServerSignal = createSignal("id"); daqServerSignal.setActive(true); - auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), NullContext()); + auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), ctx, serverContext); auto nodeId = serverSignal.registerOpcUaNode(); SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "id", clientContext, nodeId); @@ -94,7 +95,7 @@ TEST_F(TmsSignalTest, AttrActive) SignalPtr daqServerSignal = createSignal("id"); daqServerSignal.setActive(true); - auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), NullContext()); + auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), ctx, serverContext); auto nodeId = serverSignal.registerOpcUaNode(); SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); @@ -117,7 +118,7 @@ TEST_F(TmsSignalTest, AttrPublic) { SignalPtr daqServerSignal = createSignal("id"); - auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), NullContext()); + auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), ctx, serverContext); auto nodeId = serverSignal.registerOpcUaNode(); SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); @@ -160,7 +161,7 @@ TEST_F(TmsSignalTest, AttrDescriptor) serverSignal.setDescriptor(serverDataDescriptor); ASSERT_EQ(serverSignal.getDescriptor(), serverDataDescriptor); - auto tmsServerSignal = TmsServerSignal(serverSignal, this->getServer(), NullContext()); + auto tmsServerSignal = TmsServerSignal(serverSignal, this->getServer(), ctx, serverContext); auto nodeId = tmsServerSignal.registerOpcUaNode(); SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); @@ -220,11 +221,11 @@ TEST_F(TmsSignalTest, AttrDescriptor) TEST_F(TmsSignalTest, AttrDomainSignal) { SignalPtr daqServerDomainSignal = createSignal("sig1"); - auto serverDomainSignal = TmsServerSignal(daqServerDomainSignal, this->getServer(), NullContext()); + auto serverDomainSignal = TmsServerSignal(daqServerDomainSignal, this->getServer(), ctx, serverContext); auto domainNodeId = serverDomainSignal.registerOpcUaNode(); SignalPtr daqServerSignal = createSignal("sig2"); - auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), NullContext()); + auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), ctx, serverContext); auto nodeId = serverSignal.registerOpcUaNode(); OpcUaNodeId referenceTypeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASDOMAINSIGNAL); @@ -242,15 +243,15 @@ TEST_F(TmsSignalTest, AttrDomainSignal) TEST_F(TmsSignalTest, AttrRelatedSignals) { SignalPtr daqServerSignal1 = createSignal("id1"); - auto serverSignal1 = TmsServerSignal(daqServerSignal1, this->getServer(), NullContext()); + auto serverSignal1 = TmsServerSignal(daqServerSignal1, this->getServer(), ctx, serverContext); auto nodeId1 = serverSignal1.registerOpcUaNode(); SignalPtr daqServerSignal2 = createSignal("id2"); - auto serverSignal2 = TmsServerSignal(daqServerSignal2, this->getServer(), NullContext()); + auto serverSignal2 = TmsServerSignal(daqServerSignal2, this->getServer(), ctx, serverContext); auto nodeId2 = serverSignal2.registerOpcUaNode(); SignalPtr daqServerSignal3 = createSignal("id3"); - auto serverSignal3 = TmsServerSignal(daqServerSignal3, this->getServer(), NullContext()); + auto serverSignal3 = TmsServerSignal(daqServerSignal3, this->getServer(), ctx, serverContext); auto nodeId3 = serverSignal3.registerOpcUaNode(); OpcUaNodeId referenceTypeId(NAMESPACE_DAQBSP, UA_DAQBSPID_RELATESTOSIGNAL); @@ -285,7 +286,7 @@ TEST_F(TmsSignalTest, AttrRelatedSignals) TEST_F(TmsSignalTest, MethodGetConnections) { SignalPtr daqServerSignal1 = createSignal("id"); - auto serverSignal1 = TmsServerSignal(daqServerSignal1, this->getServer(), NullContext()); + auto serverSignal1 = TmsServerSignal(daqServerSignal1, this->getServer(), ctx, serverContext); auto nodeId1 = serverSignal1.registerOpcUaNode(); SignalPtr clientSignal1 = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId1); @@ -300,7 +301,7 @@ TEST_F(TmsSignalTest, MethodGetConnections) TEST_F(TmsSignalTest, ComponentMethods) { auto signal = createFullSignal("sig"); - auto serverSignal = TmsServerSignal(signal, this->getServer(), NullContext()); + auto serverSignal = TmsServerSignal(signal, this->getServer(), ctx, serverContext); auto nodeId = serverSignal.registerOpcUaNode(); SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); @@ -323,7 +324,7 @@ TEST_F(TmsSignalTest, ExplicitDomainRuleDescriptor) { const auto descriptor = DataDescriptorBuilder().setSampleType(SampleType::Int64).setRule(ExplicitDomainDataRule(5.1, 20)).build(); const auto signal = SignalWithDescriptor(NullContext(), descriptor, nullptr, "sig"); - auto serverSignal = TmsServerSignal(signal, this->getServer(), NullContext()); + auto serverSignal = TmsServerSignal(signal, this->getServer(), ctx, serverContext); auto nodeId = serverSignal.registerOpcUaNode(); SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); @@ -331,6 +332,28 @@ TEST_F(TmsSignalTest, ExplicitDomainRuleDescriptor) ASSERT_EQ(signal.getDescriptor().getRule(), clientSignal.getDescriptor().getRule()); } +TEST_F(TmsSignalTest, Visible) +{ + const auto descriptor = DataDescriptorBuilder().setSampleType(SampleType::Int64).setRule(ExplicitDomainDataRule()).build(); + const auto signal = Signal(NullContext(), nullptr, "sig"); + signal.asPtr().unlockAllAttributes(); + auto serverSignal = TmsServerSignal(signal, this->getServer(), ctx, serverContext); + const auto nodeId = serverSignal.registerOpcUaNode(); + const SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); + + ASSERT_EQ(signal.getVisible(), clientSignal.getVisible()); + ASSERT_NO_THROW(clientSignal.setVisible(false)); + ASSERT_EQ(signal.getVisible(), false); + ASSERT_EQ(clientSignal.getVisible(), false); + + signal.asPtr().lockAllAttributes(); + + ASSERT_EQ(signal.getVisible(), clientSignal.getVisible()); + ASSERT_NO_THROW(clientSignal.setVisible(true)); + ASSERT_EQ(signal.getVisible(), false); + ASSERT_EQ(clientSignal.getVisible(), false); +} + TEST_F(TmsSignalTest, GetNoValue) { auto domainDescriptor = DataDescriptorBuilder() @@ -346,7 +369,7 @@ TEST_F(TmsSignalTest, GetNoValue) auto dataDescriptor = DataDescriptorBuilder().setName("stub").setSampleType(SampleType::Float64).build(); const auto signal = SignalWithDescriptor(NullContext(), dataDescriptor, nullptr, "sig"); - auto serverSignal = TmsServerSignal(signal, this->getServer(), NullContext()); + auto serverSignal = TmsServerSignal(signal, this->getServer(), ctx, serverContext); auto nodeId = serverSignal.registerOpcUaNode(); SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); @@ -392,7 +415,7 @@ TEST_F(TmsSignalTest, GetValue) auto dataDescriptor = DataDescriptorBuilder().setName("stub").setSampleType(SampleType::Float64).build(); const auto signal = SignalWithDescriptor(NullContext(), dataDescriptor, nullptr, "sig"); - auto serverSignal = TmsServerSignal(signal, this->getServer(), NullContext()); + auto serverSignal = TmsServerSignal(signal, this->getServer(), ctx, serverContext); auto nodeId = serverSignal.registerOpcUaNode(); SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp index d025837..a670349 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp @@ -5,22 +5,20 @@ using namespace daq; using namespace daq::opcua; using namespace daq::opcua::tms; -TmsObjectIntegrationTest::TmsObjectIntegrationTest() - : TmsObjectTest() -{ -} - void TmsObjectIntegrationTest::SetUp() { TmsObjectTest::SetUp(); - context = NullContext(); - clientContext = std::make_shared(client, context); + ctx = daq::NullContext(); + clientContext = std::make_shared(client, ctx); + serverContext = std::make_shared(ctx); } void TmsObjectIntegrationTest::TearDown() { clientContext.reset(); + serverContext = nullptr; + ctx = nullptr; TmsObjectTest::TearDown(); } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h index 46ff4e3..ad24381 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h @@ -17,16 +17,17 @@ #pragma once #include "tms_object_test.h" #include +#include "opcuatms_server/tms_server_context.h" class TmsObjectIntegrationTest : public TmsObjectTest { public: - TmsObjectIntegrationTest(); - void SetUp() override; void TearDown() override; protected: daq::ContextPtr context; daq::opcua::tms::TmsClientContextPtr clientContext; + daq::opcua::tms::TmsServerContextPtr serverContext; + daq::ContextPtr ctx; }; diff --git a/shared/libraries/opcuatms/tests/test_utils/tms_object_test.h b/shared/libraries/opcuatms/tests/test_utils/tms_object_test.h index 6df52fc..2487fa3 100644 --- a/shared/libraries/opcuatms/tests/test_utils/tms_object_test.h +++ b/shared/libraries/opcuatms/tests/test_utils/tms_object_test.h @@ -24,8 +24,8 @@ class TmsObjectTest : public testing::Test public: TmsObjectTest(); - void SetUp() override; - void TearDown() override; + virtual void SetUp() override; + virtual void TearDown() override; daq::opcua::OpcUaServerPtr getServer(); daq::opcua::OpcUaClientPtr getClient(); From ee0ae1585dad291a0d22f2faa3026356157bd9c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Wed, 10 Jan 2024 09:13:02 +0100 Subject: [PATCH 049/217] Add BeginUpdate and EndUpdate function nodes to client property object --- .../objects/tms_client_property_object_impl.h | 2 + .../tms_client_property_object_impl.cpp | 30 +++++++++++++++ .../objects/tms_server_property_object.h | 2 + .../objects/tms_server_property_object.cpp | 37 +++++++++++++++++++ .../test_property_object_advanced.cpp | 32 ++++++++++++++++ 5 files changed, 103 insertions(+) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h index 7b0b4eb..8956b18 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h @@ -103,6 +103,8 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl ErrCode INTERFACE_FUNC hasProperty(IString* propertyName, Bool* hasProperty) override; ErrCode INTERFACE_FUNC getAllProperties(IList** properties) override; ErrCode INTERFACE_FUNC setPropertyOrder(IList* orderedPropertyNames) override; + ErrCode INTERFACE_FUNC beginUpdate() override; + ErrCode INTERFACE_FUNC endUpdate() override; protected: std::unordered_map introspectionVariableIdMap; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index eecb617..a6ed846 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -172,6 +172,36 @@ ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::setPropertyOrder(I return OPENDAQ_ERR_INVALID_OPERATION; } +template +ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::beginUpdate() +{ + const auto beginUpdateId = clientContext->getReferenceBrowser()->getChildNodeId(nodeId, "BeginUpdate"); + + OpcUaCallMethodRequest request; + request->inputArgumentsSize = 0; + request->objectId = nodeId.getValue(); + request->methodId = beginUpdateId.getValue(); + const auto response = client->callMethod(request); + const auto success = response->statusCode == UA_STATUSCODE_GOOD; + + return (success) ? OPENDAQ_SUCCESS : OPENDAQ_ERR_GENERALERROR; +} + +template +ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::endUpdate() +{ + const auto endUpdateId = clientContext->getReferenceBrowser()->getChildNodeId(nodeId, "EndUpdate"); + + OpcUaCallMethodRequest request; + request->inputArgumentsSize = 0; + request->objectId = nodeId.getValue(); + request->methodId = endUpdateId.getValue(); + const auto response = client->callMethod(request); + const auto success = response->statusCode == UA_STATUSCODE_GOOD; + + return (success) ? OPENDAQ_SUCCESS : OPENDAQ_ERR_GENERALERROR; +} + template void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& parentId, std::map& orderedProperties, diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h index 7205d00..b9e8d15 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h @@ -69,6 +69,8 @@ class TmsServerPropertyObject : public TmsServerObjectBaseImpladdMethodNode(params); + + auto callback = [this](NodeEventManager::MethodArgs args) + { + const auto status = this->object->beginUpdate(); + return status == OPENDAQ_SUCCESS ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADINTERNALERROR; + }; + + addEvent(methodNodeId)->onMethodCall(callback); +} + +void TmsServerPropertyObject::addEndUpdateNode() +{ + OpcUaNodeId nodeIdOut; + AddMethodNodeParams params(nodeIdOut, nodeId); + params.referenceTypeId = OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT)); + params.setBrowseName("EndUpdate"); + auto methodNodeId = server->addMethodNode(params); + + auto callback = [this](NodeEventManager::MethodArgs args) + { + const auto status = this->object->endUpdate(); + return status == OPENDAQ_SUCCESS ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADINTERNALERROR; + }; + + addEvent(methodNodeId)->onMethodCall(callback); +} + void TmsServerPropertyObject::addPropertyNode(const std::string& name, const opcua::OpcUaNodeId& parentId) { auto params = AddVariableNodeParams(UA_NODEID_NULL, parentId); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp index a252116..3d754ba 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp @@ -15,6 +15,7 @@ #include "coretypes/struct_factory.h" #include "coretypes/type_manager_factory.h" #include +#include using namespace daq; using namespace opcua::tms; @@ -764,3 +765,34 @@ TEST_F(TmsPropertyObjectAdvancedTest, PropertyOrder) for (SizeT i = 0; i < serverProps.getCount(); ++i) ASSERT_EQ(serverProps[i].getName(), clientProps[i].getName()); } + +TEST_F(TmsPropertyObjectAdvancedTest, BeginEndUpdate) +{ + bool eventTriggered = false; + + const auto obj = PropertyObject(manager, "TestClass"); + obj.addProperty(IntProperty("Prop1", 1, true)); + obj.addProperty(IntProperty("Prop2", 2, true)); + obj.addProperty(IntProperty("Prop3", 3, true)); + + obj.getOnEndUpdate() += [&eventTriggered](PropertyObjectPtr&, EndUpdateEventArgsPtr& args) + { + ASSERT_EQ(args.getEventName(), "EndUpdateEvent"); + + auto properties = args.getProperties(); + testing::ElementsAre("Prop1", "Prop2", "Prop3"); + + eventTriggered = true; + }; + + auto [serverObj, clientObj] = registerPropertyObject(obj); + + clientObj.beginUpdate(); + clientObj.setPropertyValue("Prop1", 10); + clientObj.setPropertyValue("Prop2", 20); + clientObj.setPropertyValue("Prop3", 30); + clientObj.endUpdate(); + + ASSERT_TRUE(eventTriggered); +} + From 7b106dec9858db3c08adfa9c5ee81718fda6cfe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Thu, 11 Jan 2024 13:18:43 +0100 Subject: [PATCH 050/217] Fix code review issues --- .../tms_client_property_object_impl.cpp | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index a6ed846..b921de9 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -175,31 +175,31 @@ ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::setPropertyOrder(I template ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::beginUpdate() { - const auto beginUpdateId = clientContext->getReferenceBrowser()->getChildNodeId(nodeId, "BeginUpdate"); + if (!hasReference("BeginUpdate")) + return OPENDAQ_SUCCESS; + const auto beginUpdateId = getNodeId("BeginUpdate"); OpcUaCallMethodRequest request; request->inputArgumentsSize = 0; request->objectId = nodeId.getValue(); request->methodId = beginUpdateId.getValue(); - const auto response = client->callMethod(request); - const auto success = response->statusCode == UA_STATUSCODE_GOOD; - - return (success) ? OPENDAQ_SUCCESS : OPENDAQ_ERR_GENERALERROR; + client->callMethod(request); + return OPENDAQ_SUCCESS; } template ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::endUpdate() { - const auto endUpdateId = clientContext->getReferenceBrowser()->getChildNodeId(nodeId, "EndUpdate"); + if (!hasReference("EndUpdate")) + return OPENDAQ_SUCCESS; + const auto endUpdateId = getNodeId("EndUpdate"); OpcUaCallMethodRequest request; request->inputArgumentsSize = 0; request->objectId = nodeId.getValue(); request->methodId = endUpdateId.getValue(); - const auto response = client->callMethod(request); - const auto success = response->statusCode == UA_STATUSCODE_GOOD; - - return (success) ? OPENDAQ_SUCCESS : OPENDAQ_ERR_GENERALERROR; + client->callMethod(request); + return OPENDAQ_SUCCESS; } template From 7ca8d8908eb55d63843f518c7b80968b2c79d5fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Mon, 15 Jan 2024 14:13:20 +0100 Subject: [PATCH 051/217] Skip BeginUpdate and EndUpdate when adding method properties --- .../objects/tms_client_property_object_impl.h | 1 + .../src/objects/tms_client_property_object_impl.cpp | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h index 8956b18..fe4d3e7 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h @@ -121,6 +121,7 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl std::vector& unorderedProperties, std::unordered_map& functionPropValues); void browseRawProperties(); + bool isIgnoredMethodPeoperty(const std::string& browseName); ErrCode INTERFACE_FUNC setPropertyValueInternal(IString* propertyName, IBaseObject* value, bool protectedWrite); }; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index b921de9..334a2a4 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -333,6 +333,9 @@ void TmsClientPropertyObjectBaseImpl::addMethodProperties(const OpcUaNodeI const auto typeId = OpcUaNodeId(ref->typeDefinition.nodeId); const auto propName = String(utils::ToStdString(ref->browseName.name)); + if (isIgnoredMethodPeoperty(propName)) + continue; + Bool hasProp; daq::checkErrorInfo(Impl::hasProperty(propName, &hasProp)); @@ -424,6 +427,12 @@ void TmsClientPropertyObjectBaseImpl::browseRawProperties() } +template +bool TmsClientPropertyObjectBaseImpl::isIgnoredMethodPeoperty(const std::string& browseName) +{ + return browseName == "BeginUpdate" || browseName == "EndUpdate"; +} + template class TmsClientPropertyObjectBaseImpl; template class TmsClientPropertyObjectBaseImpl>; template class TmsClientPropertyObjectBaseImpl>; From c7b650d47b2ef04f27e96412ed20ff7517cc4ad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Wed, 10 Jan 2024 14:45:26 +0100 Subject: [PATCH 052/217] Log connect time in TmsClient --- .../include/opcuatms_client/tms_client.h | 1 + .../opcuatms_client/src/tms_client.cpp | 18 +++++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h index f6c6b74..01e3fb6 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h @@ -43,6 +43,7 @@ class TmsClient final std::string opcUaUrl; FunctionPtr createStreamingCallback; ComponentPtr parent; + LoggerComponentPtr loggerComponent; private: StringPtr getUniqueLocalId(const StringPtr& localId, int iteration = 0); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp index 47c5041..3899b7d 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp @@ -27,13 +27,16 @@ TmsClient::TmsClient(const ContextPtr& context, , opcUaUrl(opcUaUrl) , createStreamingCallback(createStreamingCallback) , parent(parent) + , loggerComponent(context.getLogger().assigned() ? context.getLogger().getOrAddComponent("OpcUaClient") + : throw ArgumentNullException("Logger must not be null")) { } daq::DevicePtr TmsClient::connect() { - OpcUaEndpoint endpoint("TmsClient", opcUaUrl); + const auto startTime = std::chrono::steady_clock::now(); + OpcUaEndpoint endpoint("TmsClient", opcUaUrl); client = std::make_shared(endpoint); if (!client->connect()) throw NotFoundException(); @@ -65,17 +68,18 @@ daq::DevicePtr TmsClient::connect() if (deviceInfo.hasProperty("OpenDaqPackageVersion")) { const std::string packageVersion = deviceInfo.getPropertyValue("OpenDaqPackageVersion"); + if (packageVersion != OPENDAQ_PACKAGE_VERSION) { - const auto logger = context.getLogger(); - if (logger.assigned()) - { - const auto loggerComponent = logger.getOrAddComponent("OpcUaClient"); - LOG_I("Connected to openDAQ OPC UA server with different version. Client version: {}, server version: {}", OPENDAQ_PACKAGE_VERSION, packageVersion) - } + LOG_I("Connected to openDAQ OPC UA server with different version. Client version: {}, server version: {}", + OPENDAQ_PACKAGE_VERSION, + packageVersion); } } + const auto endTime = std::chrono::steady_clock::now(); + const auto connectTime = std::chrono::duration(endTime - startTime); + LOG_I("Connected to penDAQ OPC UA server {}. Connect took {:.2f} s.", opcUaUrl, connectTime.count()); return device; } From cc842d1a2359bfb6d67e84a7b6e51da361eae69a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Mon, 15 Jan 2024 14:38:25 +0100 Subject: [PATCH 053/217] Change log level --- shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp index 3899b7d..6acd14a 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp @@ -71,7 +71,7 @@ daq::DevicePtr TmsClient::connect() if (packageVersion != OPENDAQ_PACKAGE_VERSION) { - LOG_I("Connected to openDAQ OPC UA server with different version. Client version: {}, server version: {}", + LOG_D("Connected to openDAQ OPC UA server with different version. Client version: {}, server version: {}", OPENDAQ_PACKAGE_VERSION, packageVersion); } @@ -79,7 +79,7 @@ daq::DevicePtr TmsClient::connect() const auto endTime = std::chrono::steady_clock::now(); const auto connectTime = std::chrono::duration(endTime - startTime); - LOG_I("Connected to penDAQ OPC UA server {}. Connect took {:.2f} s.", opcUaUrl, connectTime.count()); + LOG_D("Connected to penDAQ OPC UA server {}. Connect took {:.2f} s.", opcUaUrl, connectTime.count()); return device; } From 029b46f0838088c96cd41023009d39abc04c2189 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Tue, 16 Jan 2024 13:24:10 +0100 Subject: [PATCH 054/217] Do not write property value when it's equal to the previous --- .../opcuatms/opcuatms_server/tests/test_tms_property_object.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_property_object.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_property_object.cpp index 269a20e..b8f2081 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_property_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_property_object.cpp @@ -96,7 +96,7 @@ TEST_F(TmsPropertyObjectTest, OnPropertyValueChangeEvent) waitForChangeEvent.set_value(); }); - propertyObject.setPropertyValue("IntProp", 1); + propertyObject.setPropertyValue("IntProp", 2); auto future = waitForChangeEvent.get_future(); ASSERT_NE(future.wait_for(2s), std::future_status::timeout); From a52380738140e4029c129df572d34f4ed5498e5c Mon Sep 17 00:00:00 2001 From: Nils Roettger <99480819+nilsRoettgerAtBB@users.noreply.github.com> Date: Wed, 17 Jan 2024 08:59:32 +0000 Subject: [PATCH 055/217] Fix/hbk nodeset include (openDAQ/openDAQ#96) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Temp: properly include hbk nodeset * Fix unit test after rebase to main. * Add BeginUpdate and EndUpdate function nodes to client property object * Temp: properly include hbk nodeset * Improve logging. * Add BeginUpdate and EndUpdate function nodes to client property object * Temp: properly include hbk nodeset * Add BeginUpdate and EndUpdate function nodes to client property object * Undo rebase mistakes. --------- Co-authored-by: Jaka Mohorko Co-authored-by: Jan Mikolič --- .../opcua/opcuaserver/src/opcuatmstypes.cpp | 5 ++++ .../opcuatms/include/opcuatms/opcuatms.h | 1 + .../opcuatms/src/core_types_utils.cpp | 2 ++ .../tms_client_property_object_impl.cpp | 4 ++-- .../test_property_object_advanced.cpp | 23 +++++++++++++++++++ .../tests/test_utils/tms_object_test.cpp | 4 ++++ 6 files changed, 37 insertions(+), 2 deletions(-) diff --git a/shared/libraries/opcua/opcuaserver/src/opcuatmstypes.cpp b/shared/libraries/opcua/opcuaserver/src/opcuatmstypes.cpp index 24ab390..7a5fb10 100644 --- a/shared/libraries/opcua/opcuaserver/src/opcuatmstypes.cpp +++ b/shared/libraries/opcua/opcuaserver/src/opcuatmstypes.cpp @@ -20,6 +20,7 @@ #include "opcuashared/opcuaexception.h" #include "opcuashared/opcualog.h" #include "opcuaserver/opcuatmstypes.h" +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA @@ -52,6 +53,10 @@ void addTmsTypes(UA_Server *server) CheckStatusCodeException(uaStatus, "Failed to add TMS ESP nodeset."); LOGD << "TMS ESP nodeset was added successfully."; #endif + + uaStatus = namespace_daqhbk_generated(server); + CheckStatusCodeException(uaStatus, "Failed to add TMS HBK nodeset."); + LOGD << "TMS HBK nodeset was added successfully."; } END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h index 1a52c4f..1372853 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #define BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS \ diff --git a/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp b/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp index c78c191..e36c6cb 100644 --- a/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp @@ -6,6 +6,7 @@ #include "open62541/daqbt_nodeids.h" #include "open62541/types_di_generated.h" #include "open62541/types_daqesp_generated.h" +#include "open62541/types_daqhbk_generated.h" using namespace daq::opcua; using namespace daq; @@ -243,6 +244,7 @@ const UA_DataType* GetUAStructureDataTypeByName(const std::string& structName) typeArr.add(UA_TYPES_DAQBSP_COUNT, UA_TYPES_DAQBSP); typeArr.add(UA_TYPES_DAQDEVICE_COUNT, UA_TYPES_DAQDEVICE); typeArr.add(UA_TYPES_DAQESP_COUNT, UA_TYPES_DAQESP); + typeArr.add(UA_TYPES_DAQHBK_COUNT, UA_TYPES_DAQHBK); const UA_DataTypeArray* dataType = typeArr.getCustomDataTypes(); while(dataType) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index 334a2a4..c82ea98 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -241,7 +241,7 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par } catch(const std::exception& e) { - LOG_W("Failed to add reference property {}", e.what()); + LOG_W("Failed to add {} reference property {}",propName, e.what()); continue; } } @@ -257,7 +257,7 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par } catch(const std::exception& e) { - LOG_W("Failed to add property {}", e.what()); + LOG_W("Failed to add {} property {}", propName, e.what()); continue; } } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp index 3d754ba..81698c3 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp @@ -766,6 +766,29 @@ TEST_F(TmsPropertyObjectAdvancedTest, PropertyOrder) ASSERT_EQ(serverProps[i].getName(), clientProps[i].getName()); } +TEST_F(TmsPropertyObjectAdvancedTest, GainScalingStructure) +{ + const auto typeManager = TypeManager(); + const auto type = StructType("GainScalingStructure", List("Factor", "Offset"), List(SimpleType(ctFloat), SimpleType(ctFloat))); + typeManager.addType(type); + + const auto obj = PropertyObject(); + const auto structBuilder = StructBuilder("GainScalingStructure", typeManager).set("Factor", 0.5).set("Offset", 2.5); + obj.addProperty(StructProperty("Gain", structBuilder.build())); + + + const auto logger = Logger(); + const auto serverProp = + std::make_shared(obj, server, Context(nullptr, logger, manager, nullptr), serverContext); + const auto nodeId = serverProp->registerOpcUaNode(); + + auto [serverObj, clientObj] = registerPropertyObject(obj); + + const auto structObj = obj.getPropertyValue("Gain"); + const auto newBuilder = StructBuilder(structObj); + clientObj.setPropertyValue("Gain", newBuilder.set("Factor", 2.0).set("Offset", 10.0).build()); +} + TEST_F(TmsPropertyObjectAdvancedTest, BeginEndUpdate) { bool eventTriggered = false; diff --git a/shared/libraries/opcuatms/tests/test_utils/tms_object_test.cpp b/shared/libraries/opcuatms/tests/test_utils/tms_object_test.cpp index 7cee8fa..3cbd8e6 100644 --- a/shared/libraries/opcuatms/tests/test_utils/tms_object_test.cpp +++ b/shared/libraries/opcuatms/tests/test_utils/tms_object_test.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include using namespace daq::opcua; @@ -95,6 +97,8 @@ daq::opcua::OpcUaClientPtr TmsObjectTest::CreateAndConnectTestClient() endpoint.registerCustomTypes(UA_TYPES_DAQBT_COUNT, UA_TYPES_DAQBT); endpoint.registerCustomTypes(UA_TYPES_DAQBSP_COUNT, UA_TYPES_DAQBSP); endpoint.registerCustomTypes(UA_TYPES_DAQDEVICE_COUNT, UA_TYPES_DAQDEVICE); + endpoint.registerCustomTypes(UA_TYPES_DAQESP_COUNT, UA_TYPES_DAQESP); + endpoint.registerCustomTypes(UA_TYPES_DAQHBK_COUNT, UA_TYPES_DAQHBK); auto client = std::make_shared(endpoint); client->connect(); From 0c9f5957d72f14b6a54e00915127cf21583e8360 Mon Sep 17 00:00:00 2001 From: Martin Kraner Date: Thu, 18 Jan 2024 11:40:59 +0100 Subject: [PATCH 056/217] Update the minimum required CMake version to avoid deprecation warnings --- modules/opcua_client_module/CMakeLists.txt | 2 +- modules/opcua_server_module/CMakeLists.txt | 2 +- shared/libraries/opcua/opcuaclient/CMakeLists.txt | 2 +- shared/libraries/opcua/opcuaserver/CMakeLists.txt | 2 +- shared/libraries/opcua/opcuashared/CMakeLists.txt | 2 +- shared/libraries/opcua/tests/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt | 2 +- shared/libraries/opcuatms/tests/CMakeLists.txt | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/opcua_client_module/CMakeLists.txt b/modules/opcua_client_module/CMakeLists.txt index 166a257..6f984e3 100644 --- a/modules/opcua_client_module/CMakeLists.txt +++ b/modules/opcua_client_module/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.2) +cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) project(ClientModule VERSION 2.0.0 LANGUAGES C CXX) diff --git a/modules/opcua_server_module/CMakeLists.txt b/modules/opcua_server_module/CMakeLists.txt index 62b116d..fdcc620 100644 --- a/modules/opcua_server_module/CMakeLists.txt +++ b/modules/opcua_server_module/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.2) +cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) project(ServerModule VERSION 2.0.0 LANGUAGES CXX) diff --git a/shared/libraries/opcua/opcuaclient/CMakeLists.txt b/shared/libraries/opcua/opcuaclient/CMakeLists.txt index 079968e..5164676 100644 --- a/shared/libraries/opcua/opcuaclient/CMakeLists.txt +++ b/shared/libraries/opcua/opcuaclient/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.2) +cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME client) project(OpcUaClient CXX) diff --git a/shared/libraries/opcua/opcuaserver/CMakeLists.txt b/shared/libraries/opcua/opcuaserver/CMakeLists.txt index 1692623..47cc777 100644 --- a/shared/libraries/opcua/opcuaserver/CMakeLists.txt +++ b/shared/libraries/opcua/opcuaserver/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.2) +cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME server) project(OpcUaServer CXX) diff --git a/shared/libraries/opcua/opcuashared/CMakeLists.txt b/shared/libraries/opcua/opcuashared/CMakeLists.txt index 9d2586d..94316e4 100644 --- a/shared/libraries/opcua/opcuashared/CMakeLists.txt +++ b/shared/libraries/opcua/opcuashared/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.2) +cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME shared) project(OpcUaShared CXX C) diff --git a/shared/libraries/opcua/tests/CMakeLists.txt b/shared/libraries/opcua/tests/CMakeLists.txt index 7cb4330..7521b7c 100644 --- a/shared/libraries/opcua/tests/CMakeLists.txt +++ b/shared/libraries/opcua/tests/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.2) +cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) project(OpcUaTests CXX) diff --git a/shared/libraries/opcuatms/opcuatms/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms/CMakeLists.txt index 031df0e..2a5287e 100644 --- a/shared/libraries/opcuatms/opcuatms/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.2) +cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) project(opcuatms VERSION 2.0.0 LANGUAGES CXX) diff --git a/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt index 96dcd6c..61c03e9 100644 --- a/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.2) +cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) project(opcuatms_client VERSION 2.0.0 LANGUAGES CXX) diff --git a/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt index db7412f..a608979 100644 --- a/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.2) +cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) project(opcuatms_server VERSION 2.0.0 LANGUAGES CXX) diff --git a/shared/libraries/opcuatms/tests/CMakeLists.txt b/shared/libraries/opcuatms/tests/CMakeLists.txt index a56ceac..bdecf99 100644 --- a/shared/libraries/opcuatms/tests/CMakeLists.txt +++ b/shared/libraries/opcuatms/tests/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.2) +cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) project(opcuatms_integration_tests CXX) From c0aabef259c6308a37605a3997e00e2bdbb37590 Mon Sep 17 00:00:00 2001 From: roettger Date: Wed, 17 Jan 2024 17:58:27 +0000 Subject: [PATCH 057/217] Add a work around for properties which are missing a default value. --- .../src/objects/tms_client_property_impl.cpp | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp index 12c2c43..e31a689 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp @@ -138,8 +138,27 @@ void TmsClientPropertyImpl::configurePropertyFields() switch (propertyField) { case details::PropertyField::DefaultValue: - this->defaultValue = - VariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE), daqContext); + // ToDo: This is a workarround for devices which are delivering not a default value, + // even if this is a mandatory property in the openDAQ Standard. + // However, the SDK creates too strong a requirement, which cannot be + // met by all the standards or devices to be embraced. + // In this case the actual value from the first connect is set to it. + // But, this creates a weak point: + // SDK stores only values of variables which are != to the device default value. + // The choosen default value could be not the true default value from the device. + // So, all in all we aligned on that in future the SDK will also support properties + // which have not a default value as the device for which the workaround is needed. + // But this is feature request and is covered with + // https://blueberrydaq.atlassian.net/browse/TBBAS-1216. + // But as long as the feature is not implemented this is a valid workarround to get + // devices working which are deliviering not a default value via the opc-ua interface. + // Afterwards, the workaround needs to be rolled back. + try + { + this->defaultValue = VariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE), daqContext); + }catch(const std::exception& e){ + this->defaultValue = VariantConverter::ToDaqObject(reader->getValue(nodeId, UA_ATTRIBUTEID_VALUE), daqContext); + } if (this->defaultValue.assigned() && this->defaultValue.asPtrOrNull().assigned()) this->defaultValue.freeze(); break; From 0cf6a7f8d2c379ed5c6c0b1b778c2b65d6478688 Mon Sep 17 00:00:00 2001 From: roettger Date: Wed, 17 Jan 2024 19:23:02 +0000 Subject: [PATCH 058/217] Add Unit test for HBK Devices. --- .../tests/opcuatms_integration/CMakeLists.txt | 1 + .../test_tms_fusion_device.cpp | 90 +++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt b/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt index 632cf50..65dd261 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt @@ -17,6 +17,7 @@ set(TEST_SOURCES main.cpp test_tms_component.cpp test_tms_folder.cpp test_tms_function_property.cpp + test_tms_fusion_device.cpp ) if (OPENDAQ_ENABLE_WEBSOCKET_STREAMING) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp new file mode 100644 index 0000000..3023308 --- /dev/null +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp @@ -0,0 +1,90 @@ +#include +#include "coreobjects/callable_info_factory.h" +#include "coreobjects/property_object_factory.h" +#include "coreobjects/unit_factory.h" +#include "coretypes/type_manager_factory.h" +#include "gtest/gtest.h" +#include "opcuaclient/opcuaclient.h" +#include "opcuatms_client/objects/tms_client_property_object_factory.h" +#include "opcuatms_client/objects/tms_client_property_object_impl.h" +#include "opcuatms_server/objects/tms_server_property_object.h" +#include "opcuatms_client/objects/tms_client_signal_factory.h" +#include "opcuatms_server/objects/tms_server_signal.h" +#include "tms_object_integration_test.h" +#include "opendaq/instance_factory.h" + +using namespace daq; +using namespace opcua::tms; +using namespace opcua; +using namespace std::chrono_literals; + +struct RegisteredPropertyObject +{ + TmsServerPropertyObjectPtr serverProp; + PropertyObjectPtr clientProp; +}; + +class TmsFusionDevice : public TmsObjectIntegrationTest +{ +protected: + + TypeManagerPtr objManager; + + SignalPtr createSignal(const std::string& id) + { + SignalPtr signal = Signal(NullContext(), nullptr, id); + signal->setActive(false); + return signal; + } + + void SetUp() override + { + TmsObjectIntegrationTest::SetUp(); + + // create class with name "STGAmplifier" + auto stgAmplClass = + PropertyObjectClassBuilder("StgAmp") + .addProperty(SelectionProperty( + "Measurement", List("Voltage", "Bridge", "Resistance", "Temperature", "Current", "Potentiometer"), 0)) + + .build(); + + objManager = TypeManager(); + objManager.addType(stgAmplClass); + + + } + + void TearDown() override + { + objManager.removeType("StgAmp"); + } + + RegisteredPropertyObject registerPropertyObject(const PropertyObjectPtr& prop) + { + const auto logger = Logger(); + const auto context = Context(nullptr, logger, TypeManager(), nullptr); + const auto serverProp = + std::make_shared(prop, server, context, std::make_shared(context)); + const auto nodeId = serverProp->registerOpcUaNode(); + const auto clientProp = TmsClientPropertyObject(Context(nullptr, logger, TypeManager(), nullptr), clientContext, nodeId); + return {serverProp, clientProp}; + } +}; + +TEST_F(TmsFusionDevice, IntegrationTest) +{ + + SignalPtr daqServerSignal = createSignal("id"); + daqServerSignal.addProperty(FloatProperty("SampleRate", 1.0, false)); + + auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), ctx, serverContext); + auto nodeId = serverSignal.registerOpcUaNode(); + + SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); + + ASSERT_TRUE(clientSignal.getPublic()); + + ASSERT_NO_THROW(clientSignal.getPropertyValue("SampleRate")); +} + From 51fc759ccff7d3a4c67ca7e096228a379caba09e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Thu, 18 Jan 2024 09:06:43 +0100 Subject: [PATCH 059/217] Correctly skip properties without read access on opcua --- .../objects/tms_client_property_object_impl.h | 1 + .../tms_client_property_object_impl.cpp | 93 +++++++++++-------- .../test_tms_fusion_device.cpp | 20 +++- 3 files changed, 70 insertions(+), 44 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h index fe4d3e7..bcf6ae9 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h @@ -120,6 +120,7 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl std::map& orderedProperties, std::vector& unorderedProperties, std::unordered_map& functionPropValues); + PropertyPtr addVariableBlockProperty(const StringPtr& propName, const OpcUaNodeId& propNodeId); void browseRawProperties(); bool isIgnoredMethodPeoperty(const std::string& browseName); ErrCode INTERFACE_FUNC setPropertyValueInternal(IString* propertyName, IBaseObject* value, bool protectedWrite); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index c82ea98..ce40c7e 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -220,9 +220,6 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par const auto typeId = OpcUaNodeId(ref->typeDefinition.nodeId); const auto propName = String(utils::ToStdString(ref->browseName.name)); - if (!clientContext->getAttributeReader()->hasAnyValue(childNodeId)) - continue; - Bool hasProp; daq::checkErrorInfo(Impl::hasProperty(propName, &hasProp)); PropertyPtr prop; @@ -263,46 +260,18 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par } else if (clientContext->getReferenceBrowser()->isSubtypeOf(typeId, variableBlockTypeId)) { - if (!hasProp) + try { - auto obj = TmsClientPropertyObject(daqContext, clientContext, childNodeId); - const auto description = reader->getValue(childNodeId, UA_ATTRIBUTEID_DESCRIPTION).toString(); - auto propBuilder = ObjectPropertyBuilder(propName, obj).setDescription(String(description)); - - const auto evaluationVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_EVALUATIONVARIABLETYPE); - const auto variableBlockRefs = clientContext->getReferenceBrowser()->browse(childNodeId); - - for (auto& [browseName, variableBlockRef] : variableBlockRefs.byBrowseName) - { - const auto variableBlockNodeId = OpcUaNodeId(variableBlockRef->nodeId.nodeId); - - if (clientContext->getReferenceBrowser()->isSubtypeOf(variableBlockRef->typeDefinition.nodeId, evaluationVariableTypeId)) - { - auto evalId = clientContext->getReferenceBrowser()->getChildNodeId(variableBlockNodeId, "EvaluationExpression"); - - StringPtr evalStr = VariantConverter::ToDaqObject(reader->getValue(evalId, UA_ATTRIBUTEID_VALUE)); - - if (browseName == "IsReadOnly") - { - if (evalStr.assigned()) - propBuilder.setReadOnly(EvalValue(evalStr).asPtr()); - else - propBuilder.setReadOnly(VariantConverter::ToDaqObject(reader->getValue(variableBlockNodeId, UA_ATTRIBUTEID_VALUE))); - } - else if (browseName == "IsVisible") - { - if (evalStr.assigned()) - propBuilder.setVisible(EvalValue(evalStr).asPtr()); - else - propBuilder.setVisible(VariantConverter::ToDaqObject(reader->getValue(variableBlockNodeId, UA_ATTRIBUTEID_VALUE))); - } - } - } + if (!hasProp) + prop = addVariableBlockProperty(propName, childNodeId); - prop = propBuilder.build(); + objectTypeIdMap.insert(std::pair(propName, childNodeId)); + } + catch (const std::exception& e) + { + LOG_W("Failed to add {} property {}", propName, e.what()); + continue; } - - objectTypeIdMap.insert(std::pair(propName, childNodeId)); } if (prop.assigned()) @@ -398,6 +367,50 @@ void TmsClientPropertyObjectBaseImpl::addMethodProperties(const OpcUaNodeI } } +template +PropertyPtr TmsClientPropertyObjectBaseImpl::addVariableBlockProperty(const StringPtr& propName, const OpcUaNodeId& propNodeId) +{ + auto reader = this->clientContext->getAttributeReader(); + + auto obj = TmsClientPropertyObject(daqContext, clientContext, propNodeId); + const auto description = reader->getValue(propNodeId, UA_ATTRIBUTEID_DESCRIPTION).toString(); + auto propBuilder = ObjectPropertyBuilder(propName, obj).setDescription(String(description)); + + const auto evaluationVariableTypeId = OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_EVALUATIONVARIABLETYPE); + const auto variableBlockRefs = clientContext->getReferenceBrowser()->browse(propNodeId); + + for (auto& [browseName, variableBlockRef] : variableBlockRefs.byBrowseName) + { + const auto variableBlockNodeId = OpcUaNodeId(variableBlockRef->nodeId.nodeId); + + if (clientContext->getReferenceBrowser()->isSubtypeOf(variableBlockRef->typeDefinition.nodeId, evaluationVariableTypeId)) + { + auto evalId = clientContext->getReferenceBrowser()->getChildNodeId(variableBlockNodeId, "EvaluationExpression"); + + StringPtr evalStr = VariantConverter::ToDaqObject(reader->getValue(evalId, UA_ATTRIBUTEID_VALUE)); + + if (browseName == "IsReadOnly") + { + if (evalStr.assigned()) + propBuilder.setReadOnly(EvalValue(evalStr).asPtr()); + else + propBuilder.setReadOnly( + VariantConverter::ToDaqObject(reader->getValue(variableBlockNodeId, UA_ATTRIBUTEID_VALUE))); + } + else if (browseName == "IsVisible") + { + if (evalStr.assigned()) + propBuilder.setVisible(EvalValue(evalStr).asPtr()); + else + propBuilder.setVisible( + VariantConverter::ToDaqObject(reader->getValue(variableBlockNodeId, UA_ATTRIBUTEID_VALUE))); + } + } + } + + return propBuilder.build(); +} + template void TmsClientPropertyObjectBaseImpl::browseRawProperties() { diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp index 3023308..921194a 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp @@ -12,6 +12,7 @@ #include "opcuatms_server/objects/tms_server_signal.h" #include "tms_object_integration_test.h" #include "opendaq/instance_factory.h" +#include using namespace daq; using namespace opcua::tms; @@ -51,8 +52,6 @@ class TmsFusionDevice : public TmsObjectIntegrationTest objManager = TypeManager(); objManager.addType(stgAmplClass); - - } void TearDown() override @@ -72,7 +71,7 @@ class TmsFusionDevice : public TmsObjectIntegrationTest } }; -TEST_F(TmsFusionDevice, IntegrationTest) +TEST_F(TmsFusionDevice, SampleRateTest) { SignalPtr daqServerSignal = createSignal("id"); @@ -82,9 +81,22 @@ TEST_F(TmsFusionDevice, IntegrationTest) auto nodeId = serverSignal.registerOpcUaNode(); SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); + //std::cin.get(); ASSERT_TRUE(clientSignal.getPublic()); - ASSERT_NO_THROW(clientSignal.getPropertyValue("SampleRate")); } +TEST_F(TmsFusionDevice, DISABLED_SimulatorTest) +{ + // this test should pass, if you have Fusion simulator running + + const std::string connectionString = "opc.tcp://10.0.210.201"; + + TmsClient tmsClient(NullContext(), nullptr, connectionString, nullptr); + auto clientDevice = tmsClient.connect(); + + ASSERT_TRUE(clientDevice.assigned()); +} + + From dcf7a7c27869b95bbf17663c925455d34d481721 Mon Sep 17 00:00:00 2001 From: roettger Date: Thu, 18 Jan 2024 11:36:57 +0000 Subject: [PATCH 060/217] Improve Logging and use unused local variable. --- .../opcuatms_client/objects/tms_client_property_impl.h | 2 ++ .../src/objects/tms_client_property_impl.cpp | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h index d200262..5ebc8fa 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h @@ -27,6 +27,8 @@ class TmsClientPropertyImpl : public TmsClientObjectImpl, public PropertyImpl explicit TmsClientPropertyImpl(const ContextPtr& daqContext, const TmsClientContextPtr& ctx, const opcua::OpcUaNodeId& nodeId); protected: + LoggerComponentPtr loggerComponent; + void readBasicInfo(); void configurePropertyFields(); }; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp index e31a689..90a6298 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp @@ -5,6 +5,7 @@ #include "opcuatms/converters/variant_converter.h" #include "opcuatms/converters/selection_converter.h" #include "open62541/daqbt_nodeids.h" +#include "opendaq/custom_log.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -43,6 +44,11 @@ namespace details TmsClientPropertyImpl::TmsClientPropertyImpl(const ContextPtr& daqContext, const TmsClientContextPtr& ctx, const opcua::OpcUaNodeId& nodeId) : TmsClientObjectImpl(daqContext, ctx, nodeId) { + if (!this->daqContext.getLogger().assigned()) + throw ArgumentNullException("Logger must not be null"); + + this->loggerComponent = this->daqContext.getLogger().getOrAddComponent("TmsClientPropertyImpl"); + clientContext->readObjectAttributes(nodeId); readBasicInfo(); @@ -158,6 +164,7 @@ void TmsClientPropertyImpl::configurePropertyFields() this->defaultValue = VariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE), daqContext); }catch(const std::exception& e){ this->defaultValue = VariantConverter::ToDaqObject(reader->getValue(nodeId, UA_ATTRIBUTEID_VALUE), daqContext); + LOG_W("Failed to read default value of property {}. Detault value is set to the value at connection time. {}", this->name, e.what()); } if (this->defaultValue.assigned() && this->defaultValue.asPtrOrNull().assigned()) this->defaultValue.freeze(); From 67414af3b118f510ddd8bbb8afed7c8077d58fa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Thu, 18 Jan 2024 13:41:55 +0100 Subject: [PATCH 061/217] Format code --- .../src/objects/tms_client_property_impl.cpp | 44 ++++++++++++------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp index 90a6298..d520975 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp @@ -144,64 +144,74 @@ void TmsClientPropertyImpl::configurePropertyFields() switch (propertyField) { case details::PropertyField::DefaultValue: + { // ToDo: This is a workarround for devices which are delivering not a default value, // even if this is a mandatory property in the openDAQ Standard. - // However, the SDK creates too strong a requirement, which cannot be + // However, the SDK creates too strong a requirement, which cannot be // met by all the standards or devices to be embraced. // In this case the actual value from the first connect is set to it. // But, this creates a weak point: // SDK stores only values of variables which are != to the device default value. // The choosen default value could be not the true default value from the device. // So, all in all we aligned on that in future the SDK will also support properties - // which have not a default value as the device for which the workaround is needed. - // But this is feature request and is covered with + // which have not a default value as the device for which the workaround is needed. + // But this is feature request and is covered with // https://blueberrydaq.atlassian.net/browse/TBBAS-1216. - // But as long as the feature is not implemented this is a valid workarround to get + // But as long as the feature is not implemented this is a valid workarround to get // devices working which are deliviering not a default value via the opc-ua interface. - // Afterwards, the workaround needs to be rolled back. + // Afterwards, the workaround needs to be rolled back. + try { - this->defaultValue = VariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE), daqContext); - }catch(const std::exception& e){ - this->defaultValue = VariantConverter::ToDaqObject(reader->getValue(nodeId, UA_ATTRIBUTEID_VALUE), daqContext); - LOG_W("Failed to read default value of property {}. Detault value is set to the value at connection time. {}", this->name, e.what()); + const auto value = reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE); + this->defaultValue = VariantConverter::ToDaqObject(value, daqContext); + } + catch (const std::exception& e) + { + const auto value = reader->getValue(nodeId, UA_ATTRIBUTEID_VALUE); + this->defaultValue = VariantConverter::ToDaqObject(value, daqContext); + LOG_W( + "Failed to read default value of property {}. Detault value is set to the value at connection time. {}", + this->name, + e.what()); } + if (this->defaultValue.assigned() && this->defaultValue.asPtrOrNull().assigned()) this->defaultValue.freeze(); - break; + break; + } case details::PropertyField::IsReadOnly: this->readOnly = VariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE)); break; - case details::PropertyField::IsVisible: this->visible = VariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE)); break; - case details::PropertyField::Unit: this->unit = VariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE)); break; - case details::PropertyField::MaxValue: this->maxValue = VariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE)); break; - case details::PropertyField::MinValue: this->minValue = VariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE)); break; - case details::PropertyField::SuggestedValues: + { this->suggestedValues = VariantConverter::ToDaqList(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE), daqContext); if (this->suggestedValues.assigned() && this->suggestedValues.asPtrOrNull().assigned()) this->suggestedValues.freeze(); break; - + } case details::PropertyField::SelectionValues: - this->selectionValues = SelectionVariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE)); + { + this->selectionValues = + SelectionVariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE)); if (this->selectionValues.assigned() && this->selectionValues.asPtrOrNull().assigned()) this->selectionValues.freeze(); break; + } case details::PropertyField::CoercionExpression: case details::PropertyField::ValidationExpression: break; From 16a2e9380d7ca93721a2d5014fa498a6b6f401fd Mon Sep 17 00:00:00 2001 From: Dejan Crnila Date: Mon, 22 Jan 2024 15:26:39 +0100 Subject: [PATCH 062/217] Add native configuration protocol library --- modules/opcua_client_module/src/CMakeLists.txt | 4 ++++ shared/libraries/opcua/opcuaclient/tests/CMakeLists.txt | 4 ++++ .../opcuatms_client/objects/tms_client_io_folder_impl.h | 2 +- shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt | 4 ++++ .../opcuatms_client/src/objects/tms_client_component_impl.cpp | 2 +- .../opcuatms_client/src/objects/tms_client_folder_impl.cpp | 2 +- .../opcuatms_client/src/objects/tms_client_io_folder_impl.cpp | 2 +- .../src/objects/tms_client_property_object_impl.cpp | 2 +- .../libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt | 4 ++++ shared/libraries/opcuatms/tests/CMakeLists.txt | 2 +- .../opcuatms/tests/opcuatms_integration/CMakeLists.txt | 2 +- 11 files changed, 23 insertions(+), 7 deletions(-) diff --git a/modules/opcua_client_module/src/CMakeLists.txt b/modules/opcua_client_module/src/CMakeLists.txt index 6d483c8..f665a9a 100644 --- a/modules/opcua_client_module/src/CMakeLists.txt +++ b/modules/opcua_client_module/src/CMakeLists.txt @@ -24,6 +24,10 @@ add_library(${LIB_NAME} SHARED ${SRC_Include} ) add_library(${SDK_TARGET_NAMESPACE}::${LIB_NAME} ALIAS ${LIB_NAME}) +if (MSVC) + target_compile_options(${LIB_NAME} PRIVATE /bigobj) +endif() + target_link_libraries(${LIB_NAME} PUBLIC daq::opendaq PRIVATE daq::discovery daq::opcuatms_client diff --git a/shared/libraries/opcua/opcuaclient/tests/CMakeLists.txt b/shared/libraries/opcua/opcuaclient/tests/CMakeLists.txt index e482615..1b4a4c3 100644 --- a/shared/libraries/opcua/opcuaclient/tests/CMakeLists.txt +++ b/shared/libraries/opcua/opcuaclient/tests/CMakeLists.txt @@ -35,6 +35,10 @@ add_test(NAME ${TEST_APP} WORKING_DIRECTORY bin ) +if (MSVC) + target_compile_options(${TEST_APP} PRIVATE /bigobj) +endif() + if(OPENDAQ_ENABLE_COVERAGE) setup_target_for_coverage(${MODULE_NAME}coverage ${TEST_APP} ${MODULE_NAME}coverage) endif() diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h index 783c052..3ae840f 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h @@ -20,7 +20,7 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS -class TmsClientIoFolderImpl : public TmsClientFolderImpl +class TmsClientIoFolderImpl : public TmsClientFolderImpl> { public: explicit TmsClientIoFolderImpl(const ContextPtr& ctx, diff --git a/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt index f7e1bf1..5644553 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt @@ -110,6 +110,10 @@ else() set_target_properties(${LIB_NAME} PROPERTIES POSITION_INDEPENDENT_CODE OFF) endif() +if (MSVC) + target_compile_options(${LIB_NAME} PRIVATE /bigobj) +endif() + target_link_libraries(${LIB_NAME} PUBLIC daq::opcuatms diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp index 357e075..a06b872 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp @@ -153,7 +153,7 @@ ErrCode TmsClientComponentBaseImpl::setVisible(Bool visible) template class TmsClientComponentBaseImpl>; template class TmsClientComponentBaseImpl>; -template class TmsClientComponentBaseImpl; +template class TmsClientComponentBaseImpl>; template class TmsClientComponentBaseImpl; template class TmsClientComponentBaseImpl; template class TmsClientComponentBaseImpl; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp index f6c310a..18e5ed5 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp @@ -57,6 +57,6 @@ void TmsClientFolderImpl::findAndCreateFolders(std::map>; -template class TmsClientFolderImpl; +template class TmsClientFolderImpl>; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp index 7e9b6e6..72a6b38 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp @@ -13,7 +13,7 @@ TmsClientIoFolderImpl::TmsClientIoFolderImpl(const ContextPtr& ctx, const StringPtr& localId, const TmsClientContextPtr& clientContext, const opcua::OpcUaNodeId& nodeId) - : TmsClientFolderImpl(ctx, parent, localId, clientContext, nodeId, true) + : TmsClientFolderImpl>(ctx, parent, localId, clientContext, nodeId, true) { std::map orderedComponents; std::vector unorderedComponents; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index ce40c7e..948726a 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -449,7 +449,7 @@ bool TmsClientPropertyObjectBaseImpl::isIgnoredMethodPeoperty(const std::s template class TmsClientPropertyObjectBaseImpl; template class TmsClientPropertyObjectBaseImpl>; template class TmsClientPropertyObjectBaseImpl>; -template class TmsClientPropertyObjectBaseImpl; +template class TmsClientPropertyObjectBaseImpl>; template class TmsClientPropertyObjectBaseImpl; template class TmsClientPropertyObjectBaseImpl; template class TmsClientPropertyObjectBaseImpl; diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt index 84a0f9b..1c4625f 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt @@ -17,6 +17,10 @@ add_executable(${TEST_APP} testapp.cpp ${TEST_SOURCES} ) +if (MSVC) + target_compile_options(${TEST_APP} PRIVATE /bigobj) +endif() + set_target_properties(${TEST_APP} PROPERTIES DEBUG_POSTFIX _debug) target_link_libraries(${TEST_APP} PRIVATE ${SDK_TARGET_NAMESPACE}::${MODULE_NAME} diff --git a/shared/libraries/opcuatms/tests/CMakeLists.txt b/shared/libraries/opcuatms/tests/CMakeLists.txt index bdecf99..09395d4 100644 --- a/shared/libraries/opcuatms/tests/CMakeLists.txt +++ b/shared/libraries/opcuatms/tests/CMakeLists.txt @@ -3,4 +3,4 @@ set_cmake_folder_context(TARGET_FOLDER_NAME) project(opcuatms_integration_tests CXX) add_subdirectory(test_utils) -add_subdirectory(opcuatms_integration) +#add_subdirectory(opcuatms_integration) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt b/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt index 65dd261..2437187 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt @@ -66,7 +66,7 @@ add_test(NAME ${TEST_APP} ) if (MSVC) - target_compile_options(${TEST_APP} PRIVATE /wd4324) + target_compile_options(${TEST_APP} PRIVATE /wd4324 /bigobj) endif() if (OPENDAQ_ENABLE_COVERAGE) From 99f8c40536c09671a28f6adce743564a5d48a372 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Mon, 15 Jan 2024 14:45:30 +0100 Subject: [PATCH 063/217] Freeze and clone object-type properties on add --- .../test_property_object_advanced.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp index 81698c3..0317c03 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp @@ -490,8 +490,9 @@ TEST_F(TmsPropertyObjectAdvancedTest, ObjectGetSet) testObj.addProperty(IntProperty("test", 0)); ASSERT_ANY_THROW(clientObj.setPropertyValue("Object", testObj)); - ASSERT_ANY_THROW(clientChildObj.setPropertyValue("ObjNumber", 1)); + ASSERT_NO_THROW(clientChildObj.setPropertyValue("ObjNumber", 1)); + ASSERT_EQ(clientChildObj.getPropertyValue("ObjNumber"), 1); PropertyObjectPtr serverNonClassObj = obj.getPropertyValue("NonClassObj"); PropertyObjectPtr clientNonClassObj = clientObj.getPropertyValue("NonClassObj"); ASSERT_EQ(serverNonClassObj.getPropertyValue("test"), clientNonClassObj.getPropertyValue("test")); @@ -641,10 +642,12 @@ TEST_F(TmsPropertyObjectAdvancedTest, ObjectPropWithMetadata) auto [serverObj, clientObj] = registerPropertyObject(obj); PropertyObjectPtr clientObjWithMetadata = clientObj.getPropertyValue("ObjectWithMetadata"); - ASSERT_ANY_THROW(clientObjWithMetadata.setPropertyValue("foo", "notbar")); + ASSERT_NO_THROW(clientObjWithMetadata.setPropertyValue("foo", "notbar")); + ASSERT_EQ(clientObjWithMetadata.getPropertyValue("foo"), "notbar"); PropertyObjectPtr clientLocalObjWithMetadata = clientObj.getPropertyValue("LocalObjectWithMetadata"); - ASSERT_ANY_THROW(clientLocalObjWithMetadata.setPropertyValue("foo", "notbar")); + ASSERT_NO_THROW(clientLocalObjWithMetadata.setPropertyValue("foo", "notbar")); + ASSERT_EQ(clientLocalObjWithMetadata.getPropertyValue("foo"), "notbar"); PropertyPtr clientObjectWithMetadataProp = clientObj.getProperty("ObjectWithMetadata"); PropertyPtr serverObjectWithMetadataProp = obj.getProperty("ObjectWithMetadata"); From 4e11c45e0eeb72efb5230d94d41134d24281b24c Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Tue, 16 Jan 2024 16:09:43 +0100 Subject: [PATCH 064/217] Split tags into Tags and TagsPrivate - Add TagsChanged core event - Make Tags changeable after creation --- .../objects/tms_client_tags_factory.h | 28 +++++++++ .../objects/tms_client_tags_impl.h | 44 +++++++++++++ .../opcuatms_client/src/CMakeLists.txt | 5 ++ .../src/objects/tms_client_component_impl.cpp | 13 ++-- .../src/objects/tms_client_tags_impl.cpp | 62 +++++++++++++++++++ .../tests/test_tms_input_port.cpp | 3 +- .../test_tms_component.cpp | 27 +++++++- .../opcuatms_integration/test_tms_folder.cpp | 4 +- .../test_tms_input_port.cpp | 2 +- .../opcuatms_integration/test_tms_signal.cpp | 4 +- 10 files changed, 176 insertions(+), 16 deletions(-) create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_factory.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_tags_impl.cpp diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_factory.h new file mode 100644 index 0000000..b613405 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_factory.h @@ -0,0 +1,28 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once +#include "opcuatms_client/objects/tms_client_context.h" +#include "opcuatms_client/objects/tms_client_tags_impl.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +inline TagsPtr TmsClientTags(const ContextPtr& ctx, const TmsClientContextPtr& clientContext, const OpcUaNodeId& nodeId) +{ + TagsPtr obj(createWithImplementation(ctx, clientContext, nodeId)); + return obj; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h new file mode 100644 index 0000000..e852803 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h @@ -0,0 +1,44 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "opendaq/tags_impl.h" +#include "opcuaclient/opcuaclient.h" +#include "opcuatms/opcuatms.h" +#include "opcuatms_client/objects/tms_client_object_impl.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +// TmsClientSignalImpl + +class TmsClientTagsImpl final : public TmsClientObjectImpl, public TagsImpl +{ +public: + explicit TmsClientTagsImpl(const ContextPtr& ctx, const TmsClientContextPtr& clientContext, const opcua::OpcUaNodeId& nodeId); + + + ErrCode INTERFACE_FUNC getList(IList** value) override; + ErrCode INTERFACE_FUNC add(IString* name) override; + ErrCode INTERFACE_FUNC remove(IString* name) override; + ErrCode INTERFACE_FUNC contains(IString* name, Bool* value) override; + ErrCode INTERFACE_FUNC query(IString* query, Bool* value) override; + +private: + void refreshTags(); + LoggerComponentPtr loggerComponent; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt index 5644553..2ecefdf 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt @@ -56,6 +56,9 @@ set(SRC_Objects_Headers ${OBJECT_SRC_DIR}/tms_client_object_impl.h ${OBJECT_SRC_DIR}/tms_client_procedure_impl.h ${OBJECT_SRC_DIR}/tms_client_procedure_factory.h + + ${OBJECT_SRC_DIR}/tms_client_tags_impl.h + ${OBJECT_SRC_DIR}/tms_client_tags_factory.h ) set(SRC_Objects ${OBJECT_SRC_DIR}/tms_client_object_impl.cpp @@ -73,6 +76,7 @@ set(SRC_Objects ${OBJECT_SRC_DIR}/tms_client_object_impl.cpp ${OBJECT_SRC_DIR}/tms_client_streaming_info_impl.cpp ${OBJECT_SRC_DIR}/tms_client_function_impl.cpp ${OBJECT_SRC_DIR}/tms_client_procedure_impl.cpp + ${OBJECT_SRC_DIR}/tms_client_tags_impl.cpp ) set(SRC_PublicHeaders ${SRC_PublicHeaders} ${SRC_Objects_Headers}) @@ -90,6 +94,7 @@ source_group("objects\\folder" "${OBJECT_SRC_DIR}/tms_client_folder.*") source_group("objects\\component" "${OBJECT_SRC_DIR}/tms_client_component.*") source_group("objects\\io_folder" "${OBJECT_SRC_DIR}/tms_client_io_folder.*") source_group("objects\\streaming_info" "${OBJECT_SRC_DIR}/tms_client_streaming_info.*") +source_group("objects\\tags" "${OBJECT_SRC_DIR}/tms_client_tags.*") source_group("objects\\function" "${OBJECT_SRC_DIR}/(tms_client_function_impl.*|tms_client_function_factory.h|tms_client_procedure.*)") # /objects diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp index a06b872..029190c 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp @@ -4,6 +4,7 @@ #include "opendaq/io_folder_impl.h" #include "opendaq/mirrored_signal_impl.h" #include "opendaq/input_port_impl.h" +#include "opcuatms_client/objects/tms_client_tags_factory.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -30,24 +31,20 @@ ErrCode TmsClientComponentBaseImpl::setActive(Bool active) template void TmsClientComponentBaseImpl::initComponent() { + try { - ListPtr tagValues = this->template readList("Tags"); - auto tagsObj = Tags(); - for (auto tag : tagValues) - tagsObj.add(tag); - tagsObj.freeze(); - this->tags = tagsObj.detach(); + this->tags = TmsClientTags(this->daqContext, this->clientContext, this->getNodeId("Tags")); } catch([[maybe_unused]] const std::exception& e) { const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClient"); - LOG_D("OPC UA Component {} failed to fetch tags: {}", this->localId, e.what()); + LOG_W("OPC UA Component {} failed to initialize: {}", this->localId, e.what()); } catch(...) { const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClient"); - LOG_D("OPC UA Component {} failed to fetch tags.", this->localId); + LOG_W("OPC UA Component {} failed to initialize", this->localId); } } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_tags_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_tags_impl.cpp new file mode 100644 index 0000000..69e29d3 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_tags_impl.cpp @@ -0,0 +1,62 @@ +#include "opcuatms_client/objects/tms_client_tags_impl.h" +#include "opendaq/tags_factory.h" +#include "opendaq/custom_log.h" +#include "opcuatms/errors.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +TmsClientTagsImpl::TmsClientTagsImpl(const ContextPtr& ctx, const TmsClientContextPtr& clientContext, const opcua::OpcUaNodeId& nodeId) + : TmsClientObjectImpl(ctx, clientContext, nodeId) + , TagsImpl() + , loggerComponent(ctx.getLogger().getOrAddComponent("OpcUaClient")) +{ +} + +ErrCode TmsClientTagsImpl::getList(IList** value) +{ + refreshTags(); + return TagsImpl::getList(value); +} + +ErrCode TmsClientTagsImpl::add(IString* name) +{ + return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; +} + +ErrCode TmsClientTagsImpl::remove(IString* name) +{ + return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; +} + +ErrCode TmsClientTagsImpl::contains(IString* name, Bool* value) +{ + refreshTags(); + return TagsImpl::contains(name, value); +} + +ErrCode TmsClientTagsImpl::query(IString* query, Bool* value) +{ + refreshTags(); + return TagsImpl::query(query, value); +} + +void TmsClientTagsImpl::refreshTags() +{ + try + { + const ListPtr tagValues = VariantConverter::ToDaqList(client->readValue(nodeId)); + this->tags.clear(); + for (const auto& tag : tagValues) + this->tags.insert(tag); + } + catch([[maybe_unused]] const std::exception& e) + { + LOG_D("OPC UA failed to fetch tags: {}", e.what()) + } + catch(...) + { + LOG_D("OPC UA failed to fetch tags.") + } +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp index f792238..7bb5949 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -23,7 +24,7 @@ class TmsInputPortTest : public TmsServerObjectTest InputPortPtr createInputPort() { auto port = InputPort(ctx, nullptr, "port"); - port.getTags().add("port"); + port.getTags().asPtr().add("port"); return port; } }; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_component.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_component.cpp index 716e998..1fd0d79 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_component.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_component.cpp @@ -28,8 +28,8 @@ class TmsComponentTest : public TmsObjectIntegrationTest obj.addProperty(IntProperty("int", 0)); component.addProperty(ObjectProperty("obj", obj)); - component.getTags().add("tag1"); - component.getTags().add("tag2"); + component.getTags().asPtr().add("tag1"); + component.getTags().asPtr().add("tag2"); return component; @@ -82,6 +82,29 @@ TEST_F(TmsComponentTest, Tags) auto clientTags = component.clientComponent.getTags(); ASSERT_TRUE(clientTags.query("tag1") && clientTags.query("tag2")); + ASSERT_TRUE(clientTags.contains("tag1") && clientTags.contains("tag2")); +} + + +TEST_F(TmsComponentTest, ModifyTags) +{ + auto component = registerTestComponent(); + + auto serverTags = component.serverComponent.getTags(); + auto clientTags = component.clientComponent.getTags(); + + ASSERT_TRUE(clientTags.query("tag1") && clientTags.query("tag2")); + ASSERT_TRUE(clientTags.contains("tag1") && clientTags.contains("tag2")); + + serverTags.asPtr().remove("tag2"); + + ASSERT_TRUE(clientTags.query("tag1") && !clientTags.query("tag2")); + ASSERT_TRUE(clientTags.contains("tag1") && !clientTags.contains("tag2")); + + serverTags.asPtr().add("tag3"); + + ASSERT_TRUE(clientTags.query("tag1") && clientTags.query("tag3")); + ASSERT_TRUE(clientTags.contains("tag1") && clientTags.contains("tag3")); } TEST_F(TmsComponentTest, Properties) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp index 62b38bf..ddcf2ce 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp @@ -34,8 +34,8 @@ class TmsFolderTest : public TmsObjectIntegrationTest obj.addProperty(IntProperty("int", 0)); leafFolder.addProperty(ObjectProperty("obj", obj)); - folder1.getTags().add("tag1"); - folder2.getTags().add("tag2"); + folder1.getTags().asPtr().add("tag1"); + folder2.getTags().asPtr().add("tag2"); return folder1; } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp index bb30c03..1dd29e1 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp @@ -28,7 +28,7 @@ class TmsInputPortTest : public TmsObjectIntegrationTest { auto ip = InputPort(NullContext(), nullptr, name); ip.setRequiresSignal(requiresSignal); - ip.getTags().add("port"); + ip.getTags().asPtr().add("port"); return ip; } }; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp index 5ec9329..84b01ad 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp @@ -52,8 +52,8 @@ class TmsSignalTest : public TmsObjectIntegrationTest // Build server signal auto serverSignal = SignalWithDescriptor(NullContext(), serverDataDescriptor, nullptr, "sig"); serverSignal->setActive(true); - serverSignal.getTags().add("tag1"); - serverSignal.getTags().add("tag2"); + serverSignal.getTags().asPtr().add("tag1"); + serverSignal.getTags().asPtr().add("tag2"); return serverSignal; } From cc60a68386f0252a61652ac8c18708ec9d0389e2 Mon Sep 17 00:00:00 2001 From: Martin Kraner Date: Tue, 30 Jan 2024 15:37:14 +0100 Subject: [PATCH 065/217] Fix openDAQ component (static) libraries linking --- shared/libraries/opcuatms/tests/CMakeLists.txt | 2 +- .../opcuatms/tests/opcuatms_integration/CMakeLists.txt | 1 - .../tests/opcuatms_integration/test_tms_function_block.cpp | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/shared/libraries/opcuatms/tests/CMakeLists.txt b/shared/libraries/opcuatms/tests/CMakeLists.txt index 09395d4..bdecf99 100644 --- a/shared/libraries/opcuatms/tests/CMakeLists.txt +++ b/shared/libraries/opcuatms/tests/CMakeLists.txt @@ -3,4 +3,4 @@ set_cmake_folder_context(TARGET_FOLDER_NAME) project(opcuatms_integration_tests CXX) add_subdirectory(test_utils) -#add_subdirectory(opcuatms_integration) +add_subdirectory(opcuatms_integration) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt b/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt index 2437187..29fe72e 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt @@ -47,7 +47,6 @@ endif() target_link_libraries(${TEST_APP} PRIVATE daq::opcuatms_test_utils daq::opcuatms_server - $ daq::opcuatms_client daq::opendaq_mocks ${BCRYPT_LIB} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp index 434eae9..74309b6 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include #include From 28761f83dcab2e5303b46549be005c8c29552b75 Mon Sep 17 00:00:00 2001 From: Nils Roettger <99480819+nilsRoettgerAtBB@users.noreply.github.com> Date: Wed, 31 Jan 2024 15:32:41 +0000 Subject: [PATCH 066/217] Bugfix: Float Type not supported in Structures (openDAQ/openDAQ#114) * Bugfix: Float Type not supportted in Structures Structs and so opc ua variants can have also variables with the opc ua type float. These need to be mapped in the correct way. * Fix truncation error. * Add Codereview feedback. --- .../include/opcuashared/opcuavariant.h | 1 + .../opcua/opcuashared/src/opcuavariant.cpp | 5 ++ .../src/converters/core_types_converter.cpp | 2 + .../test_tms_fusion_device.cpp | 49 +++++++++++++++---- 4 files changed, 48 insertions(+), 9 deletions(-) diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h index b393326..83f9e3f 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h @@ -161,6 +161,7 @@ class OpcUaVariant : public OpcUaObject std::string toString() const; int64_t toInteger() const; double toDouble() const; + float toFloat() const; bool toBool() const; OpcUaNodeId toNodeId() const; diff --git a/shared/libraries/opcua/opcuashared/src/opcuavariant.cpp b/shared/libraries/opcua/opcuashared/src/opcuavariant.cpp index e71dc99..0ac1bc2 100644 --- a/shared/libraries/opcua/opcuashared/src/opcuavariant.cpp +++ b/shared/libraries/opcua/opcuashared/src/opcuavariant.cpp @@ -195,6 +195,11 @@ double OpcUaVariant::toDouble() const return readScalar(); } +float OpcUaVariant::toFloat() const +{ + return readScalar(); +} + bool OpcUaVariant::toBool() const { return readScalar(); diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/core_types_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/core_types_converter.cpp index 39b4af9..1593028 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/core_types_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/core_types_converter.cpp @@ -263,6 +263,8 @@ OpcUaObject StructConverter::ToTmsType(const FloatPt template <> FloatPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& /*context*/) { + if (variant.isType()) + return variant.toFloat(); return variant.toDouble(); } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp index 921194a..7dace79 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp @@ -41,22 +41,26 @@ class TmsFusionDevice : public TmsObjectIntegrationTest void SetUp() override { TmsObjectIntegrationTest::SetUp(); + objManager = TypeManager(); - // create class with name "STGAmplifier" - auto stgAmplClass = - PropertyObjectClassBuilder("StgAmp") + // create class with name "FusionAmp" + auto fusionAmpClass = + PropertyObjectClassBuilder("FusionAmp") .addProperty(SelectionProperty( - "Measurement", List("Voltage", "Bridge", "Resistance", "Temperature", "Current", "Potentiometer"), 0)) - + "Measurement", List("Voltage", "FullBridge", "HalfBridge", "QuarterBridge"), 0)) + .addProperty(StructProperty( + "AdjustmentPoint", Struct("AdjustmentPointScalingStructure", Dict({{"Index", 1}, {"Factor", 2.1}, {"Offset", 3.0}}), objManager)) + ) + .addProperty(StructProperty( + "Scaler", Struct("GainScalingStructure", Dict({{"Factor", 2.1}, {"Offset", 3.0}}), objManager)) + ) .build(); - - objManager = TypeManager(); - objManager.addType(stgAmplClass); + objManager.addType(fusionAmpClass); } void TearDown() override { - objManager.removeType("StgAmp"); + objManager.removeType("FusionAmp"); } RegisteredPropertyObject registerPropertyObject(const PropertyObjectPtr& prop) @@ -87,6 +91,33 @@ TEST_F(TmsFusionDevice, SampleRateTest) ASSERT_NO_THROW(clientSignal.getPropertyValue("SampleRate")); } +TEST_F(TmsFusionDevice, StructTest) +{ + const auto obj = PropertyObject(objManager, "FusionAmp"); + auto [serverObj, fusionAmp] = registerPropertyObject(obj); + + // Test struct with int and float values + const auto adjustmentPoint = StructBuilder(fusionAmp.getPropertyValue("AdjustmentPoint")); + adjustmentPoint.set("Index", 10); + adjustmentPoint.set("Factor", 3.1); + fusionAmp.setPropertyValue("AdjustmentPoint", adjustmentPoint.build()); + + const auto adjustmentPointManipulated = StructBuilder(fusionAmp.getPropertyValue("AdjustmentPoint")); + ASSERT_EQ(adjustmentPointManipulated.get("Index"), 10); + ASSERT_FLOAT_EQ(adjustmentPointManipulated.get("Factor"), (float) 3.1); + + // Test strusct with double values + const auto scaler = StructBuilder(fusionAmp.getPropertyValue("Scaler")); + scaler.set("Factor", 3.62); + scaler.set("Offset", 3.1); + fusionAmp.setPropertyValue("Scaler", scaler.build()); + + const auto scalerManipulated = StructBuilder(fusionAmp.getPropertyValue("Scaler")); + ASSERT_DOUBLE_EQ(scalerManipulated.get("Factor"), (double) 3.62); + ASSERT_DOUBLE_EQ(scalerManipulated.get("Offset"), (double) 3.1); + +} + TEST_F(TmsFusionDevice, DISABLED_SimulatorTest) { // this test should pass, if you have Fusion simulator running From 583d7a77f9509816e04184b4e41a37aaf5898831 Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Mon, 5 Feb 2024 10:01:54 +0100 Subject: [PATCH 067/217] [TBBAS-939] Error recovery and logging in OPC UA client. Add debug logger sink (openDAQ/openDAQ#103) -wrapped OpcUa client components with try catch -add warnings -implement custom debug logger sink which stores last log messages -update test which expected getting and exception which checking log message --- .../objects/tms_client_component_impl.h | 1 + .../objects/tms_client_folder_impl.h | 2 + .../objects/tms_client_function_block_impl.h | 2 + .../objects/tms_client_io_folder_impl.h | 1 + .../src/objects/tms_client_component_impl.cpp | 84 +++++++---- .../src/objects/tms_client_device_impl.cpp | 133 +++++++++++------- .../src/objects/tms_client_folder_impl.cpp | 40 ++++-- .../tms_client_function_block_impl.cpp | 49 ++++--- .../src/objects/tms_client_function_impl.cpp | 18 ++- .../objects/tms_client_input_port_impl.cpp | 11 +- .../src/objects/tms_client_io_folder_impl.cpp | 54 ++++--- .../src/objects/tms_client_procedure_impl.cpp | 15 +- .../src/objects/tms_client_property_impl.cpp | 2 +- .../tms_client_property_object_impl.cpp | 60 ++++++-- .../src/objects/tms_client_signal_impl.cpp | 53 ++++--- .../test_property_object_advanced.cpp | 20 ++- .../test_tms_amplifier.cpp | 1 - .../test_tms_function_property.cpp | 26 +++- .../test_tms_property_object.cpp | 25 +++- .../tms_object_integration_test.cpp | 22 ++- .../tms_object_integration_test.h | 8 +- 21 files changed, 444 insertions(+), 183 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h index 5befca1..8a15f89 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h @@ -66,6 +66,7 @@ class TmsClientComponentBaseImpl : public TmsClientPropertyObjectBaseImpl ErrCode INTERFACE_FUNC setVisible(Bool visible) override; private: + LoggerComponentPtr getLoggerComponent(); void initComponent(); }; diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h index 3623d90..15cf0de 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h @@ -32,6 +32,8 @@ class TmsClientFolderImpl : public TmsClientComponentBaseImpl bool customFolderType); private: void findAndCreateFolders(std::map& orderedComponents, std::vector& unorderedComponents); + + LoggerComponentPtr loggerComponent; }; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h index 45f80ce..e4a388d 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h @@ -38,6 +38,8 @@ class TmsClientFunctionBlockBaseImpl : public TmsClientComponentBaseImpl SignalPtr onGetStatusSignal() override; protected: + LoggerComponentPtr loggerComponent; + void findAndCreateFunctionBlocks(); void findAndCreateSignals(); void findAndCreateInputPorts(); diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h index 3ae840f..6140cf1 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h @@ -30,6 +30,7 @@ class TmsClientIoFolderImpl : public TmsClientFolderImpl> const opcua::OpcUaNodeId& nodeId); protected: + LoggerComponentPtr loggerComponent; void findAndCreateChannels(std::map& orderedComponents, std::vector& unorderedComponents); void findAndCreateIoFolders(std::map& orderedComponents, std::vector& unorderedComponents); }; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp index 029190c..325a8c1 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp @@ -12,20 +12,34 @@ using namespace daq::opcua; template ErrCode TmsClientComponentBaseImpl::getActive(Bool* active) -{ - return daqTry([&]() { +{ + try + { *active = this->template readValue("Active"); - return OPENDAQ_SUCCESS; - }); + } + catch(...) + { + *active = true; + auto loggerComponent = getLoggerComponent(); + LOG_D("Failed to get active of component \"{}\". The default value was returned \"true\"", this->globalId); + } + return OPENDAQ_SUCCESS; } template ErrCode TmsClientComponentBaseImpl::setActive(Bool active) { - return daqTry([&]() { + try + { this->template writeValue("Active", active); return OPENDAQ_SUCCESS; - }); + } + catch(...) + { + auto loggerComponent = getLoggerComponent(); + LOG_D("Failed to set active of component \"{}\"", this->globalId); + } + return OPENDAQ_IGNORED; } template @@ -38,13 +52,13 @@ void TmsClientComponentBaseImpl::initComponent() } catch([[maybe_unused]] const std::exception& e) { - const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClient"); - LOG_W("OPC UA Component {} failed to initialize: {}", this->localId, e.what()); + const auto loggerComponent = getLoggerComponent(); + LOG_D("OpcUA Component {} failed to initialize: {}", this->globalId, e.what()); } catch(...) { - const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClient"); - LOG_W("OPC UA Component {} failed to initialize", this->localId); + const auto loggerComponent = getLoggerComponent(); + LOG_D("OpcUA Component {} failed to initialize", this->globalId); } } @@ -53,12 +67,19 @@ ErrCode TmsClientComponentBaseImpl::getName(IString** name) { OPENDAQ_PARAM_NOT_NULL(name); - return daqTry([&] + StringPtr nameObj; + try { - StringPtr nameObj =this->client->readDisplayName(this->nodeId); - *name = nameObj.detach(); - return OPENDAQ_SUCCESS; - }); + nameObj = this->client->readDisplayName(this->nodeId); + } + catch(...) + { + nameObj = this->localId; + auto loggerComponent = getLoggerComponent(); + LOG_D("Failed to get name of component \"{}\". The default value was returned \"{}\" (local id)", this->globalId, nameObj); + } + *name = nameObj.detach(); + return OPENDAQ_SUCCESS; } template @@ -74,8 +95,8 @@ ErrCode TmsClientComponentBaseImpl::setName(IString* name) } catch(...) { - auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClientComponent"); - LOG_W("Failed to set name of component \"{}\"", this->localId); + auto loggerComponent = getLoggerComponent(); + LOG_D("Failed to set name of component \"{}\"", this->globalId); } return OPENDAQ_IGNORED; @@ -86,12 +107,18 @@ ErrCode TmsClientComponentBaseImpl::getDescription(IString** description) { OPENDAQ_PARAM_NOT_NULL(description); - return daqTry([&] + try { StringPtr descObj = this->client->readDescription(this->nodeId); *description = descObj.detach(); - return OPENDAQ_SUCCESS; - }); + } + catch(...) + { + *description = StringPtr("").detach(); + auto loggerComponent = getLoggerComponent(); + LOG_D("Failed to get description of component \"{}\". The default value was returned \"\"", this->globalId); + } + return OPENDAQ_SUCCESS; } template @@ -107,8 +134,8 @@ ErrCode TmsClientComponentBaseImpl::setDescription(IString* description) } catch(...) { - auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClientComponent"); - LOG_W("Failed to set description of component \"{}\"", this->localId); + auto loggerComponent = getLoggerComponent(); + LOG_D("Failed to set description of component \"{}\"", this->globalId); } return OPENDAQ_IGNORED; @@ -124,8 +151,8 @@ ErrCode TmsClientComponentBaseImpl::getVisible(Bool* visible) catch(...) { *visible = true; - const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClient"); - LOG_D("OPC UA Component {} failed to fetch \"Visible\" state.", this->localId); + const auto loggerComponent = getLoggerComponent(); + LOG_D("OpcUA Component {} failed to fetch \"Visible\" state. The default value was returned \"true\"", this->globalId); } return OPENDAQ_SUCCESS; @@ -141,13 +168,18 @@ ErrCode TmsClientComponentBaseImpl::setVisible(Bool visible) } catch (...) { - const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClient"); - LOG_D("OPC UA Component {} failed to set \"Active\" state.", this->localId); + const auto loggerComponent = getLoggerComponent(); + LOG_D("OpcUA Component {} failed to set \"Active\" state.", this->globalId); } return OPENDAQ_IGNORED; } +template +LoggerComponentPtr TmsClientComponentBaseImpl::getLoggerComponent() +{ + return this->daqContext.getLogger().getOrAddComponent("OpcUaClientComponent"); +} template class TmsClientComponentBaseImpl>; template class TmsClientComponentBaseImpl>; template class TmsClientComponentBaseImpl>; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 24a44f2..4fe58e5 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -88,14 +88,21 @@ void TmsClientDeviceImpl::findAndCreateSubdevices() for (const auto& [browseName, ref] : references.byBrowseName) { - auto subdeviceNodeId = OpcUaNodeId(ref->nodeId.nodeId); - auto clientSubdevice = TmsClientDevice(context, devices, browseName, clientContext, subdeviceNodeId, createStreamingCallback); - - auto numberInList = this->tryReadChildNumberInList(subdeviceNodeId); - if (numberInList != std::numeric_limits::max() && !orderedDevices.count(numberInList)) - orderedDevices.insert(std::pair(numberInList, clientSubdevice)); - else - unorderedDevices.emplace_back(clientSubdevice); + try + { + auto subdeviceNodeId = OpcUaNodeId(ref->nodeId.nodeId); + auto clientSubdevice = TmsClientDevice(context, devices, browseName, clientContext, subdeviceNodeId, createStreamingCallback); + + auto numberInList = this->tryReadChildNumberInList(subdeviceNodeId); + if (numberInList != std::numeric_limits::max() && !orderedDevices.count(numberInList)) + orderedDevices.insert(std::pair(numberInList, clientSubdevice)); + else + unorderedDevices.emplace_back(clientSubdevice); + } + catch(...) + { + LOG_W("Failed to create subdevice \"{}\" in OpcUA client device \"{}\"", browseName, this->globalId); + } } for (const auto& val : orderedDevices) @@ -162,7 +169,7 @@ DeviceInfoPtr TmsClientDeviceImpl::onGetInfo() } catch (const std::exception& e) { - LOG_W("Failed to read device info attribute: {}", e.what()); + LOG_W("Failed to read device info attribute on OpcUa client device \"{}\": {}", this->globalId, e.what()); } } @@ -258,7 +265,7 @@ void TmsClientDeviceImpl::findAndCreateFunctionBlocks() } catch(...) { - // TODO: Log failure to add fb + LOG_W("Failed to create function block \"{}\" to OpcUA client device \"{}\"", browseName, this->globalId); } } @@ -278,14 +285,21 @@ void TmsClientDeviceImpl::findAndCreateSignals() for (const auto& [signalNodeId, ref] : references.byNodeId) { - auto clientSignal = FindOrCreateTmsClientSignal(context, signals, clientContext, signalNodeId); - const auto numberInList = this->tryReadChildNumberInList(signalNodeId); - if (numberInList != std::numeric_limits::max() && !orderedSignals.count(numberInList)) - orderedSignals.insert(std::pair(numberInList, clientSignal)); - else - unorderedSignals.emplace_back(clientSignal); + try + { + auto clientSignal = FindOrCreateTmsClientSignal(context, signals, clientContext, signalNodeId); + const auto numberInList = this->tryReadChildNumberInList(signalNodeId); + if (numberInList != std::numeric_limits::max() && !orderedSignals.count(numberInList)) + orderedSignals.insert(std::pair(numberInList, clientSignal)); + else + unorderedSignals.emplace_back(clientSignal); + } + catch (...) + { + LOG_W("Failed to find signal to OpcUA client device \"{}\"", this->globalId); + } } - + for (const auto& val : orderedSignals) this->addSignal(val.second); for (const auto& val : unorderedSignals) @@ -303,28 +317,42 @@ void TmsClientDeviceImpl::findAndCreateInputsOutputs() for (const auto& [browseName, ref] : channelreferences.byBrowseName) { - const auto channelNodeId = OpcUaNodeId(ref->nodeId.nodeId); - auto tmsClientChannel = TmsClientChannel(context, this->ioFolder, browseName, clientContext, channelNodeId); - - auto numberInList = this->tryReadChildNumberInList(channelNodeId); - if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) - orderedComponents.insert(std::pair(numberInList, tmsClientChannel)); - else - unorderedComponents.emplace_back(tmsClientChannel); + try + { + const auto channelNodeId = OpcUaNodeId(ref->nodeId.nodeId); + auto tmsClientChannel = TmsClientChannel(context, this->ioFolder, browseName, clientContext, channelNodeId); + + auto numberInList = this->tryReadChildNumberInList(channelNodeId); + if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) + orderedComponents.insert(std::pair(numberInList, tmsClientChannel)); + else + unorderedComponents.emplace_back(tmsClientChannel); + } + catch (...) + { + LOG_W("Failed to find channel \"{}\" to OpcUA client device \"{}\"", browseName, this->globalId); + } } const auto& folderReferences = getChildReferencesOfType(inputsOutputsNodeId, OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_IOCOMPONENTTYPE)); for (const auto& [browseName, ref] : folderReferences.byBrowseName) { - const auto folderNodeId = OpcUaNodeId(ref->nodeId.nodeId); - auto tmsClientFolder = TmsClientIoFolder(context, this->ioFolder, browseName, clientContext, folderNodeId); - - auto numberInList = this->tryReadChildNumberInList(folderNodeId); - if (numberInList != std::numeric_limits::max()) - orderedComponents.insert(std::pair(numberInList, tmsClientFolder)); - else - unorderedComponents.emplace_back(tmsClientFolder); + try + { + const auto folderNodeId = OpcUaNodeId(ref->nodeId.nodeId); + auto tmsClientFolder = TmsClientIoFolder(context, this->ioFolder, browseName, clientContext, folderNodeId); + + auto numberInList = this->tryReadChildNumberInList(folderNodeId); + if (numberInList != std::numeric_limits::max()) + orderedComponents.insert(std::pair(numberInList, tmsClientFolder)); + else + unorderedComponents.emplace_back(tmsClientFolder); + } + catch (...) + { + LOG_W("Failed to find io folder \"{}\" to OpcUA client device \"{}\"", browseName, this->globalId); + } } for (const auto& val : orderedComponents) @@ -360,7 +388,7 @@ void TmsClientDeviceImpl::findAndCreateStreamingOptions() } catch (const std::exception& e) { - LOG_E("Failed to find 'StreamingOptions' OpcUa node: {}", e.what()); + LOG_W("Failed to find 'StreamingOptions' OpcUA node on OpcUA client device \"{}\": {}", this->globalId, e.what()); } for (const auto& val : orderedStreamings) @@ -379,24 +407,31 @@ void TmsClientDeviceImpl::findAndCreateCustomComponents() for (const auto& [browseName, ref] : folderReferences.byBrowseName) { - const auto folderNodeId = OpcUaNodeId(ref->nodeId.nodeId); + try + { + const auto folderNodeId = OpcUaNodeId(ref->nodeId.nodeId); - if (detail::defaultComponents.count(browseName)) - continue; + if (detail::defaultComponents.count(browseName)) + continue; - const auto& componentReferences = getChildReferencesOfType(folderNodeId, componentId); + const auto& componentReferences = getChildReferencesOfType(folderNodeId, componentId); - ComponentPtr child; - if (!componentReferences.byNodeId.empty()) - child = TmsClientFolder(context, this->thisPtr(), browseName, clientContext, folderNodeId); - else - child = TmsClientComponent(context, this->thisPtr(), browseName, clientContext, folderNodeId); - - auto numberInList = this->tryReadChildNumberInList(folderNodeId); - if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) - orderedComponents.insert(std::pair(numberInList, child)); - else - unorderedComponents.push_back(child); + ComponentPtr child; + if (!componentReferences.byNodeId.empty()) + child = TmsClientFolder(context, this->thisPtr(), browseName, clientContext, folderNodeId); + else + child = TmsClientComponent(context, this->thisPtr(), browseName, clientContext, folderNodeId); + + auto numberInList = this->tryReadChildNumberInList(folderNodeId); + if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) + orderedComponents.insert(std::pair(numberInList, child)); + else + unorderedComponents.push_back(child); + } + catch (...) + { + LOG_W("Failed to find channel \"{}\" to OpcUA client device \"{}\"", browseName, this->globalId); + } } for (const auto& val : orderedComponents) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp index 18e5ed5..7f34158 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp @@ -15,6 +15,8 @@ TmsClientFolderImpl::TmsClientFolderImpl(const ContextPtr& ctx, const opcua::OpcUaNodeId& nodeId, bool customFolderType) : TmsClientComponentBaseImpl(ctx, parent, localId, clientContext, nodeId) + , loggerComponent(this->daqContext.getLogger().assigned() ? this->daqContext.getLogger().getOrAddComponent("OpcUaClientFolder") + : throw ArgumentNullException("Logger must not be null")) { if (!customFolderType) { @@ -37,22 +39,30 @@ void TmsClientFolderImpl::findAndCreateFolders(std::mapnodeId.nodeId); - auto thisPtr = this->template borrowPtr(); + try + { + const auto folderNodeId = OpcUaNodeId(ref->nodeId.nodeId); + auto thisPtr = this->template borrowPtr(); + + const auto& childComponentsReferences = this->getChildReferencesOfType(folderNodeId, componentId); - const auto& childComponentsReferences = this->getChildReferencesOfType(folderNodeId, componentId); - - ComponentPtr child; - if (!childComponentsReferences.byNodeId.empty()) - child = TmsClientFolder(this->context, thisPtr, browseName, this->clientContext, folderNodeId); - else - child = TmsClientComponent(this->context, thisPtr, browseName, this->clientContext, folderNodeId); - - auto numberInList = this->tryReadChildNumberInList(folderNodeId); - if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) - orderedComponents.insert(std::pair(numberInList, child)); - else - unorderedComponents.push_back(child); + ComponentPtr child; + if (!childComponentsReferences.byNodeId.empty()) + child = TmsClientFolder(this->context, thisPtr, browseName, this->clientContext, folderNodeId); + else + child = TmsClientComponent(this->context, thisPtr, browseName, this->clientContext, folderNodeId); + + auto numberInList = this->tryReadChildNumberInList(folderNodeId); + if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) + orderedComponents.insert(std::pair(numberInList, child)); + else + unorderedComponents.push_back(child); + } + catch (...) + { + LOG_W("Failed to find and create folder \"{}\" to OpcUA client folder \"{}\"", browseName, this->globalId); + throw; + } } } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp index e4929df..78e125e 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp @@ -20,6 +20,8 @@ TmsClientFunctionBlockBaseImpl::TmsClientFunctionBlockBaseImpl( const OpcUaNodeId& nodeId ) : TmsClientComponentBaseImpl(context, parent, localId, clientContext, nodeId, nullptr) + , loggerComponent(this->daqContext.getLogger().assigned() ? this->daqContext.getLogger().getOrAddComponent("OpcUaClientFunctionBlock") + : throw ArgumentNullException("Logger must not be null")) { clientContext->readObjectAttributes(nodeId); @@ -65,8 +67,7 @@ void TmsClientFunctionBlockBaseImpl::findAndCreateFunctionBlocks() } catch(...) { - // TODO: Log failure to add function/procedure. - continue; + LOG_W("Failed to create function block \"{}\" to OpcUA client device \"{}\"", browseName, this->globalId); } } @@ -86,12 +87,20 @@ void TmsClientFunctionBlockBaseImpl::findAndCreateSignals() for (const auto& [signalNodeId, ref] : references.byNodeId) { - auto clientSignal = FindOrCreateTmsClientSignal(this->context, this->signals, this->clientContext, signalNodeId); - const auto numberInList = this->tryReadChildNumberInList(signalNodeId); - if (numberInList != std::numeric_limits::max() && !orderedSignals.count(numberInList)) - orderedSignals.insert(std::pair(numberInList, clientSignal)); - else - unorderedSignals.emplace_back(clientSignal); + try + { + auto clientSignal = FindOrCreateTmsClientSignal(this->context, this->signals, this->clientContext, signalNodeId); + const auto numberInList = this->tryReadChildNumberInList(signalNodeId); + if (numberInList != std::numeric_limits::max() && !orderedSignals.count(numberInList)) + orderedSignals.insert(std::pair(numberInList, clientSignal)); + else + unorderedSignals.emplace_back(clientSignal); + } + catch (...) + { + LOG_W("Failed to create signal to OpcUA client \"{}\"", this->globalId); + throw; + } } for (const auto& val : orderedSignals) @@ -134,17 +143,25 @@ void TmsClientFunctionBlockBaseImpl::findAndCreateInputPorts() for (const auto& [browseName, ref] : references.byBrowseName) { - const auto inputPortNodeId = OpcUaNodeId(ref->nodeId.nodeId); + try + { + const auto inputPortNodeId = OpcUaNodeId(ref->nodeId.nodeId); - auto clientInputPort = TmsClientInputPort(this->context, this->inputPorts, browseName, this->clientContext, inputPortNodeId); + auto clientInputPort = TmsClientInputPort(this->context, this->inputPorts, browseName, this->clientContext, inputPortNodeId); - const auto numberInList = this->tryReadChildNumberInList(inputPortNodeId); - if (numberInList != std::numeric_limits::max() && !orderedInputPorts.count(numberInList)) - orderedInputPorts.insert(std::pair(numberInList, clientInputPort)); - else - unorderedInputPorts.emplace_back(clientInputPort); + const auto numberInList = this->tryReadChildNumberInList(inputPortNodeId); + if (numberInList != std::numeric_limits::max() && !orderedInputPorts.count(numberInList)) + orderedInputPorts.insert(std::pair(numberInList, clientInputPort)); + else + unorderedInputPorts.emplace_back(clientInputPort); + } + catch(...) + { + LOG_W("Failed to find and create input port \"{}\" to OpcUA client \"{}\"", browseName, this->globalId); + throw; + } } - + for (const auto& val : orderedInputPorts) this->addInputPort(val.second); for (const auto& val : unorderedInputPorts) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_impl.cpp index 2da85f5..5534a8f 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_impl.cpp @@ -1,4 +1,5 @@ -#include "coretypes/validation.h" +#include +#include #include "opcuatms_client/objects/tms_client_function_factory.h" #include "opcuatms/converters/variant_converter.h" #include "opcuatms/converters/list_conversion_utils.h" @@ -19,35 +20,46 @@ TmsClientFunctionImpl::TmsClientFunctionImpl(const TmsClientContextPtr& ctx, ErrCode TmsClientFunctionImpl::call(IBaseObject* args, IBaseObject** result) { - // TODO: Return more specific error depending on OPC UA status code - return daqTry([&]() + StringPtr lastProccessDescription = ""; + ErrCode errCode = daqTry([&]() { auto argsPtr = BaseObjectPtr::Borrow(args); OpcUaCallMethodRequest callRequest; if (!argsPtr.assigned()) { + lastProccessDescription = "Creating call request with no args"; callRequest = OpcUaCallMethodRequest(methodId, parentId, 0); } else if (argsPtr.asPtrOrNull().assigned()) { + lastProccessDescription = "Creating call request with list of arguments"; auto argsList = argsPtr.asPtrOrNull(); OpcUaVariant varArgs = ListConversionUtils::ToVariantTypeArrayVariant(argsList, daqContext); callRequest = OpcUaCallMethodRequest(methodId, parentId, argsList.getCount(), (UA_Variant*) varArgs->data); } else { + lastProccessDescription = "Creating call request with one arguments"; OpcUaVariant varArgs = VariantConverter::ToVariant(argsPtr, nullptr, daqContext); callRequest = OpcUaCallMethodRequest(methodId, parentId, 1, &varArgs.getValue()); } + lastProccessDescription = "Calling function"; OpcUaObject callResult = ctx->getClient()->callMethod(callRequest); if (OPCUA_STATUSCODE_FAILED(callResult->statusCode) || (callResult->outputArgumentsSize != 1)) return OPENDAQ_ERR_CALLFAILED; + lastProccessDescription = "Getting call result"; *result = VariantConverter::ToDaqObject(OpcUaVariant(callResult->outputArguments[0]), daqContext).detach(); return OPENDAQ_SUCCESS; }); + if (OPENDAQ_FAILED(errCode) && this->daqContext.getLogger().assigned()) + { + auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClientProcedure"); + LOG_W("Failed to call function on OpcUA client. Error in \"{}\"", lastProccessDescription); + } + return OPENDAQ_SUCCESS; } ErrCode TmsClientFunctionImpl::getCoreType(CoreType* coreType) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp index a52752e..3bb0124 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp @@ -17,10 +17,15 @@ TmsClientInputPortImpl::TmsClientInputPortImpl(const ContextPtr& ctx, ErrCode TmsClientInputPortImpl::getRequiresSignal(Bool* value) { - return daqTry([&]() { + try + { *value = readValue("RequiresSignal"); - return OPENDAQ_SUCCESS; - }); + } + catch(...) + { + LOG_W("Failed to get requires signals on OpcUA client input port \"{}\"", this->globalId); + } + return OPENDAQ_SUCCESS; } ErrCode TmsClientInputPortImpl::setRequiresSignal(Bool value) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp index 72a6b38..2c21ac4 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp @@ -33,16 +33,24 @@ void TmsClientIoFolderImpl::findAndCreateChannels(std::mapnodeId, OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_CHANNELTYPE)); for (const auto& [browseName, ref] : references.byBrowseName) - { - const auto channelNodeId = OpcUaNodeId(ref->nodeId.nodeId); - auto thisPtr = this->borrowPtr(); - auto tmsClientChannel = TmsClientChannel(this->context, thisPtr, browseName, this->clientContext, channelNodeId); - - auto numberInList = this->tryReadChildNumberInList(channelNodeId); - if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) - orderedComponents.insert(std::pair(numberInList, tmsClientChannel)); - else - unorderedComponents.emplace_back(tmsClientChannel); + { + try + { + const auto channelNodeId = OpcUaNodeId(ref->nodeId.nodeId); + auto thisPtr = this->borrowPtr(); + auto tmsClientChannel = TmsClientChannel(this->context, thisPtr, browseName, this->clientContext, channelNodeId); + + auto numberInList = this->tryReadChildNumberInList(channelNodeId); + if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) + orderedComponents.insert(std::pair(numberInList, tmsClientChannel)); + else + unorderedComponents.emplace_back(tmsClientChannel); + } + catch (...) + { + LOG_W("Failed to find and create channel \"{}\" to OpcUA client io folder \"{}\"", browseName, this->globalId); + throw; + } } } @@ -52,16 +60,24 @@ void TmsClientIoFolderImpl::findAndCreateIoFolders(std::mapnodeId.nodeId); - auto thisPtr = this->template borrowPtr(); - auto tmsClientFolder = TmsClientIoFolder(this->context, thisPtr, browseName, this->clientContext, folderNodeId); + try + { + const auto folderNodeId = OpcUaNodeId(ref->nodeId.nodeId); + auto thisPtr = this->template borrowPtr(); + auto tmsClientFolder = TmsClientIoFolder(this->context, thisPtr, browseName, this->clientContext, folderNodeId); - auto numberInList = this->tryReadChildNumberInList(folderNodeId); - if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) - orderedComponents.insert(std::pair(numberInList, tmsClientFolder)); - else - unorderedComponents.emplace_back(tmsClientFolder); + auto numberInList = this->tryReadChildNumberInList(folderNodeId); + if (numberInList != std::numeric_limits::max() && !orderedComponents.count(numberInList)) + orderedComponents.insert(std::pair(numberInList, tmsClientFolder)); + else + unorderedComponents.emplace_back(tmsClientFolder); + } + catch (...) + { + LOG_W("Failed to find and create folder \"{}\" to OpcUA client io folder \"{}\"", browseName, this->globalId); + throw; + } } } -END_NAMESPACE_OPENDAQ_OPCUA_TMS +END_NAMESPACE_OPENDAQ_OPCUA_TMS \ No newline at end of file diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_procedure_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_procedure_impl.cpp index 2b8e6ae..084adc5 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_procedure_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_procedure_impl.cpp @@ -2,6 +2,7 @@ #include "opcuatms_client/objects/tms_client_procedure_factory.h" #include "opcuatms/converters/variant_converter.h" #include "opcuatms/converters/list_conversion_utils.h" +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -20,34 +21,44 @@ TmsClientProcedureImpl::TmsClientProcedureImpl(const TmsClientContextPtr& ctx, ErrCode TmsClientProcedureImpl::dispatch(IBaseObject* args) { - // TODO: Return more specific error depending on OPC UA status code - return daqTry([&]() + StringPtr lastProccessDescription = ""; + ErrCode errCode = daqTry([&]() { auto argsPtr = BaseObjectPtr::Borrow(args); OpcUaCallMethodRequest callRequest; if (!argsPtr.assigned()) { + lastProccessDescription = "Creating call request with no args"; callRequest = OpcUaCallMethodRequest(methodId, parentId, 0); } else if (argsPtr.asPtrOrNull().assigned()) { + lastProccessDescription = "Creating call request with list of arguments"; auto argsList = argsPtr.asPtrOrNull(); OpcUaVariant varArgs = ListConversionUtils::ToVariantTypeArrayVariant(argsList, daqContext); callRequest = OpcUaCallMethodRequest(methodId, parentId, argsList.getCount(), (UA_Variant*) varArgs->data); } else { + lastProccessDescription = "Creating call request with one arguments"; OpcUaVariant varArgs = VariantConverter::ToVariant(argsPtr, nullptr, daqContext); callRequest = OpcUaCallMethodRequest(methodId, parentId, 1, &varArgs.getValue()); } + lastProccessDescription = "Calling procedure"; OpcUaObject callResult = ctx->getClient()->callMethod(callRequest); if (OPCUA_STATUSCODE_FAILED(callResult->statusCode) || (callResult->outputArgumentsSize != 0)) return OPENDAQ_ERR_CALLFAILED; return OPENDAQ_SUCCESS; }); + if (OPENDAQ_FAILED(errCode) && this->daqContext.getLogger().assigned()) + { + auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClientProcudure"); + LOG_W("Failed to call procedure on OpcUA client. Error: \"{}\"", lastProccessDescription); + } + return OPENDAQ_SUCCESS; } ErrCode TmsClientProcedureImpl::getCoreType(CoreType* coreType) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp index d520975..f6693c1 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp @@ -171,7 +171,7 @@ void TmsClientPropertyImpl::configurePropertyFields() const auto value = reader->getValue(nodeId, UA_ATTRIBUTEID_VALUE); this->defaultValue = VariantConverter::ToDaqObject(value, daqContext); LOG_W( - "Failed to read default value of property {}. Detault value is set to the value at connection time. {}", + "Failed to read default value of property {} on OpcUa client. Detault value is set to the value at connection time. {}", this->name, e.what()); } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index 948726a..95f3834 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -22,13 +22,22 @@ using namespace opcua; template ErrCode TmsClientPropertyObjectBaseImpl::setPropertyValueInternal(IString* propertyName, IBaseObject* value, bool protectedWrite) { - return daqTry( + if (propertyName == nullptr) + { + LOG_W("Failed to set value for property with nullptr name on OpcUA client property object"); + return OPENDAQ_SUCCESS; + } + auto propertyNamePtr = StringPtr::Borrow(propertyName); + + StringPtr lastProccessDescription = ""; + ErrCode errCode = daqTry( [&]() { - if (const auto& it = introspectionVariableIdMap.find((StringPtr) propertyName); it != introspectionVariableIdMap.cend()) + if (const auto& it = introspectionVariableIdMap.find(propertyNamePtr); it != introspectionVariableIdMap.cend()) { if (protectedWrite) { + lastProccessDescription = "Checking exisiting property is read-only"; PropertyPtr prop; checkErrorInfo(getProperty(propertyName, &prop)); const bool readOnly = prop.getReadOnly(); @@ -36,24 +45,34 @@ ErrCode TmsClientPropertyObjectBaseImpl::setPropertyValueInternal(IString* return OPENDAQ_SUCCESS; } + lastProccessDescription = "Writting property value"; const auto variant = VariantConverter::ToVariant(value, nullptr, daqContext); client->writeValue(it->second, variant); return OPENDAQ_SUCCESS; } - if (const auto& it = referenceVariableIdMap.find((StringPtr) propertyName); it != referenceVariableIdMap.cend()) + if (const auto& it = referenceVariableIdMap.find(propertyNamePtr); it != referenceVariableIdMap.cend()) { + lastProccessDescription = "Setting property value"; const auto refProp = this->objPtr.getProperty(propertyName).getReferencedProperty(); return setPropertyValue(refProp.getName(), value); } - if (const auto& it = objectTypeIdMap.find((StringPtr) propertyName); it != objectTypeIdMap.cend()) + if (const auto& it = objectTypeIdMap.find((propertyNamePtr)); it != objectTypeIdMap.cend()) { - return this->makeErrorInfo(OPENDAQ_ERR_NOTIMPLEMENTED, "Object type properties cannot be set over OPC UA"); + lastProccessDescription = "Object type properties cannot be set over OpcUA"; + return OPENDAQ_ERR_NOTIMPLEMENTED; } - + lastProccessDescription = "Property not found"; return OPENDAQ_ERR_NOTFOUND; }); + if (OPENDAQ_FAILED(errCode)) + LOG_W("Failed to set value for property \"{}\" on OpcUA client property object: {}", propertyNamePtr, lastProccessDescription); + + if (errCode == OPENDAQ_ERR_NOTFOUND) + return errCode; + + return OPENDAQ_SUCCESS; } template @@ -82,19 +101,27 @@ ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::setProtectedProper template ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::getPropertyValue(IString* propertyName, IBaseObject** value) { - return daqTry([&]() { - if (const auto& introIt = introspectionVariableIdMap.find((StringPtr) propertyName); introIt != introspectionVariableIdMap.cend()) + if (propertyName == nullptr) + { + LOG_W("Failed to get value for property with nullptr name on OpcUA client property object"); + return OPENDAQ_SUCCESS; + } + auto propertyNamePtr = StringPtr::Borrow(propertyName); + + StringPtr lastProccessDescription = ""; + ErrCode errCode = daqTry([&]() { + if (const auto& introIt = introspectionVariableIdMap.find(propertyNamePtr); introIt != introspectionVariableIdMap.cend()) { const auto variant = client->readValue(introIt->second); const auto object = VariantConverter::ToDaqObject(variant, daqContext); Impl::setProtectedPropertyValue(propertyName, object); } - else if (referenceVariableIdMap.count((StringPtr) propertyName)) + else if (referenceVariableIdMap.count(propertyNamePtr)) { const auto refProp = this->objPtr.getProperty(propertyName).getReferencedProperty(); return getPropertyValue(refProp.getName(), value); } - else if (const auto& objIt = objectTypeIdMap.find((StringPtr) propertyName); objIt != objectTypeIdMap.cend()) + else if (const auto& objIt = objectTypeIdMap.find(propertyNamePtr); objIt != objectTypeIdMap.cend()) { *value = TmsClientPropertyObject(daqContext, clientContext, objIt->second).detach(); return OPENDAQ_SUCCESS; @@ -102,6 +129,11 @@ ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::getPropertyValue(I return Impl::getPropertyValue(propertyName, value); }); + if (OPENDAQ_FAILED(errCode)) + { + LOG_W("Failed to set value for property \"{}\" on OpcUA client property object", propertyNamePtr); + } + return OPENDAQ_SUCCESS; } template @@ -238,7 +270,7 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par } catch(const std::exception& e) { - LOG_W("Failed to add {} reference property {}",propName, e.what()); + LOG_W("Failed to add {} reference property on OpcUa client property object: {}", propName, e.what()); continue; } } @@ -254,7 +286,7 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par } catch(const std::exception& e) { - LOG_W("Failed to add {} property {}", propName, e.what()); + LOG_W("Failed to add {} property on OpcUa client property object: {}", propName, e.what()); continue; } } @@ -269,7 +301,7 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par } catch (const std::exception& e) { - LOG_W("Failed to add {} property {}", propName, e.what()); + LOG_W("Failed to add {} property on OpcUa client property object: {}", propName, e.what()); continue; } } @@ -338,7 +370,7 @@ void TmsClientPropertyObjectBaseImpl::addMethodProperties(const OpcUaNodeI } catch(const std::exception& e) { - LOG_W("Failed to parse method properties {}", e.what()); + LOG_W("Failed to parse method properties on OpcUa client property object: {}", e.what()); continue; } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp index 36f4697..7417ed2 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp @@ -47,9 +47,9 @@ ErrCode TmsClientSignalImpl::setPublic(Bool valPublic) ErrCode TmsClientSignalImpl::getDescriptor(IDataDescriptor** descriptor) { - return daqTry([&]() { - *descriptor = nullptr; - + *descriptor = nullptr; + try + { if (descriptorNodeId) { OpcUaVariant opcUaVariant = client->readValue(*descriptorNodeId); @@ -57,11 +57,15 @@ ErrCode TmsClientSignalImpl::getDescriptor(IDataDescriptor** descriptor) { DataDescriptorPtr descriptorPtr = VariantConverter::ToDaqObject(opcUaVariant); *descriptor = descriptorPtr.addRefAndReturn(); + return OPENDAQ_SUCCESS; } } - - return OPENDAQ_SUCCESS; - }); + } + catch (...) + { + LOG_W("Failed to get descriptor on OpcUA client signal \"{}\"", this->globalId); + } + return OPENDAQ_SUCCESS; } ErrCode TmsClientSignalImpl::setDescriptor(IDataDescriptor* /*descriptor*/) @@ -75,8 +79,11 @@ ErrCode TmsClientSignalImpl::getDomainSignal(ISignal** signal) ErrCode errCode = wrapHandlerReturn(this, &TmsClientSignalImpl::onGetDomainSignal, signalPtr); *signal = signalPtr.detach(); - - return errCode; + if (OPENDAQ_FAILED(errCode)) + { + LOG_W("Failed to get domain signal on OpcUA client signal \"{}\"", this->globalId); + } + return OPENDAQ_SUCCESS; } SignalPtr TmsClientSignalImpl::onGetDomainSignal() @@ -107,7 +114,11 @@ ErrCode TmsClientSignalImpl::getRelatedSignals(IList** signals) ListPtr signalsPtr; ErrCode errCode = wrapHandlerReturn(this, &TmsClientSignalImpl::onGetRelatedSignals, signalsPtr); *signals = signalsPtr.detach(); - return errCode; + if (OPENDAQ_FAILED(errCode)) + { + LOG_W("Failed to get related signals on OpcUA client signal \"{}\"", this->globalId); + } + return OPENDAQ_SUCCESS; } @@ -168,24 +179,30 @@ ErrCode TmsClientSignalImpl::getLastValue(IBaseObject** value) auto readValueFunction = [this](IBaseObject** value, const std::string& nodeName) { - const auto valueNodeId = clientContext->getReferenceBrowser()->getChildNodeId(nodeId, nodeName); - OpcUaVariant opcUaVariant = client->readValue(*valueNodeId); - if (!opcUaVariant.isNull()) + try { - BaseObjectPtr valuePtr = VariantConverter::ToDaqObject(opcUaVariant); - *value = valuePtr.addRefAndReturn(); - return OPENDAQ_SUCCESS; + const auto valueNodeId = clientContext->getReferenceBrowser()->getChildNodeId(nodeId, nodeName); + OpcUaVariant opcUaVariant = client->readValue(*valueNodeId); + if (!opcUaVariant.isNull()) + { + BaseObjectPtr valuePtr = VariantConverter::ToDaqObject(opcUaVariant); + *value = valuePtr.addRefAndReturn(); + } } - return OPENDAQ_IGNORED; + catch (...) + { + LOG_W("Failed to get last value on OpcUA client signal \"{}\"", this->globalId); + } + return OPENDAQ_SUCCESS; }; - if (descriptorNodeId && readValueFunction(value, "Value") == OPENDAQ_SUCCESS) + if (descriptorNodeId && *value != nullptr) return OPENDAQ_SUCCESS; if (hasReference("AnalogValue")) return readValueFunction(value, "AnalogValue"); - return OPENDAQ_IGNORED; + return OPENDAQ_SUCCESS; } END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp index 0317c03..f170951 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp @@ -174,13 +174,24 @@ class TmsPropertyObjectAdvancedTest : public TmsObjectIntegrationTest RegisteredPropertyObject registerPropertyObject(const PropertyObjectPtr& prop) { - const auto logger = Logger(); const auto context = Context(nullptr, logger, manager, nullptr); const auto serverProp = std::make_shared(prop, server, context, std::make_shared(context)); const auto nodeId = serverProp->registerOpcUaNode(); const auto clientProp = TmsClientPropertyObject(Context(nullptr, logger, manager,nullptr), clientContext, nodeId); return {serverProp, clientProp}; + + } + + StringPtr getLastMessage() + { + logger.flush(); + auto sink = getPrivateSink(); + auto newMessage = sink.waitForMessage(2000); + if (newMessage == 0) + return StringPtr(""); + auto logMessage = sink.getLastMessage(); + return logMessage; } RatioPtr testRatio; @@ -489,7 +500,9 @@ TEST_F(TmsPropertyObjectAdvancedTest, ObjectGetSet) auto testObj = PropertyObject(); testObj.addProperty(IntProperty("test", 0)); - ASSERT_ANY_THROW(clientObj.setPropertyValue("Object", testObj)); + ASSERT_NO_THROW(clientObj.setPropertyValue("Object", testObj)); + ASSERT_EQ(getLastMessage(), "Failed to set value for property \"Object\" on OpcUA client property object: Object type properties cannot be set over OpcUA"); + ASSERT_NO_THROW(clientChildObj.setPropertyValue("ObjNumber", 1)); ASSERT_EQ(clientChildObj.getPropertyValue("ObjNumber"), 1); @@ -606,7 +619,8 @@ TEST_F(TmsPropertyObjectAdvancedTest, ValidationCoercion) ASSERT_EQ(obj.getPropertyValue("ValidatedInt"), clientObj.getPropertyValue("ValidatedInt")); ASSERT_EQ(obj.getPropertyValue("CoercedInt"), clientObj.getPropertyValue("CoercedInt")); - ASSERT_ANY_THROW(clientObj.setPropertyValue("ValidatedInt", 11)); + ASSERT_NO_THROW(clientObj.setPropertyValue("ValidatedInt", 11)); + ASSERT_EQ(getLastMessage(), "Failed to set value for property \"ValidatedInt\" on OpcUA client property object: Writting property value"); ASSERT_EQ(obj.getPropertyValue("ValidatedInt"), 5); ASSERT_EQ(clientObj.getPropertyValue("ValidatedInt"), 5); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp index 1b39f54..88471dc 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp @@ -281,7 +281,6 @@ class TMSAmplifierTest : public TmsObjectIntegrationTest RegisteredPropertyObject registerPropertyObject(const PropertyObjectPtr& prop) { - const auto logger = Logger(); const auto context = Context(nullptr, logger, TypeManager(), nullptr); const auto serverProp = std::make_shared(prop, server, context, std::make_shared(context)); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_property.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_property.cpp index 8c53564..3db5326 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_property.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_property.cpp @@ -26,9 +26,20 @@ class TmsFunctionTest: public TmsObjectIntegrationTest { const auto serverProp = std::make_shared(obj, server, ctx, serverContext); const auto nodeId = serverProp->registerOpcUaNode(); - const auto clientProp = TmsClientPropertyObject(NullContext(), clientContext, nodeId); + const auto clientProp = TmsClientPropertyObject(NullContext(logger), clientContext, nodeId); return {serverProp, clientProp}; } + + StringPtr getLastMessage() + { + logger.flush(); + auto sink = getPrivateSink(); + auto newMessage = sink.waitForMessage(2000); + if (newMessage == 0) + return StringPtr(""); + auto logMessage = sink.getLastMessage(); + return logMessage; + } }; TEST_F(TmsFunctionTest, ProcedureNoArgs) @@ -190,7 +201,8 @@ TEST_F(TmsFunctionTest, InvalidArgTypes) auto [serverObj, clientObj] = registerPropertyObject(obj); ProcedurePtr clientProc = clientObj.getPropertyValue("proc"); - ASSERT_THROW(clientProc("foo"), CallFailedException); + ASSERT_NO_THROW(clientProc("foo")); + ASSERT_EQ(getLastMessage(), "Failed to call procedure on OpcUA client. Error: \"Calling procedure\""); } // NOTE: Should this throw an error? @@ -218,8 +230,11 @@ TEST_F(TmsFunctionTest, InvalidArgCount) auto [serverObj, clientObj] = registerPropertyObject(obj); ProcedurePtr clientProc = clientObj.getPropertyValue("proc"); - ASSERT_THROW(clientProc(), CallFailedException); - ASSERT_THROW(clientProc(1, 2), CallFailedException); + ASSERT_NO_THROW(clientProc()); + ASSERT_EQ(getLastMessage(), "Failed to call procedure on OpcUA client. Error: \"Calling procedure\""); + + ASSERT_NO_THROW(clientProc(1, 2)); + ASSERT_EQ(getLastMessage(), "Failed to call procedure on OpcUA client. Error: \"Calling procedure\""); } TEST_F(TmsFunctionTest, ProcedureArgumentInfo) @@ -297,5 +312,6 @@ TEST_F(TmsFunctionTest, ServerThrow) auto [serverObj, clientObj] = registerPropertyObject(obj); FunctionPtr clientFunc = clientObj.getPropertyValue("func"); - ASSERT_ANY_THROW(clientFunc()); + ASSERT_NO_THROW(clientFunc()); + ASSERT_EQ(getLastMessage(), "Failed to call function on OpcUA client. Error in \"Calling function\""); } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp index 1f3e0fc..b187a87 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp @@ -11,8 +11,8 @@ #include "opcuatms_client/objects/tms_client_property_object_factory.h" #include -#include "coreobjects/callable_info_factory.h" -#include "opendaq/context_factory.h" +#include +#include using namespace daq; using namespace opcua::tms; @@ -64,11 +64,22 @@ class TmsPropertyObjectTest : public TmsObjectIntegrationTest return object; } + StringPtr getLastMessage() + { + logger.flush(); + auto sink = getPrivateSink(); + auto newMessage = sink.waitForMessage(2000); + if (newMessage == 0) + return StringPtr(""); + auto logMessage = sink.getLastMessage(); + return logMessage; + } + RegisteredPropertyObject registerPropertyObject(const PropertyObjectPtr& prop) { auto serverProp = std::make_shared(prop, server, ctx, serverContext); auto nodeId = serverProp->registerOpcUaNode(); - auto clientProp = TmsClientPropertyObject(NullContext(), clientContext, nodeId); + auto clientProp = TmsClientPropertyObject(NullContext(logger), clientContext, nodeId); return {serverProp, clientProp}; } }; @@ -109,8 +120,9 @@ TEST_F(TmsPropertyObjectTest, PropertyValue) clientProp.setPropertyValue("Height", 100); ASSERT_EQ(clientProp.getPropertyValue("Height"), 100); ASSERT_EQ(prop.getPropertyValue("Height"), 100); - - ASSERT_THROW(clientProp.setPropertyValue("Missing", 100), DaqException); + + ASSERT_ANY_THROW(clientProp.setPropertyValue("Missing", 100)); + ASSERT_EQ(getLastMessage(), "Failed to set value for property \"Missing\" on OpcUA client property object: Property not found"); } TEST_F(TmsPropertyObjectTest, PropertyValueRole) @@ -123,7 +135,8 @@ TEST_F(TmsPropertyObjectTest, PropertyValueRole) ASSERT_EQ(clientProp.getPropertyValue("Role"), 1); ASSERT_EQ(prop.getPropertyValue("Role"), 1); - ASSERT_THROW(clientProp.setPropertyValue("Role", 2), DaqException); + ASSERT_NO_THROW(clientProp.setPropertyValue("Role", 2)); + ASSERT_EQ(getLastMessage(), "Failed to set value for property \"Role\" on OpcUA client property object: Writting property value"); } TEST_F(TmsPropertyObjectTest, getPropertySelectionValue) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp index a670349..7a1581f 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp @@ -5,15 +5,35 @@ using namespace daq; using namespace daq::opcua; using namespace daq::opcua::tms; +static LoggerPtr CreateLoggerWithDebugSink(const LoggerSinkPtr& sink) +{ + sink.setLevel(LogLevel::Warn); + auto sinks = DefaultSinks(nullptr); + sinks.pushBack(sink); + return LoggerWithSinks(sinks); +} + void TmsObjectIntegrationTest::SetUp() { TmsObjectTest::SetUp(); + debugSink = LastMessageLoggerSink(); + logger = CreateLoggerWithDebugSink(debugSink); - ctx = daq::NullContext(); + ctx = daq::NullContext(logger); clientContext = std::make_shared(client, ctx); serverContext = std::make_shared(ctx); } +LastMessageLoggerSinkPrivatePtr TmsObjectIntegrationTest::getPrivateSink() +{ + if(!debugSink.assigned()) + throw ArgumentNullException("Sink must not be null"); + auto sinkPtr = debugSink.asPtrOrNull(); + if (sinkPtr == nullptr) + throw InvalidTypeException("Wrong sink. GetLastMessage supports only by LastMessageLoggerSink"); + return sinkPtr; +} + void TmsObjectIntegrationTest::TearDown() { clientContext.reset(); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h index ad24381..3765484 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h @@ -18,16 +18,22 @@ #include "tms_object_test.h" #include #include "opcuatms_server/tms_server_context.h" +#include +#include class TmsObjectIntegrationTest : public TmsObjectTest { public: void SetUp() override; void TearDown() override; + daq::LastMessageLoggerSinkPrivatePtr getPrivateSink(); protected: - daq::ContextPtr context; daq::opcua::tms::TmsClientContextPtr clientContext; daq::opcua::tms::TmsServerContextPtr serverContext; + + daq::LoggerPtr logger; daq::ContextPtr ctx; +private: + daq::LoggerSinkPtr debugSink; }; From cefd18e7e2848997810c1434a28c28d7c845d6a1 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Thu, 25 Jan 2024 14:44:39 +0100 Subject: [PATCH 068/217] Support core events in Native Config Client --- .../include/opcuatms_client/objects/tms_client_tags_impl.h | 1 + .../opcuatms_client/src/objects/tms_client_tags_impl.cpp | 5 +++++ .../include/opcuatms_server/objects/tms_server_component.h | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h index e852803..e3473f4 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h @@ -32,6 +32,7 @@ class TmsClientTagsImpl final : public TmsClientObjectImpl, public TagsImpl ErrCode INTERFACE_FUNC getList(IList** value) override; ErrCode INTERFACE_FUNC add(IString* name) override; + ErrCode INTERFACE_FUNC set(IList* tags) override; ErrCode INTERFACE_FUNC remove(IString* name) override; ErrCode INTERFACE_FUNC contains(IString* name, Bool* value) override; ErrCode INTERFACE_FUNC query(IString* query, Bool* value) override; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_tags_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_tags_impl.cpp index 69e29d3..5532e2e 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_tags_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_tags_impl.cpp @@ -23,6 +23,11 @@ ErrCode TmsClientTagsImpl::add(IString* name) return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; } +ErrCode TmsClientTagsImpl::set(IList* tags) +{ + return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; +} + ErrCode TmsClientTagsImpl::remove(IString* name) { return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h index 3ac7f2a..67420c1 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h @@ -233,7 +233,7 @@ void TmsServerComponent::onCoreEvent(const CoreEventArgsPtr& args) { Super::onCoreEvent(args); - if (!selfChange && args.getEventId() == core_event_ids::AttributeChanged) + if (!selfChange && args.getEventId() == static_cast(CoreEventId::AttributeChanged)) { const StringPtr attrName = args.getParameters().get("AttributeName"); From 932b7636df53722270befb096db43d44035bf2c0 Mon Sep 17 00:00:00 2001 From: Nikolai Shipilov Date: Tue, 6 Feb 2024 10:03:57 +0100 Subject: [PATCH 069/217] Enable multiple device types per single mDNS service --- .../src/opcua_client_module_impl.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 3036f13..e1d5197 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -23,11 +23,15 @@ OpcUaClientModule::OpcUaClientModule(ContextPtr context) : Module("openDAQ OpcUa client module", daq::VersionInfo(OPCUA_CLIENT_MODULE_MAJOR_VERSION, OPCUA_CLIENT_MODULE_MINOR_VERSION, OPCUA_CLIENT_MODULE_PATCH_VERSION), std::move(context)) - , discoveryClient([](const MdnsDiscoveredDevice& discoveredDevice) + , discoveryClient( { - return DaqOpcUaDevicePrefix + discoveredDevice.ipv4Address + "/"; + [](const MdnsDiscoveredDevice& discoveredDevice) + { + return DaqOpcUaDevicePrefix + discoveredDevice.ipv4Address + "/"; + } }, - {"OPENDAQ"}) + {"OPENDAQ"} + ) { discoveryClient.initMdnsClient("_opcua-tcp._tcp.local."); } From 8bf14e563006645929241ef94f8cd27b3b985009 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Thu, 8 Feb 2024 12:32:05 +0100 Subject: [PATCH 070/217] Update open62541 to opendaq-4 version --- external/open62541/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/open62541/CMakeLists.txt b/external/open62541/CMakeLists.txt index d2f3225..133c3fd 100644 --- a/external/open62541/CMakeLists.txt +++ b/external/open62541/CMakeLists.txt @@ -19,7 +19,7 @@ opendaq_dependency( NAME open62541 REQUIRED_VERSION 1.3.6 GIT_REPOSITORY https://github.com/openDAQ/open62541.git - GIT_REF v1.3.6-opendaq-3 + GIT_REF v1.3.6-opendaq-4 GIT_SUBMODULES "" EXPECT_TARGET open62541 ) From 5980d85463c74a3bc94d576e638c861b1a4049a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Thu, 25 Jan 2024 15:59:49 +0100 Subject: [PATCH 071/217] Add support for adding and removing function blocks over OPC UA --- .../converters/dict_conversion_utils.h | 31 +++ .../opcuatms/opcuatms/src/CMakeLists.txt | 4 +- .../src/converters/dict_conversion_utils.cpp | 37 ++++ .../opcuatms/opcuatms/tests/CMakeLists.txt | 1 + .../tests/test_dict_conversion_utils.cpp | 55 +++++ .../objects/tms_client_device_impl.h | 1 + .../src/objects/tms_client_device_impl.cpp | 78 ++++++- .../objects/tms_server_device.h | 10 + .../src/objects/tms_server_device.cpp | 199 ++++++++++++++++++ .../test_tms_function_block.cpp | 12 +- .../test_tms_integration.cpp | 82 ++++++++ 11 files changed, 501 insertions(+), 9 deletions(-) create mode 100644 shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/dict_conversion_utils.h create mode 100644 shared/libraries/opcuatms/opcuatms/src/converters/dict_conversion_utils.cpp create mode 100644 shared/libraries/opcuatms/opcuatms/tests/test_dict_conversion_utils.cpp diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/dict_conversion_utils.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/dict_conversion_utils.h new file mode 100644 index 0000000..9b9387b --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/dict_conversion_utils.h @@ -0,0 +1,31 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class DictConversionUtils +{ +public: + static OpcUaVariant ToDictVariant(const PropertyObjectPtr& obj); + static void ToPropertyObject(const OpcUaVariant& variant, PropertyObjectPtr& objOut); +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms/src/CMakeLists.txt index 45d56d5..a39904f 100644 --- a/shared/libraries/opcuatms/opcuatms/src/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms/src/CMakeLists.txt @@ -23,6 +23,7 @@ set(SRC_Converters_Headers ${CONVERTERS_SRC_DIR}/struct_converter.h ${CONVERTERS_SRC_DIR}/variant_converter.h ${CONVERTERS_SRC_DIR}/list_conversion_utils.h ${CONVERTERS_SRC_DIR}/selection_converter.h + ${CONVERTERS_SRC_DIR}/dict_conversion_utils.h ) set(SRC_Converters ${CONVERTERS_SRC_DIR}/range_converter.cpp @@ -41,6 +42,7 @@ set(SRC_Converters ${CONVERTERS_SRC_DIR}/range_converter.cpp ${CONVERTERS_SRC_DIR}/selection_converter.cpp ${CONVERTERS_SRC_DIR}/argument_converter.cpp ${CONVERTERS_SRC_DIR}/generic_struct_converter.cpp + ${CONVERTERS_SRC_DIR}/dict_conversion_utils.cpp ) set(SRC_PublicHeaders ${SRC_PublicHeaders} ${SRC_Converters_Headers}) @@ -71,4 +73,4 @@ target_link_libraries(${MODULE_NAME} PUBLIC daq::opendaq ) set_target_properties(${MODULE_NAME} PROPERTIES PUBLIC_HEADER "${SRC_PublicHeaders}") -opendaq_set_output_lib_name(${MODULE_NAME} ${PROJECT_VERSION_MAJOR}) \ No newline at end of file +opendaq_set_output_lib_name(${MODULE_NAME} ${PROJECT_VERSION_MAJOR}) diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/dict_conversion_utils.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/dict_conversion_utils.cpp new file mode 100644 index 0000000..fd8a603 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/src/converters/dict_conversion_utils.cpp @@ -0,0 +1,37 @@ +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +OpcUaVariant DictConversionUtils::ToDictVariant(const PropertyObjectPtr& obj) +{ + if (!obj.assigned()) + { + auto variant = OpcUaVariant(); + UA_Variant_setArray(variant.get(), nullptr, 0, &UA_TYPES_DAQBT[UA_TYPES_DAQBT_DAQKEYVALUEPAIR]); + return variant; + } + + auto dict = Dict(); + const auto properties = obj.getAllProperties(); + + for (const auto& prop : properties) + { + const auto key = prop.getName(); + const auto val = obj.getPropertyValue(key); + dict.set(key, val); + } + + return VariantConverter::ToVariant(dict); +} + +void DictConversionUtils::ToPropertyObject(const OpcUaVariant& variant, PropertyObjectPtr& objOut) +{ + const auto dict = VariantConverter::ToDaqObject(variant); + + for (const auto& entry : dict) + objOut.setPropertyValue(entry.first, entry.second); +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/tests/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms/tests/CMakeLists.txt index 4c941d8..6648c5c 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms/tests/CMakeLists.txt @@ -7,6 +7,7 @@ set(TEST_SOURCES test_core_types_utils.cpp test_variant_list_converter.cpp test_extension_object.cpp test_generic_struct_converter.cpp + test_dict_conversion_utils.cpp ) add_executable(${TEST_APP} testapp.cpp diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_dict_conversion_utils.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_dict_conversion_utils.cpp new file mode 100644 index 0000000..1fad438 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/tests/test_dict_conversion_utils.cpp @@ -0,0 +1,55 @@ +#include "gtest/gtest.h" +#include +#include +#include +#include + +using DictConversionUtilsTest = testing::Test; + +using namespace daq; +using namespace daq::opcua; +using namespace daq::opcua::tms; + + +static PropertyObjectPtr CreateTestPropertyObject() +{ + auto obj = PropertyObject(); + obj.addProperty(StringProperty("name", "")); + obj.addProperty(IntProperty("age", 0)); + obj.addProperty(FloatProperty("weight", 0.0)); + obj.addProperty(BoolProperty("isTheBest", false)); + return obj; +} + + +TEST_F(DictConversionUtilsTest, SimpleObject) +{ + auto obj = CreateTestPropertyObject(); + obj.setPropertyValue("name", "Jovanka"); + obj.setPropertyValue("age", 99); + obj.setPropertyValue("weight", 60.5); + obj.setPropertyValue("isTheBest", true); + + auto variant = DictConversionUtils::ToDictVariant(obj); + + ASSERT_TRUE(variant->type == &UA_TYPES_DAQBT[UA_TYPES_DAQBT_DAQKEYVALUEPAIR]); + ASSERT_EQ(variant->arrayLength, obj.getAllProperties().getCount()); + + auto objOut = CreateTestPropertyObject(); + DictConversionUtils::ToPropertyObject(variant, objOut); + ASSERT_TRUE(TestComparators::PropertyObjectEquals(obj, objOut)); +} + +TEST_F(DictConversionUtilsTest, EmptyObject) +{ + auto obj = CreateTestPropertyObject(); + + auto variant = DictConversionUtils::ToDictVariant(obj); + + ASSERT_TRUE(variant->type == &UA_TYPES_DAQBT[UA_TYPES_DAQBT_DAQKEYVALUEPAIR]); + ASSERT_EQ(variant->arrayLength, obj.getAllProperties().getCount()); + + auto objOut = CreateTestPropertyObject(); + DictConversionUtils::ToPropertyObject(variant, objOut); + ASSERT_TRUE(TestComparators::PropertyObjectEquals(obj, objOut)); +} diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h index 9a804ab..43ed00b 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h @@ -46,6 +46,7 @@ class TmsClientDeviceImpl : public TmsClientComponentBaseImpl void findAndCreateSignals(); void findAndCreateInputsOutputs(); void findAndCreateCustomComponents(); + DictPtr onGetAvailableFunctionBlockTypes() override; FunctionBlockPtr onAddFunctionBlock(const StringPtr& typeId, const PropertyObjectPtr& config) override; void onRemoveFunctionBlock(const FunctionBlockPtr& functionBlock) override; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 4fe58e5..d0298b7 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -19,6 +19,8 @@ #include #include "opcuatms/core_types_utils.h" #include "opcuatms/exceptions.h" +#include "opcuatms/converters/list_conversion_utils.h" +#include "opcuatms/converters/dict_conversion_utils.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS using namespace daq::opcua; @@ -440,14 +442,82 @@ void TmsClientDeviceImpl::findAndCreateCustomComponents() this->components.push_back(val); } -FunctionBlockPtr TmsClientDeviceImpl::onAddFunctionBlock(const StringPtr& /*typeId*/, const PropertyObjectPtr& /*config*/) +DictPtr TmsClientDeviceImpl::onGetAvailableFunctionBlockTypes() { - throw OpcUaClientCallNotAvailableException(); + const auto fbFolderNodeId = getNodeId("FB"); + const auto methodNodeId = clientContext->getReferenceBrowser()->getChildNodeId(fbFolderNodeId, "GetAvailableFunctionBlockTypes"); + + auto request = OpcUaCallMethodRequest(); + request->objectId = fbFolderNodeId.copyAndGetDetachedValue(); + request->methodId = methodNodeId.copyAndGetDetachedValue(); + + const auto response = this->client->callMethod(request); + + if (response->statusCode != UA_STATUSCODE_GOOD) + throw OpcUaException(response->statusCode, "Failed to get available function block types"); + + assert(response->outputArgumentsSize == 1); + const auto outvariant = OpcUaVariant(response->outputArguments[0]); + const auto typeList = ListConversionUtils::ExtensionObjectVariantToList(outvariant); + + auto dict = Dict(); + for (auto& type : typeList) + dict.set(type.getId(), type); + + return dict; } -void TmsClientDeviceImpl::onRemoveFunctionBlock(const FunctionBlockPtr& /*functionBlock*/) +FunctionBlockPtr TmsClientDeviceImpl::onAddFunctionBlock(const StringPtr& typeId, const PropertyObjectPtr& config) { - throw OpcUaClientCallNotAvailableException(); + const auto fbFolderNodeId = getNodeId("FB"); + const auto methodNodeId = clientContext->getReferenceBrowser()->getChildNodeId(fbFolderNodeId, "AddFunctionBlock"); + + const auto typeIdVariant = OpcUaVariant(typeId.toStdString().c_str()); + const auto configVariant = DictConversionUtils::ToDictVariant(config); + + auto request = OpcUaCallMethodRequest(); + request->objectId = fbFolderNodeId.copyAndGetDetachedValue(); + request->methodId = methodNodeId.copyAndGetDetachedValue(); + request->inputArgumentsSize = 2; + request->inputArguments = (UA_Variant*) UA_Array_new(request->inputArgumentsSize, &UA_TYPES[UA_TYPES_VARIANT]); + + request->inputArguments[0] = typeIdVariant.copyAndGetDetachedValue(); + request->inputArguments[1] = configVariant.copyAndGetDetachedValue(); + + auto response = this->client->callMethod(request); + + if (response->statusCode != UA_STATUSCODE_GOOD) + throw OpcUaException(response->statusCode, "Failed to add function block"); + + assert(response->outputArgumentsSize == 1); + const auto nodeId = OpcUaVariant(response->outputArguments[0]).toNodeId(); + const auto browseName = client->readBrowseName(nodeId); + + auto clientFunctionBlock = TmsClientFunctionBlock(context, this->functionBlocks, browseName, clientContext, nodeId); + addNestedFunctionBlock(clientFunctionBlock); + return clientFunctionBlock; +} + +void TmsClientDeviceImpl::onRemoveFunctionBlock(const FunctionBlockPtr& functionBlock) +{ + const auto fbFolderNodeId = getNodeId("FB"); + const auto methodNodeId = clientContext->getReferenceBrowser()->getChildNodeId(fbFolderNodeId, "RemoveFunctionBlock"); + + const auto fbIdVariant = OpcUaVariant(functionBlock.getLocalId().toStdString().c_str()); + + auto request = OpcUaCallMethodRequest(); + request->objectId = fbFolderNodeId.copyAndGetDetachedValue(); + request->methodId = methodNodeId.copyAndGetDetachedValue(); + request->inputArgumentsSize = 1; + request->inputArguments = (UA_Variant*) UA_Array_new(request->inputArgumentsSize, &UA_TYPES[UA_TYPES_VARIANT]); + request->inputArguments[0] = fbIdVariant.copyAndGetDetachedValue(); + + auto response = this->client->callMethod(request); + + if (response->statusCode != UA_STATUSCODE_GOOD) + throw OpcUaException(response->statusCode, "Failed to remove function block"); + + removeNestedFunctionBlock(functionBlock); } void TmsClientDeviceImpl::setUpStreamings() diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h index ea56f6d..dcf1591 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h @@ -46,6 +46,16 @@ class TmsServerDevice : public TmsServerComponent opcua::OpcUaNodeId getTmsTypeId() override; void populateDeviceInfo(); void populateStreamingOptions(); + void addFbMethodNodes(); + void createAddFunctionBlockNode(const OpcUaNodeId& parentId); + void createRemoveFunctionBlockNode(const OpcUaNodeId& parentId); + void createGetAvailableFunctionBlockTypesNode(const OpcUaNodeId& parentId); + void onGetAvailableFunctionBlockTypes(const NodeEventManager::MethodArgs& args); + void onAddFunctionBlock(const NodeEventManager::MethodArgs& args); + void onRemoveFunctionBlock(const NodeEventManager::MethodArgs& args); + TmsServerFunctionBlockPtr addFunctionBlock(const StringPtr& fbTypeId, const OpcUaVariant& configVariant); + TmsServerFunctionBlockPtr addFunctionBlock(const StringPtr& fbTypeId, const PropertyObjectPtr& config); + void removeFunctionBlock(const StringPtr& localId); // TODO we need following list to keep this because of handlers. Move handlers (TmsServerObject) to context and use UA_NodeTypeLifecycle // for deleting it diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index a98ec04..2322b52 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -11,6 +11,11 @@ #include #include #include +#include +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -230,6 +235,199 @@ void TmsServerDevice::populateStreamingOptions() } } +void TmsServerDevice::addFbMethodNodes() +{ + auto fbNodeId = getChildNodeId("FB"); + + createGetAvailableFunctionBlockTypesNode(fbNodeId); + createAddFunctionBlockNode(fbNodeId); + createRemoveFunctionBlockNode(fbNodeId); +} + +void TmsServerDevice::createAddFunctionBlockNode(const OpcUaNodeId& parentId) +{ + OpcUaNodeId nodeIdOut; + AddMethodNodeParams params(nodeIdOut, parentId); + params.referenceTypeId = OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT)); + params.setBrowseName("AddFunctionBlock"); + params.outputArgumentsSize = 1; + params.outputArguments = (UA_Argument*) UA_Array_new(params.outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]); + params.inputArgumentsSize = 2; + params.inputArguments = (UA_Argument*) UA_Array_new(params.inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]); + + params.outputArguments[0].name = UA_STRING_ALLOC("functionBlockNodeId"); + params.outputArguments[0].dataType = UA_TYPES[UA_TYPES_NODEID].typeId; + params.outputArguments[0].valueRank = UA_VALUERANK_SCALAR; + + params.inputArguments[0].name = UA_STRING_ALLOC("typeId"); + params.inputArguments[0].dataType = UA_TYPES[UA_TYPES_STRING].typeId; + params.inputArguments[0].valueRank = UA_VALUERANK_SCALAR; + + params.inputArguments[1].name = UA_STRING_ALLOC("config"); + params.inputArguments[1].dataType = UA_TYPES_DAQBT[UA_TYPES_DAQBT_DAQKEYVALUEPAIR].typeId; + params.inputArguments[1].valueRank = UA_VALUERANK_ONE_DIMENSION; + + auto methodNodeId = server->addMethodNode(params); + + auto callback = [this](NodeEventManager::MethodArgs args) + { + try + { + this->onAddFunctionBlock(args); + return OPENDAQ_SUCCESS; + } + catch (const OpcUaException& e) + { + return e.getStatusCode(); + } + }; + + addEvent(methodNodeId)->onMethodCall(callback); +} + +void TmsServerDevice::createRemoveFunctionBlockNode(const OpcUaNodeId& parentId) +{ + OpcUaNodeId nodeIdOut; + AddMethodNodeParams params(nodeIdOut, parentId); + params.referenceTypeId = OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT)); + params.setBrowseName("RemoveFunctionBlock"); + params.inputArgumentsSize = 1; + params.inputArguments = (UA_Argument*) UA_Array_new(params.inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]); + + params.inputArguments[0].name = UA_STRING_ALLOC("browseName"); + params.inputArguments[0].dataType = UA_TYPES[UA_TYPES_STRING].typeId; + params.inputArguments[0].valueRank = UA_VALUERANK_SCALAR; + + auto methodNodeId = server->addMethodNode(params); + + auto callback = [this](NodeEventManager::MethodArgs args) + { + try + { + this->onRemoveFunctionBlock(args); + return OPENDAQ_SUCCESS; + } + catch (const OpcUaException& e) + { + return e.getStatusCode(); + } + }; + + addEvent(methodNodeId)->onMethodCall(callback); +} + +void TmsServerDevice::createGetAvailableFunctionBlockTypesNode(const OpcUaNodeId& parentId) +{ + OpcUaNodeId nodeIdOut; + AddMethodNodeParams params(nodeIdOut, parentId); + params.referenceTypeId = OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT)); + params.setBrowseName("GetAvailableFunctionBlockTypes"); + params.inputArgumentsSize = 0; + params.outputArgumentsSize = 1; + params.outputArguments = (UA_Argument*) UA_Array_new(params.outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]); + + params.outputArguments[0].name = UA_STRING_ALLOC("availableTypes"); + params.outputArguments[0].dataType = UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_FUNCTIONBLOCKINFOSTRUCTURE].typeId; + params.outputArguments[0].valueRank = UA_VALUERANK_ONE_DIMENSION; + + auto methodNodeId = server->addMethodNode(params); + + auto callback = [this](NodeEventManager::MethodArgs args) + { + try + { + onGetAvailableFunctionBlockTypes(args); + return OPENDAQ_SUCCESS; + } + catch (const OpcUaException& e) + { + return e.getStatusCode(); + } + }; + + addEvent(methodNodeId)->onMethodCall(callback); +} + +void TmsServerDevice::onGetAvailableFunctionBlockTypes(const NodeEventManager::MethodArgs& args) +{ + assert(args.outputSize == 1); + + const auto fbTypes = object.getAvailableFunctionBlockTypes().getValueList(); + const auto variant = ListConversionUtils::ToArrayVariant(fbTypes); + args.output[0] = variant.copyAndGetDetachedValue(); +} + +void TmsServerDevice::onAddFunctionBlock(const NodeEventManager::MethodArgs& args) +{ + assert(args.inputSize == 2); + assert(args.outputSize == 1); + + const auto fbTypeId = OpcUaVariant(args.input[0]).toString(); + const auto configVariant = OpcUaVariant(args.input[1]); + + auto tmsFunctionBlock = addFunctionBlock(fbTypeId, configVariant); + + auto outVariant = OpcUaVariant(tmsFunctionBlock->getNodeId()); + args.output[0] = outVariant.copyAndGetDetachedValue(); +} + +void TmsServerDevice::onRemoveFunctionBlock(const NodeEventManager::MethodArgs& args) +{ + assert(args.inputSize == 1); + + const auto fbLocalId = OpcUaVariant(args.input[0]).toString(); + removeFunctionBlock(fbLocalId); +} + + +TmsServerFunctionBlockPtr TmsServerDevice::addFunctionBlock(const StringPtr& fbTypeId, const OpcUaVariant& configVariant) +{ + const auto fbTypes = object.getAvailableFunctionBlockTypes(); + + if (!fbTypes.hasKey(fbTypeId)) + throw OpcUaException(UA_STATUSCODE_BADNOTFOUND, "Function block type not found"); + + auto config = fbTypes.get(fbTypeId).createDefaultConfig(); + DictConversionUtils::ToPropertyObject(configVariant, config); + return addFunctionBlock(fbTypeId, config); +} + +TmsServerFunctionBlockPtr TmsServerDevice::addFunctionBlock(const StringPtr& fbTypeId, const PropertyObjectPtr& config) +{ + const auto fbFolderNodeId = getChildNodeId("FB"); + + auto functionBlock = object.addFunctionBlock(fbTypeId, config); + auto tmsFunctionBlock = registerTmsObjectOrAddReference>(fbFolderNodeId, functionBlock, functionBlocks.size()); + functionBlocks.push_back(tmsFunctionBlock); + return tmsFunctionBlock; +} + +void TmsServerDevice::removeFunctionBlock(const StringPtr& localId) +{ + for (auto it = functionBlocks.begin(); it != functionBlocks.end(); ++it) + { + auto fb = *it; + + if (fb->getBrowseName() == localId) + { + server->deleteNode(fb->getNodeId()); + functionBlocks.erase(it); + break; + } + } + + const auto objFunctionBlocks = this->object.getFunctionBlocks(search::Any()); + + for (auto& fb : objFunctionBlocks) + { + if (fb.getLocalId() == localId) + { + this->object.removeFunctionBlock(fb); + break; + } + } +} + void TmsServerDevice::addChildNodes() { populateDeviceInfo(); @@ -289,6 +487,7 @@ void TmsServerDevice::addChildNodes() } } + addFbMethodNodes(); Super::addChildNodes(); } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp index 74309b6..29802e6 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp @@ -184,12 +184,16 @@ TEST_F(TmsFunctionBlockTest, Property) auto clientFunctionBlock = TmsClientFunctionBlock(NullContext(), nullptr, "mockfb", clientContext, nodeId); auto visibleProperties = clientFunctionBlock.getVisibleProperties(); - ASSERT_EQ(visibleProperties.getCount(), 1u); - ASSERT_EQ(visibleProperties[0].getName(), "SampleRate"); + ASSERT_EQ(visibleProperties.getCount(), 3u); + ASSERT_EQ(visibleProperties[0].getName(), "TestConfigInt"); + ASSERT_EQ(visibleProperties[1].getName(), "TestConfigString"); + ASSERT_EQ(visibleProperties[2].getName(), "SampleRate"); auto properties = clientFunctionBlock.getAllProperties(); - ASSERT_EQ(properties.getCount(), 1u); - ASSERT_EQ(properties[0].getName(), "SampleRate"); + ASSERT_EQ(properties.getCount(), 3u); + ASSERT_EQ(properties[0].getName(), "TestConfigInt"); + ASSERT_EQ(properties[1].getName(), "TestConfigString"); + ASSERT_EQ(properties[2].getName(), "SampleRate"); ASSERT_TRUE(clientFunctionBlock.hasProperty("SampleRate")); ASSERT_EQ(clientFunctionBlock.getPropertyValue("SampleRate"), 100.0); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index 7b6020d..3ec1d8a 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -7,6 +7,7 @@ #include #include #include +#include using namespace daq; using namespace daq::opcua; @@ -236,3 +237,84 @@ TEST_F(TmsIntegrationTest, GetDomainSignal) ASSERT_NO_THROW(domainSignal = byteStepSignal.getDomainSignal()); ASSERT_TRUE(domainSignal.assigned()); } + +TEST_F(TmsIntegrationTest, GetAvailableFunctionBlockTypes) +{ + InstancePtr device = createDevice(); + TmsServer tmsServer(device); + tmsServer.start(); + + auto serverFbTypes = device.getAvailableFunctionBlockTypes(); + + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + auto clientDevice = tmsClient.connect(); + + const auto clientFbTypes = clientDevice.getAvailableFunctionBlockTypes(); + + ASSERT_TRUE(TestComparators::FunctionBlockTypeDictEquals(serverFbTypes, clientFbTypes)); +} + +TEST_F(TmsIntegrationTest, AddFunctionBlock) +{ + InstancePtr device = createDevice(); + TmsServer tmsServer(device); + tmsServer.start(); + + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + auto clientDevice = tmsClient.connect(); + + auto fb1 = clientDevice.addFunctionBlock("mock_fb_uid"); + ASSERT_TRUE(fb1.assigned()); + ASSERT_EQ("mock_fb_uid_1", fb1.getLocalId()); + + auto fb2 = clientDevice.addFunctionBlock("mock_fb_uid"); + ASSERT_TRUE(fb2.assigned()); + ASSERT_EQ("mock_fb_uid_2", fb2.getLocalId()); + + ASSERT_EQ(3, clientDevice.getFunctionBlocks().getCount()); +} + +TEST_F(TmsIntegrationTest, AddFunctionBlockWitchConfig) +{ + InstancePtr device = createDevice(); + TmsServer tmsServer(device); + tmsServer.start(); + + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + auto clientDevice = tmsClient.connect(); + + const auto clientFbTypes = clientDevice.getAvailableFunctionBlockTypes(); + + auto config = clientFbTypes.get("mock_fb_uid").createDefaultConfig(); + config.addProperty(IntProperty("TestConfigInt", 0)); // I realy dont like this, but there is no way of trasfering default config property object over opcua ... + config.addProperty(StringProperty("TestConfigString", "")); + config.setPropertyValue("TestConfigInt", 10); + config.setPropertyValue("TestConfigString", "Hello Property!"); + + auto fb = clientDevice.addFunctionBlock("mock_fb_uid", config); + + ASSERT_EQ(2, clientDevice.getFunctionBlocks().getCount()); + ASSERT_EQ(fb.getPropertyValue("TestConfigInt"), 10); + ASSERT_EQ(fb.getPropertyValue("TestConfigString"), "Hello Property!"); +} + + +TEST_F(TmsIntegrationTest, RemoveFunctionBlock) +{ + InstancePtr device = createDevice(); + TmsServer tmsServer(device); + tmsServer.start(); + + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + auto clientDevice = tmsClient.connect(); + + auto fb1 = clientDevice.addFunctionBlock("mock_fb_uid"); + auto fb2 = clientDevice.addFunctionBlock("mock_fb_uid"); + ASSERT_EQ(3, clientDevice.getFunctionBlocks().getCount()); + + clientDevice.removeFunctionBlock(fb1); + ASSERT_EQ(2, clientDevice.getFunctionBlocks().getCount()); + + clientDevice.removeFunctionBlock(fb2); + ASSERT_EQ(1, clientDevice.getFunctionBlocks().getCount()); +} From 88965fc76908322fccb32f38720a2a1193f34eee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Fri, 26 Jan 2024 07:40:38 +0100 Subject: [PATCH 072/217] Fix compiler warnings --- .../opcuatms_client/src/objects/tms_client_device_impl.cpp | 2 +- .../opcuatms/opcuatms_server/src/objects/tms_server_device.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index d0298b7..a055518 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -461,7 +461,7 @@ DictPtr TmsClientDeviceImpl::onGetAvailableFunction const auto typeList = ListConversionUtils::ExtensionObjectVariantToList(outvariant); auto dict = Dict(); - for (auto& type : typeList) + for (const auto& type : typeList) dict.set(type.getId(), type); return dict; diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index 2322b52..fe07b20 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -418,7 +418,7 @@ void TmsServerDevice::removeFunctionBlock(const StringPtr& localId) const auto objFunctionBlocks = this->object.getFunctionBlocks(search::Any()); - for (auto& fb : objFunctionBlocks) + for (const auto& fb : objFunctionBlocks) { if (fb.getLocalId() == localId) { From aadb1434395d5b86cd538ae4c753052cde126360 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Thu, 1 Feb 2024 07:59:18 +0100 Subject: [PATCH 073/217] Fix code review issues --- ...s.h => property_object_conversion_utils.h} | 2 +- .../opcuatms/opcuatms/src/CMakeLists.txt | 4 +- ...p => property_object_conversion_utils.cpp} | 6 +- .../opcuatms/opcuatms/tests/CMakeLists.txt | 2 +- .../tests/test_dict_conversion_utils.cpp | 10 ++-- .../test_property_object_conversion_utils.cpp | 55 +++++++++++++++++++ .../src/objects/tms_client_device_impl.cpp | 8 ++- .../src/objects/tms_server_device.cpp | 8 ++- .../test_tms_integration.cpp | 6 +- 9 files changed, 80 insertions(+), 21 deletions(-) rename shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/{dict_conversion_utils.h => property_object_conversion_utils.h} (96%) rename shared/libraries/opcuatms/opcuatms/src/converters/{dict_conversion_utils.cpp => property_object_conversion_utils.cpp} (76%) create mode 100644 shared/libraries/opcuatms/opcuatms/tests/test_property_object_conversion_utils.cpp diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/dict_conversion_utils.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/property_object_conversion_utils.h similarity index 96% rename from shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/dict_conversion_utils.h rename to shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/property_object_conversion_utils.h index 9b9387b..cb9d7dc 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/dict_conversion_utils.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/property_object_conversion_utils.h @@ -21,7 +21,7 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS -class DictConversionUtils +class PropertyObjectConversionUtils { public: static OpcUaVariant ToDictVariant(const PropertyObjectPtr& obj); diff --git a/shared/libraries/opcuatms/opcuatms/src/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms/src/CMakeLists.txt index a39904f..16eb182 100644 --- a/shared/libraries/opcuatms/opcuatms/src/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms/src/CMakeLists.txt @@ -23,7 +23,7 @@ set(SRC_Converters_Headers ${CONVERTERS_SRC_DIR}/struct_converter.h ${CONVERTERS_SRC_DIR}/variant_converter.h ${CONVERTERS_SRC_DIR}/list_conversion_utils.h ${CONVERTERS_SRC_DIR}/selection_converter.h - ${CONVERTERS_SRC_DIR}/dict_conversion_utils.h + ${CONVERTERS_SRC_DIR}/property_object_conversion_utils.h ) set(SRC_Converters ${CONVERTERS_SRC_DIR}/range_converter.cpp @@ -42,7 +42,7 @@ set(SRC_Converters ${CONVERTERS_SRC_DIR}/range_converter.cpp ${CONVERTERS_SRC_DIR}/selection_converter.cpp ${CONVERTERS_SRC_DIR}/argument_converter.cpp ${CONVERTERS_SRC_DIR}/generic_struct_converter.cpp - ${CONVERTERS_SRC_DIR}/dict_conversion_utils.cpp + ${CONVERTERS_SRC_DIR}/property_object_conversion_utils.cpp ) set(SRC_PublicHeaders ${SRC_PublicHeaders} ${SRC_Converters_Headers}) diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/dict_conversion_utils.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/property_object_conversion_utils.cpp similarity index 76% rename from shared/libraries/opcuatms/opcuatms/src/converters/dict_conversion_utils.cpp rename to shared/libraries/opcuatms/opcuatms/src/converters/property_object_conversion_utils.cpp index fd8a603..82791fe 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/dict_conversion_utils.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/property_object_conversion_utils.cpp @@ -1,10 +1,10 @@ -#include +#include #include #include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS -OpcUaVariant DictConversionUtils::ToDictVariant(const PropertyObjectPtr& obj) +OpcUaVariant PropertyObjectConversionUtils::ToDictVariant(const PropertyObjectPtr& obj) { if (!obj.assigned()) { @@ -26,7 +26,7 @@ OpcUaVariant DictConversionUtils::ToDictVariant(const PropertyObjectPtr& obj) return VariantConverter::ToVariant(dict); } -void DictConversionUtils::ToPropertyObject(const OpcUaVariant& variant, PropertyObjectPtr& objOut) +void PropertyObjectConversionUtils::ToPropertyObject(const OpcUaVariant& variant, PropertyObjectPtr& objOut) { const auto dict = VariantConverter::ToDaqObject(variant); diff --git a/shared/libraries/opcuatms/opcuatms/tests/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms/tests/CMakeLists.txt index 6648c5c..72f3084 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms/tests/CMakeLists.txt @@ -7,7 +7,7 @@ set(TEST_SOURCES test_core_types_utils.cpp test_variant_list_converter.cpp test_extension_object.cpp test_generic_struct_converter.cpp - test_dict_conversion_utils.cpp + test_property_object_conversion_utils.cpp ) add_executable(${TEST_APP} testapp.cpp diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_dict_conversion_utils.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_dict_conversion_utils.cpp index 1fad438..328778d 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/test_dict_conversion_utils.cpp +++ b/shared/libraries/opcuatms/opcuatms/tests/test_dict_conversion_utils.cpp @@ -1,5 +1,5 @@ #include "gtest/gtest.h" -#include +#include #include #include #include @@ -30,13 +30,13 @@ TEST_F(DictConversionUtilsTest, SimpleObject) obj.setPropertyValue("weight", 60.5); obj.setPropertyValue("isTheBest", true); - auto variant = DictConversionUtils::ToDictVariant(obj); + auto variant = PropertyObjectConversionUtils::ToDictVariant(obj); ASSERT_TRUE(variant->type == &UA_TYPES_DAQBT[UA_TYPES_DAQBT_DAQKEYVALUEPAIR]); ASSERT_EQ(variant->arrayLength, obj.getAllProperties().getCount()); auto objOut = CreateTestPropertyObject(); - DictConversionUtils::ToPropertyObject(variant, objOut); + PropertyObjectConversionUtils::ToPropertyObject(variant, objOut); ASSERT_TRUE(TestComparators::PropertyObjectEquals(obj, objOut)); } @@ -44,12 +44,12 @@ TEST_F(DictConversionUtilsTest, EmptyObject) { auto obj = CreateTestPropertyObject(); - auto variant = DictConversionUtils::ToDictVariant(obj); + auto variant = PropertyObjectConversionUtils::ToDictVariant(obj); ASSERT_TRUE(variant->type == &UA_TYPES_DAQBT[UA_TYPES_DAQBT_DAQKEYVALUEPAIR]); ASSERT_EQ(variant->arrayLength, obj.getAllProperties().getCount()); auto objOut = CreateTestPropertyObject(); - DictConversionUtils::ToPropertyObject(variant, objOut); + PropertyObjectConversionUtils::ToPropertyObject(variant, objOut); ASSERT_TRUE(TestComparators::PropertyObjectEquals(obj, objOut)); } diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_property_object_conversion_utils.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_property_object_conversion_utils.cpp new file mode 100644 index 0000000..e10cbc2 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/tests/test_property_object_conversion_utils.cpp @@ -0,0 +1,55 @@ +#include "gtest/gtest.h" +#include +#include +#include +#include + +using PropertyObjectConversionUtilsTest = testing::Test; + +using namespace daq; +using namespace daq::opcua; +using namespace daq::opcua::tms; + + +static PropertyObjectPtr CreateTestPropertyObject() +{ + auto obj = PropertyObject(); + obj.addProperty(StringProperty("name", "")); + obj.addProperty(IntProperty("age", 0)); + obj.addProperty(FloatProperty("weight", 0.0)); + obj.addProperty(BoolProperty("isTheBest", false)); + return obj; +} + + +TEST_F(PropertyObjectConversionUtilsTest, SimpleObject) +{ + auto obj = CreateTestPropertyObject(); + obj.setPropertyValue("name", "Jovanka"); + obj.setPropertyValue("age", 99); + obj.setPropertyValue("weight", 60.5); + obj.setPropertyValue("isTheBest", true); + + auto variant = PropertyObjectConversionUtils::ToDictVariant(obj); + + ASSERT_TRUE(variant->type == &UA_TYPES_DAQBT[UA_TYPES_DAQBT_DAQKEYVALUEPAIR]); + ASSERT_EQ(variant->arrayLength, obj.getAllProperties().getCount()); + + auto objOut = CreateTestPropertyObject(); + PropertyObjectConversionUtils::ToPropertyObject(variant, objOut); + ASSERT_TRUE(TestComparators::PropertyObjectEquals(obj, objOut)); +} + +TEST_F(PropertyObjectConversionUtilsTest, EmptyObject) +{ + auto obj = CreateTestPropertyObject(); + + auto variant = PropertyObjectConversionUtils::ToDictVariant(obj); + + ASSERT_TRUE(variant->type == &UA_TYPES_DAQBT[UA_TYPES_DAQBT_DAQKEYVALUEPAIR]); + ASSERT_EQ(variant->arrayLength, obj.getAllProperties().getCount()); + + auto objOut = CreateTestPropertyObject(); + PropertyObjectConversionUtils::ToPropertyObject(variant, objOut); + ASSERT_TRUE(TestComparators::PropertyObjectEquals(obj, objOut)); +} diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index a055518..7e07a52 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -20,7 +20,7 @@ #include "opcuatms/core_types_utils.h" #include "opcuatms/exceptions.h" #include "opcuatms/converters/list_conversion_utils.h" -#include "opcuatms/converters/dict_conversion_utils.h" +#include "opcuatms/converters/property_object_conversion_utils.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS using namespace daq::opcua; @@ -444,8 +444,10 @@ void TmsClientDeviceImpl::findAndCreateCustomComponents() DictPtr TmsClientDeviceImpl::onGetAvailableFunctionBlockTypes() { + // todo: migrate to AvailableTypes folder node + const auto fbFolderNodeId = getNodeId("FB"); - const auto methodNodeId = clientContext->getReferenceBrowser()->getChildNodeId(fbFolderNodeId, "GetAvailableFunctionBlockTypes"); + const auto methodNodeId = clientContext->getReferenceBrowser()->getChildNodeId(fbFolderNodeId, "_TmpGetAvailableFunctionBlockTypes"); auto request = OpcUaCallMethodRequest(); request->objectId = fbFolderNodeId.copyAndGetDetachedValue(); @@ -473,7 +475,7 @@ FunctionBlockPtr TmsClientDeviceImpl::onAddFunctionBlock(const StringPtr& typeId const auto methodNodeId = clientContext->getReferenceBrowser()->getChildNodeId(fbFolderNodeId, "AddFunctionBlock"); const auto typeIdVariant = OpcUaVariant(typeId.toStdString().c_str()); - const auto configVariant = DictConversionUtils::ToDictVariant(config); + const auto configVariant = PropertyObjectConversionUtils::ToDictVariant(config); auto request = OpcUaCallMethodRequest(); request->objectId = fbFolderNodeId.copyAndGetDetachedValue(); diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index fe07b20..8c9b012 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -318,10 +318,12 @@ void TmsServerDevice::createRemoveFunctionBlockNode(const OpcUaNodeId& parentId) void TmsServerDevice::createGetAvailableFunctionBlockTypesNode(const OpcUaNodeId& parentId) { + // todo: migrate to AvailableTypes folder node + OpcUaNodeId nodeIdOut; AddMethodNodeParams params(nodeIdOut, parentId); params.referenceTypeId = OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT)); - params.setBrowseName("GetAvailableFunctionBlockTypes"); + params.setBrowseName("_TmpGetAvailableFunctionBlockTypes"); params.inputArgumentsSize = 0; params.outputArgumentsSize = 1; params.outputArguments = (UA_Argument*) UA_Array_new(params.outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]); @@ -388,7 +390,7 @@ TmsServerFunctionBlockPtr TmsServerDevice::addFunctionBlock(const StringPtr& fbT throw OpcUaException(UA_STATUSCODE_BADNOTFOUND, "Function block type not found"); auto config = fbTypes.get(fbTypeId).createDefaultConfig(); - DictConversionUtils::ToPropertyObject(configVariant, config); + PropertyObjectConversionUtils::ToPropertyObject(configVariant, config); return addFunctionBlock(fbTypeId, config); } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index 3ec1d8a..3a96dd7 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -274,8 +274,10 @@ TEST_F(TmsIntegrationTest, AddFunctionBlock) ASSERT_EQ(3, clientDevice.getFunctionBlocks().getCount()); } -TEST_F(TmsIntegrationTest, AddFunctionBlockWitchConfig) +TEST_F(TmsIntegrationTest, DISABLED_AddFunctionBlockWitchConfig) { + // Work in progress + InstancePtr device = createDevice(); TmsServer tmsServer(device); tmsServer.start(); @@ -286,8 +288,6 @@ TEST_F(TmsIntegrationTest, AddFunctionBlockWitchConfig) const auto clientFbTypes = clientDevice.getAvailableFunctionBlockTypes(); auto config = clientFbTypes.get("mock_fb_uid").createDefaultConfig(); - config.addProperty(IntProperty("TestConfigInt", 0)); // I realy dont like this, but there is no way of trasfering default config property object over opcua ... - config.addProperty(StringProperty("TestConfigString", "")); config.setPropertyValue("TestConfigInt", 10); config.setPropertyValue("TestConfigString", "Hello Property!"); From 5cb7a2fbad21690737a6e9ca954f54ab135da25e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Wed, 7 Feb 2024 14:52:16 +0100 Subject: [PATCH 074/217] Add ITmsClientComponent interface --- .../objects/tms_client_component.h | 39 +++++++++++++++++++ .../objects/tms_client_component_impl.h | 3 +- .../opcuatms_client/src/CMakeLists.txt | 3 +- .../objects/tms_client_input_port_impl.cpp | 37 ++---------------- 4 files changed, 47 insertions(+), 35 deletions(-) create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component.h diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component.h new file mode 100644 index 0000000..82021d3 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component.h @@ -0,0 +1,39 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include + +BEGIN_NAMESPACE_OPENDAQ + +/*! + * @brief Extends IComponent interface with functionality needed for openDAQ client components. + */ +DECLARE_OPENDAQ_INTERFACE(ITmsClientComponent, IBaseObject) +{ + /*! + * @brief Gets the global ID of the component as defined by openDAQ server. + * @param[out] globalId The global ID of the server component. + * + * OpenDAQ client device can be connected to multiple openDAQ servers. This means that the global ID which was unique on the server, + * is no longer unique on the client device. In that case a unique prefix is added to each client openDAQ device. + * This means that global ID of a client component can be differnet that the one of the same component on the server side. + * This method returs global ID as defined by openDAQ server. + */ + virtual ErrCode INTERFACE_FUNC getRemoteGlobalId(IString * *globalId) = 0; +}; + +END_NAMESPACE_OPENDAQ diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h index 8a15f89..5389759 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h @@ -17,13 +17,14 @@ #pragma once #include "opcuatms_client/objects/tms_client_property_object_impl.h" #include "opendaq/channel_impl.h" +#include "opcuatms_client/objects/tms_client_component.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS template class TmsClientComponentBaseImpl; -using TmsClientComponentImpl = TmsClientComponentBaseImpl>; +using TmsClientComponentImpl = TmsClientComponentBaseImpl>; template class TmsClientComponentBaseImpl : public TmsClientPropertyObjectBaseImpl diff --git a/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt index 2ecefdf..e302639 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt @@ -44,7 +44,8 @@ set(SRC_Objects_Headers ${OBJECT_SRC_DIR}/tms_client_object_impl.h ${OBJECT_SRC_DIR}/tms_client_io_folder_impl.h ${OBJECT_SRC_DIR}/tms_client_io_folder_factory.h - + + ${OBJECT_SRC_DIR}/tms_client_component.h ${OBJECT_SRC_DIR}/tms_client_component_impl.h ${OBJECT_SRC_DIR}/tms_client_component_factory.h diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp index 3bb0124..661bb0c 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp @@ -58,44 +58,15 @@ ErrCode TmsClientInputPortImpl::acceptsSignal(ISignal* signal, Bool* accepts) ErrCode TmsClientInputPortImpl::connect(ISignal* signal) { - return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; - //return daqTry([&]() { - // OpcUaNodeId methodId(NAMESPACE_DAQBSP, UA_DAQBSPID_INPUTPORTTYPE_CONNECTSIGNAL); - - // auto signalNodeId = clientContext->getNodeId(signal); - // OpcUaVariant inputArg; - // inputArg.setScalar(*signalNodeId); + // SignalPtr singalPtr = signal; + // StringPtr remoteId = singalPtr.asPtr().getRemoteGlobalId(); - // OpcUaCallMethodRequest callRequest(methodId, nodeId, 1, inputArg.get()); - // OpcUaObject result = client->callMethod(callRequest); - // if (OPCUA_STATUSCODE_FAILED(result->statusCode)) - // return OPENDAQ_ERR_CALLFAILED; - // else - // { - // referenceUtils.updateReferences(nodeId); - // return OPENDAQ_SUCCESS; - // - // } - //}); + return OPENDAQ_ERR_NOTIMPLEMENTED; } ErrCode TmsClientInputPortImpl::disconnect() { - return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; - - //return daqTry([&]() { - // OpcUaNodeId methodId(NAMESPACE_DAQBSP, UA_DAQBSPID_INPUTPORTTYPE_DISCONNECTSIGNAL); - - // OpcUaCallMethodRequest callRequest(methodId, nodeId, 0, nullptr); - // OpcUaObject result = client->callMethod(callRequest); - // if (OPCUA_STATUSCODE_FAILED(result->statusCode)) - // return OPENDAQ_ERR_CALLFAILED; - // else - // { - // referenceUtils.updateReferences(nodeId); - // return OPENDAQ_SUCCESS; - // } - //}); + return OPENDAQ_ERR_NOTIMPLEMENTED; } ErrCode TmsClientInputPortImpl::getSignal(ISignal** signal) From 8a60b12f85006270e97994192483ae339a7aa515 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Mon, 12 Feb 2024 09:30:14 +0100 Subject: [PATCH 075/217] Fix TMS client template issues --- .../objects/tms_client_channel_impl.h | 2 +- .../objects/tms_client_component.h | 2 +- .../objects/tms_client_component_impl.h | 9 ++++--- .../objects/tms_client_device_impl.h | 2 +- .../objects/tms_client_folder_impl.h | 2 +- .../objects/tms_client_function_block_impl.h | 2 +- .../objects/tms_client_input_port_impl.h | 2 +- .../objects/tms_client_io_folder_impl.h | 2 +- .../objects/tms_client_property_object_impl.h | 5 ++-- .../objects/tms_client_signal_impl.h | 2 +- .../src/objects/tms_client_component_impl.cpp | 27 ++++++++++++------- .../src/objects/tms_client_folder_impl.cpp | 4 +-- .../tms_client_function_block_impl.cpp | 4 +-- .../src/objects/tms_client_io_folder_impl.cpp | 2 +- .../tms_client_property_object_impl.cpp | 16 +++++------ 15 files changed, 47 insertions(+), 36 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_impl.h index 9cd9113..337fcd1 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_impl.h @@ -19,7 +19,7 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS -class TmsClientChannelImpl : public TmsClientFunctionBlockBaseImpl +class TmsClientChannelImpl : public TmsClientFunctionBlockBaseImpl> { public: explicit TmsClientChannelImpl( diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component.h index 82021d3..d9621ec 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component.h @@ -33,7 +33,7 @@ DECLARE_OPENDAQ_INTERFACE(ITmsClientComponent, IBaseObject) * This means that global ID of a client component can be differnet that the one of the same component on the server side. * This method returs global ID as defined by openDAQ server. */ - virtual ErrCode INTERFACE_FUNC getRemoteGlobalId(IString * *globalId) = 0; + virtual ErrCode INTERFACE_FUNC getRemoteGlobalId(IString** globalId) = 0; }; END_NAMESPACE_OPENDAQ diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h index 5389759..ba3defc 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h @@ -24,14 +24,14 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS template class TmsClientComponentBaseImpl; -using TmsClientComponentImpl = TmsClientComponentBaseImpl>; +using TmsClientComponentImpl = TmsClientComponentBaseImpl>; template class TmsClientComponentBaseImpl : public TmsClientPropertyObjectBaseImpl { public: - template = 0> + template, ChannelImpl> = 0> TmsClientComponentBaseImpl(const ContextPtr& ctx, const ComponentPtr& parent, const StringPtr& localId, @@ -43,7 +43,7 @@ class TmsClientComponentBaseImpl : public TmsClientPropertyObjectBaseImpl clientContext->readObjectAttributes(nodeId); } - template = 0> + template, ChannelImpl> = 0> TmsClientComponentBaseImpl(const ContextPtr& ctx, const ComponentPtr& parent, const StringPtr& localId, @@ -66,6 +66,9 @@ class TmsClientComponentBaseImpl : public TmsClientPropertyObjectBaseImpl ErrCode INTERFACE_FUNC getVisible(Bool* visible) override; ErrCode INTERFACE_FUNC setVisible(Bool visible) override; + + ErrCode INTERFACE_FUNC getRemoteGlobalId(IString** globalId) override; + private: LoggerComponentPtr getLoggerComponent(); void initComponent(); diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h index 43ed00b..2cad354 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h @@ -22,7 +22,7 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS -class TmsClientDeviceImpl : public TmsClientComponentBaseImpl +class TmsClientDeviceImpl : public TmsClientComponentBaseImpl> { public: explicit TmsClientDeviceImpl(const ContextPtr& ctx, diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h index 15cf0de..8ca78cd 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h @@ -20,7 +20,7 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS -template > +template > class TmsClientFolderImpl : public TmsClientComponentBaseImpl { public: diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h index e4a388d..ba6e98e 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h @@ -22,7 +22,7 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS template class TmsClientFunctionBlockBaseImpl; -using TmsClientFunctionBlockImpl = TmsClientFunctionBlockBaseImpl; +using TmsClientFunctionBlockImpl = TmsClientFunctionBlockBaseImpl>; template class TmsClientFunctionBlockBaseImpl : public TmsClientComponentBaseImpl diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h index 8932dac..453e945 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h @@ -20,7 +20,7 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS -class TmsClientInputPortImpl : public TmsClientComponentBaseImpl +class TmsClientInputPortImpl : public TmsClientComponentBaseImpl> { public: explicit TmsClientInputPortImpl(const ContextPtr& ctx, diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h index 6140cf1..b134d82 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h @@ -20,7 +20,7 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS -class TmsClientIoFolderImpl : public TmsClientFolderImpl> +class TmsClientIoFolderImpl : public TmsClientFolderImpl> { public: explicit TmsClientIoFolderImpl(const ContextPtr& ctx, diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h index bcf6ae9..a03227c 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h @@ -21,6 +21,7 @@ #include "opcuatms_client/objects/tms_client_object_impl.h" #include "opendaq/channel_impl.h" #include "opendaq/streaming_info_impl.h" +#include "opcuatms_client/objects/tms_client_component.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -62,7 +63,7 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl init(); } - template = 0> + template, ChannelImpl, PropertyObjectImpl, StreamingInfoConfigImpl> = 0> TmsClientPropertyObjectBaseImpl(const ContextPtr& ctx, const ComponentPtr& parent, const StringPtr& localId, @@ -74,7 +75,7 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl init(); } - template = 0> + template, ChannelImpl> = 0> TmsClientPropertyObjectBaseImpl(const ContextPtr& ctx, const ComponentPtr& parent, const StringPtr& localId, diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h index bdba54b..e39bc53 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h @@ -23,7 +23,7 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS // TmsClientSignalImpl -class TmsClientSignalImpl final : public TmsClientComponentBaseImpl +class TmsClientSignalImpl final : public TmsClientComponentBaseImpl> { public: explicit TmsClientSignalImpl(const ContextPtr& ctx, diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp index 325a8c1..bbbe51c 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp @@ -12,7 +12,7 @@ using namespace daq::opcua; template ErrCode TmsClientComponentBaseImpl::getActive(Bool* active) -{ +{ try { *active = this->template readValue("Active"); @@ -178,15 +178,22 @@ ErrCode TmsClientComponentBaseImpl::setVisible(Bool visible) template LoggerComponentPtr TmsClientComponentBaseImpl::getLoggerComponent() { - return this->daqContext.getLogger().getOrAddComponent("OpcUaClientComponent"); + return this->daqContext.getLogger().getOrAddComponent("OpcUaClientComponent"); } -template class TmsClientComponentBaseImpl>; -template class TmsClientComponentBaseImpl>; -template class TmsClientComponentBaseImpl>; -template class TmsClientComponentBaseImpl; -template class TmsClientComponentBaseImpl; -template class TmsClientComponentBaseImpl; -template class TmsClientComponentBaseImpl; -template class TmsClientComponentBaseImpl; + +template +ErrCode TmsClientComponentBaseImpl::getRemoteGlobalId(IString** /*globalId*/) +{ + return OPENDAQ_SUCCESS; +} + +template class TmsClientComponentBaseImpl>; +template class TmsClientComponentBaseImpl>; +template class TmsClientComponentBaseImpl>; +template class TmsClientComponentBaseImpl>; +template class TmsClientComponentBaseImpl>; +template class TmsClientComponentBaseImpl>; +template class TmsClientComponentBaseImpl>; +template class TmsClientComponentBaseImpl>; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp index 7f34158..d0dd31c 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp @@ -66,7 +66,7 @@ void TmsClientFolderImpl::findAndCreateFolders(std::map>; -template class TmsClientFolderImpl>; +template class TmsClientFolderImpl>; +template class TmsClientFolderImpl>; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp index 78e125e..8ffd370 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp @@ -197,7 +197,7 @@ SignalPtr TmsClientFunctionBlockBaseImpl::onGetStatusSignal() // To force the compiler to generate the template classes that are used elsewhere // If this is not done, then you will get linker errors if using it outside the static library -template class TmsClientFunctionBlockBaseImpl; -template class TmsClientFunctionBlockBaseImpl; +template class TmsClientFunctionBlockBaseImpl>; +template class TmsClientFunctionBlockBaseImpl>; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp index 2c21ac4..fc15dd9 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp @@ -13,7 +13,7 @@ TmsClientIoFolderImpl::TmsClientIoFolderImpl(const ContextPtr& ctx, const StringPtr& localId, const TmsClientContextPtr& clientContext, const opcua::OpcUaNodeId& nodeId) - : TmsClientFolderImpl>(ctx, parent, localId, clientContext, nodeId, true) + : TmsClientFolderImpl(ctx, parent, localId, clientContext, nodeId, true) { std::map orderedComponents; std::vector unorderedComponents; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index 95f3834..47c48d4 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -479,14 +479,14 @@ bool TmsClientPropertyObjectBaseImpl::isIgnoredMethodPeoperty(const std::s } template class TmsClientPropertyObjectBaseImpl; -template class TmsClientPropertyObjectBaseImpl>; -template class TmsClientPropertyObjectBaseImpl>; -template class TmsClientPropertyObjectBaseImpl>; -template class TmsClientPropertyObjectBaseImpl; -template class TmsClientPropertyObjectBaseImpl; -template class TmsClientPropertyObjectBaseImpl; -template class TmsClientPropertyObjectBaseImpl; -template class TmsClientPropertyObjectBaseImpl; +template class TmsClientPropertyObjectBaseImpl>; +template class TmsClientPropertyObjectBaseImpl>; +template class TmsClientPropertyObjectBaseImpl>; +template class TmsClientPropertyObjectBaseImpl>; +template class TmsClientPropertyObjectBaseImpl>; +template class TmsClientPropertyObjectBaseImpl>; +template class TmsClientPropertyObjectBaseImpl>; +template class TmsClientPropertyObjectBaseImpl>; template class TmsClientPropertyObjectBaseImpl; From 818b274f534cc5ad4d4a8d1cdb9ca1c519e6c87a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Mon, 12 Feb 2024 14:15:25 +0100 Subject: [PATCH 076/217] Expose input port connect() and disconnect() methods over OPC UA --- .../opcuaclient/cached_reference_browser.h | 4 +- .../src/cached_reference_browser.cpp | 20 ++- .../src/test_cached_reference_browser.cpp | 2 +- .../objects/tms_client_component_impl.h | 5 +- .../objects/tms_client_context.h | 5 + .../src/objects/tms_client_component_impl.cpp | 22 ++- .../src/objects/tms_client_context.cpp | 10 ++ .../src/objects/tms_client_device_impl.cpp | 7 +- .../objects/tms_client_input_port_impl.cpp | 46 +++++- .../objects/tms_server_input_port.h | 5 + .../objects/tms_server_object.h | 3 +- .../opcuatms_server/tms_server_context.h | 6 +- .../src/objects/tms_server_device.cpp | 6 +- .../src/objects/tms_server_input_port.cpp | 155 +++++++++++------- .../src/objects/tms_server_object.cpp | 13 ++ .../opcuatms_server/src/tms_server.cpp | 4 +- .../src/tms_server_context.cpp | 23 ++- .../opcuatms_server/tests/tms_server_test.cpp | 2 +- .../test_property_object_advanced.cpp | 2 +- .../test_tms_amplifier.cpp | 2 +- .../test_tms_fusion_device.cpp | 2 +- .../test_tms_integration.cpp | 68 ++++++++ .../tms_object_integration_test.cpp | 2 +- 23 files changed, 331 insertions(+), 83 deletions(-) diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h index 9672928..c3be86f 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h @@ -49,8 +49,9 @@ class CachedReferenceBrowser public: CachedReferenceBrowser(const OpcUaClientPtr& client, size_t maxNodesPerBrowse = 0); - const CachedReferences& browse(const OpcUaNodeId& nodeId, bool forceInvalidate = false); + const CachedReferences& browse(const OpcUaNodeId& nodeId); void invalidate(const OpcUaNodeId& nodeId); + void invalidateRecursive(const OpcUaNodeId& nodeId); bool isSubtypeOf(const OpcUaNodeId& typeId, const OpcUaNodeId& baseType); OpcUaNodeId getTypeDefinition(const OpcUaNodeId& nodeId); @@ -59,6 +60,7 @@ class CachedReferenceBrowser CachedReferences browseFiltered(const OpcUaNodeId& nodeId, const BrowseFilter& filter); private: + void invalidate(const OpcUaNodeId& nodeId, bool recursive); bool isCached(const OpcUaNodeId& nodeId); void markAsCached(const OpcUaNodeId& nodeId); void browseMultiple(const std::vector& nodes); diff --git a/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp b/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp index f75fa50..b5501e6 100644 --- a/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp +++ b/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp @@ -9,18 +9,15 @@ CachedReferenceBrowser::CachedReferenceBrowser(const OpcUaClientPtr& client, siz { } -const CachedReferences& CachedReferenceBrowser::browse(const OpcUaNodeId& nodeId, bool forceInvalidate) +const CachedReferences& CachedReferenceBrowser::browse(const OpcUaNodeId& nodeId) { - if (forceInvalidate) - invalidate(nodeId); - if (!isCached(nodeId)) browseMultiple({nodeId}); return references[nodeId]; } -void CachedReferenceBrowser::invalidate(const OpcUaNodeId& nodeId) +void CachedReferenceBrowser::invalidate(const OpcUaNodeId& nodeId, bool recursive) { if (!isCached(nodeId)) return; @@ -28,6 +25,9 @@ void CachedReferenceBrowser::invalidate(const OpcUaNodeId& nodeId) const auto children = references[nodeId].byNodeId; references.erase(nodeId); + if (!recursive) + return; + for (const auto& [refNodeId, ref] : children) { if (ref->isForward) @@ -35,6 +35,16 @@ void CachedReferenceBrowser::invalidate(const OpcUaNodeId& nodeId) } } +void CachedReferenceBrowser::invalidate(const OpcUaNodeId& nodeId) +{ + invalidate(nodeId, false); +} + +void CachedReferenceBrowser::invalidateRecursive(const OpcUaNodeId& nodeId) +{ + invalidate(nodeId, true); +} + bool CachedReferenceBrowser::isSubtypeOf(const OpcUaNodeId& typeId, const OpcUaNodeId& baseType) { if (typeId == baseType) diff --git a/shared/libraries/opcua/opcuaclient/tests/src/test_cached_reference_browser.cpp b/shared/libraries/opcua/opcuaclient/tests/src/test_cached_reference_browser.cpp index fe11899..b352e19 100644 --- a/shared/libraries/opcua/opcuaclient/tests/src/test_cached_reference_browser.cpp +++ b/shared/libraries/opcua/opcuaclient/tests/src/test_cached_reference_browser.cpp @@ -22,7 +22,7 @@ TEST_F(CachedReferenceBrowserTest, ObjectsFolder) auto references = browser.browse(nodeId); ASSERT_GT(references.byNodeId.size(), 0u); - ASSERT_NO_THROW(browser.invalidate(nodeId)); + ASSERT_NO_THROW(browser.invalidateRecursive(nodeId)); } TEST_F(CachedReferenceBrowserTest, ServerStatus) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h index ba3defc..e30041f 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h @@ -66,9 +66,12 @@ class TmsClientComponentBaseImpl : public TmsClientPropertyObjectBaseImpl ErrCode INTERFACE_FUNC getVisible(Bool* visible) override; ErrCode INTERFACE_FUNC setVisible(Bool visible) override; - + // ITmsClientComponent ErrCode INTERFACE_FUNC getRemoteGlobalId(IString** globalId) override; +protected: + bool isChildComponent(const ComponentPtr& component); + private: LoggerComponentPtr getLoggerComponent(); void initComponent(); diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h index 9f98f39..1745637 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h @@ -22,6 +22,8 @@ #include #include #include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -35,6 +37,8 @@ class TmsClientContext const opcua::OpcUaClientPtr& getClient() const; + void registerRootDevice(const DevicePtr& rootDevice); + DevicePtr getRootDevice(); void registerObject(const opcua::OpcUaNodeId& nodeId, const BaseObjectPtr& object); void unregisterObject(const opcua::OpcUaNodeId& nodeId); BaseObjectPtr getObject(const opcua::OpcUaNodeId& nodeId) const; @@ -71,6 +75,7 @@ class TmsClientContext std::unordered_map objects; size_t maxNodesPerBrowse = 0; size_t maxNodesPerRead = 0; + WeakRefPtr rootDevice; void initReferenceBrowser(); void initAttributeReader(); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp index bbbe51c..2c7ab06 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp @@ -182,11 +182,31 @@ LoggerComponentPtr TmsClientComponentBaseImpl::getLoggerComponent() } template -ErrCode TmsClientComponentBaseImpl::getRemoteGlobalId(IString** /*globalId*/) +ErrCode TmsClientComponentBaseImpl::getRemoteGlobalId(IString** globalId) { + OPENDAQ_PARAM_NOT_NULL(globalId); + + *globalId = String(this->nodeId.getIdentifier()) .detach(); return OPENDAQ_SUCCESS; } +template +bool TmsClientComponentBaseImpl::isChildComponent(const ComponentPtr& component) +{ + DevicePtr parentDevice = this->clientContext->getRootDevice(); + ComponentPtr currentComponent = component; + + do + { + if (currentComponent == parentDevice) + return true; + + currentComponent = currentComponent.getParent(); + } while (currentComponent.assigned()); + + return false; +} + template class TmsClientComponentBaseImpl>; template class TmsClientComponentBaseImpl>; template class TmsClientComponentBaseImpl>; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp index 001e212..e92790f 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp @@ -22,6 +22,16 @@ const opcua::OpcUaClientPtr& TmsClientContext::getClient() const return client; } +void TmsClientContext::registerRootDevice(const DevicePtr& rootDevice) +{ + this->rootDevice = rootDevice; +} + +DevicePtr TmsClientContext::getRootDevice() +{ + return this->rootDevice.getRef(); +} + void TmsClientContext::registerObject(const OpcUaNodeId& nodeId, const BaseObjectPtr& object) { std::lock_guard guard(mutex); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 7e07a52..ac19927 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -70,6 +70,9 @@ TmsClientDeviceImpl::TmsClientDeviceImpl(const ContextPtr& ctx, { clientContext->readObjectAttributes(nodeId); + if (isRootDevice) + clientContext->registerRootDevice(thisInterface()); + findAndCreateSubdevices(); findAndCreateFunctionBlocks(); findAndCreateSignals(); @@ -472,7 +475,7 @@ DictPtr TmsClientDeviceImpl::onGetAvailableFunction FunctionBlockPtr TmsClientDeviceImpl::onAddFunctionBlock(const StringPtr& typeId, const PropertyObjectPtr& config) { const auto fbFolderNodeId = getNodeId("FB"); - const auto methodNodeId = clientContext->getReferenceBrowser()->getChildNodeId(fbFolderNodeId, "AddFunctionBlock"); + const auto methodNodeId = clientContext->getReferenceBrowser()->getChildNodeId(fbFolderNodeId, "Add"); const auto typeIdVariant = OpcUaVariant(typeId.toStdString().c_str()); const auto configVariant = PropertyObjectConversionUtils::ToDictVariant(config); @@ -503,7 +506,7 @@ FunctionBlockPtr TmsClientDeviceImpl::onAddFunctionBlock(const StringPtr& typeId void TmsClientDeviceImpl::onRemoveFunctionBlock(const FunctionBlockPtr& functionBlock) { const auto fbFolderNodeId = getNodeId("FB"); - const auto methodNodeId = clientContext->getReferenceBrowser()->getChildNodeId(fbFolderNodeId, "RemoveFunctionBlock"); + const auto methodNodeId = clientContext->getReferenceBrowser()->getChildNodeId(fbFolderNodeId, "Remove"); const auto fbIdVariant = OpcUaVariant(functionBlock.getLocalId().toStdString().c_str()); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp index 661bb0c..5f4f9e4 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp @@ -2,6 +2,8 @@ #include "opcuatms/converters/variant_converter.h" #include "opcuatms_client/objects/tms_client_input_port_impl.h" #include "opcuatms/errors.h" +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS using namespace opcua; @@ -58,15 +60,46 @@ ErrCode TmsClientInputPortImpl::acceptsSignal(ISignal* signal, Bool* accepts) ErrCode TmsClientInputPortImpl::connect(ISignal* signal) { - // SignalPtr singalPtr = signal; - // StringPtr remoteId = singalPtr.asPtr().getRemoteGlobalId(); + return daqTry([&]() { + if (!isChildComponent(signal)) + throw NotFoundException(); - return OPENDAQ_ERR_NOTIMPLEMENTED; + const SignalPtr signalPtr = signal; + const auto methodNodeId = getNodeId("Connect"); + + StringPtr remoteId; + signalPtr.asPtr()->getRemoteGlobalId(&remoteId); + const auto signalIdVariant = OpcUaVariant(remoteId.toStdString().c_str()); + + auto request = OpcUaCallMethodRequest(); + request->objectId = nodeId.copyAndGetDetachedValue(); + request->methodId = methodNodeId.copyAndGetDetachedValue(); + request->inputArgumentsSize = 1; + request->inputArguments = (UA_Variant*) UA_Array_new(request->inputArgumentsSize, &UA_TYPES[UA_TYPES_VARIANT]); + request->inputArguments[0] = signalIdVariant.copyAndGetDetachedValue(); + + auto response = client->callMethod(request); + + if (response->statusCode != UA_STATUSCODE_GOOD) + throw OpcUaGeneralException(); + }); } ErrCode TmsClientInputPortImpl::disconnect() { - return OPENDAQ_ERR_NOTIMPLEMENTED; + return daqTry([&]() { + const auto methodNodeId = getNodeId("Disconnect"); + + auto request = OpcUaCallMethodRequest(); + request->objectId = nodeId.copyAndGetDetachedValue(); + request->methodId = methodNodeId.copyAndGetDetachedValue(); + request->inputArgumentsSize = 0; + + auto response = client->callMethod(request); + + if (response->statusCode != UA_STATUSCODE_GOOD) + throw OpcUaGeneralException(); + }); } ErrCode TmsClientInputPortImpl::getSignal(ISignal** signal) @@ -80,11 +113,14 @@ ErrCode TmsClientInputPortImpl::getSignal(ISignal** signal) SignalPtr TmsClientInputPortImpl::onGetSignal() { + auto browser = clientContext->getReferenceBrowser(); + auto filter = BrowseFilter(); filter.referenceTypeId = OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_CONNECTEDTOSIGNAL); filter.direction = UA_BROWSEDIRECTION_FORWARD; - const auto& references = clientContext->getReferenceBrowser()->browseFiltered(nodeId, filter); + browser->invalidate(nodeId); + const auto& references = browser->browseFiltered(nodeId, filter); assert(references.byNodeId.size() <= 1); if (!references.byNodeId.empty()) diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h index 6ba393a..01cbb94 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h @@ -31,11 +31,16 @@ class TmsServerInputPort : public TmsServerComponent TmsServerInputPort(const InputPortPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext); opcua::OpcUaNodeId getReferenceType() override; + void addChildNodes() override; void bindCallbacks() override; void createNonhierarchicalReferences() override; protected: opcua::OpcUaNodeId getTmsTypeId() override; + void createConnectMethodNode(); + void createDisconnectMethodNode(); + void onConnectSignal(NodeEventManager::MethodArgs args); + void onDisconenctSignal(NodeEventManager::MethodArgs args); }; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h index 1654234..c863f2b 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h @@ -91,6 +91,7 @@ class TmsServerObject : public std::enable_shared_from_this void addReadCallback(const opcua::OpcUaNodeId& nodeId, ReadVariantCallback readFunc); void addWriteCallback(const opcua::OpcUaNodeId& nodeId, WriteVariantCallback writeFunc); void addReference(const opcua::OpcUaNodeId& targetNodeId, const opcua::OpcUaNodeId& referenceTypeId); + void deleteReferencesOfType(const opcua::OpcUaNodeId& referenceTypeId); void bindReadWriteCallbacks(); void browseReferences(); bool hasChildNode(const std::string& nodeName) const; @@ -145,13 +146,13 @@ class TmsServerObject : public std::enable_shared_from_this ContextPtr daqContext; uint32_t numberInList; TmsServerContextPtr tmsContext; + std::unordered_map> references; private: void bindCallbacksInternal(); std::unordered_map readCallbacks; std::unordered_map writeCallbacks; - std::unordered_map> references; std::unordered_map eventManagers; }; diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server_context.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server_context.h index 0912971..500aaf7 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server_context.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server_context.h @@ -17,6 +17,7 @@ #pragma once #include #include +#include #include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -24,12 +25,15 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS class TmsServerContext : public std::enable_shared_from_this { public: - TmsServerContext(const ContextPtr& context); + TmsServerContext(const ContextPtr& context, const DevicePtr& rootDevice); ~TmsServerContext(); void registerComponent(const ComponentPtr& component, TmsServerObject& obj); + DevicePtr getRootDevice(); + SignalPtr findSingal(const StringPtr& globalId); private: ContextPtr context; + DevicePtr rootDevice; std::unordered_map> idToObjMap; void coreEventCallback(ComponentPtr& component, CoreEventArgsPtr& eventArgs); diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index 8c9b012..791d1c3 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -249,13 +249,13 @@ void TmsServerDevice::createAddFunctionBlockNode(const OpcUaNodeId& parentId) OpcUaNodeId nodeIdOut; AddMethodNodeParams params(nodeIdOut, parentId); params.referenceTypeId = OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT)); - params.setBrowseName("AddFunctionBlock"); + params.setBrowseName("Add"); params.outputArgumentsSize = 1; params.outputArguments = (UA_Argument*) UA_Array_new(params.outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]); params.inputArgumentsSize = 2; params.inputArguments = (UA_Argument*) UA_Array_new(params.inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]); - params.outputArguments[0].name = UA_STRING_ALLOC("functionBlockNodeId"); + params.outputArguments[0].name = UA_STRING_ALLOC("nodeId"); params.outputArguments[0].dataType = UA_TYPES[UA_TYPES_NODEID].typeId; params.outputArguments[0].valueRank = UA_VALUERANK_SCALAR; @@ -290,7 +290,7 @@ void TmsServerDevice::createRemoveFunctionBlockNode(const OpcUaNodeId& parentId) OpcUaNodeId nodeIdOut; AddMethodNodeParams params(nodeIdOut, parentId); params.referenceTypeId = OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT)); - params.setBrowseName("RemoveFunctionBlock"); + params.setBrowseName("Remove"); params.inputArgumentsSize = 1; params.inputArguments = (UA_Argument*) UA_Array_new(params.inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]); diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp index 85615fd..05eb919 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp @@ -5,6 +5,7 @@ #include "open62541/daqbsp_nodeids.h" #include "open62541/di_nodeids.h" #include "open62541/daqbsp_nodeids.h" +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -20,69 +21,113 @@ OpcUaNodeId TmsServerInputPort::getReferenceType() return OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASINPUTPORT); } +void TmsServerInputPort::addChildNodes() +{ + Super::addChildNodes(); + + createConnectMethodNode(); + createDisconnectMethodNode(); +} + OpcUaNodeId TmsServerInputPort::getTmsTypeId() { return OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_INPUTPORTTYPE); } -void TmsServerInputPort::bindCallbacks() +void TmsServerInputPort::createConnectMethodNode() { + OpcUaNodeId nodeIdOut; + AddMethodNodeParams params(nodeIdOut, nodeId); + params.referenceTypeId = OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT)); + params.setBrowseName("Connect"); + params.inputArgumentsSize = 1; + params.inputArguments = (UA_Argument*) UA_Array_new(params.inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]); - addReadCallback("RequiresSignal", [this]() { return VariantConverter::ToVariant(object.getRequiresSignal()); }); + params.inputArguments[0].name = UA_STRING_ALLOC("signalGlobalId"); + params.inputArguments[0].dataType = UA_TYPES[UA_TYPES_STRING].typeId; + params.inputArguments[0].valueRank = UA_VALUERANK_SCALAR; + + auto methodNodeId = server->addMethodNode(params); - //addEvent("AcceptsSignal")->onMethodCall([this](NodeEventManager::MethodArgs args) - //{ - // if (args.inputSize != 1 || args.outputSize != 1) - // return static_cast(UA_STATUSCODE_BADINTERNALERROR); - - // auto nodeId = OpcUaVariant(args.input[0]).toNodeId(); - // //TODO: check if signal can be accepted, for now allow all signals - // // Pseudocode: - // // signal = lookUpSignal(nodeId) - // // if (signal == nullptr) - // // return static_cast(UA_STATUSCODE_BADNOTFOUND); - // // Whatever else that needs to be done... - - // bool accepts = true; - // - // OpcUaVariant result; - // result.setScalar(accepts); - // args.output[0] = result.getDetachedValue(); - // return static_cast(UA_STATUSCODE_GOOD); - //}); - - //addEvent("ConnectSignal")->onMethodCall([this](NodeEventManager::MethodArgs args) - //{ - // if (args.inputSize != 1) - // return static_cast(UA_STATUSCODE_BADINTERNALERROR); - - // auto nodeId = OpcUaVariant(args.input[0]).toNodeId(); - - // //TODO: Connect the signal to the input port - // // Pseudocode: - // // signalNodeId = lookUpSignal(nodeId) - // // if (signalNodeId == nullptr) - // // return static_cast(UA_STATUSCODE_BADNOTFOUND); - // // OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_CONNECTEDTO); - // // server->addReference(signalNodeId, referenceTypeId, getNodeId(), true); - // // Whatever else that needs to be done... - - // return static_cast(UA_STATUSCODE_GOOD); - //}); - - //addEvent("DisconnectSignal")->onMethodCall([this](NodeEventManager::MethodArgs args) - //{ - // // TODO: Disconnect the signal to the input port - // // Pseudocode: - // // auto signal = object.getSignal(); - // // if (signal == nullptr) - // // return static_cast(UA_STATUSCODE_BADNOTFOUND); - // // OpcUaNodeId referenceTypeId(NAMESPACE_TMSBSP, UA_TMSBSPID_CONNECTEDTO); - // // server->deleteReference(this->getNodeId(), referenceTypeId, false); - // // Whatever else that needs to be done... - // auto signal = object.getSignal(); - // return static_cast(UA_STATUSCODE_GOOD); - //}); + auto callback = [this](NodeEventManager::MethodArgs args) -> UA_StatusCode + { + try + { + onConnectSignal(args); + } + catch (const OpcUaException& e) + { + return e.getStatusCode(); + } + + return UA_STATUSCODE_GOOD; + }; + + addEvent(methodNodeId)->onMethodCall(callback); +} + +void TmsServerInputPort::createDisconnectMethodNode() +{ + OpcUaNodeId nodeIdOut; + AddMethodNodeParams params(nodeIdOut, nodeId); + params.referenceTypeId = OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT)); + params.setBrowseName("Disconnect"); + params.inputArgumentsSize = 0; + + auto methodNodeId = server->addMethodNode(params); + + auto callback = [this](NodeEventManager::MethodArgs args) -> UA_StatusCode + { + try + { + onDisconenctSignal(args); + } + catch (const OpcUaException& e) + { + return e.getStatusCode(); + } + + return UA_STATUSCODE_GOOD; + }; + + addEvent(methodNodeId)->onMethodCall(callback); +} + +void TmsServerInputPort::onConnectSignal(NodeEventManager::MethodArgs args) +{ + assert(args.inputSize == 1); + + const auto globalId = OpcUaVariant(args.input[0]).toString(); + const auto signal = tmsContext->findSingal(globalId); + + if (!signal.assigned()) + throw OpcUaException(UA_STATUSCODE_BADNOTFOUND, "Signal not found"); + + const auto refType = OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_CONNECTEDTOSIGNAL); + const auto sourceId = nodeId; + const auto signalNodeId = findSignalNodeId(signal); + + deleteReferencesOfType(refType); + addReference(signalNodeId, refType); + browseReferences(); + + object.connect(signal); +} + +void TmsServerInputPort::onDisconenctSignal(NodeEventManager::MethodArgs args) +{ + assert(args.inputSize == 0); + + const auto refType = OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_CONNECTEDTOSIGNAL); + + deleteReferencesOfType(refType); + + object.disconnect(); +} + +void TmsServerInputPort::bindCallbacks() +{ + addReadCallback("RequiresSignal", [this]() { return VariantConverter::ToVariant(object.getRequiresSignal()); }); Super::bindCallbacks(); } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp index 95148e4..0716a42 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp @@ -280,6 +280,19 @@ void TmsServerObject::addReference(const OpcUaNodeId& targetNodeId, const OpcUaN server->addReference(nodeId, referenceTypeId, targetNodeId, true); } +void TmsServerObject::deleteReferencesOfType(const opcua::OpcUaNodeId& referenceTypeId) +{ + browseReferences(); + + for (const auto& [browseName, ref] : references) + { + if (OpcUaNodeId(ref->referenceTypeId) == referenceTypeId) + server->deleteReference(nodeId, referenceTypeId, ref->nodeId.nodeId, ref->isForward); + } + + browseReferences(); +} + void TmsServerObject::browseReferences() { OpcUaObject bd; diff --git a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp index 65af638..bc40e0c 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp @@ -47,10 +47,12 @@ void TmsServer::start() server->setPort(opcUaPort); server->prepare(); - tmsContext = std::make_shared(context); + tmsContext = std::make_shared(context, device); + auto signals = device.getSignals(); tmsDevice = std::make_unique(device, server, context, tmsContext); tmsDevice->registerOpcUaNode(OpcUaNodeId(NAMESPACE_DI, UA_DIID_DEVICESET)); + if (!versionStr.empty()) { OpcUaNodeId newNodeId(0); diff --git a/shared/libraries/opcuatms/opcuatms_server/src/tms_server_context.cpp b/shared/libraries/opcuatms/opcuatms_server/src/tms_server_context.cpp index fd82fe6..9ea9686 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/tms_server_context.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/tms_server_context.cpp @@ -1,9 +1,12 @@ #include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS -TmsServerContext::TmsServerContext(const ContextPtr& context) +TmsServerContext::TmsServerContext(const ContextPtr& context, const DevicePtr& rootDevice) : context(context) + , rootDevice(rootDevice) { this->context.getOnCoreEvent() += event(this, &TmsServerContext::coreEventCallback); } @@ -18,6 +21,24 @@ void TmsServerContext::registerComponent(const ComponentPtr& component, tms::Tms idToObjMap.insert(std::make_pair(component.getGlobalId(), obj.weak_from_this())); } +DevicePtr TmsServerContext::getRootDevice() +{ + return rootDevice; +} + +SignalPtr TmsServerContext::findSingal(const StringPtr& globalId) +{ + const auto& signals = rootDevice.getSignals(search::Recursive(search::Any())); + + for (const auto& signal : signals) + { + if (signal.getGlobalId() == globalId) + return signal; + } + + return nullptr; +} + void TmsServerContext::coreEventCallback(ComponentPtr& component, CoreEventArgsPtr& eventArgs) { if (const auto it = idToObjMap.find(component.getGlobalId()); it != idToObjMap.end()) diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.cpp index 6b56cb7..59a92ec 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.cpp @@ -5,7 +5,7 @@ void TmsServerObjectTest::SetUp() TmsObjectTest::SetUp(); ctx = daq::NullContext(); - tmsCtx = std::make_shared(ctx); + tmsCtx = std::make_shared(ctx, nullptr); } void TmsServerObjectTest::TearDown() diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp index f170951..6741d31 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp @@ -176,7 +176,7 @@ class TmsPropertyObjectAdvancedTest : public TmsObjectIntegrationTest { const auto context = Context(nullptr, logger, manager, nullptr); const auto serverProp = - std::make_shared(prop, server, context, std::make_shared(context)); + std::make_shared(prop, server, context, std::make_shared(context, nullptr)); const auto nodeId = serverProp->registerOpcUaNode(); const auto clientProp = TmsClientPropertyObject(Context(nullptr, logger, manager,nullptr), clientContext, nodeId); return {serverProp, clientProp}; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp index 88471dc..a9f55ad 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp @@ -283,7 +283,7 @@ class TMSAmplifierTest : public TmsObjectIntegrationTest { const auto context = Context(nullptr, logger, TypeManager(), nullptr); const auto serverProp = - std::make_shared(prop, server, context, std::make_shared(context)); + std::make_shared(prop, server, context, std::make_shared(context, nullptr)); const auto nodeId = serverProp->registerOpcUaNode(); const auto clientProp = TmsClientPropertyObject(Context(nullptr, logger, TypeManager(), nullptr), clientContext, nodeId); return {serverProp, clientProp}; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp index 7dace79..f72cc8c 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp @@ -68,7 +68,7 @@ class TmsFusionDevice : public TmsObjectIntegrationTest const auto logger = Logger(); const auto context = Context(nullptr, logger, TypeManager(), nullptr); const auto serverProp = - std::make_shared(prop, server, context, std::make_shared(context)); + std::make_shared(prop, server, context, std::make_shared(context, nullptr)); const auto nodeId = serverProp->registerOpcUaNode(); const auto clientProp = TmsClientPropertyObject(Context(nullptr, logger, TypeManager(), nullptr), clientContext, nodeId); return {serverProp, clientProp}; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index 3a96dd7..a9a2c96 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -318,3 +318,71 @@ TEST_F(TmsIntegrationTest, RemoveFunctionBlock) clientDevice.removeFunctionBlock(fb2); ASSERT_EQ(1, clientDevice.getFunctionBlocks().getCount()); } + +TEST_F(TmsIntegrationTest, InputPortConnect) +{ + InstancePtr device = createDevice(); + TmsServer tmsServer(device); + tmsServer.start(); + + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + auto clientDevice = tmsClient.connect(); + + auto inputPort = clientDevice.getChannelsRecursive().getItemAt(0).getInputPorts().getItemAt(0); + auto signal1 = clientDevice.getSignalsRecursive().getItemAt(0); + auto signal2 = clientDevice.getSignalsRecursive().getItemAt(1); + + SignalPtr portSignal = inputPort.getSignal(); + ASSERT_FALSE(portSignal.assigned()); + + inputPort.connect(signal1); + portSignal = inputPort.getSignal(); + ASSERT_TRUE(portSignal.assigned()); + ASSERT_EQ(portSignal, signal1); + + inputPort.connect(signal2); + portSignal = inputPort.getSignal(); + ASSERT_TRUE(portSignal.assigned()); + ASSERT_EQ(portSignal, signal2); + + inputPort.disconnect(); + portSignal = inputPort.getSignal(); + ASSERT_FALSE(portSignal.assigned()); +} + +TEST_F(TmsIntegrationTest, InputPortMultipleServers) +{ + auto StartServerDevice = [&](const InstancePtr& device, uint16_t port) + { + auto tmsServer = std::make_shared(device); + tmsServer->setOpcUaPort(port); + tmsServer->start(); + return tmsServer; + }; + + InstancePtr device1 = createDevice(); + InstancePtr device2 = createDevice(); + auto server1 = StartServerDevice(device1, 4001); + auto server2 = StartServerDevice(device1, 4002); + + InstancePtr instance = Instance(); + auto clientDevice1 = instance.addDevice("daq.opcua://127.0.0.1:4001"); + auto clientDevice2 = instance.addDevice("daq.opcua://127.0.0.1:4002"); + + auto inputPort1 = clientDevice1.getChannelsRecursive().getItemAt(0).getInputPorts().getItemAt(0); + auto inputPort2 = clientDevice2.getChannelsRecursive().getItemAt(0).getInputPorts().getItemAt(0); + auto signal1 = clientDevice1.getSignalsRecursive().getItemAt(0); + auto signal2 = clientDevice2.getSignalsRecursive().getItemAt(0); + SignalPtr portSignal; + + ASSERT_NO_THROW(inputPort1.connect(signal1)); + portSignal = inputPort1.getSignal(); + ASSERT_EQ(portSignal, signal1); + + ASSERT_NO_THROW(inputPort2.connect(signal2)); + portSignal = inputPort2.getSignal(); + ASSERT_EQ(portSignal, signal2); + + ASSERT_THROW(inputPort1.connect(signal2), NotFoundException); + ASSERT_THROW(inputPort2.connect(signal1), NotFoundException); +} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp index 7a1581f..d7ce2cb 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp @@ -21,7 +21,7 @@ void TmsObjectIntegrationTest::SetUp() ctx = daq::NullContext(logger); clientContext = std::make_shared(client, ctx); - serverContext = std::make_shared(ctx); + serverContext = std::make_shared(ctx, nullptr); } LastMessageLoggerSinkPrivatePtr TmsObjectIntegrationTest::getPrivateSink() From a91815056cf33dcc99b8f0dd519857b1ee8c7907 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Tue, 13 Feb 2024 10:17:54 +0100 Subject: [PATCH 077/217] Use findComponent() in TmsServerInputPort, add localId parameter to opcua input port connect() method --- .../src/objects/tms_client_device_impl.cpp | 8 +++--- .../opcuatms_server/tms_server_context.h | 3 ++- .../src/objects/tms_server_device.cpp | 16 +++++++---- .../src/objects/tms_server_input_port.cpp | 2 +- .../src/objects/tms_server_object.cpp | 2 ++ .../src/tms_server_context.cpp | 27 ++++++++++++------- 6 files changed, 37 insertions(+), 21 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index ac19927..711f85e 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -494,11 +494,11 @@ FunctionBlockPtr TmsClientDeviceImpl::onAddFunctionBlock(const StringPtr& typeId if (response->statusCode != UA_STATUSCODE_GOOD) throw OpcUaException(response->statusCode, "Failed to add function block"); - assert(response->outputArgumentsSize == 1); - const auto nodeId = OpcUaVariant(response->outputArguments[0]).toNodeId(); - const auto browseName = client->readBrowseName(nodeId); + assert(response->outputArgumentsSize == 2); + const auto fbNodeId = OpcUaVariant(response->outputArguments[0]).toNodeId(); + const auto localId = OpcUaVariant(response->outputArguments[1]).toString(); - auto clientFunctionBlock = TmsClientFunctionBlock(context, this->functionBlocks, browseName, clientContext, nodeId); + auto clientFunctionBlock = TmsClientFunctionBlock(context, this->functionBlocks, localId, clientContext, fbNodeId); addNestedFunctionBlock(clientFunctionBlock); return clientFunctionBlock; } diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server_context.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server_context.h index 500aaf7..9af07c0 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server_context.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server_context.h @@ -29,7 +29,7 @@ class TmsServerContext : public std::enable_shared_from_this ~TmsServerContext(); void registerComponent(const ComponentPtr& component, TmsServerObject& obj); DevicePtr getRootDevice(); - SignalPtr findSingal(const StringPtr& globalId); + ComponentPtr findComponent(const std::string& globalId); private: ContextPtr context; @@ -37,6 +37,7 @@ class TmsServerContext : public std::enable_shared_from_this std::unordered_map> idToObjMap; void coreEventCallback(ComponentPtr& component, CoreEventArgsPtr& eventArgs); + std::string toRelativeGlobalId(const std::string& globalId); }; using TmsServerContextPtr = std::shared_ptr; diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index 791d1c3..c726a42 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -250,7 +250,7 @@ void TmsServerDevice::createAddFunctionBlockNode(const OpcUaNodeId& parentId) AddMethodNodeParams params(nodeIdOut, parentId); params.referenceTypeId = OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT)); params.setBrowseName("Add"); - params.outputArgumentsSize = 1; + params.outputArgumentsSize = 2; params.outputArguments = (UA_Argument*) UA_Array_new(params.outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]); params.inputArgumentsSize = 2; params.inputArguments = (UA_Argument*) UA_Array_new(params.inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]); @@ -259,6 +259,10 @@ void TmsServerDevice::createAddFunctionBlockNode(const OpcUaNodeId& parentId) params.outputArguments[0].dataType = UA_TYPES[UA_TYPES_NODEID].typeId; params.outputArguments[0].valueRank = UA_VALUERANK_SCALAR; + params.outputArguments[1].name = UA_STRING_ALLOC("localId"); + params.outputArguments[1].dataType = UA_TYPES[UA_TYPES_STRING].typeId; + params.outputArguments[1].valueRank = UA_VALUERANK_SCALAR; + params.inputArguments[0].name = UA_STRING_ALLOC("typeId"); params.inputArguments[0].dataType = UA_TYPES[UA_TYPES_STRING].typeId; params.inputArguments[0].valueRank = UA_VALUERANK_SCALAR; @@ -294,7 +298,7 @@ void TmsServerDevice::createRemoveFunctionBlockNode(const OpcUaNodeId& parentId) params.inputArgumentsSize = 1; params.inputArguments = (UA_Argument*) UA_Array_new(params.inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]); - params.inputArguments[0].name = UA_STRING_ALLOC("browseName"); + params.inputArguments[0].name = UA_STRING_ALLOC("localId"); params.inputArguments[0].dataType = UA_TYPES[UA_TYPES_STRING].typeId; params.inputArguments[0].valueRank = UA_VALUERANK_SCALAR; @@ -362,15 +366,17 @@ void TmsServerDevice::onGetAvailableFunctionBlockTypes(const NodeEventManager::M void TmsServerDevice::onAddFunctionBlock(const NodeEventManager::MethodArgs& args) { assert(args.inputSize == 2); - assert(args.outputSize == 1); + assert(args.outputSize == 2); const auto fbTypeId = OpcUaVariant(args.input[0]).toString(); const auto configVariant = OpcUaVariant(args.input[1]); auto tmsFunctionBlock = addFunctionBlock(fbTypeId, configVariant); - auto outVariant = OpcUaVariant(tmsFunctionBlock->getNodeId()); - args.output[0] = outVariant.copyAndGetDetachedValue(); + auto nodeIdOut = OpcUaVariant(tmsFunctionBlock->getNodeId()); + auto localIdOut = OpcUaVariant(tmsFunctionBlock->getBrowseName().c_str()); + args.output[0] = nodeIdOut.copyAndGetDetachedValue(); + args.output[1] = localIdOut.copyAndGetDetachedValue(); } void TmsServerDevice::onRemoveFunctionBlock(const NodeEventManager::MethodArgs& args) diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp index 05eb919..f5abe09 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp @@ -98,7 +98,7 @@ void TmsServerInputPort::onConnectSignal(NodeEventManager::MethodArgs args) assert(args.inputSize == 1); const auto globalId = OpcUaVariant(args.input[0]).toString(); - const auto signal = tmsContext->findSingal(globalId); + SignalPtr signal = tmsContext->findComponent(globalId).asPtrOrNull(); if (!signal.assigned()) throw OpcUaException(UA_STATUSCODE_BADNOTFOUND, "Signal not found"); diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp index 0716a42..60b4aae 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp @@ -295,6 +295,8 @@ void TmsServerObject::deleteReferencesOfType(const opcua::OpcUaNodeId& reference void TmsServerObject::browseReferences() { + references.clear(); + OpcUaObject bd; bd->nodeId = nodeId.copyAndGetDetachedValue(); bd->resultMask = UA_BROWSERESULTMASK_ALL; diff --git a/shared/libraries/opcuatms/opcuatms_server/src/tms_server_context.cpp b/shared/libraries/opcuatms/opcuatms_server/src/tms_server_context.cpp index 9ea9686..9c55e66 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/tms_server_context.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/tms_server_context.cpp @@ -1,6 +1,7 @@ #include #include #include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -26,17 +27,10 @@ DevicePtr TmsServerContext::getRootDevice() return rootDevice; } -SignalPtr TmsServerContext::findSingal(const StringPtr& globalId) +ComponentPtr TmsServerContext::findComponent(const std::string& globalId) { - const auto& signals = rootDevice.getSignals(search::Recursive(search::Any())); - - for (const auto& signal : signals) - { - if (signal.getGlobalId() == globalId) - return signal; - } - - return nullptr; + std::string relativeGlobalId = toRelativeGlobalId(globalId); + return rootDevice.findComponent(relativeGlobalId); } void TmsServerContext::coreEventCallback(ComponentPtr& component, CoreEventArgsPtr& eventArgs) @@ -46,4 +40,17 @@ void TmsServerContext::coreEventCallback(ComponentPtr& component, CoreEventArgsP spt->onCoreEvent(eventArgs); } +std::string TmsServerContext::toRelativeGlobalId(const std::string& globalId) +{ + const std::string rootDeviceId = rootDevice.getGlobalId().toStdString(); + std::string relativeGlobalId = globalId; + + if (relativeGlobalId.rfind(rootDeviceId, 0) == 0) + relativeGlobalId = relativeGlobalId.substr(rootDeviceId.size()); + if (relativeGlobalId.rfind("/", 0) == 0) + relativeGlobalId = relativeGlobalId.substr(1); + + return relativeGlobalId; +} + END_NAMESPACE_OPENDAQ_OPCUA_TMS From b67e58219d04cdf9d7313eef0fae993587bb3731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Tue, 13 Feb 2024 11:56:55 +0100 Subject: [PATCH 078/217] Remove tms input port connect test as they are now covered by tms integration tests --- .../test_tms_input_port.cpp | 38 ------------------- .../test_tms_integration.cpp | 2 + 2 files changed, 2 insertions(+), 38 deletions(-) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp index 1dd29e1..9b137f7 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp @@ -115,44 +115,6 @@ TEST_F(TmsInputPortTest, MethodAcceptsSignal) EXPECT_THROW(clientInputPort.acceptsSignal(signal), daq::opcua::OpcUaClientCallNotAvailableException); } -TEST_F(TmsInputPortTest, MethodConnectSignal) -{ - SignalPtr signal = Signal(NullContext(), nullptr, "sig"); - - InputPortPtr daqServerInputPort = createInputPort("The Name", true); - auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), ctx, serverContext); - auto nodeId = serverInputPort.registerOpcUaNode(); - - InputPortPtr clientInputPort = TmsClientInputPort(NullContext(), nullptr, "inputPort", clientContext, nodeId); - - //TODO: More testing when the server in fact really can connect the signal - EXPECT_THROW(clientInputPort.connect(signal), daq::opcua::OpcUaClientCallNotAvailableException); -} - -TEST_F(TmsInputPortTest, MethodDisconnectSignal) -{ - InputPortPtr daqServerInputPort = createInputPort("The Name", true); - auto serverInputPort = TmsServerInputPort(daqServerInputPort, this->getServer(), ctx, serverContext); - auto nodeId = serverInputPort.registerOpcUaNode(); - - InputPortPtr clientInputPort = TmsClientInputPort(NullContext(), nullptr, "inputPort", clientContext, nodeId); - - //TODO: More testing when the server in fact really can disconnect the signal - EXPECT_THROW(clientInputPort.disconnect(), daq::opcua::OpcUaClientCallNotAvailableException); - //auto status = clientInputPort->disconnect(); - //ASSERT_EQ(status, OPENDAQ_SUCCESS); //TODO: Should fail when implemented on the server as nothing is connected - - //SignalPtr signal = Signal(nullptr); - //status = clientInputPort->connect(signal); - //ASSERT_EQ(status, OPENDAQ_SUCCESS); - - //status = clientInputPort->disconnect(); - //ASSERT_EQ(status, OPENDAQ_SUCCESS); - - //status = clientInputPort->disconnect(); - //ASSERT_EQ(status, OPENDAQ_SUCCESS); //TODO: Should fail when implemented on the server as nothing is connected -} - TEST_F(TmsInputPortTest, ConnectedToReference) { const auto logger = Logger(); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index a9a2c96..7a29066 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -335,6 +335,8 @@ TEST_F(TmsIntegrationTest, InputPortConnect) SignalPtr portSignal = inputPort.getSignal(); ASSERT_FALSE(portSignal.assigned()); + ASSERT_NO_THROW(inputPort.disconnect()); + inputPort.connect(signal1); portSignal = inputPort.getSignal(); ASSERT_TRUE(portSignal.assigned()); From dc19bc79108effca3e50c9c5173f3066b22bf741 Mon Sep 17 00:00:00 2001 From: Martin Kraner Date: Mon, 12 Feb 2024 10:44:08 +0100 Subject: [PATCH 079/217] Fix Visual Studio 2017 compilation --- .../opcuatms/tests/test_generic_struct_converter.cpp | 4 ++-- .../test_tms_function_property.cpp | 4 ++-- .../opcuatms_integration/test_tms_integration.cpp | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_generic_struct_converter.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_generic_struct_converter.cpp index 405ae03..d78c930 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/test_generic_struct_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/tests/test_generic_struct_converter.cpp @@ -193,7 +193,7 @@ TEST_F(GenericStructConverterTest, TestStructWithArrays1) const auto rule = static_cast(var->data); ASSERT_EQ(utils::ToStdString(rule->type), "list"); - ASSERT_EQ(rule->elementsSize, 2); + ASSERT_EQ(rule->elementsSize, 2u); const StructPtr convertedStructure = VariantConverter::ToDaqObject(var, context); ASSERT_EQ(structure, convertedStructure); @@ -211,7 +211,7 @@ TEST_F(GenericStructConverterTest, TestStructWithArrays2) const auto rule = static_cast(var->data); ASSERT_EQ(utils::ToStdString(rule->type), "list"); - ASSERT_EQ(rule->parametersSize, 2); + ASSERT_EQ(rule->parametersSize, 2u); auto keyVariant = OpcUaVariant(rule->parameters[0].key); ASSERT_EQ(VariantConverter::ToDaqObject(keyVariant, context), "foo"); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_property.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_property.cpp index 3db5326..8b7f32c 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_property.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_property.cpp @@ -280,7 +280,7 @@ TEST_F(TmsFunctionTest, UnsupportedArgumentInfo) obj.addProperty(FunctionProperty("proc8", ProcedureInfo(List(ArgumentInfo("undefined", ctUndefined))))); auto [serverObj, clientObj] = registerPropertyObject(obj); - ASSERT_EQ(clientObj.getAllProperties().getCount(), 0); + ASSERT_EQ(clientObj.getAllProperties().getCount(), 0u); } TEST_F(TmsFunctionTest, UnsupportedReturnType) @@ -295,7 +295,7 @@ TEST_F(TmsFunctionTest, UnsupportedReturnType) obj.addProperty(FunctionProperty("func7", FunctionInfo(ctComplexNumber))); auto [serverObj, clientObj] = registerPropertyObject(obj); - ASSERT_EQ(clientObj.getAllProperties().getCount(), 0); + ASSERT_EQ(clientObj.getAllProperties().getCount(), 0u); } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index 7a29066..1cc83a0 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -160,7 +160,7 @@ TEST_F(TmsIntegrationTest, InputsOutputs) ASSERT_EQ(device1.getChannels().getCount(), 0u); auto device1IoFolder = device1.getInputsOutputsFolder(); // io ASSERT_TRUE(device1IoFolder.assigned()); - ASSERT_EQ(device1IoFolder.getItems().getCount(), 0); + ASSERT_EQ(device1IoFolder.getItems().getCount(), 0u); auto device2 = devices.getItemAt(1); // device 2: 4 channels @@ -169,7 +169,7 @@ TEST_F(TmsIntegrationTest, InputsOutputs) auto device2IoFolder = device2.getInputsOutputsFolder(); // io: 1 channnel, 2 folders ASSERT_TRUE(device2IoFolder.assigned()); auto ioItems = device2IoFolder.getItems(); - ASSERT_EQ(ioItems.getCount(), 3); + ASSERT_EQ(ioItems.getCount(), 3u); ASSERT_EQ(ioItems[0].getName(), "mockch1"); // io/mockch1 ASSERT_TRUE(ioItems[0].asPtrOrNull().assigned()); ASSERT_TRUE(ioItems[0].asPtrOrNull().assigned()); @@ -179,7 +179,7 @@ TEST_F(TmsIntegrationTest, InputsOutputs) ASSERT_FALSE(ioItems[1].asPtrOrNull().assigned()); auto mockFolderAItems = ioItems[1].asPtr().getItems(); - ASSERT_EQ(mockFolderAItems.getCount(), 1); + ASSERT_EQ(mockFolderAItems.getCount(), 1u); ASSERT_EQ(mockFolderAItems[0].getName(), "mockchA1"); // io/mockfolderA/mockchA1 ASSERT_TRUE(mockFolderAItems[0].asPtrOrNull().assigned()); @@ -191,7 +191,7 @@ TEST_F(TmsIntegrationTest, InputsOutputs) ASSERT_FALSE(ioItems[2].asPtrOrNull().assigned()); auto mockFolderBItems = ioItems[2].asPtr().getItems(); - ASSERT_EQ(mockFolderBItems.getCount(), 2); + ASSERT_EQ(mockFolderBItems.getCount(), 2u); ASSERT_EQ(mockFolderBItems[0].getName(), "mockchB1"); // io/mockfolderB/mockchB1 ASSERT_TRUE(mockFolderBItems[0].asPtrOrNull().assigned()); @@ -208,11 +208,11 @@ TEST_F(TmsIntegrationTest, CustomComponents) auto devices = instance.getDevices(); ASSERT_EQ(devices.getCount(), 2u); - auto device2 = devices.getItemAt(1); + auto device2 = devices.getItemAt(1u); ASSERT_EQ(device2.getCustomComponents().getCount(), 2u); FolderPtr componentA = device2.getCustomComponents()[0]; - ASSERT_EQ(componentA.getItems().getCount(), 1); + ASSERT_EQ(componentA.getItems().getCount(), 1u); } TEST_F(TmsIntegrationTest, GetDomainSignal) From 423ff35e0e62c97c7a9c12131a7810b2c0ebe8f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?An=C5=BEe=20=C5=A0kerjanc?= Date: Wed, 14 Feb 2024 13:30:57 +0100 Subject: [PATCH 080/217] Fix first call of TmsClientDevice::GetTickSinceOrigin --- .../objects/tms_client_device_impl.h | 2 +- .../src/objects/tms_client_device_impl.cpp | 3 +++ .../opcuatms_integration/test_tms_device.cpp | 16 ++++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h index 2cad354..e44fb19 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h @@ -68,7 +68,7 @@ class TmsClientDeviceImpl : public TmsClientComponentBaseImplunit.quantity)); else domainUnit = Unit(""); + + ticksSinceOrigin = deviceDomain->ticksSinceOrigin; + timeDomainFetched = true; } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp index d603568..8e9f4cb 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp @@ -218,6 +218,22 @@ TEST_F(TmsDeviceTest, DeviceInfo) ASSERT_EQ(clientDeviceInfo.getPropertyValue("custom_int"), 1); } +TEST_F(TmsDeviceTest, DeviceGetTicksSinceOrigin) +{ + auto ctx = NullContext(); + DevicePtr serverDevice = createDevice(); + + auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); + auto nodeId = serverTmsDevice.registerOpcUaNode(); + + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + auto clientSubDevices = clientDevice.getDevices(); + auto clientSubDevice = clientSubDevices[1]; + + auto ticksSinceOrigin = clientSubDevice.asPtr(true).getTicksSinceOrigin(); + ASSERT_EQ(ticksSinceOrigin, 789); +} + TEST_F(TmsDeviceTest, DeviceDomain) { auto ctx = NullContext(); From 808411dbf235eaacd2119bf53dc6bd182b62d261 Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Wed, 21 Feb 2024 12:32:59 +0100 Subject: [PATCH 081/217] implement logic for signal.setPublic(...) --- .../src/objects/tms_server_device.cpp | 7 +++++-- .../src/objects/tms_server_function_block.cpp | 7 +++++-- .../tests/opcuatms_integration/test_tms_device.cpp | 3 ++- .../test_tms_function_block.cpp | 14 ++++++++++++-- .../opcuatms_integration/test_tms_integration.cpp | 3 ++- 5 files changed, 26 insertions(+), 8 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index c726a42..76b907d 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -464,8 +464,11 @@ void TmsServerDevice::addChildNodes() numberInList = 0; for (const auto& signal : object.getSignals(search::Any())) { - auto tmsSignal = registerTmsObjectOrAddReference(signalsNodeId, signal, numberInList++); - signals.push_back(std::move(tmsSignal)); + if (signal.getPublic()) + { + auto tmsSignal = registerTmsObjectOrAddReference(signalsNodeId, signal, numberInList++); + signals.push_back(std::move(tmsSignal)); + } } auto inputsOutputsNodeId = getChildNodeId("IO"); diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp index 2c4b49d..10d72ba 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp @@ -53,8 +53,11 @@ void TmsServerFunctionBlock::addChildNodes() uint32_t numberInList = 0; for (const auto& signal : this->object.getSignals(search::Any())) { - auto tmsSignal = this->template registerTmsObjectOrAddReference(signalsNodeId, signal, numberInList++); - signals.push_back(std::move(tmsSignal)); + if (signal.getPublic()) + { + auto tmsSignal = this->template registerTmsObjectOrAddReference(signalsNodeId, signal, numberInList++); + signals.push_back(std::move(tmsSignal)); + } } auto inputPortsNodeId = this->getChildNodeId("IP"); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp index 8e9f4cb..4f9e68c 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp @@ -105,7 +105,8 @@ TEST_F(TmsDeviceTest, GetSignals) } ASSERT_NO_THROW(signals = clientDevice.getSignals(search::Recursive(search::Visible()))); - ASSERT_EQ(signals.getCount(), serverDevice.getSignals(search::Recursive(search::Visible())).getCount()); + // one private signal in MockFunctionBlockImpl. and one in MockPhysicalDeviceImpl + ASSERT_EQ(signals.getCount(), serverDevice.getSignals(search::Recursive(search::Visible())).getCount() - 2); } TEST_F(TmsDeviceTest, GetChannels) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp index 29802e6..f1af544 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp @@ -144,8 +144,18 @@ TEST_F(TmsFunctionBlockTest, SignalCheckGlobalId) ListPtr serverSignals = serverFunctionBlock.getSignals(); ListPtr clientSignals = clientFunctionBlock.getSignals(); - for (size_t i = 0; i < serverSignals.getCount(); i++) - ASSERT_EQ(serverSignals[i].getGlobalId(), clientSignals[i].getGlobalId()); + // one private signal in MockPhysicalDeviceImpl + ASSERT_EQ(clientSignals.getCount(), serverSignals.getCount() - 1); + + std::vector serverSignalsName; + for (const auto & signal : serverSignals) + serverSignalsName.push_back(signal.getGlobalId()); + + for (const auto & signal : clientSignals) + { + auto it = find(serverSignalsName.begin(), serverSignalsName.end(), signal.getGlobalId().toStdString()); + ASSERT_NE(it, serverSignalsName.end()); + } } TEST_F(TmsFunctionBlockTest, MethodGetStatusSignal) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index 1cc83a0..cb380d4 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -129,7 +129,8 @@ TEST_F(TmsIntegrationTest, GetSignals) ListPtr signals; ASSERT_NO_THROW(signals = clientDevice.getSignals(search::Recursive(search::Visible()))); - ASSERT_EQ(signals.getCount(), device.getSignals(search::Recursive(search::Visible())).getCount()); + // one private signal in MockFunctionBlockImpl. and one in MockPhysicalDeviceImpl + ASSERT_EQ(signals.getCount(), device.getSignals(search::Recursive(search::Visible())).getCount() - 2); ASSERT_NO_THROW(signals = clientDevice.getSignals()); ASSERT_EQ(signals.getCount(), 0u); From 9cd10d16648d3b8a8c2aabbafb2189ee8e5454ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Fri, 16 Feb 2024 12:47:29 +0100 Subject: [PATCH 082/217] Add support for adding function blocks with config object --- .../property_object_conversion_utils.h | 1 + .../property_object_conversion_utils.cpp | 11 ++ .../test_property_object_conversion_utils.cpp | 34 +++++ .../tms_client_function_block_type_factory.h | 30 ++++ .../tms_client_function_block_type_impl.h | 42 ++++++ .../opcuatms_client/src/CMakeLists.txt | 4 + .../src/objects/tms_client_device_impl.cpp | 34 ++--- .../tms_client_function_block_type_impl.cpp | 59 ++++++++ .../objects/tms_server_device.h | 7 +- .../objects/tms_server_function_block_type.h | 56 +++++++ .../opcuatms_server/src/CMakeLists.txt | 2 + .../src/objects/tms_server_device.cpp | 60 +++----- .../tms_server_function_block_type.cpp | 71 +++++++++ .../src/objects/tms_server_variable.cpp | 5 +- .../tests/opcuatms_integration/CMakeLists.txt | 1 + .../test_tms_function_block_type.cpp | 138 ++++++++++++++++++ .../test_tms_integration.cpp | 13 +- 17 files changed, 503 insertions(+), 65 deletions(-) create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_factory.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_impl.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_type_impl.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block_type.h create mode 100644 shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block_type.cpp create mode 100644 shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block_type.cpp diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/property_object_conversion_utils.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/property_object_conversion_utils.h index cb9d7dc..bc2eb19 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/property_object_conversion_utils.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/property_object_conversion_utils.h @@ -26,6 +26,7 @@ class PropertyObjectConversionUtils public: static OpcUaVariant ToDictVariant(const PropertyObjectPtr& obj); static void ToPropertyObject(const OpcUaVariant& variant, PropertyObjectPtr& objOut); + static PropertyObjectPtr ClonePropertyObject(const PropertyObjectPtr& obj); }; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/property_object_conversion_utils.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/property_object_conversion_utils.cpp index 82791fe..432198a 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/property_object_conversion_utils.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/property_object_conversion_utils.cpp @@ -34,4 +34,15 @@ void PropertyObjectConversionUtils::ToPropertyObject(const OpcUaVariant& variant objOut.setPropertyValue(entry.first, entry.second); } +PropertyObjectPtr PropertyObjectConversionUtils::ClonePropertyObject(const PropertyObjectPtr& obj) +{ + // This is a workaround until PropertyObject implemnts IClonable. + + auto serializer = JsonSerializer(); + auto deserializer = JsonDeserializer(); + obj.serialize(serializer); + const auto clone = deserializer.deserialize(serializer.getOutput()); + return clone; +} + END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_property_object_conversion_utils.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_property_object_conversion_utils.cpp index e10cbc2..9baab4d 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/test_property_object_conversion_utils.cpp +++ b/shared/libraries/opcuatms/opcuatms/tests/test_property_object_conversion_utils.cpp @@ -53,3 +53,37 @@ TEST_F(PropertyObjectConversionUtilsTest, EmptyObject) PropertyObjectConversionUtils::ToPropertyObject(variant, objOut); ASSERT_TRUE(TestComparators::PropertyObjectEquals(obj, objOut)); } + +TEST_F(PropertyObjectConversionUtilsTest, CloneDefault) +{ + auto obj = CreateTestPropertyObject(); + auto clone = PropertyObjectConversionUtils::ClonePropertyObject(obj); + + ASSERT_TRUE(TestComparators::PropertyObjectEquals(obj, clone)); +} + +TEST_F(PropertyObjectConversionUtilsTest, Clone) +{ + auto obj = CreateTestPropertyObject(); + obj.setPropertyValue("name", "Jovanka"); + obj.setPropertyValue("age", 99); + obj.setPropertyValue("weight", 60.5); + obj.setPropertyValue("isTheBest", true); + + auto clone = PropertyObjectConversionUtils::ClonePropertyObject(obj); + + ASSERT_TRUE(TestComparators::PropertyObjectEquals(obj, clone)); +} + +TEST_F(PropertyObjectConversionUtilsTest, DISABLED_CloneList) +{ + // Serializer fails to serialize default empty list property correctly. + + auto obj = CreateTestPropertyObject(); + obj.addProperty(ListProperty("list", List())); + obj.setPropertyValue("list", List(1, 2, 3)); + + auto clone = PropertyObjectConversionUtils::ClonePropertyObject(obj); + + ASSERT_TRUE(TestComparators::PropertyObjectEquals(obj, clone)); +} diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_factory.h new file mode 100644 index 0000000..d767cff --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_factory.h @@ -0,0 +1,30 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +inline FunctionBlockTypePtr TmsClientFunctionBlockType(const ContextPtr& context, + const TmsClientContextPtr& tmsContext, + const OpcUaNodeId& nodeId) +{ + FunctionBlockTypePtr obj(createWithImplementation(context, tmsContext, nodeId)); + return obj; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_impl.h new file mode 100644 index 0000000..be20054 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_impl.h @@ -0,0 +1,42 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class TmsClientFunctionBlockTypeImpl final : public TmsClientObjectImpl, public FunctionBlockTypeImpl +{ +public: + explicit TmsClientFunctionBlockTypeImpl(const ContextPtr& context, + const TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId); + // IFunctionBlockType + ErrCode INTERFACE_FUNC getId(IString** id) override; + ErrCode INTERFACE_FUNC getName(IString** name) override; + ErrCode INTERFACE_FUNC getDescription(IString** description) override; + ErrCode INTERFACE_FUNC createDefaultConfig(IPropertyObject** defaultConfig) override; + +private: + void readAttributes(); + + FunctionBlockTypePtr type; + PropertyObjectPtr defaultConfig; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt index e302639..78458ef 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt @@ -24,6 +24,9 @@ set(SRC_Objects_Headers ${OBJECT_SRC_DIR}/tms_client_object_impl.h ${OBJECT_SRC_DIR}/tms_client_function_block_impl.h ${OBJECT_SRC_DIR}/tms_client_function_block_factory.h + ${OBJECT_SRC_DIR}/tms_client_function_block_type_impl.h + ${OBJECT_SRC_DIR}/tms_client_function_block_type_factory.h + ${OBJECT_SRC_DIR}/tms_client_channel_impl.h ${OBJECT_SRC_DIR}/tms_client_channel_factory.h @@ -78,6 +81,7 @@ set(SRC_Objects ${OBJECT_SRC_DIR}/tms_client_object_impl.cpp ${OBJECT_SRC_DIR}/tms_client_function_impl.cpp ${OBJECT_SRC_DIR}/tms_client_procedure_impl.cpp ${OBJECT_SRC_DIR}/tms_client_tags_impl.cpp + ${OBJECT_SRC_DIR}/tms_client_function_block_type_impl.cpp ) set(SRC_PublicHeaders ${SRC_PublicHeaders} ${SRC_Objects_Headers}) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 85790c3..ccadb99 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -21,6 +21,7 @@ #include "opcuatms/exceptions.h" #include "opcuatms/converters/list_conversion_utils.h" #include "opcuatms/converters/property_object_conversion_utils.h" +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS using namespace daq::opcua; @@ -450,29 +451,26 @@ void TmsClientDeviceImpl::findAndCreateCustomComponents() DictPtr TmsClientDeviceImpl::onGetAvailableFunctionBlockTypes() { - // todo: migrate to AvailableTypes folder node + auto browser = clientContext->getReferenceBrowser(); - const auto fbFolderNodeId = getNodeId("FB"); - const auto methodNodeId = clientContext->getReferenceBrowser()->getChildNodeId(fbFolderNodeId, "_TmpGetAvailableFunctionBlockTypes"); + const auto fbFolderNodeId = browser->getChildNodeId(nodeId, "FB"); + const auto availableTypesId = browser->getChildNodeId(fbFolderNodeId, "AvailableTypes"); - auto request = OpcUaCallMethodRequest(); - request->objectId = fbFolderNodeId.copyAndGetDetachedValue(); - request->methodId = methodNodeId.copyAndGetDetachedValue(); + auto filter = BrowseFilter(); + filter.direction = UA_BROWSEDIRECTION_FORWARD; + filter.referenceTypeId = OpcUaNodeId(UA_NS0ID_HASPROPERTY); + filter.nodeClass = UA_NODECLASS_VARIABLE; - const auto response = this->client->callMethod(request); + auto fbTypesReferences = browser->browseFiltered(availableTypesId, filter); + auto types = Dict(); - if (response->statusCode != UA_STATUSCODE_GOOD) - throw OpcUaException(response->statusCode, "Failed to get available function block types"); - - assert(response->outputArgumentsSize == 1); - const auto outvariant = OpcUaVariant(response->outputArguments[0]); - const auto typeList = ListConversionUtils::ExtensionObjectVariantToList(outvariant); - - auto dict = Dict(); - for (const auto& type : typeList) - dict.set(type.getId(), type); + for (const auto& [refNodeId, ref] : fbTypesReferences.byNodeId) + { + auto tmsFbType = TmsClientFunctionBlockType(daqContext, clientContext, refNodeId); + types.set(tmsFbType.getId(), tmsFbType); + } - return dict; + return types; } FunctionBlockPtr TmsClientDeviceImpl::onAddFunctionBlock(const StringPtr& typeId, const PropertyObjectPtr& config) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_type_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_type_impl.cpp new file mode 100644 index 0000000..a761484 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_type_impl.cpp @@ -0,0 +1,59 @@ +#include +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +TmsClientFunctionBlockTypeImpl::TmsClientFunctionBlockTypeImpl(const ContextPtr& context, + const TmsClientContextPtr& tmsContext, + const opcua::OpcUaNodeId& nodeId) + : TmsClientObjectImpl(context, tmsContext, nodeId) + , FunctionBlockTypeImpl("", "", "", nullptr) +{ + readAttributes(); +} + +ErrCode TmsClientFunctionBlockTypeImpl::getId(IString** id) +{ + OPENDAQ_PARAM_NOT_NULL(id); + + *id = type.getId().detach(); + return OPENDAQ_SUCCESS; +} + +ErrCode TmsClientFunctionBlockTypeImpl::getName(IString** name) +{ + OPENDAQ_PARAM_NOT_NULL(name); + + *name = type.getName().detach(); + return OPENDAQ_SUCCESS; +} + +ErrCode TmsClientFunctionBlockTypeImpl::getDescription(IString** description) +{ + OPENDAQ_PARAM_NOT_NULL(description); + + *description = type.getDescription().detach(); + return OPENDAQ_SUCCESS; +} + +ErrCode TmsClientFunctionBlockTypeImpl::createDefaultConfig(IPropertyObject** defaultConfig) +{ + OPENDAQ_PARAM_NOT_NULL(defaultConfig); + + auto clone = PropertyObjectConversionUtils::ClonePropertyObject(this->defaultConfig); + *defaultConfig = clone.detach(); + return OPENDAQ_SUCCESS; +} + +void TmsClientFunctionBlockTypeImpl::readAttributes() +{ + const auto value = client->readValue(nodeId); + this->type = VariantConverter::ToDaqObject(value); + + const auto defaultConfigId = getNodeId("DefaultConfig"); + this->defaultConfig = TmsClientPropertyObject(daqContext, clientContext, defaultConfigId); +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h index dcf1591..fc0f212 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h @@ -21,6 +21,8 @@ #include "opcuatms_server/objects/tms_server_folder.h" #include "opcuatms_server/objects/tms_server_component.h" #include "opcuatms_server/objects/tms_server_property_object.h" +#include "opcuatms_server/objects/tms_server_function_block_type.h" + #include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -46,10 +48,10 @@ class TmsServerDevice : public TmsServerComponent opcua::OpcUaNodeId getTmsTypeId() override; void populateDeviceInfo(); void populateStreamingOptions(); - void addFbMethodNodes(); + void addFunctionBlockFolderNodes(); + void createFunctionBlockTypesFolder(const OpcUaNodeId& parentId); void createAddFunctionBlockNode(const OpcUaNodeId& parentId); void createRemoveFunctionBlockNode(const OpcUaNodeId& parentId); - void createGetAvailableFunctionBlockTypesNode(const OpcUaNodeId& parentId); void onGetAvailableFunctionBlockTypes(const NodeEventManager::MethodArgs& args); void onAddFunctionBlock(const NodeEventManager::MethodArgs& args); void onRemoveFunctionBlock(const NodeEventManager::MethodArgs& args); @@ -65,6 +67,7 @@ class TmsServerDevice : public TmsServerComponent std::list folders; std::list components; std::list streamingOptions; + std::list functionBlockTypes; }; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block_type.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block_type.h new file mode 100644 index 0000000..d97f2bd --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block_type.h @@ -0,0 +1,56 @@ +/* + * Copyright 2022-2023 Blueberry d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class TmsServerFunctionBlockType; +using TmsServerFunctionBlockTypePtr = std::shared_ptr; + +class TmsServerFunctionBlockType : public TmsServerVariable +{ +public: + using Super = TmsServerVariable; + + TmsServerFunctionBlockType(const FunctionBlockTypePtr& object, + const OpcUaServerPtr& server, + const ContextPtr& context, + const TmsServerContextPtr& tmsContext); + + std::string getBrowseName() override; + std::string getDisplayName() override; + std::string getDescription() override; + +protected: + OpcUaNodeId getTmsTypeId() override; + void addChildNodes() override; + void configureVariableNodeAttributes(OpcUaObject& attr) override; + +private: + void addIdNode(); + void addNameNode(); + void addDescriptionNode(); + void addDefaultConfigNode(); + + TmsServerPropertyObjectPtr tmsDefaultConfig; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_server/src/CMakeLists.txt index 00568a4..887553e 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_server/src/CMakeLists.txt @@ -27,6 +27,7 @@ set(SRC_Objects_Headers ${OBJECT_SRC_DIR}/tms_server_object.h ${OBJECT_SRC_DIR}/tms_server_component.h ${OBJECT_SRC_DIR}/tms_server_property.h ${OBJECT_SRC_DIR}/tms_server_eval_value.h + ${OBJECT_SRC_DIR}/tms_server_function_block_type.h ) set(SRC_Objects ${OBJECT_SRC_DIR}/tms_server_object.cpp @@ -41,6 +42,7 @@ set(SRC_Objects ${OBJECT_SRC_DIR}/tms_server_object.cpp ${OBJECT_SRC_DIR}/tms_server_component.cpp ${OBJECT_SRC_DIR}/tms_server_property.cpp ${OBJECT_SRC_DIR}/tms_server_eval_value.cpp + ${OBJECT_SRC_DIR}/tms_server_function_block_type.cpp ) set(SRC_PublicHeaders ${SRC_PublicHeaders} ${SRC_Objects_Headers}) diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index 76b907d..756b03c 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -16,6 +16,7 @@ #include #include #include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -235,15 +236,34 @@ void TmsServerDevice::populateStreamingOptions() } } -void TmsServerDevice::addFbMethodNodes() +void TmsServerDevice::addFunctionBlockFolderNodes() { auto fbNodeId = getChildNodeId("FB"); - createGetAvailableFunctionBlockTypesNode(fbNodeId); + createFunctionBlockTypesFolder(fbNodeId); createAddFunctionBlockNode(fbNodeId); createRemoveFunctionBlockNode(fbNodeId); } +void TmsServerDevice::createFunctionBlockTypesFolder(const OpcUaNodeId& parentId) +{ + OpcUaNodeId nodeIdOut; + AddObjectNodeParams params(nodeIdOut, parentId); + params.referenceTypeId = OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT)); + params.typeDefinition = OpcUaNodeId(UA_NS0ID_FOLDERTYPE); + params.setBrowseName("AvailableTypes"); + + const auto typesFolderId = server->addObjectNode(params); + const auto fbTypes = this->object.getAvailableFunctionBlockTypes().getValueList(); + + for (const auto& fbType : fbTypes) + { + auto tmsFbType = std::make_shared(fbType, server, daqContext, tmsContext); + tmsFbType->registerOpcUaNode(typesFolderId); + functionBlockTypes.push_back(tmsFbType); + } +} + void TmsServerDevice::createAddFunctionBlockNode(const OpcUaNodeId& parentId) { OpcUaNodeId nodeIdOut; @@ -320,40 +340,6 @@ void TmsServerDevice::createRemoveFunctionBlockNode(const OpcUaNodeId& parentId) addEvent(methodNodeId)->onMethodCall(callback); } -void TmsServerDevice::createGetAvailableFunctionBlockTypesNode(const OpcUaNodeId& parentId) -{ - // todo: migrate to AvailableTypes folder node - - OpcUaNodeId nodeIdOut; - AddMethodNodeParams params(nodeIdOut, parentId); - params.referenceTypeId = OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT)); - params.setBrowseName("_TmpGetAvailableFunctionBlockTypes"); - params.inputArgumentsSize = 0; - params.outputArgumentsSize = 1; - params.outputArguments = (UA_Argument*) UA_Array_new(params.outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]); - - params.outputArguments[0].name = UA_STRING_ALLOC("availableTypes"); - params.outputArguments[0].dataType = UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_FUNCTIONBLOCKINFOSTRUCTURE].typeId; - params.outputArguments[0].valueRank = UA_VALUERANK_ONE_DIMENSION; - - auto methodNodeId = server->addMethodNode(params); - - auto callback = [this](NodeEventManager::MethodArgs args) - { - try - { - onGetAvailableFunctionBlockTypes(args); - return OPENDAQ_SUCCESS; - } - catch (const OpcUaException& e) - { - return e.getStatusCode(); - } - }; - - addEvent(methodNodeId)->onMethodCall(callback); -} - void TmsServerDevice::onGetAvailableFunctionBlockTypes(const NodeEventManager::MethodArgs& args) { assert(args.outputSize == 1); @@ -498,7 +484,7 @@ void TmsServerDevice::addChildNodes() } } - addFbMethodNodes(); + addFunctionBlockFolderNodes(); Super::addChildNodes(); } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block_type.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block_type.cpp new file mode 100644 index 0000000..fb93763 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block_type.cpp @@ -0,0 +1,71 @@ +#include +#include +#include +#include + +using namespace daq::opcua; + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +TmsServerFunctionBlockType::TmsServerFunctionBlockType(const FunctionBlockTypePtr& object, + const OpcUaServerPtr& server, + const ContextPtr& context, + const TmsServerContextPtr& tmsContext) + : Super(object, server, context, tmsContext) +{ +} + +std::string TmsServerFunctionBlockType::getBrowseName() +{ + return object.getId(); +} + +std::string TmsServerFunctionBlockType::getDisplayName() +{ + return object.getId(); +} + +std::string TmsServerFunctionBlockType::getDescription() +{ + return object.getDescription(); +} + +OpcUaNodeId TmsServerFunctionBlockType::getTmsTypeId() +{ + return OpcUaNodeId(UA_NS0ID_BASEDATAVARIABLETYPE); +} + +void TmsServerFunctionBlockType::addChildNodes() +{ + Super::addChildNodes(); + addDefaultConfigNode(); +} + +void TmsServerFunctionBlockType::configureVariableNodeAttributes(OpcUaObject& attr) +{ + Super::configureVariableNodeAttributes(attr); + + attr->dataType = UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_FUNCTIONBLOCKINFOSTRUCTURE].typeId; + attr->accessLevel = UA_ACCESSLEVELMASK_READ; + attr->writeMask = 0; + + const auto defaultValue = VariantConverter::ToVariant(object); + attr->value = defaultValue.copyAndGetDetachedValue(); +} + +void TmsServerFunctionBlockType::addDefaultConfigNode() +{ + auto defaultConfig = object.createDefaultConfig(); + + if (!defaultConfig.assigned()) + return; + + if (!defaultConfig.isFrozen()) + defaultConfig.freeze(); + + tmsDefaultConfig = std::make_shared(defaultConfig, server, daqContext, tmsContext, "DefaultConfig"); + tmsDefaultConfig->registerOpcUaNode(nodeId); +} + + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp index 97b3375..32b4407 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp @@ -1,6 +1,7 @@ #include "opcuatms_server/objects/tms_server_variable.h" #include "coreobjects/eval_value_ptr.h" #include "open62541/server.h" +#include "opendaq/function_block_type_ptr.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -34,7 +35,8 @@ opcua::OpcUaNodeId TmsServerVariable::createNode(const opcua::OpcUaNod template void TmsServerVariable::configureVariableNodeAttributes(opcua::OpcUaObject& attr) { - const auto dataTypeId = this->server->readDataType(this->getTmsTypeId()); + const auto tmsTypeId = this->getTmsTypeId(); + const auto dataTypeId = this->server->readDataType(tmsTypeId); attr->dataType = *dataTypeId; attr->accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; @@ -44,5 +46,6 @@ void TmsServerVariable::configureVariableNodeAttributes(opcua::OpcUaOb template class TmsServerVariable>; template class TmsServerVariable; template class TmsServerVariable; +template class TmsServerVariable; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt b/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt index 29fe72e..cf5d37f 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt @@ -18,6 +18,7 @@ set(TEST_SOURCES main.cpp test_tms_folder.cpp test_tms_function_property.cpp test_tms_fusion_device.cpp + test_tms_function_block_type.cpp ) if (OPENDAQ_ENABLE_WEBSOCKET_STREAMING) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block_type.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block_type.cpp new file mode 100644 index 0000000..68c1777 --- /dev/null +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block_type.cpp @@ -0,0 +1,138 @@ +#include "gtest/gtest.h" +#include "tms_object_integration_test.h" +#include +#include +#include +#include +#include +#include + +using namespace daq; +using namespace opcua::tms; +using namespace opcua; + +class TmsFunctionBlockTypeTest : public TmsObjectIntegrationTest +{ +public: + FunctionBlockTypePtr createFunctionBlockType() + { + auto createDefaultConfig = [](IBaseObject* /*params*/, IBaseObject** result) + { + auto config = PropertyObject(); + config.addProperty(IntProperty("port", 1000)); + config.addProperty(StringProperty("name", "vlado")); + config.addProperty(ListProperty("scaling", List(1.0, 2.0, 3.0))); + + *result = config.detach(); + return OPENDAQ_SUCCESS; + }; + + return FunctionBlockType("ref_fb", "Reference function block", "Description", createDefaultConfig); + } +}; + +TEST_F(TmsFunctionBlockTypeTest, Create) +{ + auto fbType = createFunctionBlockType(); + + auto serverFbType = std::make_shared(fbType, server, ctx, serverContext); + auto nodeId = serverFbType->registerOpcUaNode(); + ASSERT_TRUE(server->nodeExists(nodeId)); + + auto clientFbType = TmsClientFunctionBlockType(ctx, clientContext, nodeId); + ASSERT_TRUE(clientFbType.assigned()); +} + +TEST_F(TmsFunctionBlockTypeTest, Values) +{ + auto fbType = createFunctionBlockType(); + auto serverFbType = std::make_shared(fbType, server, ctx, serverContext); + auto nodeId = serverFbType->registerOpcUaNode(); + auto clientFbType = TmsClientFunctionBlockType(ctx, clientContext, nodeId); + + ASSERT_EQ(fbType.getId(), clientFbType.getId()); + ASSERT_EQ(fbType.getName(), clientFbType.getName()); + ASSERT_EQ(fbType.getDescription(), clientFbType.getDescription()); + + auto serverConfig = fbType.createDefaultConfig(); + auto clientConfig = clientFbType.createDefaultConfig(); + ASSERT_TRUE(TestComparators::PropertyObjectEquals(serverConfig, clientConfig)); + + ASSERT_TRUE(TestComparators::FunctionBlockTypeEquals(fbType, clientFbType)); +} + +TEST_F(TmsFunctionBlockTypeTest, NullConfig) +{ + auto fbType = FunctionBlockType("id", "", "", nullptr); + auto serverFbType = std::make_shared(fbType, server, ctx, serverContext); + auto nodeId = serverFbType->registerOpcUaNode(); + auto clientFbType = TmsClientFunctionBlockType(ctx, clientContext, nodeId); + + ASSERT_TRUE(TestComparators::FunctionBlockTypeEquals(fbType, clientFbType)); +} + +TEST_F(TmsFunctionBlockTypeTest, CloneConfig) +{ + auto fbType = createFunctionBlockType(); + auto serverFbType = std::make_shared(fbType, server, ctx, serverContext); + auto nodeId = serverFbType->registerOpcUaNode(); + auto clientFbType = TmsClientFunctionBlockType(ctx, clientContext, nodeId); + + auto clientConfig1 = clientFbType.createDefaultConfig(); + auto clientConfig2 = clientFbType.createDefaultConfig(); + clientConfig1.setPropertyValue("name", "name1"); + clientConfig2.setPropertyValue("name", "name2"); + + ASSERT_EQ(clientConfig1.getPropertyValue("name"), "name1"); + ASSERT_EQ(clientConfig2.getPropertyValue("name"), "name2"); +} + +TEST_F(TmsFunctionBlockTypeTest, ReadOnly) +{ + auto fbType = createFunctionBlockType(); + auto serverFbType = std::make_shared(fbType, server, ctx, serverContext); + auto nodeId = serverFbType->registerOpcUaNode(); + auto clientFbType = TmsClientFunctionBlockType(ctx, clientContext, nodeId); + + auto fbTypeVariant = VariantConverter::ToVariant(fbType); + ASSERT_THROW(client->writeValue(nodeId, fbTypeVariant), OpcUaException); + ASSERT_THROW(client->writeDisplayName(nodeId, "Display name"), OpcUaException); + ASSERT_THROW(client->writeDescription(nodeId, "Description"), OpcUaException); + + auto browser = CachedReferenceBrowser(client); + const auto defaultConfigId = browser.getChildNodeId(nodeId, "DefaultConfig"); + const auto nameId = browser.getChildNodeId(defaultConfigId, "name"); + const auto portId = browser.getChildNodeId(defaultConfigId, "port"); + const auto scalingId = browser.getChildNodeId(defaultConfigId, "scaling"); + + ASSERT_THROW(client->writeValue(nameId, OpcUaVariant("value")), OpcUaException); + ASSERT_THROW(client->writeValue(portId, OpcUaVariant(1001)), OpcUaException); + ASSERT_THROW(client->writeValue(scalingId, OpcUaVariant()), OpcUaException); +} + +TEST_F(TmsFunctionBlockTypeTest, DISABLED_NonDefaultValues) +{ + // This should work, but it doesnt, because of an error in client property object. + + auto createDefaultConfig = [](IBaseObject* /*params*/, IBaseObject** result) + { + auto config = PropertyObject(); + config.addProperty(IntProperty("port", 0)); + config.addProperty(StringProperty("name", "")); + + config.setPropertyValue("port", 1000); + config.setPropertyValue("name", "vlado"); + + *result = config.detach(); + return OPENDAQ_SUCCESS; + }; + + auto fbType = FunctionBlockType("ref_fb", "Reference function block", "Description", createDefaultConfig); + + auto serverFbType = std::make_shared(fbType, server, ctx, serverContext); + auto nodeId = serverFbType->registerOpcUaNode(); + auto clientFbType = TmsClientFunctionBlockType(ctx, clientContext, nodeId); + + ASSERT_TRUE(TestComparators::FunctionBlockTypeEquals(fbType, clientFbType)); +} + diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index cb380d4..99e4fe4 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -251,8 +251,10 @@ TEST_F(TmsIntegrationTest, GetAvailableFunctionBlockTypes) auto clientDevice = tmsClient.connect(); const auto clientFbTypes = clientDevice.getAvailableFunctionBlockTypes(); - - ASSERT_TRUE(TestComparators::FunctionBlockTypeDictEquals(serverFbTypes, clientFbTypes)); + + ASSERT_EQ(serverFbTypes.getCount(), 1u); + ASSERT_EQ(serverFbTypes.getCount(), clientFbTypes.getCount()); + ASSERT_TRUE(TestComparators::FunctionBlockTypeEquals(serverFbTypes.get("mock_fb_uid"), clientFbTypes.get("mock_fb_uid"))); } TEST_F(TmsIntegrationTest, AddFunctionBlock) @@ -275,10 +277,8 @@ TEST_F(TmsIntegrationTest, AddFunctionBlock) ASSERT_EQ(3, clientDevice.getFunctionBlocks().getCount()); } -TEST_F(TmsIntegrationTest, DISABLED_AddFunctionBlockWitchConfig) +TEST_F(TmsIntegrationTest, AddFunctionBlockWitchConfig) { - // Work in progress - InstancePtr device = createDevice(); TmsServer tmsServer(device); tmsServer.start(); @@ -289,13 +289,12 @@ TEST_F(TmsIntegrationTest, DISABLED_AddFunctionBlockWitchConfig) const auto clientFbTypes = clientDevice.getAvailableFunctionBlockTypes(); auto config = clientFbTypes.get("mock_fb_uid").createDefaultConfig(); - config.setPropertyValue("TestConfigInt", 10); config.setPropertyValue("TestConfigString", "Hello Property!"); auto fb = clientDevice.addFunctionBlock("mock_fb_uid", config); ASSERT_EQ(2, clientDevice.getFunctionBlocks().getCount()); - ASSERT_EQ(fb.getPropertyValue("TestConfigInt"), 10); + ASSERT_EQ(fb.getPropertyValue("TestConfigInt"), 0); ASSERT_EQ(fb.getPropertyValue("TestConfigString"), "Hello Property!"); } From 79e39148598096592392221f858d83d0323550fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Mon, 19 Feb 2024 09:52:31 +0100 Subject: [PATCH 083/217] Correctly handle missing signals on input port connect method --- .../opcuatms_server/src/objects/tms_server_input_port.cpp | 3 ++- .../tests/opcuatms_integration/test_tms_integration.cpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp index f5abe09..cb013dc 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp @@ -98,7 +98,8 @@ void TmsServerInputPort::onConnectSignal(NodeEventManager::MethodArgs args) assert(args.inputSize == 1); const auto globalId = OpcUaVariant(args.input[0]).toString(); - SignalPtr signal = tmsContext->findComponent(globalId).asPtrOrNull(); + ComponentPtr signalComponent = tmsContext->findComponent(globalId); + SignalPtr signal = signalComponent.assigned() ? signalComponent.asPtrOrNull() : nullptr; if (!signal.assigned()) throw OpcUaException(UA_STATUSCODE_BADNOTFOUND, "Signal not found"); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index 99e4fe4..2d193e3 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -287,6 +287,7 @@ TEST_F(TmsIntegrationTest, AddFunctionBlockWitchConfig) auto clientDevice = tmsClient.connect(); const auto clientFbTypes = clientDevice.getAvailableFunctionBlockTypes(); + ASSERT_TRUE(clientFbTypes.hasKey("mock_fb_uid")); auto config = clientFbTypes.get("mock_fb_uid").createDefaultConfig(); config.setPropertyValue("TestConfigString", "Hello Property!"); From 76b4e458224f5458b6c43047edbc591c4eb00fb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Wed, 21 Feb 2024 09:01:03 +0100 Subject: [PATCH 084/217] Add list serialization test for property object --- .../tests/test_property_object_conversion_utils.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_property_object_conversion_utils.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_property_object_conversion_utils.cpp index 9baab4d..fa75998 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/test_property_object_conversion_utils.cpp +++ b/shared/libraries/opcuatms/opcuatms/tests/test_property_object_conversion_utils.cpp @@ -74,16 +74,3 @@ TEST_F(PropertyObjectConversionUtilsTest, Clone) ASSERT_TRUE(TestComparators::PropertyObjectEquals(obj, clone)); } - -TEST_F(PropertyObjectConversionUtilsTest, DISABLED_CloneList) -{ - // Serializer fails to serialize default empty list property correctly. - - auto obj = CreateTestPropertyObject(); - obj.addProperty(ListProperty("list", List())); - obj.setPropertyValue("list", List(1, 2, 3)); - - auto clone = PropertyObjectConversionUtils::ClonePropertyObject(obj); - - ASSERT_TRUE(TestComparators::PropertyObjectEquals(obj, clone)); -} From 1d5d44a9cedb1b55ac5ace3e8658175ab817208d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Wed, 21 Feb 2024 09:09:43 +0100 Subject: [PATCH 085/217] Return empty list if AvailableTypes node is missing --- .../opcuatms_client/src/objects/tms_client_device_impl.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index ccadb99..129281b 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -452,8 +452,13 @@ void TmsClientDeviceImpl::findAndCreateCustomComponents() DictPtr TmsClientDeviceImpl::onGetAvailableFunctionBlockTypes() { auto browser = clientContext->getReferenceBrowser(); + auto types = Dict(); const auto fbFolderNodeId = browser->getChildNodeId(nodeId, "FB"); + + if (!browser->hasReference(fbFolderNodeId, "AvailableTypes")) + return types; + const auto availableTypesId = browser->getChildNodeId(fbFolderNodeId, "AvailableTypes"); auto filter = BrowseFilter(); @@ -462,7 +467,6 @@ DictPtr TmsClientDeviceImpl::onGetAvailableFunction filter.nodeClass = UA_NODECLASS_VARIABLE; auto fbTypesReferences = browser->browseFiltered(availableTypesId, filter); - auto types = Dict(); for (const auto& [refNodeId, ref] : fbTypesReferences.byNodeId) { From 42217ee68d180cd92936fe9ac436aab402b5a032 Mon Sep 17 00:00:00 2001 From: Dejan Crnila Date: Fri, 23 Feb 2024 10:30:23 +0100 Subject: [PATCH 086/217] Add struct sample type --- .../opcuatms/src/converters/data_descriptor_converter.cpp | 4 ++-- shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp | 2 ++ .../opcuatms/opcuatms/tests/test_variant_converter.cpp | 4 ++-- .../opcuatms/opcuatms/tests/test_variant_list_converter.cpp | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/data_descriptor_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/data_descriptor_converter.cpp index 021539c..e2327f2 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/data_descriptor_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/data_descriptor_converter.cpp @@ -138,7 +138,7 @@ DataDescriptorPtr StructConverter } const auto descriptor = DataDescriptorBuilder() - .setSampleType(SampleType::Undefined) + .setSampleType(SampleType::Struct) .setName(ConvertToDaqCoreString(tmsStruct.name)) .setDimensions(ReadDimensions(tmsStruct.dimensions, tmsStruct.dimensionsSize)) .setMetadata(ReadMetadata(tmsStruct.metadata, tmsStruct.metadataSize)) @@ -273,7 +273,7 @@ OpcUaVariant VariantConverter::ToVariant(const DataDescriptorPt if (targetType ==nullptr || targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_BASEDATADESCRIPTORSTRUCTURE]) { - if (object.isStructDescriptor()) + if (object.getSampleType() == SampleType::Struct) variant.setScalar(*StructConverter::ToTmsType(object)); else variant.setScalar(*StructConverter::ToTmsType(object)); diff --git a/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp b/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp index e36c6cb..6d00b38 100644 --- a/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp @@ -142,6 +142,8 @@ UA_SampleTypeEnumeration SampleTypeToTmsEnum(SampleType daqEnum) return UA_SAMPLETYPEENUMERATION_STRING; case SampleType::RangeInt64: return UA_SAMPLETYPEENUMERATION_RANGEINT64; + case SampleType::Struct: + return UA_SAMPLETYPEENUMERATION_INVALID; default: throw ConversionFailedException(); } diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_variant_converter.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_variant_converter.cpp index 5c8819f..5217418 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/test_variant_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/tests/test_variant_converter.cpp @@ -60,14 +60,14 @@ static DataDescriptorBuilderPtr CreateTestStructDescriptorBuilder() .build(); auto meta = DataDescriptorBuilder() - .setSampleType(SampleType::Undefined) + .setSampleType(SampleType::Struct) .setName("meta") .setDimensions(CreateTestDimensions()) .setStructFields(List(desc)) .build(); auto can = DataDescriptorBuilder() - .setSampleType(SampleType::Undefined) + .setSampleType(SampleType::Struct) .setName("CAN message") .setStructFields(List(id, data, meta)); diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_variant_list_converter.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_variant_list_converter.cpp index 8aafd73..9156181 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/test_variant_list_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/tests/test_variant_list_converter.cpp @@ -187,7 +187,7 @@ TEST_F(VariantListConverterTest, DataDescriptor) auto id = DataDescriptorBuilder().setSampleType(SampleType::Int32).setName("id").build(); auto data = DataDescriptorBuilder().setSampleType(SampleType::UInt8).setName("data").build(); auto can = DataDescriptorBuilder() - .setSampleType(SampleType::Undefined) + .setSampleType(SampleType::Struct) .setName("CAN message") .setStructFields(List(id, data)) .build(); From 640e2524cf7186ca7c029eaceeef4a962bebe700 Mon Sep 17 00:00:00 2001 From: Nikolai Shipilov Date: Wed, 14 Feb 2024 12:34:52 +0100 Subject: [PATCH 087/217] Refactoring of the streaming framework: * pass the signal IDs instead of signal objects themselves to Streaming private interface functions invoked from internal signal implementation - subscribe / unsubscribe / createDataDescriptorChangedEventPacket * use the inherited component mutex within the base implementation of MirroredSignal. * replace the overriden interface getDomainSignal function with a virtual onGetDomainSignal method for MirroredSignal implementations --- .../objects/tms_client_signal_impl.h | 4 +-- .../src/objects/tms_client_signal_impl.cpp | 36 ++++++++----------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h index e39bc53..456aa35 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h @@ -38,8 +38,6 @@ class TmsClientSignalImpl final : public TmsClientComponentBaseImpl isPublic = true; std::string deviceSignalId; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp index 7417ed2..6542621 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp @@ -73,32 +73,26 @@ ErrCode TmsClientSignalImpl::setDescriptor(IDataDescriptor* /*descriptor*/) return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; } -ErrCode TmsClientSignalImpl::getDomainSignal(ISignal** signal) -{ - SignalPtr signalPtr; - ErrCode errCode = wrapHandlerReturn(this, &TmsClientSignalImpl::onGetDomainSignal, signalPtr); - - *signal = signalPtr.detach(); - if (OPENDAQ_FAILED(errCode)) - { - LOG_W("Failed to get domain signal on OpcUA client signal \"{}\"", this->globalId); - } - return OPENDAQ_SUCCESS; -} - SignalPtr TmsClientSignalImpl::onGetDomainSignal() { - auto filter = BrowseFilter(); - filter.referenceTypeId = OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASDOMAINSIGNAL); - filter.direction = UA_BROWSEDIRECTION_FORWARD; + try + { + auto filter = BrowseFilter(); + filter.referenceTypeId = OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASDOMAINSIGNAL); + filter.direction = UA_BROWSEDIRECTION_FORWARD; - const auto& references = clientContext->getReferenceBrowser()->browseFiltered(nodeId, filter); - assert(references.byNodeId.size() <= 1); + const auto& references = clientContext->getReferenceBrowser()->browseFiltered(nodeId, filter); + assert(references.byNodeId.size() <= 1); - if (!references.byNodeId.empty()) + if (!references.byNodeId.empty()) + { + auto domainSignalNodeId = references.byNodeId.begin().key(); + return findSignal(domainSignalNodeId); + } + } + catch (...) { - auto domainSignalNodeId = references.byNodeId.begin().key(); - return findSignal(domainSignalNodeId); + LOG_W("Failed to get domain signal on OpcUA client signal \"{}\"", this->globalId); } return nullptr; From e309c7da57dec248feda14cd6a1ff724227fe696 Mon Sep 17 00:00:00 2001 From: Nikolai Shipilov Date: Fri, 16 Feb 2024 09:43:51 +0100 Subject: [PATCH 088/217] Disable failing tests --- .../tests/opcuatms_integration/test_tms_fusion_device.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp index f72cc8c..85295c7 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp @@ -91,7 +91,7 @@ TEST_F(TmsFusionDevice, SampleRateTest) ASSERT_NO_THROW(clientSignal.getPropertyValue("SampleRate")); } -TEST_F(TmsFusionDevice, StructTest) +TEST_F(TmsFusionDevice, DISABLED_StructTest) { const auto obj = PropertyObject(objManager, "FusionAmp"); auto [serverObj, fusionAmp] = registerPropertyObject(obj); From 1a1a9455c0d6dc3c5fe611773d1544c3feeae250 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Fri, 23 Feb 2024 15:02:07 +0100 Subject: [PATCH 089/217] Fix TMS Server core event callback --- .../opcuatms/opcuatms_server/src/tms_server_context.cpp | 3 +++ .../tests/opcuatms_integration/test_tms_fusion_device.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/shared/libraries/opcuatms/opcuatms_server/src/tms_server_context.cpp b/shared/libraries/opcuatms/opcuatms_server/src/tms_server_context.cpp index 9c55e66..1b01fd9 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/tms_server_context.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/tms_server_context.cpp @@ -35,6 +35,9 @@ ComponentPtr TmsServerContext::findComponent(const std::string& globalId) void TmsServerContext::coreEventCallback(ComponentPtr& component, CoreEventArgsPtr& eventArgs) { + if (!component.assigned()) + return; + if (const auto it = idToObjMap.find(component.getGlobalId()); it != idToObjMap.end()) if (const std::shared_ptr spt = it->second.lock()) spt->onCoreEvent(eventArgs); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp index 85295c7..f72cc8c 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp @@ -91,7 +91,7 @@ TEST_F(TmsFusionDevice, SampleRateTest) ASSERT_NO_THROW(clientSignal.getPropertyValue("SampleRate")); } -TEST_F(TmsFusionDevice, DISABLED_StructTest) +TEST_F(TmsFusionDevice, StructTest) { const auto obj = PropertyObject(objManager, "FusionAmp"); auto [serverObj, fusionAmp] = registerPropertyObject(obj); From ecceaabcecb563688fa62702b733f0d03b524797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Tue, 27 Feb 2024 12:25:29 +0100 Subject: [PATCH 090/217] Copy node ids in BeginUpdate and EndUpdate methods --- .../src/objects/tms_client_property_object_impl.cpp | 8 ++++---- .../opcuatms_integration/test_tms_integration.cpp | 13 +++++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index 47c48d4..bd3e6c0 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -213,8 +213,8 @@ ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::beginUpdate() const auto beginUpdateId = getNodeId("BeginUpdate"); OpcUaCallMethodRequest request; request->inputArgumentsSize = 0; - request->objectId = nodeId.getValue(); - request->methodId = beginUpdateId.getValue(); + request->objectId = nodeId.copyAndGetDetachedValue(); + request->methodId = beginUpdateId.copyAndGetDetachedValue(); client->callMethod(request); return OPENDAQ_SUCCESS; } @@ -228,8 +228,8 @@ ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::endUpdate() const auto endUpdateId = getNodeId("EndUpdate"); OpcUaCallMethodRequest request; request->inputArgumentsSize = 0; - request->objectId = nodeId.getValue(); - request->methodId = endUpdateId.getValue(); + request->objectId = nodeId.copyAndGetDetachedValue(); + request->methodId = endUpdateId.copyAndGetDetachedValue(); client->callMethod(request); return OPENDAQ_SUCCESS; } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index 2d193e3..e8fe6e8 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -389,3 +389,16 @@ TEST_F(TmsIntegrationTest, InputPortMultipleServers) ASSERT_THROW(inputPort1.connect(signal2), NotFoundException); ASSERT_THROW(inputPort2.connect(signal1), NotFoundException); } + +TEST_F(TmsIntegrationTest, BeginEndUpdateDevice) +{ + InstancePtr device = createDevice(); + TmsServer tmsServer(device); + tmsServer.start(); + + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + auto clientDevice = tmsClient.connect(); + + ASSERT_NO_THROW(clientDevice.beginUpdate()); + ASSERT_NO_THROW(clientDevice.endUpdate()); +} From 11faf568af50648e547756bece684fbef5c96f39 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Tue, 27 Feb 2024 17:20:43 +0100 Subject: [PATCH 091/217] Add sdk version to device info --- .../src/opcua_server_impl.cpp | 1 - .../src/objects/tms_client_device_impl.cpp | 3 ++- .../include/opcuatms_server/tms_server.h | 2 -- .../src/objects/tms_server_device.cpp | 11 +++++++++-- .../opcuatms_server/src/tms_server.cpp | 18 ------------------ .../opcuatms_integration/test_tms_device.cpp | 10 ++++++++++ 6 files changed, 21 insertions(+), 24 deletions(-) diff --git a/modules/opcua_server_module/src/opcua_server_impl.cpp b/modules/opcua_server_module/src/opcua_server_impl.cpp index ce5c8f1..dfa9a55 100644 --- a/modules/opcua_server_module/src/opcua_server_impl.cpp +++ b/modules/opcua_server_module/src/opcua_server_impl.cpp @@ -17,7 +17,6 @@ OpcUaServerImpl::OpcUaServerImpl(DevicePtr rootDevice, PropertyObjectPtr config, { const uint16_t port = config.getPropertyValue("Port"); - server.setOpendaqVersion(OPENDAQ_PACKAGE_VERSION); server.setOpcUaPort(port); server.start(); } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 129281b..d4463c2 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -50,7 +50,8 @@ namespace detail {"Platform", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setPlatform(v.toString()); }}, {"Position", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setPosition(v.toInteger()); }}, {"SystemType", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setSystemType(v.toString()); }}, - {"SystemUUID", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setSystemUuid(v.toString()); }} + {"SystemUUID", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setSystemUuid(v.toString()); }}, + {"OpenDaqPackageVersion",[](const DeviceInfoConfigPtr& info, const OpcUaVariant& v){ info.asPtr().setProtectedPropertyValue("sdkVersion", v.toString()); }}, }; } diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h index b509d53..3050acf 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h @@ -32,7 +32,6 @@ class TmsServer ~TmsServer(); void setOpcUaPort(uint16_t port); - void setOpendaqVersion(const std::string& version); void start(); void stop(); @@ -43,7 +42,6 @@ class TmsServer std::shared_ptr tmsContext; daq::opcua::OpcUaServerPtr server; uint16_t opcUaPort = 4840; - std::string versionStr = ""; }; diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index 756b03c..447052a 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -52,7 +52,7 @@ namespace detail {"Platform", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getPlatform().getCharPtr()}; }}, {"Position", [](const DeviceInfoPtr& info) { return OpcUaVariant{static_cast(info.getPosition())}; }}, {"SystemType", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getSystemType().getCharPtr()}; }}, - {"SystemUUID", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getSystemUuid().getCharPtr()}; }} + {"SystemUUID", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getSystemUuid().getCharPtr()}; }}, }; } @@ -121,6 +121,7 @@ void TmsServerDevice::bindCallbacks() void TmsServerDevice::populateDeviceInfo() { + auto createNode = [this](std::string name, CoreType type) { OpcUaNodeId newNodeId(0); @@ -150,6 +151,8 @@ void TmsServerDevice::populateDeviceInfo() auto deviceInfo = object.getInfo(); + createNode("OpenDaqPackageVersion", ctString); + const auto customInfoNames = deviceInfo.getCustomInfoPropertyNames(); std::unordered_set customInfoNamesSet; @@ -162,7 +165,6 @@ void TmsServerDevice::populateDeviceInfo() } catch(...) { - } } @@ -181,6 +183,11 @@ void TmsServerDevice::populateDeviceInfo() auto v = detail::componentFieldToVariant[browseName](deviceInfo); server->writeValue(reference.nodeId.nodeId, *v); } + else if (browseName == "OpenDaqPackageVersion") + { + auto v = OpcUaVariant{deviceInfo.getSdkVersion().getCharPtr()}; + server->writeValue(reference.nodeId.nodeId, *v); + } else if (customInfoNamesSet.count(browseName)) { const auto valueType = deviceInfo.getProperty(browseName).getValueType(); diff --git a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp index bc40e0c..1b83a44 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp @@ -31,11 +31,6 @@ void TmsServer::setOpcUaPort(uint16_t port) this->opcUaPort = port; } -void TmsServer::setOpendaqVersion(const std::string& version) -{ - this->versionStr = version; -} - void TmsServer::start() { if (!device.assigned()) @@ -52,19 +47,6 @@ void TmsServer::start() tmsDevice = std::make_unique(device, server, context, tmsContext); tmsDevice->registerOpcUaNode(OpcUaNodeId(NAMESPACE_DI, UA_DIID_DEVICESET)); - - if (!versionStr.empty()) - { - OpcUaNodeId newNodeId(0); - AddVariableNodeParams params(newNodeId, tmsDevice->getNodeId()); - params.setBrowseName("OpenDaqPackageVersion"); - params.setDataType(OpcUaNodeId(UA_TYPES[UA_TYPES_STRING].typeId)); - params.typeDefinition = OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE)); - const auto nodeId = server->addVariableNode(params); - - server->writeValue(nodeId, OpcUaVariant(versionStr.c_str())); - } - tmsDevice->createNonhierarchicalReferences(); server->start(); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp index 4f9e68c..a7aa5c0 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp @@ -455,3 +455,13 @@ TEST_F(TmsDeviceTest, CustomComponentOrder) for (SizeT i = 0; i < serverCmps.getCount(); ++i) ASSERT_EQ(serverCmps[i].getName(), clientCmps[i].getName()); } + +TEST_F(TmsDeviceTest, SdkPackageVersion) +{ + auto serverDevice = createDevice(); + auto tmsServerDevice = TmsServerDevice(serverDevice.getRootDevice(), this->getServer(), ctx, serverContext); + auto nodeId = tmsServerDevice.registerOpcUaNode(); + DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "Dev", clientContext, nodeId, nullptr); + + ASSERT_EQ(clientDevice.getInfo().getSdkVersion(), OPENDAQ_PACKAGE_VERSION); +} From 5e215f92a99ebdeb3bac190386fe2273dcfa7690 Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Mon, 4 Mar 2024 11:38:21 +0100 Subject: [PATCH 092/217] [TBBAS-1306] Example of using the config provider options in a reference module -add id in module -add enableStandardProviders in context (by default disabled) -add configuring native streaming client module from options -add configuring NumberOfChannels and EnableCANChannel for ref device from options --- modules/opcua_client_module/src/opcua_client_module_impl.cpp | 5 +++-- modules/opcua_server_module/src/opcua_server_module_impl.cpp | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index e1d5197..79fa98b 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -22,7 +22,8 @@ using namespace daq::opcua; OpcUaClientModule::OpcUaClientModule(ContextPtr context) : Module("openDAQ OpcUa client module", daq::VersionInfo(OPCUA_CLIENT_MODULE_MAJOR_VERSION, OPCUA_CLIENT_MODULE_MINOR_VERSION, OPCUA_CLIENT_MODULE_PATCH_VERSION), - std::move(context)) + std::move(context), + "OpcUaClient") , discoveryClient( { [](const MdnsDiscoveredDevice& discoveredDevice) @@ -128,7 +129,7 @@ bool OpcUaClientModule::onAcceptsConnectionParameters(const StringPtr& connectio if (found != 0) return false; - if ( config.assigned() && !acceptDeviceProperties(config)) + if (config.assigned() && !acceptDeviceProperties(config)) { LOG_W("Connection string \"{}\" is accepted but config is incomplete", connectionString); return false; diff --git a/modules/opcua_server_module/src/opcua_server_module_impl.cpp b/modules/opcua_server_module/src/opcua_server_module_impl.cpp index 4cb6b78..a8d7c3b 100644 --- a/modules/opcua_server_module/src/opcua_server_module_impl.cpp +++ b/modules/opcua_server_module/src/opcua_server_module_impl.cpp @@ -9,7 +9,8 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_SERVER_MODULE OpcUaServerModule::OpcUaServerModule(ContextPtr context) : Module("openDAQ OpcUa server module", daq::VersionInfo(OPCUA_SERVER_MODULE_MAJOR_VERSION, OPCUA_SERVER_MODULE_MINOR_VERSION, OPCUA_SERVER_MODULE_PATCH_VERSION), - std::move(context)) + std::move(context), + "OpcUaServer") { } From 55014c8586e272e2fde01ae3fa2c7adc247f66a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE?= Date: Wed, 6 Mar 2024 09:28:04 +0100 Subject: [PATCH 093/217] getLastValue update (openDAQ/openDAQ#186) Support getLastValue method in data packet in addition to signal, support UInt64, ComplexFloat32, ComplexFloat64, and RangeInt64 for getLastValue in core with tests and Int8 though Int32, UInt8 though UInt64, Float32, ComplexFloat32, ComplexFloat64, and RangeInt64 via OPC UA with tests added for Int8 though Int64, Uint8 though Uint64, Float32, Float64, ComplexFloat32, ComplexFloat64, and RangeInt64 --- .../include/opcuashared/opcuaobject.h | 13 +- .../include/opcuatms/converter_maps.h | 18 +- .../opcuatms/opcuatms/src/CMakeLists.txt | 1 + .../converters/complex_number_converter.cpp | 109 ++++++++ .../opcuatms/src/core_types_utils.cpp | 47 ++-- .../opcuatms/tests/test_core_types_utils.cpp | 1 - .../src/objects/tms_server_signal.cpp | 68 ++--- .../opcuatms_integration/test_tms_signal.cpp | 234 +++++++++++++++--- 8 files changed, 394 insertions(+), 97 deletions(-) create mode 100644 shared/libraries/opcuatms/opcuatms/src/converters/complex_number_converter.cpp diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaobject.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaobject.h index bfd675e..ae1a84a 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaobject.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaobject.h @@ -40,11 +40,11 @@ inline constexpr const UA_DataType* GetUaDataType() constexpr static const UA_DataType* DataType = &UA_TYPES[TYPE_INDEX]; \ }; -#define ADD_CUSTOM_TYPE_MAPPING(TYPE, DATA_TYPE) \ - template <> \ - struct TypeToUaDataType \ - { \ - constexpr static const UA_DataType* DataType = DATA_TYPE; \ +#define ADD_CUSTOM_TYPE_MAPPING(TYPE, DATA_TYPE) \ + template <> \ + struct TypeToUaDataType \ + { \ + constexpr static const UA_DataType* DataType = DATA_TYPE; \ }; #define ADD_STANDARD_TYPE_ALIAS_MAPPING(MAPPING_NAME, TYPE_INDEX) \ @@ -204,7 +204,6 @@ UATYPE* OpcUaObject::get() noexcept return &this->value; } - template const UATYPE* OpcUaObject::operator->() const noexcept { @@ -327,6 +326,8 @@ ADD_STANDARD_TYPE_MAPPING(UA_CreateSubscriptionResponse, UA_TYPES_CREATESUBSCRIP ADD_STANDARD_TYPE_MAPPING(UA_CallMethodRequest, UA_TYPES_CALLMETHODREQUEST) ADD_STANDARD_TYPE_MAPPING(UA_CallMethodResult, UA_TYPES_CALLMETHODRESULT) ADD_STANDARD_TYPE_MAPPING(UA_Range, UA_TYPES_RANGE) +ADD_STANDARD_TYPE_MAPPING(UA_ComplexNumberType, UA_TYPES_COMPLEXNUMBERTYPE) +ADD_STANDARD_TYPE_MAPPING(UA_DoubleComplexNumberType, UA_TYPES_DOUBLECOMPLEXNUMBERTYPE) ADD_STANDARD_TYPE_MAPPING(UA_KeyValuePair, UA_TYPES_KEYVALUEPAIR) ADD_STANDARD_TYPE_MAPPING(UA_ExtensionObject, UA_TYPES_EXTENSIONOBJECT) ADD_STANDARD_TYPE_MAPPING(UA_RationalNumber, UA_TYPES_RATIONALNUMBER) diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h index 982c083..e8be922 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h @@ -88,6 +88,9 @@ namespace converters {IRange::Id, [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) { return VariantConverter::ToVariant(object, targetType, ctx); }}, + {IComplexNumber::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToVariant(object, targetType, ctx); }}, {IStruct::Id, [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) { return VariantConverter::ToVariant(object, targetType, ctx); }}, @@ -138,6 +141,9 @@ namespace converters {IRange::Id, [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) { return VariantConverter::ToArrayVariant(object, targetType, ctx); }}, + {IComplexNumber::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToArrayVariant(object, targetType, ctx); }}, {IStruct::Id, [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) { return VariantConverter::ToArrayVariant(object, targetType, ctx); }}, @@ -200,7 +206,11 @@ namespace converters {OpcUaNodeId(0, UA_NS0ID_ARGUMENT), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, {OpcUaNodeId(0, UA_NS0ID_RANGE), - [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}}; + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_COMPLEXNUMBERTYPE), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_DOUBLECOMPLEXNUMBERTYPE), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqObject(var, context); }}}; static std::unordered_map(const OpcUaVariant&, const ContextPtr& context)>> uaTypeToDaqList{ @@ -255,7 +265,11 @@ namespace converters {OpcUaNodeId(0, UA_NS0ID_ARGUMENT), [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, {OpcUaNodeId(0, UA_NS0ID_RANGE), - [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}}; + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_COMPLEXNUMBERTYPE), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}, + {OpcUaNodeId(0, UA_NS0ID_DOUBLECOMPLEXNUMBERTYPE), + [](const OpcUaVariant& var, const ContextPtr& context) { return VariantConverter::ToDaqList(var, context); }}}; static OpcUaVariant convertToVariant(IntfID interfaceId, const BaseObjectPtr& object, diff --git a/shared/libraries/opcuatms/opcuatms/src/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms/src/CMakeLists.txt index 16eb182..9188c33 100644 --- a/shared/libraries/opcuatms/opcuatms/src/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms/src/CMakeLists.txt @@ -28,6 +28,7 @@ set(SRC_Converters_Headers ${CONVERTERS_SRC_DIR}/struct_converter.h set(SRC_Converters ${CONVERTERS_SRC_DIR}/range_converter.cpp ${CONVERTERS_SRC_DIR}/unit_converter.cpp + ${CONVERTERS_SRC_DIR}/complex_number_converter.cpp ${CONVERTERS_SRC_DIR}/number_converter.cpp ${CONVERTERS_SRC_DIR}/data_rule_converter.cpp ${CONVERTERS_SRC_DIR}/dimension_rule_converter.cpp diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/complex_number_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/complex_number_converter.cpp new file mode 100644 index 0000000..66fca59 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/src/converters/complex_number_converter.cpp @@ -0,0 +1,109 @@ +#include "opcuatms/converters/list_conversion_utils.h" +#include "opcuatms/converters/struct_converter.h" +#include "opcuatms/converters/variant_converter.h" +#include "opcuatms/core_types_utils.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +// Template specializations + +template class StructConverter; +template class StructConverter; +template class VariantConverter; + +// UA_DoubleComplexNumberType + +template <> +ComplexNumberPtr StructConverter::ToDaqObject(const UA_DoubleComplexNumberType& tmsStruct, + const ContextPtr& /*context*/) +{ + return ComplexNumber(tmsStruct.real, tmsStruct.imaginary); +} + +template <> +OpcUaObject StructConverter::ToTmsType( + const ComplexNumberPtr& object, const ContextPtr& /*context*/) +{ + OpcUaObject complex; + complex->real = object.getReal(); + complex->imaginary = object.getImaginary(); + return complex; +} + +// UA_ComplexNumberType + +template <> +ComplexNumberPtr StructConverter::ToDaqObject(const UA_ComplexNumberType& tmsStruct, + const ContextPtr& /*context*/) +{ + return ComplexNumber(tmsStruct.real, tmsStruct.imaginary); +} + +template <> +OpcUaObject StructConverter::ToTmsType(const ComplexNumberPtr& object, + const ContextPtr& /*context*/) +{ + OpcUaObject complex; + complex->real = object.getReal(); + complex->imaginary = object.getImaginary(); + return complex; +} + +// Variant converter + +template <> +ComplexNumberPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + const auto decodedVariant = DecodeIfExtensionObject(variant); + + if (decodedVariant.isType()) + return StructConverter::ToDaqObject( + *static_cast(decodedVariant->data)); + if (decodedVariant.isType()) + return StructConverter::ToDaqObject( + *static_cast(decodedVariant->data)); + + throw ConversionFailedException(); +} + +template <> +OpcUaVariant VariantConverter::ToVariant(const ComplexNumberPtr& object, + const UA_DataType* targetType, + const ContextPtr& /*context*/) +{ + auto variant = OpcUaVariant(); + + if (targetType == nullptr || targetType == &UA_TYPES[UA_TYPES_DOUBLECOMPLEXNUMBERTYPE]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else if (targetType == &UA_TYPES[UA_TYPES_COMPLEXNUMBERTYPE]) + variant.setScalar(*StructConverter::ToTmsType(object)); + else + throw ConversionFailedException{}; + return variant; +} + +template <> +ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, const ContextPtr& /*context*/) +{ + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + if (variant.isType()) + return ListConversionUtils::VariantToList(variant); + + throw ConversionFailedException{}; +} + +template <> +OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& list, + const UA_DataType* targetType, + const ContextPtr& /*context*/) +{ + if (targetType == nullptr || targetType == &UA_TYPES[UA_TYPES_DOUBLECOMPLEXNUMBERTYPE]) + return ListConversionUtils::ToArrayVariant(list); + if (targetType == nullptr || targetType == &UA_TYPES[UA_TYPES_COMPLEXNUMBERTYPE]) + return ListConversionUtils::ToArrayVariant(list); + + throw ConversionFailedException{}; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp b/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp index 6d00b38..1ac34e4 100644 --- a/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp @@ -2,37 +2,35 @@ #include "opcuashared/opcuadatatypearraylist.h" #include "opcuatms/extension_object.h" -#include "open62541/nodeids.h" #include "open62541/daqbt_nodeids.h" -#include "open62541/types_di_generated.h" +#include "open62541/nodeids.h" #include "open62541/types_daqesp_generated.h" #include "open62541/types_daqhbk_generated.h" +#include "open62541/types_di_generated.h" using namespace daq::opcua; using namespace daq; -using namespace daq::opcua; BEGIN_NAMESPACE_OPENDAQ_OPCUA namespace details { - static std::unordered_map nodeIdToCoreTypeMap = { - {OpcUaNodeId(0, UA_NS0ID_BOOLEAN), ctBool}, - {OpcUaNodeId(0, UA_NS0ID_FLOAT), ctFloat}, - {OpcUaNodeId(0, UA_NS0ID_DOUBLE), ctFloat}, - {OpcUaNodeId(0, UA_NS0ID_SBYTE), ctInt}, - {OpcUaNodeId(0, UA_NS0ID_BYTE), ctInt}, - {OpcUaNodeId(0, UA_NS0ID_INT16), ctInt}, - {OpcUaNodeId(0, UA_NS0ID_UINT16), ctInt}, - {OpcUaNodeId(0, UA_NS0ID_INT32), ctInt}, - {OpcUaNodeId(0, UA_NS0ID_UINT32), ctInt}, - {OpcUaNodeId(0, UA_NS0ID_INT64), ctInt}, - {OpcUaNodeId(0, UA_NS0ID_UINT64), ctInt}, - {OpcUaNodeId(0, UA_NS0ID_STRING), ctString}, - {OpcUaNodeId(0, UA_NS0ID_RATIONALNUMBER), ctRatio}, - {OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_RATIONALNUMBER64), ctRatio}, - {OpcUaNodeId(0, UA_DAQBTID_RATIONALNUMBER64), ctRatio} - }; +static std::unordered_map nodeIdToCoreTypeMap = { + {OpcUaNodeId(0, UA_NS0ID_BOOLEAN), ctBool}, + {OpcUaNodeId(0, UA_NS0ID_FLOAT), ctFloat}, + {OpcUaNodeId(0, UA_NS0ID_DOUBLE), ctFloat}, + {OpcUaNodeId(0, UA_NS0ID_SBYTE), ctInt}, + {OpcUaNodeId(0, UA_NS0ID_BYTE), ctInt}, + {OpcUaNodeId(0, UA_NS0ID_INT16), ctInt}, + {OpcUaNodeId(0, UA_NS0ID_UINT16), ctInt}, + {OpcUaNodeId(0, UA_NS0ID_INT32), ctInt}, + {OpcUaNodeId(0, UA_NS0ID_UINT32), ctInt}, + {OpcUaNodeId(0, UA_NS0ID_INT64), ctInt}, + {OpcUaNodeId(0, UA_NS0ID_UINT64), ctInt}, + {OpcUaNodeId(0, UA_NS0ID_STRING), ctString}, + {OpcUaNodeId(0, UA_NS0ID_RATIONALNUMBER), ctRatio}, + {OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_RATIONALNUMBER64), ctRatio}, + {OpcUaNodeId(0, UA_DAQBTID_RATIONALNUMBER64), ctRatio}}; } StringPtr ConvertToDaqCoreString(const UA_String& uaString) @@ -149,7 +147,6 @@ UA_SampleTypeEnumeration SampleTypeToTmsEnum(SampleType daqEnum) } } - ScaledSampleType ScaledSampleTypeFromTmsEnum(UA_SampleTypeEnumeration tmsEnum) { switch (tmsEnum) @@ -178,7 +175,7 @@ UA_SampleTypeEnumeration ScaledSampleTypeToTmsEnum(ScaledSampleType daqEnum) OpcUaNodeId CoreTypeToUANodeID(CoreType type) { - switch(type) + switch (type) { case ctBool: return OpcUaNodeId(0, UA_NS0ID_BOOLEAN); @@ -247,11 +244,11 @@ const UA_DataType* GetUAStructureDataTypeByName(const std::string& structName) typeArr.add(UA_TYPES_DAQDEVICE_COUNT, UA_TYPES_DAQDEVICE); typeArr.add(UA_TYPES_DAQESP_COUNT, UA_TYPES_DAQESP); typeArr.add(UA_TYPES_DAQHBK_COUNT, UA_TYPES_DAQHBK); - + const UA_DataTypeArray* dataType = typeArr.getCustomDataTypes(); - while(dataType) + while (dataType) { - for(size_t i = 0; i < dataType->typesSize; ++i) + for (size_t i = 0; i < dataType->typesSize; ++i) { if (dataType->types[i].typeName == structName) { diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_core_types_utils.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_core_types_utils.cpp index 5848583..6e6ead7 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/test_core_types_utils.cpp +++ b/shared/libraries/opcuatms/opcuatms/tests/test_core_types_utils.cpp @@ -6,7 +6,6 @@ using CoreTypesUtilsTest = testing::Test; using namespace daq; using namespace daq::opcua; -using namespace daq::opcua; TEST_F(CoreTypesUtilsTest, ConvertToDaqCoreString) { diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp index c5d542a..5a4feac 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp @@ -1,20 +1,23 @@ #include "opcuatms_server/objects/tms_server_signal.h" #include "opcuatms/converters/variant_converter.h" -#include "open62541/statuscodes.h" #include "open62541/daqbsp_nodeids.h" +#include "open62541/statuscodes.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS using namespace opcua; -TmsServerSignal::TmsServerSignal(const SignalPtr& object, const OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext) +TmsServerSignal::TmsServerSignal(const SignalPtr& object, + const OpcUaServerPtr& server, + const ContextPtr& context, + const TmsServerContextPtr& tmsContext) : Super(object, server, context, tmsContext) { } OpcUaNodeId TmsServerSignal::getReferenceType() { - //TODO UA_DAQBSPID_HASSTATUSSIGNAL + // TODO UA_DAQBSPID_HASSTATUSSIGNAL return OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASVALUESIGNAL); } @@ -38,36 +41,46 @@ void TmsServerSignal::bindCallbacks() if (browseName == "DataDescriptor") { OpcUaNodeId descriptorId{reference.nodeId.nodeId}; - addReadCallback(descriptorId, [this]() { - DataDescriptorPtr descriptor = object.getDescriptor(); - if (descriptor != nullptr) - return VariantConverter::ToVariant(descriptor, nullptr, daqContext); - else - return OpcUaVariant(); - }); + addReadCallback(descriptorId, + [this]() + { + DataDescriptorPtr descriptor = object.getDescriptor(); + if (descriptor != nullptr) + return VariantConverter::ToVariant(descriptor, nullptr, daqContext); + else + return OpcUaVariant(); + }); } } - addReadCallback(valueId, [this]() { - ObjectPtr lastValue = object.getLastValue(); - if (lastValue != nullptr) - return VariantConverter::ToVariant(lastValue, nullptr, daqContext); + addReadCallback(valueId, + [this]() + { + ObjectPtr lastValue = object.getLastValue(); + if (lastValue != nullptr) + return VariantConverter::ToVariant(lastValue, nullptr, daqContext); - return OpcUaVariant(); - }); + return OpcUaVariant(); + }); auto analogValueId = getChildNodeId("AnalogValue"); - addReadCallback(analogValueId, [this]() { - SampleType type = object.getDescriptor().getSampleType(); - if (type != SampleType::Float64 && type != SampleType::Int64) - return OpcUaVariant(); - - ObjectPtr lastValue = object.getLastValue(); - if (lastValue != nullptr) - return VariantConverter::ToVariant(lastValue, nullptr, daqContext); - - return OpcUaVariant(); - }); + addReadCallback(analogValueId, + [this]() + { + SampleType type = object.getDescriptor().getSampleType(); + if (type != SampleType::Float32 && type != SampleType::Float64 && type != SampleType::Int8 && + type != SampleType::Int16 && type != SampleType::Int32 && type != SampleType::Int64 && + type != SampleType::UInt8 && type != SampleType::UInt16 && type != SampleType::UInt32 && + type != SampleType::UInt64 && type != SampleType::RangeInt64 && type != SampleType::ComplexFloat32 && + type != SampleType::ComplexFloat64) + return OpcUaVariant(); + + ObjectPtr lastValue = object.getLastValue(); + if (lastValue != nullptr) + return VariantConverter::ToVariant(lastValue, nullptr, daqContext); + + return OpcUaVariant(); + }); // TODO: Value, AnalogValue, Status Super::bindCallbacks(); @@ -101,7 +114,6 @@ void TmsServerSignal::createNonhierarchicalReferences() if (ex.getStatusCode() != UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED) throw; } - } } } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp index 84b01ad..0b577f0 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp @@ -1,5 +1,9 @@ -#include +#include +#include #include +#include +#include +#include #include #include #include "gtest/gtest.h" @@ -8,11 +12,7 @@ #include "opcuatms_client/objects/tms_client_signal_factory.h" #include "opcuatms_server/objects/tms_server_signal.h" #include "open62541/daqbsp_nodeids.h" -#include -#include -#include #include "tms_object_integration_test.h" -#include using namespace daq; using namespace opcua::tms; @@ -57,13 +57,85 @@ class TmsSignalTest : public TmsObjectIntegrationTest return serverSignal; } + + void checkLastValueComplex(const SignalPtr& signal, const double& realValue, const double& imaginaryValue) + { + ComplexNumberPtr ptr = signal.getLastValue().asPtr(); + auto real = ptr.getReal(); + auto imaginary = ptr.getImaginary(); + + ASSERT_DOUBLE_EQ(real, realValue); + ASSERT_DOUBLE_EQ(imaginary, imaginaryValue); + } + + void checkLastValueRange(const SignalPtr& signal, const int64_t& lowValue, const int64_t& highValue) + { + RangePtr ptr = signal.getLastValue().asPtr(); + auto low = ptr.getLowValue().getIntValue(); + auto high = ptr.getHighValue().getIntValue(); + + ASSERT_EQ(low, lowValue); + ASSERT_EQ(high, highValue); + } + + template + void testGetLastValue(const SampleType& sampleType, const T& value) + { + auto daqServerSignal = Signal(NullContext(), nullptr, "id"); + + auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), ctx, serverContext); + auto nodeId = serverSignal.registerOpcUaNode(); + + daqServerSignal.setDescriptor(DataDescriptorBuilder().setSampleType(sampleType).build()); + + auto dataPacket = DataPacket(daqServerSignal.getDescriptor(), 5); + auto data = static_cast(dataPacket.getData()); + data[4] = value; + + daqServerSignal.sendPacket(dataPacket); + + auto clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); + + if (sampleType == SampleType::Float32 || sampleType == SampleType::Float64) + { + ASSERT_DOUBLE_EQ(clientSignal.getLastValue(), static_cast(value)); + ASSERT_DOUBLE_EQ(daqServerSignal.getLastValue(), static_cast(value)); + } + else + { + ASSERT_EQ(clientSignal.getLastValue(), static_cast(value)); + ASSERT_EQ(daqServerSignal.getLastValue(), static_cast(value)); + } + } + + template + void testGetLastValueComplex(const SampleType& sampleType, const T& realValue, const T& imaginaryValue) + { + auto daqServerSignal = Signal(NullContext(), nullptr, "id"); + + auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), ctx, serverContext); + auto nodeId = serverSignal.registerOpcUaNode(); + + daqServerSignal.setDescriptor(DataDescriptorBuilder().setSampleType(sampleType).build()); + + auto dataPacket = DataPacket(daqServerSignal.getDescriptor(), 5); + auto data = static_cast(dataPacket.getData()); + data[8] = realValue; + data[9] = imaginaryValue; + + daqServerSignal.sendPacket(dataPacket); + + auto clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); + + checkLastValueComplex(clientSignal, realValue, imaginaryValue); + checkLastValueComplex(daqServerSignal, realValue, imaginaryValue); + } }; TEST_F(TmsSignalTest, Create) { SignalPtr signal = Signal(NullContext(), nullptr, "sig"); auto tmsSignal = TmsServerSignal(signal, this->getServer(), ctx, serverContext); - } TEST_F(TmsSignalTest, Register) @@ -128,11 +200,105 @@ TEST_F(TmsSignalTest, AttrPublic) // client side change is reflected on client side (public is not transferred): clientSignal.setPublic(false); ASSERT_FALSE(clientSignal.getPublic()); - + clientSignal.setPublic(true); ASSERT_TRUE(clientSignal.getPublic()); } +TEST_F(TmsSignalTest, GetLastValueFloat32) +{ + float value = 4.1f; + testGetLastValue(SampleType::Float32, value); +} + +TEST_F(TmsSignalTest, GetLastValueFloat64) +{ + double value = 4.1; + testGetLastValue(SampleType::Float64, value); +} + +TEST_F(TmsSignalTest, GetLastValueInt8) +{ + int8_t value = 4; + testGetLastValue(SampleType::Int8, value); +} + +TEST_F(TmsSignalTest, GetLastValueInt16) +{ + int16_t value = 4; + testGetLastValue(SampleType::Int16, value); +} + +TEST_F(TmsSignalTest, GetLastValueInt32) +{ + int32_t value = 4; + testGetLastValue(SampleType::Int32, value); +} +TEST_F(TmsSignalTest, GetLastValueInt64) +{ + int64_t value = 4; + testGetLastValue(SampleType::Int64, value); +} + +TEST_F(TmsSignalTest, GetLastValueUInt8) +{ + uint8_t value = 4u; + testGetLastValue(SampleType::UInt8, value); +} + +TEST_F(TmsSignalTest, GetLastValueUInt16) +{ + uint16_t value = 4u; + testGetLastValue(SampleType::UInt16, value); +} + +TEST_F(TmsSignalTest, GetLastValueUInt32) +{ + uint32_t value = 4u; + testGetLastValue(SampleType::UInt32, value); +} +TEST_F(TmsSignalTest, GetLastValueUInt64) +{ + uint64_t value = 4u; + testGetLastValue(SampleType::UInt64, value); +} + +TEST_F(TmsSignalTest, GetLastValueRange) +{ + auto daqServerSignal = Signal(NullContext(), nullptr, "id"); + + auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), ctx, serverContext); + auto nodeId = serverSignal.registerOpcUaNode(); + + daqServerSignal.setDescriptor(DataDescriptorBuilder().setSampleType(SampleType::RangeInt64).build()); + + auto dataPacket = DataPacket(daqServerSignal.getDescriptor(), 5); + auto data = static_cast(dataPacket.getData()); + data[8] = 8; + data[9] = 9; + + daqServerSignal.sendPacket(dataPacket); + + auto clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); + + checkLastValueRange(clientSignal, 8, 9); + checkLastValueRange(daqServerSignal, 8, 9); +} + +TEST_F(TmsSignalTest, GetLastValueComplexFloat32) +{ + float real = 8.1f; + float imaginary = 9.1f; + testGetLastValueComplex(SampleType::ComplexFloat32, real, imaginary); +} + +TEST_F(TmsSignalTest, GetLastValueComplexFloat64) +{ + double real = 8.1; + double imaginary = 9.1; + testGetLastValueComplex(SampleType::ComplexFloat64, real, imaginary); +} + TEST_F(TmsSignalTest, AttrDescriptor) { auto serverMetadata = Dict(); @@ -140,7 +306,7 @@ TEST_F(TmsSignalTest, AttrDescriptor) { serverMetadata.set("Metadata" + std::to_string(i), "Value " + std::to_string(i)); } - + auto serverDataDescriptor = DataDescriptorBuilder() .setSampleType(SampleType::Float32) .setDimensions(List()) @@ -168,7 +334,7 @@ TEST_F(TmsSignalTest, AttrDescriptor) ASSERT_EQ(clientSignal.getActive(), serverSignal.getActive()); // TODO: TMS signal should be implemented similar as fb, i.e. it needs to include property object - //ASSERT_EQ(clientSignal.getName(), "My signal"); + // ASSERT_EQ(clientSignal.getName(), "My signal"); // ASSERT_EQ(clientSignal.getDescription(), "My signal description"); auto clientDataDescriptor = clientSignal.getDescriptor(); ASSERT_EQ(clientDataDescriptor.getName(), "Signal Name"); @@ -201,7 +367,6 @@ TEST_F(TmsSignalTest, AttrDescriptor) auto v = clientValueList.getItemAt(0); ASSERT_EQ(clientValueList.getItemAt(0), 1.0); - auto clientUnit = clientDataDescriptor.getUnit(); ASSERT_EQ(clientUnit.getQuantity(), "quantity"); ASSERT_EQ(clientUnit.getName(), "name"); @@ -232,8 +397,7 @@ TEST_F(TmsSignalTest, AttrDomainSignal) getServer()->addReference(nodeId, referenceTypeId, domainNodeId); SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); - [[maybe_unused]] - SignalPtr clientDomainSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, domainNodeId); + [[maybe_unused]] SignalPtr clientDomainSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, domainNodeId); SignalPtr domainSignal; EXPECT_NO_THROW(domainSignal = clientSignal.getDomainSignal()); @@ -289,13 +453,13 @@ TEST_F(TmsSignalTest, MethodGetConnections) auto serverSignal1 = TmsServerSignal(daqServerSignal1, this->getServer(), ctx, serverContext); auto nodeId1 = serverSignal1.registerOpcUaNode(); - SignalPtr clientSignal1 = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId1); + SignalPtr clientSignal1 = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId1); ASSERT_EQ(clientSignal1.getConnections().getCount(), 0u); - //TODO: Implement more test when related signals actually can be returned - //ASSERT_EQ(relatedSignals1.getCount(), 2u); - //ASSERT_EQ(relatedSignals2.getCount(), 2u); - //ASSERT_EQ(relatedSignals3.getCount(), 2u); + // TODO: Implement more test when related signals actually can be returned + // ASSERT_EQ(relatedSignals1.getCount(), 2u); + // ASSERT_EQ(relatedSignals2.getCount(), 2u); + // ASSERT_EQ(relatedSignals3.getCount(), 2u); } TEST_F(TmsSignalTest, ComponentMethods) @@ -347,7 +511,7 @@ TEST_F(TmsSignalTest, Visible) ASSERT_EQ(clientSignal.getVisible(), false); signal.asPtr().lockAllAttributes(); - + ASSERT_EQ(signal.getVisible(), clientSignal.getVisible()); ASSERT_NO_THROW(clientSignal.setVisible(true)); ASSERT_EQ(signal.getVisible(), false); @@ -357,13 +521,13 @@ TEST_F(TmsSignalTest, Visible) TEST_F(TmsSignalTest, GetNoValue) { auto domainDescriptor = DataDescriptorBuilder() - .setName("domain stub") - .setSampleType(SampleType::UInt64) - .setOrigin("2024-01-08T00:02:03+00:00") - .setTickResolution(Ratio(1, 1000000)) - .setRule(LinearDataRule(1000, 0)) - .setUnit(Unit("s", -1, "seconds", "time")) - .build(); + .setName("domain stub") + .setSampleType(SampleType::UInt64) + .setOrigin("2024-01-08T00:02:03+00:00") + .setTickResolution(Ratio(1, 1000000)) + .setRule(LinearDataRule(1000, 0)) + .setUnit(Unit("s", -1, "seconds", "time")) + .build(); const auto domainSignal = SignalWithDescriptor(NullContext(), domainDescriptor, nullptr, "domainSig"); auto dataDescriptor = DataDescriptorBuilder().setName("stub").setSampleType(SampleType::Float64).build(); @@ -384,7 +548,7 @@ static void sendValueToSignal(const SignalConfigPtr& signal, const T& value) return; DataPacketPtr packet; - + if (signal.getDomainSignal().assigned()) { auto domainPacket = DataPacket(signal.getDomainSignal().getDescriptor(), 1); @@ -397,19 +561,19 @@ static void sendValueToSignal(const SignalConfigPtr& signal, const T& value) auto dst = static_cast(packet.getData()); *dst = value; - signal.sendPacket(packet); -} + signal.sendPacket(packet); +} TEST_F(TmsSignalTest, GetValue) { auto domainDescriptor = DataDescriptorBuilder() - .setName("domain stub") - .setSampleType(SampleType::UInt64) - .setOrigin("2024-01-08T00:02:03+00:00") - .setTickResolution(Ratio(1, 1000000)) - .setRule(LinearDataRule(1000, 0)) - .setUnit(Unit("s", -1, "seconds", "time")) - .build(); + .setName("domain stub") + .setSampleType(SampleType::UInt64) + .setOrigin("2024-01-08T00:02:03+00:00") + .setTickResolution(Ratio(1, 1000000)) + .setRule(LinearDataRule(1000, 0)) + .setUnit(Unit("s", -1, "seconds", "time")) + .build(); const auto domainSignal = SignalWithDescriptor(NullContext(), domainDescriptor, nullptr, "domainSig"); auto dataDescriptor = DataDescriptorBuilder().setName("stub").setSampleType(SampleType::Float64).build(); From ae02ade0191adfc9042caaef7a7eba6c96bf4c1c Mon Sep 17 00:00:00 2001 From: Nils Roettger <99480819+nilsRoettgerAtBB@users.noreply.github.com> Date: Wed, 6 Mar 2024 12:10:22 +0000 Subject: [PATCH 094/217] ToDaqObject returns nullptr instead of throwing an exception. (openDAQ/openDAQ#188) * ToDaqObject returns nullptr instead of throwing an exception. * Remove Warning. --- .../src/objects/tms_client_property_impl.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp index f6693c1..775e798 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp @@ -161,20 +161,17 @@ void TmsClientPropertyImpl::configurePropertyFields() // devices working which are deliviering not a default value via the opc-ua interface. // Afterwards, the workaround needs to be rolled back. - try + auto value = reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE); + if(value.isNull()) { - const auto value = reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE); - this->defaultValue = VariantConverter::ToDaqObject(value, daqContext); - } - catch (const std::exception& e) - { - const auto value = reader->getValue(nodeId, UA_ATTRIBUTEID_VALUE); + value = reader->getValue(nodeId, UA_ATTRIBUTEID_VALUE); this->defaultValue = VariantConverter::ToDaqObject(value, daqContext); LOG_W( - "Failed to read default value of property {} on OpcUa client. Detault value is set to the value at connection time. {}", - this->name, - e.what()); + "Failed to read default value of property {} on OpcUa client. Detault value is set to the value at connection time.", + this->name); } + this->defaultValue = VariantConverter::ToDaqObject(value, daqContext); + if (this->defaultValue.assigned() && this->defaultValue.asPtrOrNull().assigned()) this->defaultValue.freeze(); From 57c9b8ac726fb6408814f5a05c849c43d25a3541 Mon Sep 17 00:00:00 2001 From: Martin Kraner Date: Tue, 20 Feb 2024 13:33:46 +0100 Subject: [PATCH 095/217] Change `ITagsPrivate.set()` to `ITagsPrivate.replace()` as `set` is a reserved keyword in Delphi --- .../include/opcuatms_client/objects/tms_client_tags_impl.h | 2 +- .../opcuatms_client/src/objects/tms_client_tags_impl.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h index e3473f4..31f1c9b 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h @@ -32,7 +32,7 @@ class TmsClientTagsImpl final : public TmsClientObjectImpl, public TagsImpl ErrCode INTERFACE_FUNC getList(IList** value) override; ErrCode INTERFACE_FUNC add(IString* name) override; - ErrCode INTERFACE_FUNC set(IList* tags) override; + ErrCode INTERFACE_FUNC replace(IList* tags) override; ErrCode INTERFACE_FUNC remove(IString* name) override; ErrCode INTERFACE_FUNC contains(IString* name, Bool* value) override; ErrCode INTERFACE_FUNC query(IString* query, Bool* value) override; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_tags_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_tags_impl.cpp index 5532e2e..6770cce 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_tags_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_tags_impl.cpp @@ -23,7 +23,7 @@ ErrCode TmsClientTagsImpl::add(IString* name) return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; } -ErrCode TmsClientTagsImpl::set(IList* tags) +ErrCode TmsClientTagsImpl::replace(IList* tags) { return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; } From 6b1056fdd26d09cac5d284327fa59ad7243a6714 Mon Sep 17 00:00:00 2001 From: Martin Kraner Date: Thu, 29 Feb 2024 09:26:06 +0100 Subject: [PATCH 096/217] MSVC 2017 compatibility fixes --- .../opcuatms_integration/test_tms_integration.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index e8fe6e8..908cf6d 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -274,7 +274,7 @@ TEST_F(TmsIntegrationTest, AddFunctionBlock) ASSERT_TRUE(fb2.assigned()); ASSERT_EQ("mock_fb_uid_2", fb2.getLocalId()); - ASSERT_EQ(3, clientDevice.getFunctionBlocks().getCount()); + ASSERT_EQ(3u, clientDevice.getFunctionBlocks().getCount()); } TEST_F(TmsIntegrationTest, AddFunctionBlockWitchConfig) @@ -294,7 +294,7 @@ TEST_F(TmsIntegrationTest, AddFunctionBlockWitchConfig) auto fb = clientDevice.addFunctionBlock("mock_fb_uid", config); - ASSERT_EQ(2, clientDevice.getFunctionBlocks().getCount()); + ASSERT_EQ(2u, clientDevice.getFunctionBlocks().getCount()); ASSERT_EQ(fb.getPropertyValue("TestConfigInt"), 0); ASSERT_EQ(fb.getPropertyValue("TestConfigString"), "Hello Property!"); } @@ -311,13 +311,13 @@ TEST_F(TmsIntegrationTest, RemoveFunctionBlock) auto fb1 = clientDevice.addFunctionBlock("mock_fb_uid"); auto fb2 = clientDevice.addFunctionBlock("mock_fb_uid"); - ASSERT_EQ(3, clientDevice.getFunctionBlocks().getCount()); + ASSERT_EQ(3u, clientDevice.getFunctionBlocks().getCount()); clientDevice.removeFunctionBlock(fb1); - ASSERT_EQ(2, clientDevice.getFunctionBlocks().getCount()); + ASSERT_EQ(2u, clientDevice.getFunctionBlocks().getCount()); clientDevice.removeFunctionBlock(fb2); - ASSERT_EQ(1, clientDevice.getFunctionBlocks().getCount()); + ASSERT_EQ(1u, clientDevice.getFunctionBlocks().getCount()); } TEST_F(TmsIntegrationTest, InputPortConnect) From 1a8d199cdd8b2a4a2713c996576c68fd3221b37b Mon Sep 17 00:00:00 2001 From: Martin Kraner Date: Wed, 13 Mar 2024 09:00:06 +0100 Subject: [PATCH 097/217] Gate integration tests behind and option and fix ConfigProtocol tests without RefDevice and RefFb --- shared/libraries/opcuatms/tests/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/shared/libraries/opcuatms/tests/CMakeLists.txt b/shared/libraries/opcuatms/tests/CMakeLists.txt index bdecf99..de099d6 100644 --- a/shared/libraries/opcuatms/tests/CMakeLists.txt +++ b/shared/libraries/opcuatms/tests/CMakeLists.txt @@ -3,4 +3,7 @@ set_cmake_folder_context(TARGET_FOLDER_NAME) project(opcuatms_integration_tests CXX) add_subdirectory(test_utils) -add_subdirectory(opcuatms_integration) + +if (OPENDAQ_ENABLE_INTEGRATION_TESTS) + add_subdirectory(opcuatms_integration) +endif() From 00de9467429b92ca88beab20969ca8e84bcf6b5d Mon Sep 17 00:00:00 2001 From: Martin Kraner Date: Wed, 13 Mar 2024 18:08:34 +0100 Subject: [PATCH 098/217] Fix MinGW GCC and fix GCC 10 bug causing spurious warning --- shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt | 2 ++ .../opcuatms/tests/opcuatms_integration/CMakeLists.txt | 2 ++ 2 files changed, 4 insertions(+) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt index 78458ef..e06abc3 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt @@ -122,6 +122,8 @@ endif() if (MSVC) target_compile_options(${LIB_NAME} PRIVATE /bigobj) +elseif (MINGW AND CMAKE_COMPILER_IS_GNUCXX) + target_compile_options(${LIB_NAME} PRIVATE -Wa,-mbig-obj) endif() target_link_libraries(${LIB_NAME} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt b/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt index cf5d37f..2f34235 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt @@ -67,6 +67,8 @@ add_test(NAME ${TEST_APP} if (MSVC) target_compile_options(${TEST_APP} PRIVATE /wd4324 /bigobj) +elseif (MINGW AND CMAKE_COMPILER_IS_GNUCXX) + target_compile_options(${TEST_APP} PRIVATE -Wa,-mbig-obj) endif() if (OPENDAQ_ENABLE_COVERAGE) From 2015999da49a5ff70a107cdd76e46fbe0d7c8d98 Mon Sep 17 00:00:00 2001 From: Daniel Barros <113608885+dduraesdebarros@users.noreply.github.com> Date: Mon, 18 Mar 2024 16:29:49 +0100 Subject: [PATCH 099/217] Added support for EnumerationType properties in OPC UA (openDAQ/openDAQ#117) * Work in Progress for adding Enum Support. * Added support for Enum parsing as UA_Int32 type * [OpenDaq] Work in Progress (WIP) Added support for unit testing EnumProperties * [WorkInProgress] Adding converters for Enum types * [WorkInProgress] Added some more logs * Added more debug logs * ToDaqObject returns nullptr instead of throwing an exception. * Remove Warning. * Added initial implementation of ToDaqObject of enumeration * Added support for Enumeration to DaqObject and server publishing * Removed unnecessary includes * Removed obsolete unit test * Fixed issue with not being able to write to Enumeration type node * Removed unused variable causing ci to fail * Fixed Enumeration ToVariant converter * AddToEnumType * Fix enumeration conversion in property object implementation and OPC UA server * Revert "AddToEnumType" This reverts commit 7bb07fe9381135951c5b817c6fc8fefbf250b6a8. * Added check for EnumerationType and fixed PR comments * Removed test placeholder * Added validation for the EnumerationProperty fields * Added check if defaultEnumeration is assigned * Added verification for the struct name before adding the property * Removed deprecated test * Fix OPC UA conversion issues and tests * Set value type of tms properties to ctEnumeration if datatype is enum * Added method for retrieving the EnumerationType name from the NodeId * Added overload of ToDaqObject to include name of dataType * Rework enumeration property default value setting * Add new factory for enumerations with "Type" instead of "TypeName" * Fix access violation on test tear down * Removed unnecessary code changes to DaqObject and AddEnumerationTypesToTypeManager --------- Co-authored-by: roettger Co-authored-by: Jaka Mohorko --- .../opcuaclient/cached_reference_browser.h | 2 +- .../include/opcuaserver/opcuaaddnodeparams.h | 2 +- .../include/opcuashared/opcuanodeid.h | 1 + .../include/opcuashared/opcuavariant.h | 4 +- .../opcua/opcuashared/src/opcuanodeid.cpp | 5 + .../include/opcuatms/converter_maps.h | 8 ++ .../include/opcuatms/core_types_utils.h | 2 + .../opcuatms/opcuatms/src/CMakeLists.txt | 1 + .../src/converters/base_object_converter.cpp | 14 ++- .../generic_enumeration_converter.cpp | 78 +++++++++++++ .../converters/generic_struct_converter.cpp | 6 +- .../opcuatms/src/core_types_utils.cpp | 30 +++++ .../include/opcuatms_client/tms_client.h | 2 + .../src/objects/tms_client_property_impl.cpp | 39 ++++++- .../tms_client_property_object_impl.cpp | 18 ++- .../src/tms_attribute_collector.cpp | 1 + .../opcuatms_client/src/tms_client.cpp | 59 +++++++++- .../objects/tms_server_property.h | 1 + .../objects/tms_server_variable.h | 2 + .../src/objects/tms_server_property.cpp | 66 ++++++++++- .../objects/tms_server_property_object.cpp | 25 +++++ .../src/objects/tms_server_variable.cpp | 21 +++- .../test_property_object_advanced.cpp | 18 +-- .../test_tms_fusion_device.cpp | 104 +++++++++++++----- .../test_tms_property_object.cpp | 2 +- 25 files changed, 446 insertions(+), 65 deletions(-) create mode 100644 shared/libraries/opcuatms/opcuatms/src/converters/generic_enumeration_converter.cpp diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h index c3be86f..71ed811 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h @@ -50,6 +50,7 @@ class CachedReferenceBrowser CachedReferenceBrowser(const OpcUaClientPtr& client, size_t maxNodesPerBrowse = 0); const CachedReferences& browse(const OpcUaNodeId& nodeId); + void browseMultiple(const std::vector& nodes); void invalidate(const OpcUaNodeId& nodeId); void invalidateRecursive(const OpcUaNodeId& nodeId); @@ -63,7 +64,6 @@ class CachedReferenceBrowser void invalidate(const OpcUaNodeId& nodeId, bool recursive); bool isCached(const OpcUaNodeId& nodeId); void markAsCached(const OpcUaNodeId& nodeId); - void browseMultiple(const std::vector& nodes); size_t browseBatch(const std::vector& nodes, size_t startIndex, size_t size, std::vector& browseNext); void processBrowseResults(const std::vector& nodes, size_t startIndex, diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h index 017fed5..f9ff14c 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h @@ -64,7 +64,7 @@ class AddVariableNodeParams : public GenericAddNodeParams AddVariableNodeParams(const OpcUaNodeId& requestedNewNodeId, const OpcUaNodeId& parentNodeId); void setDataType(const OpcUaNodeId& dataTypeId); - + OpcUaNodeId typeDefinition = OpcUaNodeId(UA_NS0ID_BASEDATAVARIABLETYPE); }; diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodeid.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodeid.h index 33b6144..dd711b6 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodeid.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodeid.h @@ -103,6 +103,7 @@ class OpcUaNodeId : public OpcUaObject UA_NodeId* getPtr() noexcept; uint16_t getNamespaceIndex() const noexcept; + uint32_t getIdentifierNumeric() const; OpcUaIdentifierUniversal getIdentifier() const; OpcUaIdentifierType getIdentifierType() const; std::string toString() const; diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h index 83f9e3f..e9c58da 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h @@ -54,7 +54,7 @@ namespace VariantUtils { if (!IsScalar(value)) throw std::runtime_error("Variant is not a scalar"); - if (!IsType(value)) + if (!IsType(value) && value.type->typeKind != UA_TYPES_ENUMERATION) throw std::runtime_error("Variant does not contain a scalar of specified return type"); return *static_cast(value.data); } @@ -77,6 +77,7 @@ namespace VariantUtils case UA_TYPES_UINT16: return ReadScalar(value); case UA_TYPES_INT32: + case UA_TYPES_ENUMERATION: return ReadScalar(value); case UA_TYPES_UINT32: return ReadScalar(value); @@ -84,6 +85,7 @@ namespace VariantUtils return ReadScalar(value); case UA_TYPES_UINT64: return ReadScalar(value); + default: throw std::runtime_error("Type not supported!"); } diff --git a/shared/libraries/opcua/opcuashared/src/opcuanodeid.cpp b/shared/libraries/opcua/opcuashared/src/opcuanodeid.cpp index 80ba803..15352c0 100644 --- a/shared/libraries/opcua/opcuashared/src/opcuanodeid.cpp +++ b/shared/libraries/opcua/opcuashared/src/opcuanodeid.cpp @@ -43,6 +43,11 @@ uint16_t OpcUaNodeId::getNamespaceIndex() const noexcept return value.namespaceIndex; } +uint32_t OpcUaNodeId::getIdentifierNumeric() const +{ + return value.identifier.numeric; +} + bool OpcUaNodeId::isNull() const noexcept { return UA_NodeId_isNull(&value); diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h index e8be922..8e3ef25 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h @@ -21,6 +21,7 @@ #include "opendaq/data_descriptor_ptr.h" #include "open62541/daqbt_nodeids.h" #include "open62541/daqbsp_nodeids.h" +#include "open62541/daqhbk_nodeids.h" #include "open62541/nodeids.h" #include "opendaq/function_block_type_ptr.h" @@ -94,6 +95,9 @@ namespace converters {IStruct::Id, [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) { return VariantConverter::ToVariant(object, targetType, ctx); }}, + {IEnumeration::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToVariant(object, targetType, ctx); }}, {IList::Id, [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) { return VariantConverter::ToArrayVariant(object, targetType, ctx); }}}; @@ -147,6 +151,9 @@ namespace converters {IStruct::Id, [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) { return VariantConverter::ToArrayVariant(object, targetType, ctx); }}, + {IEnumeration::Id, + [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) + { return VariantConverter::ToArrayVariant(object, targetType, ctx); }}, {IArgumentInfo::Id, [](const BaseObjectPtr& object, const UA_DataType* targetType, const ContextPtr& ctx) { return VariantConverter::ToArrayVariant(object, targetType, ctx); }}}; @@ -299,6 +306,7 @@ namespace converters return nullptr; const auto typeId = variant.getValue().type->typeId; + if (const auto it = uaTypeToDaqObject.find(OpcUaNodeId(typeId)); it != uaTypeToDaqObject.cend()) return it->second(variant, context); diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h index b3b5f97..e4959bb 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h @@ -37,5 +37,7 @@ CoreType UANodeIdToCoreType(OpcUaNodeId nodeId); OpcUaVariant DecodeIfExtensionObject(const OpcUaVariant& variant); OpcUaVariant UnwrapIfVariant(const OpcUaVariant& variant); const UA_DataType* GetUAStructureDataTypeByName(const std::string& structName); +const UA_DataType* GetUAEnumerationDataTypeByName(const std::string& enumerationName); +const std::string GetUATypeName(UA_UInt16 namespaceIndex, UA_UInt32 identifierNumeric); END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcuatms/opcuatms/src/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms/src/CMakeLists.txt index 9188c33..2daf1ac 100644 --- a/shared/libraries/opcuatms/opcuatms/src/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms/src/CMakeLists.txt @@ -43,6 +43,7 @@ set(SRC_Converters ${CONVERTERS_SRC_DIR}/range_converter.cpp ${CONVERTERS_SRC_DIR}/selection_converter.cpp ${CONVERTERS_SRC_DIR}/argument_converter.cpp ${CONVERTERS_SRC_DIR}/generic_struct_converter.cpp + ${CONVERTERS_SRC_DIR}/generic_enumeration_converter.cpp ${CONVERTERS_SRC_DIR}/property_object_conversion_utils.cpp ) diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp index 198e8fb..ac3311e 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp @@ -85,17 +85,21 @@ BaseObjectPtr VariantConverter::ToDaqObject(const OpcUaVariant& var auto decoded = DecodeIfExtensionObject(variant); auto unwrapped = UnwrapIfVariant(decoded); + if (unwrapped.isNull()) + return nullptr; + + const auto typeKind = unwrapped.getValue().type->typeKind; + if (typeKind == UA_DATATYPEKIND_ENUM ) + return VariantConverter::ToDaqObject(unwrapped, context); + const auto obj = converters::convertToDaqObject(unwrapped, context); if (obj.assigned()) return obj; - if (unwrapped.isNull()) - return nullptr; - - const auto typeKind = unwrapped.getValue().type->typeKind; if (typeKind == UA_DATATYPEKIND_STRUCTURE || typeKind == UA_DATATYPEKIND_OPTSTRUCT) return VariantConverter::ToDaqObject(unwrapped, context); + throw ConversionFailedException(); } @@ -131,7 +135,7 @@ OpcUaVariant VariantConverter::ToVariant(const BaseObjectPtr& objec { if (!object.assigned()) return {}; - + const auto ids = object.asPtr().getInterfaceIds(); auto wrapConvertedValue = targetType == &UA_TYPES[UA_TYPES_EXTENSIONOBJECT] || targetType == &UA_TYPES[UA_TYPES_VARIANT]; wrapConvertedValue = wrapConvertedValue && !object.asPtrOrNull().assigned(); diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/generic_enumeration_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/generic_enumeration_converter.cpp new file mode 100644 index 0000000..02ac526 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms/src/converters/generic_enumeration_converter.cpp @@ -0,0 +1,78 @@ +#include "coretypes/enumeration_factory.h" +#include "coretypes/enumeration_type_factory.h" +#include "coretypes/simple_type_factory.h" +#include "opcuatms/converters/list_conversion_utils.h" +#include "opcuatms/converters/struct_converter.h" +#include "opcuatms/converters/variant_converter.h" +#include "opcuatms/core_types_utils.h" +#include "opcuatms/extension_object.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +template <> +EnumerationPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& context) +{ + if (variant.isNull()) + return nullptr; + + if (!context.assigned() || !context.getTypeManager().assigned()) + throw ConversionFailedException{"Generic numeration conversion requires the TypeManager."}; + + const auto typeManager = context.getTypeManager(); + + // Get UAEnumerationType by name + const auto DataType = GetUAEnumerationDataTypeByName(variant->type->typeName); + + EnumerationTypePtr Type; + + if (typeManager.hasType(DataType->typeName)) + Type = typeManager.getType(DataType->typeName); + else + throw ConversionFailedException{"EnumerationType is not present in Type Manager."}; + + DictPtr dictEnumValues = Type.getAsDictionary(); + + auto listKeyword = dictEnumValues.getKeyList(); + auto listValues = dictEnumValues.getValueList(); + StringPtr keyword; + auto data = variant.toInteger(); + + for(int i = 0; i < static_cast(listKeyword.getCount()); i++) + { + if(listValues[i] == data) + keyword = listKeyword[i]; + } + + return Enumeration(DataType->typeName, keyword, typeManager); +} + +template <> +OpcUaVariant VariantConverter::ToVariant(const EnumerationPtr& object, + const UA_DataType* /*targetType*/, + const ContextPtr& /*context*/) +{ + const auto dataType = GetUAEnumerationDataTypeByName(object.getEnumerationType().getName()); + assert(dataType->memSize == sizeof(uint32_t)); + + const auto intVariant = VariantConverter::ToVariant(object.getIntValue(), &UA_TYPES[UA_TYPES_INT32]); + OpcUaVariant variant{}; + UA_Variant_setScalarCopy(&variant.getValue(), intVariant->data, dataType); + + return variant; +} + +template <> +ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, const ContextPtr& context) +{ + throw ConversionFailedException{}; +} + +template <> +OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& list, + const UA_DataType* /*targetType*/, + const ContextPtr& context) +{ + throw ConversionFailedException{}; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/generic_struct_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/generic_struct_converter.cpp index 4c0829f..2db9d9b 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/generic_struct_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/generic_struct_converter.cpp @@ -31,7 +31,7 @@ StructPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, co if (!context.assigned() || !context.getTypeManager().assigned()) throw ConversionFailedException{"Generic struct conversion requires the TypeManager."}; - const auto typeManager = context.getTypeManager(); + const auto typeManager = context.getTypeManager(); const auto type = variant->type; @@ -164,10 +164,10 @@ OpcUaVariant VariantConverter::ToVariant(const StructPtr& object, const throw ConversionFailedException{}; } - OpcUaVariant variant = VariantConverter::ToVariant(daqMember, memberType, context); + OpcUaVariant variant = VariantConverter::ToVariant(daqMember, memberType, context); if (variant->type != memberType && !(variant->data == UA_EMPTY_ARRAY_SENTINEL && variant->arrayLength == 0)) throw ConversionFailedException{}; - + void* src = variant->data; if (!member->isArray) diff --git a/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp b/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp index 1ac34e4..453c767 100644 --- a/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp @@ -263,4 +263,34 @@ const UA_DataType* GetUAStructureDataTypeByName(const std::string& structName) return nullptr; } +const UA_DataType* GetUAEnumerationDataTypeByName(const std::string& enumerationName) +{ + // TODO: Create static list, add any custom types added automatically. + OpcUaDataTypeArrayList typeArr; + typeArr.add(UA_TYPES_COUNT, UA_TYPES); + typeArr.add(UA_TYPES_DI_COUNT, UA_TYPES_DI); + typeArr.add(UA_TYPES_DAQBT_COUNT, UA_TYPES_DAQBT); + typeArr.add(UA_TYPES_DAQBSP_COUNT, UA_TYPES_DAQBSP); + typeArr.add(UA_TYPES_DAQDEVICE_COUNT, UA_TYPES_DAQDEVICE); + typeArr.add(UA_TYPES_DAQESP_COUNT, UA_TYPES_DAQESP); + typeArr.add(UA_TYPES_DAQHBK_COUNT, UA_TYPES_DAQHBK); + + const UA_DataTypeArray* dataType = typeArr.getCustomDataTypes(); + while(dataType) + { + for(size_t i = 0; i < dataType->typesSize; ++i) + { + if (dataType->types[i].typeName == enumerationName) + { + const auto typeKind = dataType->types[i].typeKind; + if (typeKind == UA_DATATYPEKIND_ENUM) + return &dataType->types[i]; + } + } + dataType = dataType->next; + } + + return nullptr; +} + END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h index 01e3fb6..7533636 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h @@ -33,6 +33,8 @@ class TmsClient final const FunctionPtr& createStreamingCallback); daq::DevicePtr connect(); + void AddEnumerationTypesToTypeManager(); + protected: void getRootDeviceNodeAttributes(OpcUaNodeId& nodeIdOut, std::string& browseNameOut); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp index 775e798..094c953 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp @@ -1,4 +1,5 @@ #include "opcuatms_client/objects/tms_client_property_impl.h" +#include #include "coreobjects/coercer_factory.h" #include "coreobjects/eval_value_factory.h" #include "coreobjects/validator_factory.h" @@ -58,12 +59,22 @@ TmsClientPropertyImpl::TmsClientPropertyImpl(const ContextPtr& daqContext, const void TmsClientPropertyImpl::readBasicInfo() { auto reader = clientContext->getAttributeReader(); - const auto variant = reader->getValue(nodeId, UA_ATTRIBUTEID_VALUE); - const auto object = VariantConverter::ToDaqObject(variant, daqContext); - this->valueType = object.getCoreType(); - this->name = String(reader->getValue(nodeId, UA_ATTRIBUTEID_DISPLAYNAME).toString()); this->description = String(reader->getValue(nodeId, UA_ATTRIBUTEID_DESCRIPTION).toString()); + + const auto dataType = reader->getValue(nodeId, UA_ATTRIBUTEID_DATATYPE).toNodeId(); + const auto enumerationTypeId = OpcUaNodeId(0, UA_NS0ID_ENUMERATION); + + if (clientContext->getReferenceBrowser()->isSubtypeOf(dataType, enumerationTypeId)) + { + this->valueType = ctEnumeration; + } + else + { + const auto variant = reader->getValue(nodeId, UA_ATTRIBUTEID_VALUE); + const auto object = VariantConverter::ToDaqObject(variant, daqContext); + this->valueType = object.getCoreType(); + } } void TmsClientPropertyImpl::configurePropertyFields() @@ -170,8 +181,24 @@ void TmsClientPropertyImpl::configurePropertyFields() "Failed to read default value of property {} on OpcUa client. Detault value is set to the value at connection time.", this->name); } - this->defaultValue = VariantConverter::ToDaqObject(value, daqContext); - + + //Special handling for enumerations as this data type is encoded as Int32 in OPCUA + const auto dataType = reader->getValue(nodeId, UA_ATTRIBUTEID_DATATYPE).toNodeId(); + const auto enumerationTypeId = OpcUaNodeId(0, UA_NS0ID_ENUMERATION); + + if (clientContext->getReferenceBrowser()->isSubtypeOf(dataType, enumerationTypeId)) + { + if (value->type != &UA_TYPES[UA_TYPES_INT32]) + throw ConversionFailedException{"Enumeration node data type is not uint32_t"}; + + const auto enumBrowseName = client->readBrowseName(dataType); + const auto enumType = GetUAEnumerationDataTypeByName(enumBrowseName); + OpcUaVariant variant{}; + UA_Variant_setScalarCopy(&variant.getValue(), value->data, enumType); + this->defaultValue = VariantConverter::ToDaqObject(variant, daqContext); + } + else + this->defaultValue = VariantConverter::ToDaqObject(value, daqContext); if (this->defaultValue.assigned() && this->defaultValue.asPtrOrNull().assigned()) this->defaultValue.freeze(); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index bd3e6c0..f697400 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -35,18 +35,24 @@ ErrCode TmsClientPropertyObjectBaseImpl::setPropertyValueInternal(IString* { if (const auto& it = introspectionVariableIdMap.find(propertyNamePtr); it != introspectionVariableIdMap.cend()) { + PropertyPtr prop; + checkErrorInfo(getProperty(propertyName, &prop)); if (protectedWrite) { lastProccessDescription = "Checking exisiting property is read-only"; - PropertyPtr prop; - checkErrorInfo(getProperty(propertyName, &prop)); const bool readOnly = prop.getReadOnly(); if (readOnly) return OPENDAQ_SUCCESS; } - lastProccessDescription = "Writting property value"; - const auto variant = VariantConverter::ToVariant(value, nullptr, daqContext); + BaseObjectPtr valuePtr = value; + const auto ct = prop.getValueType(); + const auto valueCt = valuePtr.getCoreType(); + if (ct != valueCt) + valuePtr = valuePtr.convertTo(ct); + + lastProccessDescription = "Writing property value"; + const auto variant = VariantConverter::ToVariant(valuePtr, nullptr, daqContext); client->writeValue(it->second, variant); return OPENDAQ_SUCCESS; } @@ -283,7 +289,7 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par prop = TmsClientProperty(daqContext, clientContext, ref->nodeId.nodeId); introspectionVariableIdMap.insert(std::pair(propName, childNodeId)); - } + } catch(const std::exception& e) { LOG_W("Failed to add {} property on OpcUa client property object: {}", propName, e.what()); @@ -451,7 +457,7 @@ void TmsClientPropertyObjectBaseImpl::browseRawProperties() std::unordered_map functionPropValues; addProperties(nodeId, orderedProperties, unorderedProperties); - + // TODO: Make sure that this is a DeviceType node if (hasReference("MethodSet")) { diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_attribute_collector.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_attribute_collector.cpp index f0392b4..0e8813b 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_attribute_collector.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_attribute_collector.cpp @@ -161,6 +161,7 @@ void TmsAttributeCollector::collectPropertyAttributes(const OpcUaNodeId& nodeId) attributes.insert({nodeId, UA_ATTRIBUTEID_VALUE}); attributes.insert({nodeId, UA_ATTRIBUTEID_DISPLAYNAME}); attributes.insert({nodeId, UA_ATTRIBUTEID_DESCRIPTION}); + attributes.insert({nodeId, UA_ATTRIBUTEID_DATATYPE}); if (browser->hasReference(nodeId, "ValidationExpression")) attributes.insert({browser->getChildNodeId(nodeId, "ValidationExpression"), UA_ATTRIBUTEID_VALUE}); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp index 6acd14a..bb4fc83 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp @@ -57,6 +57,9 @@ daq::DevicePtr TmsClient::connect() tmsClientContext = std::make_shared(client, context); + //On connect add server broadcasted enumeration types to the type manager + AddEnumerationTypesToTypeManager(); + OpcUaNodeId rootDeviceNodeId; std::string rootDeviceBrowseName; getRootDeviceNodeAttributes(rootDeviceNodeId, rootDeviceBrowseName); @@ -79,10 +82,64 @@ daq::DevicePtr TmsClient::connect() const auto endTime = std::chrono::steady_clock::now(); const auto connectTime = std::chrono::duration(endTime - startTime); - LOG_D("Connected to penDAQ OPC UA server {}. Connect took {:.2f} s.", opcUaUrl, connectTime.count()); + LOG_D("Connected to openDAQ OPC UA server {}. Connect took {:.2f} s.", opcUaUrl, connectTime.count()); return device; } +void TmsClient::AddEnumerationTypesToTypeManager() +{ + if (!context.assigned() || !context.getTypeManager().assigned()) + return; // TypeManager required. Do nothing. + + auto typeManager = context.getTypeManager(); + + const auto DataTypeEnumerationNodeId = OpcUaNodeId(UA_NS0ID_ENUMERATION); + const auto& references = tmsClientContext->getReferenceBrowser()->browse(DataTypeEnumerationNodeId); + StructPtr EnumValuesStruct; + std::vector vecEnumerationsNodeIds; + + for (auto [browseName, ref] : references.byBrowseName) + vecEnumerationsNodeIds.push_back(ref->nodeId.nodeId); + + //Cache NodeIds + tmsClientContext->getReferenceBrowser()->browseMultiple(vecEnumerationsNodeIds); + + auto listEnumValues = List(); + + for (auto [browseName, ref] : references.byBrowseName) + { + //If type already exists, skip + if(typeManager.hasType(browseName)) + continue; + + const auto& references1 = tmsClientContext->getReferenceBrowser()->browse(ref->nodeId.nodeId); + for (auto [childBrowseName, ChildRef] : references1.byBrowseName) + { + const auto childNodeValue = client->readValue(ChildRef->nodeId.nodeId); + const auto childNodeObject = VariantConverter::ToDaqObject(childNodeValue, context); + + if (childBrowseName == "EnumStrings") + { + for (auto value : childNodeObject.asPtr()) + listEnumValues.pushBack(value); + } + else if (childBrowseName == "EnumValues") + { + for (const auto& value : childNodeObject.asPtr()) + { + if (EnumValuesStruct = value.asPtrOrNull(); EnumValuesStruct.assigned()) + listEnumValues.pushBack(EnumValuesStruct.get("DisplayName")); + } + } + } + + auto enumExcitationType = EnumerationType(browseName, listEnumValues); + typeManager.addType(enumExcitationType); + + listEnumValues.clear(); + } +} + void TmsClient::getRootDeviceNodeAttributes(OpcUaNodeId& nodeIdOut, std::string& browseNameOut) { const OpcUaNodeId rootNodeId(NAMESPACE_DI, UA_DIID_DEVICESET); diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h index 126bb32..0ee8c82 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h @@ -56,6 +56,7 @@ class TmsServerProperty : public TmsServerVariable void addChildNodes() override; void configureVariableNodeAttributes(opcua::OpcUaObject& attr) override; void validate() override; + opcua::OpcUaNodeId getDataTypeId() override; private: void registerEvalValueNode(const std::string& nodeName, TmsServerEvalValue::ReadCallback readCallback, bool isSelection = false); diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h index 10d106c..ce37802 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h @@ -29,6 +29,8 @@ class TmsServerVariable : public TmsServerObjectBaseImpl opcua::OpcUaNodeId createNode(const opcua::OpcUaNodeId& parentNodeId) override; + virtual opcua::OpcUaNodeId getDataTypeId(); + protected: virtual void configureVariableNodeAttributes(opcua::OpcUaObject& attr); }; diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp index efc4c76..c337660 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "opcuatms/converters/variant_converter.h" #include "open62541/daqbsp_nodeids.h" #include @@ -108,8 +109,9 @@ opcua::OpcUaNodeId TmsServerProperty::getTmsTypeId() if (objectInternal.getReferencedPropertyUnresolved().assigned()) return OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_REFERENCEVARIABLETYPE); - + const auto type = object.getValueType(); + switch (type) { case CoreType::ctInt: @@ -117,6 +119,7 @@ opcua::OpcUaNodeId TmsServerProperty::getTmsTypeId() return OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_NUMERICVARIABLETYPE); case CoreType::ctStruct: return OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_STRUCTUREVARIABLETYPE); + case CoreType::ctEnumeration: default: break; } @@ -157,6 +160,50 @@ void TmsServerProperty::configureVariableNodeAttributes(opcua::OpcUaObjectdescription = UA_LOCALIZEDTEXT_ALLOC("", object.getDescription().getCharPtr()); } +opcua::OpcUaNodeId TmsServerProperty::getDataTypeId() +{ + const auto objInternal = object.asPtr(); + if (objInternal.getReferencedPropertyUnresolved().assigned()) + return OpcUaNodeId(0, UA_NS0ID_STRING); + + const auto type = objInternal.getValueTypeUnresolved(); + switch (type) + { + case CoreType::ctBool: + return OpcUaNodeId(0, UA_NS0ID_BOOLEAN); + case CoreType::ctInt: + return OpcUaNodeId(0, UA_NS0ID_INT64); + case CoreType::ctFloat: + return OpcUaNodeId(0, UA_NS0ID_DOUBLE); + case CoreType::ctString: + return OpcUaNodeId(0, UA_NS0ID_STRING); + case CoreType::ctEnumeration: + { + EnumerationPtr enumPtr = this->parent.getRef().getPropertyValue(object.getName()); + std::string enumTypeName = enumPtr.getEnumerationType().getName(); + const auto DataType = GetUAEnumerationDataTypeByName(enumTypeName); + if (DataType != nullptr) + return DataType->typeId; + else + break; + } + case CoreType::ctStruct: + { + StructPtr structPtr = this->parent.getRef().getPropertyValue(object.getName()); + std::string structTypeName = structPtr.getStructType().getName(); + const auto DataType = GetUAStructureDataTypeByName(structTypeName); + if(DataType != nullptr) + return DataType->typeId; + else + break; + } + default: + break; + } + + return {}; +} + void TmsServerProperty::validate() { } @@ -250,6 +297,23 @@ void TmsServerProperty::hideStructureTypeChildren() void TmsServerProperty::addReferenceTypeChildNodes() { + const auto type = object.getValueType(); + if (type == CoreType::ctStruct) + { + StructPtr structPtr = this->parent.getRef().getPropertyValue(object.getName()); + std::string structTypeName = structPtr.getStructType().getName(); + if(GetUAStructureDataTypeByName(structTypeName) == nullptr) + return; + } + + if (type == CoreType::ctEnumeration) + { + EnumerationPtr enumPtr = this->parent.getRef().getPropertyValue(object.getName()); + std::string enumTypeName = enumPtr.getEnumerationType().getName(); + if(GetUAEnumerationDataTypeByName(enumTypeName) == nullptr) + return; + } + const auto refNames = objectInternal.getReferencedPropertyUnresolved().getPropertyReferences(); for (auto propName : refNames) { diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp index 61c6fda..a1354fd 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp @@ -5,6 +5,7 @@ #include "coreobjects/property_object_internal_ptr.h" #include "opcuatms/converters/variant_converter.h" #include "opcuatms_server/objects/tms_server_property.h" +#include #include "open62541/nodeids.h" #include "open62541/statuscodes.h" #include "open62541/daqbsp_nodeids.h" @@ -103,6 +104,30 @@ void TmsServerPropertyObject::addChildNodes() continue; } + //Don't add property if struct is not part of UA data types list + if(prop.getValueType() == ctStruct) + { + StructPtr structPtr = prop.getDefaultValue().asPtrOrNull(); + if(structPtr.assigned()) + { + std::string structTypeName = structPtr.getStructType().getName(); + if(GetUAStructureDataTypeByName(structTypeName) == nullptr) + continue; + } + } + + //Don't add property if enumeration is not part of UA data types list + if (prop.getValueType() == ctEnumeration) + { + EnumerationPtr enumPtr = prop.getDefaultValue().asPtrOrNull(); + if(enumPtr.assigned()) + { + std::string enumTypeName = enumPtr.getEnumerationType().getName(); + if(GetUAEnumerationDataTypeByName(enumTypeName) == nullptr) + continue; + } + } + OpcUaNodeId childNodeId; std::shared_ptr serverInfo; const auto propName = prop.getName(); diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp index 32b4407..f2458de 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp @@ -33,12 +33,25 @@ opcua::OpcUaNodeId TmsServerVariable::createNode(const opcua::OpcUaNod } template -void TmsServerVariable::configureVariableNodeAttributes(opcua::OpcUaObject& attr) +opcua::OpcUaNodeId TmsServerVariable::getDataTypeId() { - const auto tmsTypeId = this->getTmsTypeId(); - const auto dataTypeId = this->server->readDataType(tmsTypeId); + return {}; +} - attr->dataType = *dataTypeId; +template +void TmsServerVariable::configureVariableNodeAttributes(opcua::OpcUaObject& attr) +{ + const auto dataType = this->getDataTypeId(); + if (!dataType.isNull()) + { + attr->dataType = dataType.getValue(); + } + else + { + const auto tmsTypeId = this->getTmsTypeId(); + const auto dataTypeId = this->server->readDataType(tmsTypeId); + attr->dataType = *dataTypeId; + } attr->accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; attr->writeMask |= UA_WRITEMASK_DISPLAYNAME | UA_WRITEMASK_DESCRIPTION; } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp index 6741d31..3225e83 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp @@ -126,8 +126,8 @@ class TmsPropertyObjectAdvancedTest : public TmsObjectIntegrationTest .addProperty(IntPropertyBuilder("CoercedInt", 10).setCoercer(Coercer("if(Value > 10, 10, Value)")).build()) .addProperty(RatioProperty("Ratio", Ratio(1, 1000))) .addProperty(ObjectPropertyBuilder("ObjectWithMetadata", obj1).setReadOnly(true).setVisible(false).build()) - .addProperty(StructProperty("UnitStruct", Unit("s", -1, "second", "time"))) - .addProperty(StructProperty("ArgumentStruct", ArgumentInfo("Arg", ctInt))) + //.addProperty(StructProperty("UnitStruct", Unit("s", -1, "second", "time"))) + //.addProperty(StructProperty("ArgumentStruct", ArgumentInfo("Arg", ctInt))) .addProperty(StructProperty("DeviceDomainStructure", Struct("DeviceDomainStructure", Dict({{"Resolution", Ratio(10, 20)}, @@ -620,7 +620,7 @@ TEST_F(TmsPropertyObjectAdvancedTest, ValidationCoercion) ASSERT_EQ(obj.getPropertyValue("CoercedInt"), clientObj.getPropertyValue("CoercedInt")); ASSERT_NO_THROW(clientObj.setPropertyValue("ValidatedInt", 11)); - ASSERT_EQ(getLastMessage(), "Failed to set value for property \"ValidatedInt\" on OpcUA client property object: Writting property value"); + ASSERT_EQ(getLastMessage(), "Failed to set value for property \"ValidatedInt\" on OpcUA client property object: Writing property value"); ASSERT_EQ(obj.getPropertyValue("ValidatedInt"), 5); ASSERT_EQ(clientObj.getPropertyValue("ValidatedInt"), 5); @@ -719,8 +719,8 @@ TEST_F(TmsPropertyObjectAdvancedTest, StructureGet) const auto obj = PropertyObject(manager, "TestClass"); auto [serverObj, clientObj] = registerPropertyObject(obj); - ASSERT_EQ(clientObj.getPropertyValue("UnitStruct"), obj.getPropertyValue("UnitStruct")); - ASSERT_EQ(clientObj.getPropertyValue("ArgumentStruct"), obj.getPropertyValue("ArgumentStruct")); + //ASSERT_EQ(clientObj.getPropertyValue("UnitStruct"), obj.getPropertyValue("UnitStruct")); + //ASSERT_EQ(clientObj.getPropertyValue("ArgumentStruct"), obj.getPropertyValue("ArgumentStruct")); ASSERT_EQ(clientObj.getPropertyValue("DeviceDomainStructure"), obj.getPropertyValue("DeviceDomainStructure")); ASSERT_EQ(clientObj.getPropertyValue("ListRuleDescriptionStructure"), obj.getPropertyValue("ListRuleDescriptionStructure")); ASSERT_EQ(clientObj.getPropertyValue("CustomRuleDescriptionStructure"), obj.getPropertyValue("CustomRuleDescriptionStructure")); @@ -732,8 +732,8 @@ TEST_F(TmsPropertyObjectAdvancedTest, StructureSet) const auto obj = PropertyObject(manager, "TestClass"); auto [serverObj, clientObj] = registerPropertyObject(obj); - clientObj.setPropertyValue("UnitStruct", Unit("V", 5, "volt", "voltage")); - clientObj.setPropertyValue("ArgumentStruct", ArgumentInfo("test", ctFloat)); + //clientObj.setPropertyValue("UnitStruct", Unit("V", 5, "volt", "voltage")); + //clientObj.setPropertyValue("ArgumentStruct", ArgumentInfo("test", ctFloat)); clientObj.setPropertyValue("DeviceDomainStructure", Struct("DeviceDomainStructure", Dict({{"Resolution", Ratio(20, 30)}, @@ -761,8 +761,8 @@ TEST_F(TmsPropertyObjectAdvancedTest, StructureSet) Dict({{"Parameters", keyValuePairList}}), manager)); - ASSERT_EQ(clientObj.getPropertyValue("UnitStruct"), obj.getPropertyValue("UnitStruct")); - ASSERT_EQ(clientObj.getPropertyValue("ArgumentStruct"), obj.getPropertyValue("ArgumentStruct")); + //ASSERT_EQ(clientObj.getPropertyValue("UnitStruct"), obj.getPropertyValue("UnitStruct")); + //ASSERT_EQ(clientObj.getPropertyValue("ArgumentStruct"), obj.getPropertyValue("ArgumentStruct")); ASSERT_EQ(clientObj.getPropertyValue("DeviceDomainStructure"), obj.getPropertyValue("DeviceDomainStructure")); ASSERT_EQ(clientObj.getPropertyValue("ListRuleDescriptionStructure"), obj.getPropertyValue("ListRuleDescriptionStructure")); ASSERT_EQ(clientObj.getPropertyValue("CustomRuleDescriptionStructure"), obj.getPropertyValue("CustomRuleDescriptionStructure")); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp index f72cc8c..4d8c9ac 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp @@ -1,4 +1,5 @@ #include +#include #include "coreobjects/callable_info_factory.h" #include "coreobjects/property_object_factory.h" #include "coreobjects/unit_factory.h" @@ -7,12 +8,11 @@ #include "opcuaclient/opcuaclient.h" #include "opcuatms_client/objects/tms_client_property_object_factory.h" #include "opcuatms_client/objects/tms_client_property_object_impl.h" -#include "opcuatms_server/objects/tms_server_property_object.h" #include "opcuatms_client/objects/tms_client_signal_factory.h" +#include "opcuatms_server/objects/tms_server_property_object.h" #include "opcuatms_server/objects/tms_server_signal.h" -#include "tms_object_integration_test.h" #include "opendaq/instance_factory.h" -#include +#include "tms_object_integration_test.h" using namespace daq; using namespace opcua::tms; @@ -28,7 +28,6 @@ struct RegisteredPropertyObject class TmsFusionDevice : public TmsObjectIntegrationTest { protected: - TypeManagerPtr objManager; SignalPtr createSignal(const std::string& id) @@ -43,41 +42,62 @@ class TmsFusionDevice : public TmsObjectIntegrationTest TmsObjectIntegrationTest::SetUp(); objManager = TypeManager(); + // Add Enumeration type to Type Manager + const auto enumExcitationType = EnumerationType( + "ExcitationTypeEnumeration", List("DoNotCare", "DCVoltage", "ACVoltage", "ACVoltageRectangle", "ACVoltageSinewave")); + objManager.addType(enumExcitationType); + // create class with name "FusionAmp" auto fusionAmpClass = PropertyObjectClassBuilder("FusionAmp") - .addProperty(SelectionProperty( - "Measurement", List("Voltage", "FullBridge", "HalfBridge", "QuarterBridge"), 0)) + .addProperty(SelectionProperty("Measurement", List("Voltage", "FullBridge", "HalfBridge", "QuarterBridge"), 0)) + .addProperty(StructProperty("AdjustmentPoint", + Struct("AdjustmentPointScalingStructure", + Dict({{"Index", 1}, {"Factor", 2.1}, {"Offset", 3.0}}), + objManager))) .addProperty(StructProperty( - "AdjustmentPoint", Struct("AdjustmentPointScalingStructure", Dict({{"Index", 1}, {"Factor", 2.1}, {"Offset", 3.0}}), objManager)) - ) - .addProperty(StructProperty( - "Scaler", Struct("GainScalingStructure", Dict({{"Factor", 2.1}, {"Offset", 3.0}}), objManager)) - ) + "Scaler", Struct("GainScalingStructure", Dict({{"Factor", 2.1}, {"Offset", 3.0}}), objManager))) + .addProperty(EnumerationProperty("ExcitationType", Enumeration("ExcitationTypeEnumeration", "DCVoltage", objManager))) + //.addProperty(StructProperty( + // "FullBridge", + // Struct("FullBridgeSensorStructure", + // Dict( + // {{"ExcitationVoltage", + // Struct("ExcitationVoltageStructure", + // Dict( + // {{"ActualValue", 5.0}, + // {"NominalValue", 5.0}, + // {"NominalValueRange", + // Struct("Range", Dict({{"Low", 4.0}, {"High", 6.0}}), objManager)}, + // {"Type", Enumeration("ExcitationTypeEnumeration", "DCVoltage", objManager)}, + // {"Frequency", 0}}), + // objManager)}, + // {"Resistance", 350.0}, + // {"MaximumElectrical", 5.0}, + // {"UsedWires", 6}}), + // objManager))) .build(); objManager.addType(fusionAmpClass); } void TearDown() override { - objManager.removeType("FusionAmp"); } RegisteredPropertyObject registerPropertyObject(const PropertyObjectPtr& prop) { const auto logger = Logger(); - const auto context = Context(nullptr, logger, TypeManager(), nullptr); + const auto context = Context(nullptr, logger, objManager, nullptr); const auto serverProp = std::make_shared(prop, server, context, std::make_shared(context, nullptr)); const auto nodeId = serverProp->registerOpcUaNode(); - const auto clientProp = TmsClientPropertyObject(Context(nullptr, logger, TypeManager(), nullptr), clientContext, nodeId); + const auto clientProp = TmsClientPropertyObject(Context(nullptr, logger, objManager, nullptr), clientContext, nodeId); return {serverProp, clientProp}; } }; TEST_F(TmsFusionDevice, SampleRateTest) { - SignalPtr daqServerSignal = createSignal("id"); daqServerSignal.addProperty(FloatProperty("SampleRate", 1.0, false)); @@ -85,7 +105,7 @@ TEST_F(TmsFusionDevice, SampleRateTest) auto nodeId = serverSignal.registerOpcUaNode(); SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); - //std::cin.get(); + // std::cin.get(); ASSERT_TRUE(clientSignal.getPublic()); ASSERT_NO_THROW(clientSignal.getPropertyValue("SampleRate")); @@ -95,27 +115,61 @@ TEST_F(TmsFusionDevice, StructTest) { const auto obj = PropertyObject(objManager, "FusionAmp"); auto [serverObj, fusionAmp] = registerPropertyObject(obj); - + // Test struct with int and float values - const auto adjustmentPoint = StructBuilder(fusionAmp.getPropertyValue("AdjustmentPoint")); + const auto adjustmentPoint = StructBuilder(fusionAmp.getPropertyValue("AdjustmentPoint")); adjustmentPoint.set("Index", 10); adjustmentPoint.set("Factor", 3.1); fusionAmp.setPropertyValue("AdjustmentPoint", adjustmentPoint.build()); - - const auto adjustmentPointManipulated = StructBuilder(fusionAmp.getPropertyValue("AdjustmentPoint")); + + const auto adjustmentPointManipulated = StructBuilder(fusionAmp.getPropertyValue("AdjustmentPoint")); ASSERT_EQ(adjustmentPointManipulated.get("Index"), 10); ASSERT_FLOAT_EQ(adjustmentPointManipulated.get("Factor"), (float) 3.1); - // Test strusct with double values - const auto scaler = StructBuilder(fusionAmp.getPropertyValue("Scaler")); + // Test struct with double values + const auto scaler = StructBuilder(fusionAmp.getPropertyValue("Scaler")); scaler.set("Factor", 3.62); scaler.set("Offset", 3.1); fusionAmp.setPropertyValue("Scaler", scaler.build()); - - const auto scalerManipulated = StructBuilder(fusionAmp.getPropertyValue("Scaler")); + + const auto scalerManipulated = StructBuilder(fusionAmp.getPropertyValue("Scaler")); ASSERT_DOUBLE_EQ(scalerManipulated.get("Factor"), (double) 3.62); ASSERT_DOUBLE_EQ(scalerManipulated.get("Offset"), (double) 3.1); +} +TEST_F(TmsFusionDevice, EnumTest) +{ + // This test should be moved to coreobjects + const auto obj = PropertyObject(objManager, "FusionAmp"); + + // Test enum property + obj.setPropertyValue("ExcitationType", Enumeration("ExcitationTypeEnumeration", "ACVoltage", objManager)); + ASSERT_EQ(obj.getPropertyValue("ExcitationType"), Enumeration("ExcitationTypeEnumeration", "ACVoltage", objManager)); +} + +TEST_F(TmsFusionDevice, DISABLED_DebugServerPublishingTest) +{ + // This test asserts nothing. It is used to debug the OPCUA server + const auto obj = PropertyObject(objManager, "FusionAmp"); + const auto logger = Logger(); + const auto context = Context(nullptr, logger, TypeManager(), nullptr); + const auto serverProp = + std::make_shared(obj, server, context, std::make_shared(context, nullptr)); + const auto nodeId = serverProp->registerOpcUaNode(); + while (true) + { + } +} + +TEST_F(TmsFusionDevice, EnumPropertyTest) +{ + const auto obj = PropertyObject(objManager, "FusionAmp"); + auto [serverObj, fusionAmp] = registerPropertyObject(obj); + + // Test enum + fusionAmp.setPropertyValue("ExcitationType", Enumeration("ExcitationTypeEnumeration", "ACVoltage", objManager)); + ASSERT_EQ(obj.getPropertyValue("ExcitationType"), Enumeration("ExcitationTypeEnumeration", "ACVoltage", objManager)); + ASSERT_EQ(fusionAmp.getPropertyValue("ExcitationType"), Enumeration("ExcitationTypeEnumeration", "ACVoltage", objManager)); } TEST_F(TmsFusionDevice, DISABLED_SimulatorTest) @@ -129,5 +183,3 @@ TEST_F(TmsFusionDevice, DISABLED_SimulatorTest) ASSERT_TRUE(clientDevice.assigned()); } - - diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp index b187a87..9ee2bf9 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp @@ -136,7 +136,7 @@ TEST_F(TmsPropertyObjectTest, PropertyValueRole) ASSERT_EQ(prop.getPropertyValue("Role"), 1); ASSERT_NO_THROW(clientProp.setPropertyValue("Role", 2)); - ASSERT_EQ(getLastMessage(), "Failed to set value for property \"Role\" on OpcUA client property object: Writting property value"); + ASSERT_EQ(getLastMessage(), "Failed to set value for property \"Role\" on OpcUA client property object: Writing property value"); } TEST_F(TmsPropertyObjectTest, getPropertySelectionValue) From b8454316a90f9248952046b0b3d7e17477ebd5f1 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Mon, 18 Mar 2024 18:34:26 +0100 Subject: [PATCH 100/217] Allow convertible openDAQ structs over OPC UA --- .../include/opcuatms/core_types_utils.h | 1 + .../src/converters/core_types_converter.cpp | 3 +- .../opcuatms/src/core_types_utils.cpp | 9 ++ .../objects/tms_client_context.h | 2 + .../include/opcuatms_client/tms_client.h | 1 - .../src/objects/tms_client_context.cpp | 68 ++++++++++++++ .../opcuatms_client/src/tms_client.cpp | 58 +----------- .../src/objects/tms_server_property.cpp | 2 +- .../objects/tms_server_property_object.cpp | 2 +- .../test_property_object_advanced.cpp | 39 +++++++- .../test_tms_fusion_device.cpp | 89 +++++++++---------- .../tms_object_integration_test.cpp | 6 +- .../tms_object_integration_test.h | 1 + 13 files changed, 172 insertions(+), 109 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h index e4959bb..1c397e1 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h @@ -39,5 +39,6 @@ OpcUaVariant UnwrapIfVariant(const OpcUaVariant& variant); const UA_DataType* GetUAStructureDataTypeByName(const std::string& structName); const UA_DataType* GetUAEnumerationDataTypeByName(const std::string& enumerationName); const std::string GetUATypeName(UA_UInt16 namespaceIndex, UA_UInt32 identifierNumeric); +bool nativeStructConversionSupported(const std::string& structName); END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/core_types_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/core_types_converter.cpp index 1593028..7789421 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/core_types_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/core_types_converter.cpp @@ -135,7 +135,8 @@ IntegerPtr StructConverter::ToDaqObject(const UA_Byte& value, template <> OpcUaObject StructConverter::ToTmsType(const IntegerPtr& object, const ContextPtr& /*context*/) { - return {static_cast(object)}; + const int64_t val = object; + return {static_cast(val)}; } template <> diff --git a/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp b/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp index 453c767..6c0b348 100644 --- a/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp @@ -15,6 +15,7 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA namespace details { + static std::unordered_map nodeIdToCoreTypeMap = { {OpcUaNodeId(0, UA_NS0ID_BOOLEAN), ctBool}, {OpcUaNodeId(0, UA_NS0ID_FLOAT), ctFloat}, @@ -31,6 +32,9 @@ static std::unordered_map nodeIdToCoreTypeMap = { {OpcUaNodeId(0, UA_NS0ID_RATIONALNUMBER), ctRatio}, {OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_RATIONALNUMBER64), ctRatio}, {OpcUaNodeId(0, UA_DAQBTID_RATIONALNUMBER64), ctRatio}}; + +static std::unordered_set convertibleNativeStructs = { + "unit", "range", "argumentInfo", "complexNumber", "functionBlockType"}; } StringPtr ConvertToDaqCoreString(const UA_String& uaString) @@ -293,4 +297,9 @@ const UA_DataType* GetUAEnumerationDataTypeByName(const std::string& enumeration return nullptr; } +bool nativeStructConversionSupported(const std::string& structName) +{ + return details::convertibleNativeStructs.count(structName); +} + END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h index 1745637..ef0bdd5 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h @@ -48,6 +48,7 @@ class TmsClientContext void readObjectAttributes(const OpcUaNodeId& nodeId, bool forceRead = false); size_t getMaxNodesPerBrowse(); size_t getMaxNodesPerRead(); + void addEnumerationTypesToTypeManager(); template ::SmartPtr> Ptr getObject(const opcua::OpcUaNodeId& nodeId) @@ -76,6 +77,7 @@ class TmsClientContext size_t maxNodesPerBrowse = 0; size_t maxNodesPerRead = 0; WeakRefPtr rootDevice; + bool enumerationTypesAdded = false; void initReferenceBrowser(); void initAttributeReader(); diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h index 7533636..269803d 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h @@ -33,7 +33,6 @@ class TmsClient final const FunctionPtr& createStreamingCallback); daq::DevicePtr connect(); - void AddEnumerationTypesToTypeManager(); protected: diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp index e92790f..74d6036 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp @@ -1,5 +1,6 @@ #include "opcuatms_client/objects/tms_client_context.h" #include +#include #include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -128,4 +129,71 @@ void TmsClientContext::initAttributeReader() attributeReader = std::make_shared(client, maxNodesPerRead); } +void TmsClientContext::addEnumerationTypesToTypeManager() +{ + if (enumerationTypesAdded) + return; + + if (!context.assigned() || !context.getTypeManager().assigned()) + return; // TypeManager required. Do nothing. + + auto typeManager = context.getTypeManager(); + + const auto DataTypeEnumerationNodeId = OpcUaNodeId(UA_NS0ID_ENUMERATION); + const auto& references = referenceBrowser->browse(DataTypeEnumerationNodeId); + StructPtr EnumValuesStruct; + std::vector vecEnumerationsNodeIds; + + for (auto [browseName, ref] : references.byBrowseName) + vecEnumerationsNodeIds.push_back(ref->nodeId.nodeId); + + //Cache NodeIds + referenceBrowser->browseMultiple(vecEnumerationsNodeIds); + + auto listEnumValues = List(); + + for (auto [browseName, ref] : references.byBrowseName) + { + //If type already exists, skip + if(typeManager.hasType(browseName)) + continue; + + const auto& references1 = referenceBrowser->browse(ref->nodeId.nodeId); + for (auto [childBrowseName, ChildRef] : references1.byBrowseName) + { + const auto childNodeValue = client->readValue(ChildRef->nodeId.nodeId); + const auto childNodeObject = VariantConverter::ToDaqObject(childNodeValue, context); + + if (childBrowseName == "EnumStrings") + { + for (auto value : childNodeObject.asPtr()) + listEnumValues.pushBack(value); + } + else if (childBrowseName == "EnumValues") + { + for (const auto& value : childNodeObject.asPtr()) + { + if (EnumValuesStruct = value.asPtrOrNull(); EnumValuesStruct.assigned()) + listEnumValues.pushBack(EnumValuesStruct.get("DisplayName")); + } + } + } + + auto enumType = EnumerationType(browseName, listEnumValues); + + try + { + typeManager.addType(enumType); + } + catch (...) + { + LOG_I("Failed to add OPC UA type {} to type manager.", enumType.getName()); + } + + listEnumValues.clear(); + } + + enumerationTypesAdded = true; +} + END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp index bb4fc83..db95c5f 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp @@ -56,9 +56,7 @@ daq::DevicePtr TmsClient::connect() client->runIterate(); tmsClientContext = std::make_shared(client, context); - - //On connect add server broadcasted enumeration types to the type manager - AddEnumerationTypesToTypeManager(); + tmsClientContext->addEnumerationTypesToTypeManager(); OpcUaNodeId rootDeviceNodeId; std::string rootDeviceBrowseName; @@ -86,60 +84,6 @@ daq::DevicePtr TmsClient::connect() return device; } -void TmsClient::AddEnumerationTypesToTypeManager() -{ - if (!context.assigned() || !context.getTypeManager().assigned()) - return; // TypeManager required. Do nothing. - - auto typeManager = context.getTypeManager(); - - const auto DataTypeEnumerationNodeId = OpcUaNodeId(UA_NS0ID_ENUMERATION); - const auto& references = tmsClientContext->getReferenceBrowser()->browse(DataTypeEnumerationNodeId); - StructPtr EnumValuesStruct; - std::vector vecEnumerationsNodeIds; - - for (auto [browseName, ref] : references.byBrowseName) - vecEnumerationsNodeIds.push_back(ref->nodeId.nodeId); - - //Cache NodeIds - tmsClientContext->getReferenceBrowser()->browseMultiple(vecEnumerationsNodeIds); - - auto listEnumValues = List(); - - for (auto [browseName, ref] : references.byBrowseName) - { - //If type already exists, skip - if(typeManager.hasType(browseName)) - continue; - - const auto& references1 = tmsClientContext->getReferenceBrowser()->browse(ref->nodeId.nodeId); - for (auto [childBrowseName, ChildRef] : references1.byBrowseName) - { - const auto childNodeValue = client->readValue(ChildRef->nodeId.nodeId); - const auto childNodeObject = VariantConverter::ToDaqObject(childNodeValue, context); - - if (childBrowseName == "EnumStrings") - { - for (auto value : childNodeObject.asPtr()) - listEnumValues.pushBack(value); - } - else if (childBrowseName == "EnumValues") - { - for (const auto& value : childNodeObject.asPtr()) - { - if (EnumValuesStruct = value.asPtrOrNull(); EnumValuesStruct.assigned()) - listEnumValues.pushBack(EnumValuesStruct.get("DisplayName")); - } - } - } - - auto enumExcitationType = EnumerationType(browseName, listEnumValues); - typeManager.addType(enumExcitationType); - - listEnumValues.clear(); - } -} - void TmsClient::getRootDeviceNodeAttributes(OpcUaNodeId& nodeIdOut, std::string& browseNameOut) { const OpcUaNodeId rootNodeId(NAMESPACE_DI, UA_DIID_DEVICESET); diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp index c337660..3c12fa6 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp @@ -302,7 +302,7 @@ void TmsServerProperty::addReferenceTypeChildNodes() { StructPtr structPtr = this->parent.getRef().getPropertyValue(object.getName()); std::string structTypeName = structPtr.getStructType().getName(); - if(GetUAStructureDataTypeByName(structTypeName) == nullptr) + if (!nativeStructConversionSupported(structTypeName) && GetUAStructureDataTypeByName(structTypeName) == nullptr) return; } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp index a1354fd..afbf352 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp @@ -111,7 +111,7 @@ void TmsServerPropertyObject::addChildNodes() if(structPtr.assigned()) { std::string structTypeName = structPtr.getStructType().getName(); - if(GetUAStructureDataTypeByName(structTypeName) == nullptr) + if (!nativeStructConversionSupported(structTypeName) && GetUAStructureDataTypeByName(structTypeName) == nullptr) continue; } } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp index 3225e83..4ad3333 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp @@ -16,6 +16,8 @@ #include "coretypes/type_manager_factory.h" #include #include +#include "opendaq/device_type_factory.h" +#include "opendaq/server_type_factory.h" using namespace daq; using namespace opcua::tms; @@ -126,8 +128,11 @@ class TmsPropertyObjectAdvancedTest : public TmsObjectIntegrationTest .addProperty(IntPropertyBuilder("CoercedInt", 10).setCoercer(Coercer("if(Value > 10, 10, Value)")).build()) .addProperty(RatioProperty("Ratio", Ratio(1, 1000))) .addProperty(ObjectPropertyBuilder("ObjectWithMetadata", obj1).setReadOnly(true).setVisible(false).build()) - //.addProperty(StructProperty("UnitStruct", Unit("s", -1, "second", "time"))) - //.addProperty(StructProperty("ArgumentStruct", ArgumentInfo("Arg", ctInt))) + .addProperty(StructProperty("UnitStruct", Unit("s", -1, "second", "time"))) + .addProperty(StructProperty("ArgumentStruct", ArgumentInfo("Arg", ctInt))) + .addProperty(StructProperty("RangeStruct", Range(1, 2))) + .addProperty(StructProperty("ComplexNumberStruct", ComplexNumber(1, 2))) + .addProperty(StructProperty("FunctionBlockTypeStruct", FunctionBlockType("id", "name", "desc"))) .addProperty(StructProperty("DeviceDomainStructure", Struct("DeviceDomainStructure", Dict({{"Resolution", Ratio(10, 20)}, @@ -836,3 +841,33 @@ TEST_F(TmsPropertyObjectAdvancedTest, BeginEndUpdate) ASSERT_TRUE(eventTriggered); } +TEST_F(TmsPropertyObjectAdvancedTest, NativeStructTypes) +{ + const auto obj = PropertyObject(manager, "TestClass"); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + ASSERT_EQ(obj.getPropertyValue("UnitStruct"), clientObj.getPropertyValue("UnitStruct")); + ASSERT_EQ(obj.getPropertyValue("ArgumentStruct"), clientObj.getPropertyValue("ArgumentStruct")); + ASSERT_EQ(obj.getPropertyValue("RangeStruct"), clientObj.getPropertyValue("RangeStruct")); + ASSERT_EQ(obj.getPropertyValue("ComplexNumberStruct"), clientObj.getPropertyValue("ComplexNumberStruct")); + ASSERT_EQ(obj.getPropertyValue("FunctionBlockTypeStruct"), clientObj.getPropertyValue("FunctionBlockTypeStruct")); + + clientObj.setPropertyValue("UnitStruct", Unit("new_symbol", 2, "new_name", "new_quantity")); + clientObj.setPropertyValue("ArgumentStruct", ArgumentInfo("new_name", CoreType::ctFloat)); + clientObj.setPropertyValue("RangeStruct", Range(100, 2000)); + clientObj.setPropertyValue("ComplexNumberStruct", ComplexNumber(100, 2000)); + clientObj.setPropertyValue("FunctionBlockTypeStruct", FunctionBlockType("new_id", "new_name", "new_desc")); + + ASSERT_EQ(obj.getPropertyValue("UnitStruct"), Unit("new_symbol", 2, "new_name", "new_quantity")); + ASSERT_EQ(obj.getPropertyValue("ArgumentStruct"), ArgumentInfo("new_name", CoreType::ctFloat)); + ASSERT_EQ(obj.getPropertyValue("RangeStruct"), Range(100, 2000)); + ASSERT_EQ(obj.getPropertyValue("ComplexNumberStruct"), ComplexNumber(100, 2000)); + ASSERT_EQ(obj.getPropertyValue("FunctionBlockTypeStruct"), FunctionBlockType("new_id", "new_name", "new_desc")); + + ASSERT_EQ(obj.getPropertyValue("UnitStruct"), clientObj.getPropertyValue("UnitStruct")); + ASSERT_EQ(obj.getPropertyValue("ArgumentStruct"), clientObj.getPropertyValue("ArgumentStruct")); + ASSERT_EQ(obj.getPropertyValue("RangeStruct"), clientObj.getPropertyValue("RangeStruct")); + ASSERT_EQ(obj.getPropertyValue("ComplexNumberStruct"), clientObj.getPropertyValue("ComplexNumberStruct")); + ASSERT_EQ(obj.getPropertyValue("FunctionBlockTypeStruct"), clientObj.getPropertyValue("FunctionBlockTypeStruct")); +} + diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp index 4d8c9ac..514898f 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp @@ -58,24 +58,23 @@ class TmsFusionDevice : public TmsObjectIntegrationTest .addProperty(StructProperty( "Scaler", Struct("GainScalingStructure", Dict({{"Factor", 2.1}, {"Offset", 3.0}}), objManager))) .addProperty(EnumerationProperty("ExcitationType", Enumeration("ExcitationTypeEnumeration", "DCVoltage", objManager))) - //.addProperty(StructProperty( - // "FullBridge", - // Struct("FullBridgeSensorStructure", - // Dict( - // {{"ExcitationVoltage", - // Struct("ExcitationVoltageStructure", - // Dict( - // {{"ActualValue", 5.0}, - // {"NominalValue", 5.0}, - // {"NominalValueRange", - // Struct("Range", Dict({{"Low", 4.0}, {"High", 6.0}}), objManager)}, - // {"Type", Enumeration("ExcitationTypeEnumeration", "DCVoltage", objManager)}, - // {"Frequency", 0}}), - // objManager)}, - // {"Resistance", 350.0}, - // {"MaximumElectrical", 5.0}, - // {"UsedWires", 6}}), - // objManager))) + .addProperty(StructProperty( + "FullBridge", + Struct("FullBridgeSensorStructure", + Dict( + {{"ExcitationVoltage", + Struct("ExcitationVoltageStructure", + Dict( + {{"ActualValue", 5.0}, + {"NominalValue", 5.0}, + {"NominalValueRange", Range(4.0, 6.0)}, + {"Type", Enumeration("ExcitationTypeEnumeration", "DCVoltage", objManager)}, + {"Frequency", 0}}), + objManager)}, + {"Resistance", 350.0}, + {"MaximumElectrical", 5.0}, + {"UsedWires", 6}}), + objManager))) .build(); objManager.addType(fusionAmpClass); } @@ -91,7 +90,7 @@ class TmsFusionDevice : public TmsObjectIntegrationTest const auto serverProp = std::make_shared(prop, server, context, std::make_shared(context, nullptr)); const auto nodeId = serverProp->registerOpcUaNode(); - const auto clientProp = TmsClientPropertyObject(Context(nullptr, logger, objManager, nullptr), clientContext, nodeId); + const auto clientProp = TmsClientPropertyObject(ctxClient, clientContext, nodeId); return {serverProp, clientProp}; } }; @@ -137,6 +136,32 @@ TEST_F(TmsFusionDevice, StructTest) ASSERT_DOUBLE_EQ(scalerManipulated.get("Offset"), (double) 3.1); } +TEST_F(TmsFusionDevice, FullBridge) +{ + const auto obj = PropertyObject(objManager, "FusionAmp"); + auto [serverObj, fusionAmp] = registerPropertyObject(obj); + + const StructPtr fullBridge = fusionAmp.getPropertyValue("FullBridge"); + + const auto newExcitationVoltage = StructBuilder(fullBridge.get("ExcitationVoltage")) + .set("NominalValueRange", Range(1.2, 6.2)) + .set("ActualValue", 5.9) + .build(); + + const auto newFullBridge = StructBuilder(fullBridge) + .set("ExcitationVoltage", newExcitationVoltage) + .set("UsedWires", 9) + .set("Resistance", 100.1) + .build(); + + fusionAmp.setPropertyValue("FullBridge", newFullBridge); + const auto serverFullBridge = obj.getPropertyValue("FullBridge"); + const auto clientFullBridge = fusionAmp.getPropertyValue("FullBridge"); + + ASSERT_EQ(serverFullBridge, clientFullBridge); + ASSERT_EQ(serverFullBridge, newFullBridge); +} + TEST_F(TmsFusionDevice, EnumTest) { // This test should be moved to coreobjects @@ -147,20 +172,6 @@ TEST_F(TmsFusionDevice, EnumTest) ASSERT_EQ(obj.getPropertyValue("ExcitationType"), Enumeration("ExcitationTypeEnumeration", "ACVoltage", objManager)); } -TEST_F(TmsFusionDevice, DISABLED_DebugServerPublishingTest) -{ - // This test asserts nothing. It is used to debug the OPCUA server - const auto obj = PropertyObject(objManager, "FusionAmp"); - const auto logger = Logger(); - const auto context = Context(nullptr, logger, TypeManager(), nullptr); - const auto serverProp = - std::make_shared(obj, server, context, std::make_shared(context, nullptr)); - const auto nodeId = serverProp->registerOpcUaNode(); - while (true) - { - } -} - TEST_F(TmsFusionDevice, EnumPropertyTest) { const auto obj = PropertyObject(objManager, "FusionAmp"); @@ -171,15 +182,3 @@ TEST_F(TmsFusionDevice, EnumPropertyTest) ASSERT_EQ(obj.getPropertyValue("ExcitationType"), Enumeration("ExcitationTypeEnumeration", "ACVoltage", objManager)); ASSERT_EQ(fusionAmp.getPropertyValue("ExcitationType"), Enumeration("ExcitationTypeEnumeration", "ACVoltage", objManager)); } - -TEST_F(TmsFusionDevice, DISABLED_SimulatorTest) -{ - // this test should pass, if you have Fusion simulator running - - const std::string connectionString = "opc.tcp://10.0.210.201"; - - TmsClient tmsClient(NullContext(), nullptr, connectionString, nullptr); - auto clientDevice = tmsClient.connect(); - - ASSERT_TRUE(clientDevice.assigned()); -} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp index d7ce2cb..e4d3708 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp @@ -20,8 +20,11 @@ void TmsObjectIntegrationTest::SetUp() logger = CreateLoggerWithDebugSink(debugSink); ctx = daq::NullContext(logger); - clientContext = std::make_shared(client, ctx); + ctxClient = daq::NullContext(logger); + clientContext = std::make_shared(client, ctxClient); serverContext = std::make_shared(ctx, nullptr); + + clientContext->addEnumerationTypesToTypeManager(); } LastMessageLoggerSinkPrivatePtr TmsObjectIntegrationTest::getPrivateSink() @@ -39,6 +42,7 @@ void TmsObjectIntegrationTest::TearDown() clientContext.reset(); serverContext = nullptr; ctx = nullptr; + ctxClient = nullptr; TmsObjectTest::TearDown(); } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h index 3765484..2c69b2e 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h @@ -34,6 +34,7 @@ class TmsObjectIntegrationTest : public TmsObjectTest daq::LoggerPtr logger; daq::ContextPtr ctx; + daq::ContextPtr ctxClient; private: daq::LoggerSinkPtr debugSink; }; From 080161b82f5e4b785faac2148f45b2c9d9382045 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Mon, 18 Mar 2024 15:18:04 +0100 Subject: [PATCH 101/217] Make DeviceDomain a standalone object in DeviceImpl --- .../objects/tms_client_device_impl.h | 11 +---- .../src/objects/tms_client_device_impl.cpp | 42 ++++++------------- .../src/objects/tms_server_device.cpp | 2 +- .../opcuatms_integration/test_tms_device.cpp | 4 +- 4 files changed, 17 insertions(+), 42 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h index e44fb19..4280fbe 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h @@ -32,16 +32,15 @@ class TmsClientDeviceImpl : public TmsClientComponentBaseImpl streamings; FunctionPtr createStreamingCallback; @@ -66,11 +63,7 @@ class TmsClientDeviceImpl : public TmsClientComponentBaseImpl +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS using namespace daq::opcua; @@ -86,6 +87,12 @@ TmsClientDeviceImpl::TmsClientDeviceImpl(const ContextPtr& ctx, setUpStreamings(); } +ErrCode TmsClientDeviceImpl::getDomain(IDeviceDomain** deviceDomain) +{ + fetchTimeDomain(); + return TmsClientComponentBaseImpl>::getDomain(deviceDomain); +} + void TmsClientDeviceImpl::findAndCreateSubdevices() { std::map orderedDevices; @@ -186,8 +193,6 @@ DeviceInfoPtr TmsClientDeviceImpl::onGetInfo() void TmsClientDeviceImpl::fetchTimeDomain() { - if (timeDomainFetched) - return; auto timeDomainNodeId = getNodeId("Domain"); auto variant = client->readValue(timeDomainNodeId); @@ -198,8 +203,9 @@ void TmsClientDeviceImpl::fetchTimeDomain() auto denominator = deviceDomain->resolution.denominator; if (denominator == 0) denominator = 1; - resolution = Ratio(numerator, denominator); - origin = ConvertToDaqCoreString(deviceDomain->origin); + const auto resolution = Ratio(numerator, denominator); + const auto origin = ConvertToDaqCoreString(deviceDomain->origin); + UnitPtr domainUnit; if (deviceDomain->unit.unitId > 0) domainUnit = Unit(ConvertToDaqCoreString(deviceDomain->unit.displayName.text), deviceDomain->unit.unitId, @@ -208,9 +214,8 @@ void TmsClientDeviceImpl::fetchTimeDomain() else domainUnit = Unit(""); + setDeviceDomainNoCoreEvent(DeviceDomain(resolution, origin, domainUnit)); ticksSinceOrigin = deviceDomain->ticksSinceOrigin; - - timeDomainFetched = true; } void TmsClientDeviceImpl::fetchTicksSinceOrigin() @@ -222,35 +227,12 @@ void TmsClientDeviceImpl::fetchTicksSinceOrigin() deviceDomain = (UA_DeviceDomainStructure*) variant.getValue().data; ticksSinceOrigin = deviceDomain->ticksSinceOrigin; } - -RatioPtr TmsClientDeviceImpl::onGetResolution() -{ - fetchTimeDomain(); - return resolution; -} - uint64_t TmsClientDeviceImpl::onGetTicksSinceOrigin() { - if(!timeDomainFetched) - fetchTimeDomain(); - else - fetchTicksSinceOrigin(); - + fetchTicksSinceOrigin(); return ticksSinceOrigin; } -std::string TmsClientDeviceImpl::onGetOrigin() -{ - fetchTimeDomain(); - return origin; -} - -UnitPtr TmsClientDeviceImpl::onGetDomainUnit() -{ - fetchTimeDomain(); - return domainUnit; -} - void TmsClientDeviceImpl::findAndCreateFunctionBlocks() { diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index 447052a..77ec116 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -102,7 +102,7 @@ void TmsServerDevice::bindCallbacks() uaDeviceDomain->resolution.numerator = deviceDomain.getTickResolution().getNumerator(); uaDeviceDomain->resolution.denominator = deviceDomain.getTickResolution().getDenominator(); uaDeviceDomain->origin = ConvertToOpcUaString(deviceDomain.getOrigin()).getDetachedValue(); - uaDeviceDomain->ticksSinceOrigin = deviceDomain.getTicksSinceOrigin(); + uaDeviceDomain->ticksSinceOrigin = object.getTicksSinceOrigin(); auto unit = StructConverter::ToTmsType(deviceDomain.getUnit()); uaDeviceDomain->unit = unit.getDetachedValue(); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp index a7aa5c0..8537155 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp @@ -231,7 +231,7 @@ TEST_F(TmsDeviceTest, DeviceGetTicksSinceOrigin) auto clientSubDevices = clientDevice.getDevices(); auto clientSubDevice = clientSubDevices[1]; - auto ticksSinceOrigin = clientSubDevice.asPtr(true).getTicksSinceOrigin(); + auto ticksSinceOrigin = clientSubDevice.getTicksSinceOrigin(); ASSERT_EQ(ticksSinceOrigin, 789); } @@ -260,7 +260,7 @@ TEST_F(TmsDeviceTest, DeviceDomain) ASSERT_EQ(resolution.getNumerator(), 123); ASSERT_EQ(resolution.getDenominator(), 456); - auto ticksSinceOrigin = deviceDomain.getTicksSinceOrigin(); + auto ticksSinceOrigin = clientSubDevice.getTicksSinceOrigin(); ASSERT_EQ(ticksSinceOrigin, 789); auto origin = deviceDomain.getOrigin(); From 552a1db9fa126f94af2826b663d13f761fe279ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE?= Date: Thu, 21 Mar 2024 10:03:55 +0100 Subject: [PATCH 102/217] Make type manager thread safe (openDAQ/openDAQ#214) --- .../src/converters/generic_struct_converter.cpp | 15 ++++++++++++++- .../test_property_object_advanced.cpp | 7 ++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/generic_struct_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/generic_struct_converter.cpp index 2db9d9b..767b668 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/generic_struct_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/generic_struct_converter.cpp @@ -7,6 +7,7 @@ #include "coretypes/simple_type_factory.h" #include "opcuatms/converters/list_conversion_utils.h" #include "iostream" +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -117,8 +118,20 @@ StructPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, co } } - if (!typeManager.hasType(type->typeName)) + try + { typeManager.addType(StructType(type->typeName, daqMembers.getKeyList(), memberTypes)); + } + catch (const std::exception& e) + { + const auto loggerComponent = context.getLogger().getOrAddComponent("GenericStructConverter"); + LOG_W("Couldn't add type {} to type manager: {}", type->typeName, e.what()); + } + catch (...) + { + const auto loggerComponent = context.getLogger().getOrAddComponent("GenericStructConverter"); + LOG_W("Couldn't add type {} to type manager!", type->typeName); + } return Struct(type->typeName, daqMembers, typeManager); } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp index 4ad3333..fafe132 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp @@ -192,9 +192,10 @@ class TmsPropertyObjectAdvancedTest : public TmsObjectIntegrationTest { logger.flush(); auto sink = getPrivateSink(); - auto newMessage = sink.waitForMessage(2000); - if (newMessage == 0) - return StringPtr(""); + while (sink.waitForMessage(2000)) + { + // Wait for actual last message + } auto logMessage = sink.getLastMessage(); return logMessage; } From a4a3fefe07df1d2fc9947cebe1c6ba4f385587ed Mon Sep 17 00:00:00 2001 From: Daniel Barros <113608885+dduraesdebarros@users.noreply.github.com> Date: Thu, 21 Mar 2024 17:27:28 +0100 Subject: [PATCH 103/217] =?UTF-8?q?Fixed=20InvalidParameterException=20exc?= =?UTF-8?q?eption=20when=20trying=20to=20set=20Enumerat=E2=80=A6=20(openDA?= =?UTF-8?q?Q/openDAQ#222)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fixed InvalidParameterException exception when trying to set Enumeration field of a struct property * Added check for enumeration type when setting enumeration property in struct field * Fixed typo in comment * Reverted changes to StructBuilder and fixed incorrect type in Struct Fields * Removed deprecated variable --- .../opcuatms/src/converters/generic_struct_converter.cpp | 8 +++++--- .../tests/opcuatms_integration/test_tms_fusion_device.cpp | 6 +++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/generic_struct_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/generic_struct_converter.cpp index 767b668..8aeef51 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/generic_struct_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/generic_struct_converter.cpp @@ -18,8 +18,10 @@ namespace detail const auto ct = obj.getCoreType(); if (ct == ctStruct) return obj.asPtr().getStructType(); - - return SimpleType(ct); + else if (ct == ctEnumeration) + return obj.asPtr().getEnumerationType(); + else + return SimpleType(ct); } } @@ -109,7 +111,7 @@ StructPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, co } else { - daqMembers.set(member->memberName, nullptr); + daqMembers.set(member->memberName, nullptr); src += sizeof(size_t*); memberTypes.pushBack(SimpleType(ctUndefined)); } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp index 514898f..eedd26c 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp @@ -146,18 +146,22 @@ TEST_F(TmsFusionDevice, FullBridge) const auto newExcitationVoltage = StructBuilder(fullBridge.get("ExcitationVoltage")) .set("NominalValueRange", Range(1.2, 6.2)) .set("ActualValue", 5.9) + .set("Type", Enumeration("ExcitationTypeEnumeration", "ACVoltage", objManager)) + .set("Frequency", 0) + .set("NominalValue", 5.0) .build(); const auto newFullBridge = StructBuilder(fullBridge) .set("ExcitationVoltage", newExcitationVoltage) .set("UsedWires", 9) .set("Resistance", 100.1) + .set("MaximumElectrical", 8.0) .build(); fusionAmp.setPropertyValue("FullBridge", newFullBridge); const auto serverFullBridge = obj.getPropertyValue("FullBridge"); const auto clientFullBridge = fusionAmp.getPropertyValue("FullBridge"); - + ASSERT_EQ(serverFullBridge, clientFullBridge); ASSERT_EQ(serverFullBridge, newFullBridge); } From 95264d172c64a05ee8fdce04950e8fb90cd09845 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Thu, 21 Mar 2024 13:39:18 +0100 Subject: [PATCH 104/217] Do not allow devices with same local ID --- .../include/opcuatms_client/tms_client.h | 3 --- .../opcuatms_client/src/tms_client.cpp | 25 +------------------ .../test_tms_integration.cpp | 10 ++++---- 3 files changed, 6 insertions(+), 32 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h index 269803d..6a0850f 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h @@ -45,9 +45,6 @@ class TmsClient final FunctionPtr createStreamingCallback; ComponentPtr parent; LoggerComponentPtr loggerComponent; - -private: - StringPtr getUniqueLocalId(const StringPtr& localId, int iteration = 0); }; END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp index db95c5f..d9ff37c 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp @@ -62,8 +62,7 @@ daq::DevicePtr TmsClient::connect() std::string rootDeviceBrowseName; getRootDeviceNodeAttributes(rootDeviceNodeId, rootDeviceBrowseName); - const auto localId = getUniqueLocalId(rootDeviceBrowseName); - auto device = TmsClientRootDevice(context, parent, localId, tmsClientContext, rootDeviceNodeId, createStreamingCallback); + auto device = TmsClientRootDevice(context, parent, rootDeviceBrowseName, tmsClientContext, rootDeviceNodeId, createStreamingCallback); const auto deviceInfo = device.getInfo(); if (deviceInfo.hasProperty("OpenDaqPackageVersion")) @@ -101,26 +100,4 @@ void TmsClient::getRootDeviceNodeAttributes(OpcUaNodeId& nodeIdOut, std::string& browseNameOut = references.byBrowseName.begin().key(); } -StringPtr TmsClient::getUniqueLocalId(const StringPtr& localId, int iteration) -{ - if (!parent.assigned()) - return localId; - - StringPtr uniqueId = localId; - if (iteration != 0) - uniqueId = uniqueId + "_" + std::to_string(iteration); - - const auto parentFolder = parent.asPtrOrNull(); - if (parentFolder.assigned()) - { - for (auto item : parentFolder.getItems()) - { - if (item.getLocalId() == uniqueId) - return getUniqueLocalId(localId, iteration + 1); - } - } - - return uniqueId; -} - END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index 908cf6d..d1d2849 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -18,7 +18,7 @@ class TmsIntegrationTest : public testing::Test public: const std::string OPC_URL = "opc.tcp://localhost/"; - InstancePtr createDevice() + InstancePtr createDevice(const StringPtr& localId = "localInstance") { const auto moduleManager = ModuleManager("[[none]]"); auto logger = Logger(); @@ -30,7 +30,7 @@ class TmsIntegrationTest : public testing::Test const ModulePtr fbModule(MockFunctionBlockModule_Create(context)); moduleManager.addModule(fbModule); - auto instance = InstanceCustom(context, "localInstance"); + auto instance = InstanceCustom(context, localId); instance.addDevice("daq_client_device"); instance.addDevice("mock_phys_device"); instance.addFunctionBlock("mock_fb_uid"); @@ -364,10 +364,10 @@ TEST_F(TmsIntegrationTest, InputPortMultipleServers) }; InstancePtr device1 = createDevice(); - InstancePtr device2 = createDevice(); + InstancePtr device2 = createDevice("localInstance2"); auto server1 = StartServerDevice(device1, 4001); - auto server2 = StartServerDevice(device1, 4002); - + auto server2 = StartServerDevice(device2, 4002); + InstancePtr instance = Instance(); auto clientDevice1 = instance.addDevice("daq.opcua://127.0.0.1:4001"); auto clientDevice2 = instance.addDevice("daq.opcua://127.0.0.1:4002"); From 29ff5f03e1d825668e8d967e7d6a239fdb5e8c33 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Thu, 21 Mar 2024 16:38:05 +0100 Subject: [PATCH 105/217] Fix failing tests --- .../tests/opcuatms_integration/test_tms_integration.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index d1d2849..239e914 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -265,14 +265,15 @@ TEST_F(TmsIntegrationTest, AddFunctionBlock) TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); auto clientDevice = tmsClient.connect(); + ASSERT_EQ("mock_fb_uid_1", clientDevice.getFunctionBlocks()[0].getLocalId()); auto fb1 = clientDevice.addFunctionBlock("mock_fb_uid"); ASSERT_TRUE(fb1.assigned()); - ASSERT_EQ("mock_fb_uid_1", fb1.getLocalId()); + ASSERT_EQ("mock_fb_uid_2", fb1.getLocalId()); auto fb2 = clientDevice.addFunctionBlock("mock_fb_uid"); ASSERT_TRUE(fb2.assigned()); - ASSERT_EQ("mock_fb_uid_2", fb2.getLocalId()); + ASSERT_EQ("mock_fb_uid_3", fb2.getLocalId()); ASSERT_EQ(3u, clientDevice.getFunctionBlocks().getCount()); } From 899228c33d22a93e5a71fafd4097c17da72aaf57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE?= Date: Tue, 26 Mar 2024 14:28:55 +0100 Subject: [PATCH 106/217] Update license year from 2023 to 2024 (openDAQ/openDAQ#235) --- .../opcua_client_module/include/opcua_client_module/common.h | 2 +- .../include/opcua_client_module/module_dll.h | 2 +- .../include/opcua_client_module/opcua_client_module_impl.h | 2 +- .../opcua_server_module/include/opcua_server_module/common.h | 2 +- .../include/opcua_server_module/module_dll.h | 2 +- .../include/opcua_server_module/opcua_server_impl.h | 2 +- .../include/opcua_server_module/opcua_server_module_impl.h | 2 +- .../opcua/opcuaclient/include/opcuaclient/attribute_reader.h | 2 +- .../opcua/opcuaclient/include/opcuaclient/browse_request.h | 2 +- .../opcuaclient/include/opcuaclient/browser/opcuabrowser.h | 2 +- .../include/opcuaclient/browser/opcuanodefactorybrowser.h | 2 +- .../opcuaclient/include/opcuaclient/browser/opcuanodevisitor.h | 2 +- .../include/opcuaclient/browser/opcuatransactionbrowser.h | 2 +- .../opcuaclient/include/opcuaclient/cached_reference_browser.h | 2 +- .../include/opcuaclient/chdatagather/_alignsyncchdatagather.h | 2 +- .../include/opcuaclient/chdatagather/_chdatagather.h | 2 +- .../opcua/opcuaclient/include/opcuaclient/event_filter.h | 2 +- .../include/opcuaclient/monitored_item_create_request.h | 2 +- .../opcuaclient/include/opcuaclient/opcuaasyncexecthread.h | 2 +- .../opcuaclient/include/opcuaclient/opcuacallmethodrequest.h | 2 +- .../opcua/opcuaclient/include/opcuaclient/opcuaclient.h | 2 +- .../opcua/opcuaclient/include/opcuaclient/opcuanodefactory.h | 2 +- .../opcua/opcuaclient/include/opcuaclient/opcuareadvalueid.h | 2 +- .../include/opcuaclient/opcuatimertaskcontextcollection.h | 2 +- .../opcuaclient/include/opcuaclient/opcuatimertaskhelper.h | 2 +- .../opcua/opcuaclient/include/opcuaclient/request_handler.h | 2 +- .../opcua/opcuaclient/include/opcuaclient/subscriptions.h | 2 +- .../include/opcuaclient/taskprocessor/opcuataskprocessor.h | 2 +- .../opcua/opcuaclient/tests/include/opcuaservertesthelper.h | 2 +- shared/libraries/opcua/opcuaserver/include/opcuaserver/common.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/event_attributes.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/node_event_manager.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/opcuaserver.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/opcuaserverlock.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/opcuaservernode.h | 2 +- .../opcuaserver/include/opcuaserver/opcuaservernodefactory.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/opcuasession.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/opcuataskqueue.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/opcuatmstypes.h | 2 +- .../opcuaserver/include/opcuaserver/server_event_manager.h | 2 +- .../libraries/opcua/opcuaserver/tests/common_test_functions.h | 2 +- shared/libraries/opcua/opcuashared/include/opcuashared/bcrypt.h | 2 +- .../opcua/opcuashared/include/opcuashared/node/opcuadatatype.h | 2 +- .../opcua/opcuashared/include/opcuashared/node/opcuanode.h | 2 +- .../opcuashared/include/opcuashared/node/opcuanodemethod.h | 2 +- .../opcuashared/include/opcuashared/node/opcuanodeobject.h | 2 +- .../opcuashared/include/opcuashared/node/opcuanodevariable.h | 2 +- .../opcuashared/include/opcuashared/node/opcuaobjecttype.h | 2 +- .../opcua/opcuashared/include/opcuashared/node/opcuatype.h | 2 +- .../opcuashared/include/opcuashared/node/opcuavariabletype.h | 2 +- shared/libraries/opcua/opcuashared/include/opcuashared/opcua.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcua_attribute.h | 2 +- .../opcuashared/include/opcuashared/opcuacallmethodresult.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuacollection.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuacommon.h | 2 +- .../opcuashared/include/opcuashared/opcuadatatypearraylist.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuadatavalue.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuaendpoint.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuaexception.h | 2 +- .../libraries/opcua/opcuashared/include/opcuashared/opcualog.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuanodecollection.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuanodeid.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuaobject.h | 2 +- .../opcuashared/include/opcuashared/opcuasecurity_config.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuasecuritycommon.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuavariant.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuavector.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuaversion.h | 2 +- .../opcuatms/opcuatms/include/opcuatms/converter_maps.h | 2 +- .../include/opcuatms/converters/list_conversion_utils.h | 2 +- .../opcuatms/converters/property_object_conversion_utils.h | 2 +- .../opcuatms/include/opcuatms/converters/selection_converter.h | 2 +- .../opcuatms/include/opcuatms/converters/struct_converter.h | 2 +- .../opcuatms/include/opcuatms/converters/variant_converter.h | 2 +- .../opcuatms/opcuatms/include/opcuatms/core_types_utils.h | 2 +- shared/libraries/opcuatms/opcuatms/include/opcuatms/errors.h | 2 +- .../libraries/opcuatms/opcuatms/include/opcuatms/exceptions.h | 2 +- .../opcuatms/opcuatms/include/opcuatms/extension_object.h | 2 +- shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h | 2 +- .../opcuatms/opcuatms/include/opcuatms/type_mappings.h | 2 +- .../opcuatms_client/objects/tms_client_channel_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_channel_impl.h | 2 +- .../include/opcuatms_client/objects/tms_client_component.h | 2 +- .../opcuatms_client/objects/tms_client_component_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_component_impl.h | 2 +- .../include/opcuatms_client/objects/tms_client_context.h | 2 +- .../include/opcuatms_client/objects/tms_client_device_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_device_impl.h | 2 +- .../include/opcuatms_client/objects/tms_client_folder_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_folder_impl.h | 2 +- .../opcuatms_client/objects/tms_client_function_block_factory.h | 2 +- .../opcuatms_client/objects/tms_client_function_block_impl.h | 2 +- .../objects/tms_client_function_block_type_factory.h | 2 +- .../objects/tms_client_function_block_type_impl.h | 2 +- .../opcuatms_client/objects/tms_client_function_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_function_impl.h | 2 +- .../opcuatms_client/objects/tms_client_input_port_factory.h | 2 +- .../opcuatms_client/objects/tms_client_input_port_impl.h | 2 +- .../opcuatms_client/objects/tms_client_io_folder_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_io_folder_impl.h | 2 +- .../include/opcuatms_client/objects/tms_client_object_impl.h | 2 +- .../opcuatms_client/objects/tms_client_procedure_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_procedure_impl.h | 2 +- .../opcuatms_client/objects/tms_client_property_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_property_impl.h | 2 +- .../objects/tms_client_property_object_factory.h | 2 +- .../opcuatms_client/objects/tms_client_property_object_impl.h | 2 +- .../include/opcuatms_client/objects/tms_client_signal_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_signal_impl.h | 2 +- .../opcuatms_client/objects/tms_client_streaming_info_factory.h | 2 +- .../opcuatms_client/objects/tms_client_streaming_info_impl.h | 2 +- .../include/opcuatms_client/objects/tms_client_tags_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_tags_impl.h | 2 +- .../include/opcuatms_client/tms_attribute_collector.h | 2 +- .../opcuatms_client/include/opcuatms_client/tms_client.h | 2 +- .../include/opcuatms_server/objects/tms_server_channel.h | 2 +- .../include/opcuatms_server/objects/tms_server_component.h | 2 +- .../include/opcuatms_server/objects/tms_server_device.h | 2 +- .../include/opcuatms_server/objects/tms_server_eval_value.h | 2 +- .../include/opcuatms_server/objects/tms_server_folder.h | 2 +- .../include/opcuatms_server/objects/tms_server_function_block.h | 2 +- .../opcuatms_server/objects/tms_server_function_block_type.h | 2 +- .../include/opcuatms_server/objects/tms_server_input_port.h | 2 +- .../include/opcuatms_server/objects/tms_server_object.h | 2 +- .../include/opcuatms_server/objects/tms_server_property.h | 2 +- .../opcuatms_server/objects/tms_server_property_object.h | 2 +- .../include/opcuatms_server/objects/tms_server_signal.h | 2 +- .../include/opcuatms_server/objects/tms_server_variable.h | 2 +- .../opcuatms_server/include/opcuatms_server/tms_server.h | 2 +- .../include/opcuatms_server/tms_server_context.h | 2 +- shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h | 2 +- .../libraries/opcuatms/opcuatms_server/tests/tms_server_test.h | 2 +- .../tests/opcuatms_integration/tms_object_integration_test.h | 2 +- .../opcuatms/tests/test_utils/test_input_port_notifications.h | 2 +- shared/libraries/opcuatms/tests/test_utils/tms_object_test.h | 2 +- 136 files changed, 136 insertions(+), 136 deletions(-) diff --git a/modules/opcua_client_module/include/opcua_client_module/common.h b/modules/opcua_client_module/include/opcua_client_module/common.h index 2475862..318794d 100644 --- a/modules/opcua_client_module/include/opcua_client_module/common.h +++ b/modules/opcua_client_module/include/opcua_client_module/common.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/modules/opcua_client_module/include/opcua_client_module/module_dll.h b/modules/opcua_client_module/include/opcua_client_module/module_dll.h index b20d47b..ea56e47 100644 --- a/modules/opcua_client_module/include/opcua_client_module/module_dll.h +++ b/modules/opcua_client_module/include/opcua_client_module/module_dll.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h index f5968be..d6449a5 100644 --- a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h +++ b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/modules/opcua_server_module/include/opcua_server_module/common.h b/modules/opcua_server_module/include/opcua_server_module/common.h index 06191fa..1a53c8e 100644 --- a/modules/opcua_server_module/include/opcua_server_module/common.h +++ b/modules/opcua_server_module/include/opcua_server_module/common.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/modules/opcua_server_module/include/opcua_server_module/module_dll.h b/modules/opcua_server_module/include/opcua_server_module/module_dll.h index 17e37aa..6ba4ef4 100644 --- a/modules/opcua_server_module/include/opcua_server_module/module_dll.h +++ b/modules/opcua_server_module/include/opcua_server_module/module_dll.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h b/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h index 1fea1b7..5cbb3ad 100644 --- a/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h +++ b/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/modules/opcua_server_module/include/opcua_server_module/opcua_server_module_impl.h b/modules/opcua_server_module/include/opcua_server_module/opcua_server_module_impl.h index 2c04dd6..81f51b8 100644 --- a/modules/opcua_server_module/include/opcua_server_module/opcua_server_module_impl.h +++ b/modules/opcua_server_module/include/opcua_server_module/opcua_server_module_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/attribute_reader.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/attribute_reader.h index 8a408ee..4e26cac 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/attribute_reader.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/attribute_reader.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browse_request.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browse_request.h index e3f3ca7..9347db6 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browse_request.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browse_request.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuabrowser.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuabrowser.h index c326b6f..0e74f14 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuabrowser.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuabrowser.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodefactorybrowser.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodefactorybrowser.h index 42d5b41..d77aa9f 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodefactorybrowser.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodefactorybrowser.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodevisitor.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodevisitor.h index 736d13d..da3638a 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodevisitor.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodevisitor.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuatransactionbrowser.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuatransactionbrowser.h index 063e096..87b38d1 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuatransactionbrowser.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuatransactionbrowser.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h index 71ed811..297911e 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_alignsyncchdatagather.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_alignsyncchdatagather.h index f64e3a8..52abb55 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_alignsyncchdatagather.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_alignsyncchdatagather.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_chdatagather.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_chdatagather.h index 35a95df..cf82b57 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_chdatagather.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_chdatagather.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/event_filter.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/event_filter.h index 9ffa7cc..050449d 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/event_filter.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/event_filter.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/monitored_item_create_request.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/monitored_item_create_request.h index 0b0a9e0..bf8faf1 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/monitored_item_create_request.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/monitored_item_create_request.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaasyncexecthread.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaasyncexecthread.h index 816903a..e863f96 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaasyncexecthread.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaasyncexecthread.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuacallmethodrequest.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuacallmethodrequest.h index f982fe9..d94bb44 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuacallmethodrequest.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuacallmethodrequest.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h index 24acc1c..a3a0836 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuanodefactory.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuanodefactory.h index 0114108..9d43f14 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuanodefactory.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuanodefactory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuareadvalueid.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuareadvalueid.h index 91664be..d578633 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuareadvalueid.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuareadvalueid.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskcontextcollection.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskcontextcollection.h index b053d6f..c294058 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskcontextcollection.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskcontextcollection.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskhelper.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskhelper.h index e483951..3568f3a 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskhelper.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskhelper.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/request_handler.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/request_handler.h index 4bad7ff..08245c4 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/request_handler.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/request_handler.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/subscriptions.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/subscriptions.h index 3cb5f5a..a39843b 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/subscriptions.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/subscriptions.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/taskprocessor/opcuataskprocessor.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/taskprocessor/opcuataskprocessor.h index 622188a..691a54b 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/taskprocessor/opcuataskprocessor.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/taskprocessor/opcuataskprocessor.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h b/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h index d02a8e1..3ea2c28 100644 --- a/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h +++ b/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/common.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/common.h index 7be3140..024d0d4 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/common.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/common.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/event_attributes.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/event_attributes.h index 07dd9f2..9fa8ac3 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/event_attributes.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/event_attributes.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/node_event_manager.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/node_event_manager.h index c4fc9e3..bfbf867 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/node_event_manager.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/node_event_manager.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h index f9ff14c..dbfc869 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h index c88eb66..e531b9c 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserverlock.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserverlock.h index 533c067..354a439 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserverlock.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserverlock.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernode.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernode.h index a971fbf..518f8ab 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernode.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernode.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernodefactory.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernodefactory.h index c956006..9df9cdf 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernodefactory.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernodefactory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuasession.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuasession.h index 9cd0826..8287cd8 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuasession.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuasession.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuataskqueue.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuataskqueue.h index 1a90c64..e96c191 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuataskqueue.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuataskqueue.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuatmstypes.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuatmstypes.h index 3b51c8e..45d78e9 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuatmstypes.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuatmstypes.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/server_event_manager.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/server_event_manager.h index 5092e3b..d55c097 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/server_event_manager.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/server_event_manager.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/tests/common_test_functions.h b/shared/libraries/opcua/opcuaserver/tests/common_test_functions.h index 4afa6e9..e71c065 100644 --- a/shared/libraries/opcua/opcuaserver/tests/common_test_functions.h +++ b/shared/libraries/opcua/opcuaserver/tests/common_test_functions.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/bcrypt.h b/shared/libraries/opcua/opcuashared/include/opcuashared/bcrypt.h index 759945c..8d5c253 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/bcrypt.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/bcrypt.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuadatatype.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuadatatype.h index 2971223..d12a79c 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuadatatype.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuadatatype.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanode.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanode.h index 1220e6c..e97b6d4 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanode.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanode.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodemethod.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodemethod.h index 7b7472a..7da9dbc 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodemethod.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodemethod.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodeobject.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodeobject.h index 98386c0..ad4be69 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodeobject.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodeobject.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodevariable.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodevariable.h index ffea435..1656c4e 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodevariable.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodevariable.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuaobjecttype.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuaobjecttype.h index a4cc122..faccf67 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuaobjecttype.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuaobjecttype.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuatype.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuatype.h index 671156c..41738fa 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuatype.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuatype.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuavariabletype.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuavariabletype.h index d628b82..db5b08e 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuavariabletype.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuavariabletype.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcua.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcua.h index 81efd15..060d041 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcua.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcua.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcua_attribute.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcua_attribute.h index 4bbefac..fafa188 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcua_attribute.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcua_attribute.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacallmethodresult.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacallmethodresult.h index 526a4b2..dcdd123 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacallmethodresult.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacallmethodresult.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacollection.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacollection.h index 150bc0a..37f4a00 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacollection.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacollection.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacommon.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacommon.h index 6a4d607..f298247 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacommon.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacommon.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatatypearraylist.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatatypearraylist.h index 9fdc7bf..949ed90 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatatypearraylist.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatatypearraylist.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatavalue.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatavalue.h index e532872..771dd8e 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatavalue.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatavalue.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaendpoint.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaendpoint.h index 042da82..001d8dd 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaendpoint.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaendpoint.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaexception.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaexception.h index e04e6ee..207990e 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaexception.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaexception.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcualog.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcualog.h index 82731e0..7993ba6 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcualog.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcualog.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodecollection.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodecollection.h index 91f0b90..8c2d229 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodecollection.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodecollection.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodeid.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodeid.h index dd711b6..b2b4e46 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodeid.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodeid.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaobject.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaobject.h index ae1a84a..c692a4c 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaobject.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaobject.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecurity_config.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecurity_config.h index 9730d9b..f9ef49d 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecurity_config.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecurity_config.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecuritycommon.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecuritycommon.h index 0afee20..7edb642 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecuritycommon.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecuritycommon.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h index e9c58da..cfd1a4f 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavector.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavector.h index f3ec30b..109a940 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavector.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavector.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaversion.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaversion.h index 8b221e3..3d9bc5d 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaversion.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaversion.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h index 8e3ef25..b068c06 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/list_conversion_utils.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/list_conversion_utils.h index 247f290..2bb7bfe 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/list_conversion_utils.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/list_conversion_utils.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/property_object_conversion_utils.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/property_object_conversion_utils.h index bc2eb19..8f34c14 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/property_object_conversion_utils.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/property_object_conversion_utils.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/selection_converter.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/selection_converter.h index 23d7e53..d8d8e50 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/selection_converter.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/selection_converter.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/struct_converter.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/struct_converter.h index 852783b..076514c 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/struct_converter.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/struct_converter.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/variant_converter.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/variant_converter.h index cc969b0..4b98b47 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/variant_converter.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/variant_converter.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h index 1c397e1..1881af3 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/errors.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/errors.h index ea6d0b1..1eed3ae 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/errors.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/errors.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/exceptions.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/exceptions.h index 24e0065..5a0a2bf 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/exceptions.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/exceptions.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/extension_object.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/extension_object.h index f6bfa41..832ba22 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/extension_object.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/extension_object.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h index 1372853..1c07a52 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h index d2d1ad9..43cc041 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_factory.h index e51da29..fb0ea76 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_impl.h index 337fcd1..60aa107 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component.h index d9621ec..16ec6fd 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_factory.h index 7d04d7f..bb3837e 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h index e30041f..60f5bd8 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h index ef0bdd5..983144a 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_factory.h index 5749904..f1894e1 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h index 4280fbe..e6cc117 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_factory.h index a36083e..80f3c7c 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h index 8ca78cd..d7a414b 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_factory.h index 05204f6..f97385a 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h index ba6e98e..385da8b 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_factory.h index d767cff..712befb 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_impl.h index be20054..85ada30 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_factory.h index e2c88a0..5a39919 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_impl.h index 93ca4bd..839a251 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_factory.h index a67af90..44e53fe 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h index 453e945..c55f701 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_factory.h index e06f398..4c73533 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h index b134d82..d8d178a 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h index 010512d..e48d614 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_factory.h index 0869534..69b8607 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_impl.h index c7a5f7c..254341a 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_factory.h index 8933455..ed38185 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h index 5ebc8fa..0cb33c4 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_factory.h index db3600f..36ab68a 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h index a03227c..77f7ee8 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_factory.h index 3614dbf..48ecf56 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h index 456aa35..88bd227 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_streaming_info_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_streaming_info_factory.h index 84cafeb..a6015fd 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_streaming_info_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_streaming_info_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_streaming_info_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_streaming_info_impl.h index 7523ae1..3dfe46e 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_streaming_info_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_streaming_info_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_factory.h index b613405..6ba21e0 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h index 31f1c9b..e655451 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_attribute_collector.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_attribute_collector.h index b0eb085..512cfc8 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_attribute_collector.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_attribute_collector.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h index 6a0850f..13f37e7 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_channel.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_channel.h index 83d0dff..1749187 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_channel.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_channel.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h index 67420c1..16fe448 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h index fc0f212..f02af7c 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_eval_value.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_eval_value.h index 4984bc7..4489b16 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_eval_value.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_eval_value.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_folder.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_folder.h index a7d4cee..4d23014 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_folder.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_folder.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block.h index 3f2f10c..789f841 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block_type.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block_type.h index d97f2bd..b593203 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block_type.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block_type.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h index 01cbb94..3bf360d 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h index c863f2b..885e1a9 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h index 0ee8c82..eba75b4 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h index b9e8d15..6d1b9f2 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h index c8e8050..c5aa26a 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h index ce37802..36c3e4f 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h index 3050acf..17cf075 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server_context.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server_context.h index 9af07c0..f38d8e0 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server_context.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server_context.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h b/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h index 5f365a9..17bd1c3 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.h b/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.h index 8f1eb46..39d2575 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.h +++ b/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h index 2c69b2e..b98825a 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/tests/test_utils/test_input_port_notifications.h b/shared/libraries/opcuatms/tests/test_utils/test_input_port_notifications.h index 50d519d..1b2bb9b 100644 --- a/shared/libraries/opcuatms/tests/test_utils/test_input_port_notifications.h +++ b/shared/libraries/opcuatms/tests/test_utils/test_input_port_notifications.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/tests/test_utils/tms_object_test.h b/shared/libraries/opcuatms/tests/test_utils/tms_object_test.h index 2487fa3..66f3af1 100644 --- a/shared/libraries/opcuatms/tests/test_utils/tms_object_test.h +++ b/shared/libraries/opcuatms/tests/test_utils/tms_object_test.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 Blueberry d.o.o. + * Copyright 2022-2024 Blueberry d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From f44176e7a228029e347789657b5e8920a59c00b7 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Fri, 22 Mar 2024 14:59:55 +0100 Subject: [PATCH 107/217] Ask config for descriptor if mirrored streaming desc is not yet available --- .../objects/tms_client_signal_impl.h | 4 +- .../src/objects/tms_client_device_impl.cpp | 2 + .../src/objects/tms_client_signal_impl.cpp | 50 +++++++++---------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h index 88bd227..38b470c 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h @@ -35,7 +35,6 @@ class TmsClientSignalImpl final : public TmsClientComponentBaseImpl isPublic = true; std::string deviceSignalId; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 53a72de..97825a4 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -198,6 +198,8 @@ void TmsClientDeviceImpl::fetchTimeDomain() UA_DeviceDomainStructure* deviceDomain; deviceDomain = (UA_DeviceDomainStructure*) variant.getValue().data; + if (!deviceDomain) + return; auto numerator = deviceDomain->resolution.numerator; auto denominator = deviceDomain->resolution.denominator; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp index 6542621..34374a5 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp @@ -45,29 +45,6 @@ ErrCode TmsClientSignalImpl::setPublic(Bool valPublic) return OPENDAQ_SUCCESS; } -ErrCode TmsClientSignalImpl::getDescriptor(IDataDescriptor** descriptor) -{ - *descriptor = nullptr; - try - { - if (descriptorNodeId) - { - OpcUaVariant opcUaVariant = client->readValue(*descriptorNodeId); - if (!opcUaVariant.isNull()) - { - DataDescriptorPtr descriptorPtr = VariantConverter::ToDaqObject(opcUaVariant); - *descriptor = descriptorPtr.addRefAndReturn(); - return OPENDAQ_SUCCESS; - } - } - } - catch (...) - { - LOG_W("Failed to get descriptor on OpcUA client signal \"{}\"", this->globalId); - } - return OPENDAQ_SUCCESS; -} - ErrCode TmsClientSignalImpl::setDescriptor(IDataDescriptor* /*descriptor*/) { return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; @@ -98,6 +75,28 @@ SignalPtr TmsClientSignalImpl::onGetDomainSignal() return nullptr; } +DataDescriptorPtr TmsClientSignalImpl::onGetDescriptor() +{ + try + { + if (descriptorNodeId) + { + OpcUaVariant opcUaVariant = client->readValue(*descriptorNodeId); + if (!opcUaVariant.isNull()) + { + DataDescriptorPtr descriptorPtr = VariantConverter::ToDaqObject(opcUaVariant); + return descriptorPtr.addRefAndReturn(); + } + } + } + catch (...) + { + LOG_W("Failed to get descriptor on OpcUA client signal \"{}\"", this->globalId); + } + + return nullptr; +} + ErrCode TmsClientSignalImpl::setDomainSignal(ISignal* signal) { return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; @@ -155,10 +154,9 @@ ErrCode TmsClientSignalImpl::clearRelatedSignals() return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; } -Bool TmsClientSignalImpl::onTriggerEvent(EventPacketPtr eventPacket) +Bool TmsClientSignalImpl::onTriggerEvent(const EventPacketPtr& eventPacket) { - // No new duplicated event packets have been created so returns true to forward original packet - return True; + return Self::onTriggerEvent(eventPacket); } From a53df79bddafe1324369ca9947d9b02805b2a2f5 Mon Sep 17 00:00:00 2001 From: Nikolai Shipilov Date: Wed, 20 Mar 2024 15:40:55 +0100 Subject: [PATCH 108/217] Integrate streaming-lt changes for shared domain signals: * Split server output signals implementation to domain and value signals * Assign real domain signal for websocket pseudo-device data signal if domain signal is publsihed by server * Streaming-lt server packet readers - sync packets of signal with shared domain read single packets one by one for each signal being processed, rather than reading all available packets per signal * Remove mock test server used for shared domain signal test * Add log messages to follow streaming-lt client / server threads joining * Increase timeout for streaming-lt subscription ack test --- .../libraries/opcuatms/tests/opcuatms_integration/main.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/main.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/main.cpp index d7951f9..242492a 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/main.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/main.cpp @@ -1,10 +1,6 @@ #include #include -#ifdef OPENDAQ_ENABLE_WEBSOCKET_STREAMING -#include -#endif - #include #include #include @@ -13,9 +9,6 @@ int main(int argc, char** args) { daq::daqInitializeCoreObjectsTesting(); -#ifdef OPENDAQ_ENABLE_WEBSOCKET_STREAMING - daqInitStreamingLibrary(); -#endif daqInitModuleManagerLibrary(); daqInitOpenDaqLibrary(); From 82f79e01be1037eeb862fcf6e2572fa838ff060d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE?= Date: Wed, 27 Mar 2024 21:51:14 +0100 Subject: [PATCH 109/217] Support lists in getLastValue (openDAQ/openDAQ#232) Support lists in getLastValue (including list of structs), support lists as a nested type for structs in getLastValue for core with tests (also add test for lists of simple (non-struct) values via OPC UA, which works out of the box) --- .../opcuatms_integration/test_tms_signal.cpp | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp index 0b577f0..e53c73f 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -78,6 +79,15 @@ class TmsSignalTest : public TmsObjectIntegrationTest ASSERT_EQ(high, highValue); } + void checkLastValueListOfInt64(const SignalPtr& signal) + { + auto lv = signal.getLastValue(); + ListPtr ptr; + ASSERT_NO_THROW(ptr = lv.asPtr()); + ASSERT_EQ(ptr.getItemAt(0), 4); + ASSERT_EQ(ptr.getItemAt(1), 44); + } + template void testGetLastValue(const SampleType& sampleType, const T& value) { @@ -285,6 +295,36 @@ TEST_F(TmsSignalTest, GetLastValueRange) checkLastValueRange(daqServerSignal, 8, 9); } +TEST_F(TmsSignalTest, GetLastValueListOfInt64) +{ + auto daqServerSignal = Signal(NullContext(), nullptr, "id"); + + auto numbers = List(); + numbers.pushBack(1); + numbers.pushBack(2); + + auto dimensions = List(); + dimensions.pushBack(Dimension(ListDimensionRule(numbers))); + + auto descriptor = DataDescriptorBuilder().setName("test").setSampleType(SampleType::Int64).setDimensions(dimensions).build(); + + auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), ctx, serverContext); + auto nodeId = serverSignal.registerOpcUaNode(); + daqServerSignal.setDescriptor(DataDescriptorBuilder().setSampleType(SampleType::RangeInt64).build()); + + auto dataPacket = DataPacket(descriptor, 5); + auto data = static_cast(dataPacket.getData()); + data[8] = 4; + data[9] = 44; + + daqServerSignal.sendPacket(dataPacket); + + auto clientSignal = TmsClientSignal(NullContext(), nullptr, "sig", clientContext, nodeId); + + checkLastValueListOfInt64(clientSignal); + checkLastValueListOfInt64(daqServerSignal); +} + TEST_F(TmsSignalTest, GetLastValueComplexFloat32) { float real = 8.1f; From 1a7bbed0b84f735b8987ddace8218f7502a90163 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Wed, 27 Mar 2024 11:41:44 +0100 Subject: [PATCH 110/217] Reset mirrored descriptor on unsubscribe --- .../include/opcuatms_client/objects/tms_client_signal_impl.h | 1 + .../opcuatms_client/src/objects/tms_client_signal_impl.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h index 38b470c..3412b8d 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h @@ -53,6 +53,7 @@ class TmsClientSignalImpl final : public TmsClientComponentBaseImpl isPublic = true; std::string deviceSignalId; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp index 34374a5..4be3a6c 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp @@ -97,6 +97,11 @@ DataDescriptorPtr TmsClientSignalImpl::onGetDescriptor() return nullptr; } +bool TmsClientSignalImpl::clearDescriptorOnUnsubscribe() +{ + return true; +} + ErrCode TmsClientSignalImpl::setDomainSignal(ISignal* signal) { return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; From 5ca9df89347e9e30f0a7a0a87169c72db02864e1 Mon Sep 17 00:00:00 2001 From: Dejan Crnila Date: Mon, 25 Mar 2024 15:41:53 +0100 Subject: [PATCH 111/217] Rework constant data rule --- .../opcuatms/src/converters/data_rule_converter.cpp | 4 ++-- .../opcuatms/tests/test_variant_converter.cpp | 4 +--- .../opcuatms/tests/test_variant_list_converter.cpp | 2 +- .../tests/opcuatms_integration/test_tms_signal.cpp | 12 +++--------- 4 files changed, 7 insertions(+), 15 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/data_rule_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/data_rule_converter.cpp index 015779e..18c94e6 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/data_rule_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/data_rule_converter.cpp @@ -52,14 +52,14 @@ DataRulePtr StructConverter::ToD throw ConversionFailedException(); const NumberPtr value = VariantConverter::ToDaqObject(tmsStruct.value); - return ConstantDataRule(value); + return ConstantDataRule(); } template <> OpcUaObject StructConverter::ToTmsType( const DataRulePtr& object, const ContextPtr& /*context*/) { - const NumberPtr value = object.getParameters().get("constant"); + const NumberPtr value = Integer(0); // TODO: temporary solution until model is adapted OpcUaObject uaRuleDescription; uaRuleDescription->type = UA_STRING_ALLOC("constant"); diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_variant_converter.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_variant_converter.cpp index 5217418..dc4f050 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/test_variant_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/tests/test_variant_converter.cpp @@ -222,14 +222,12 @@ TEST_F(VariantConverterTest, LinearDataRule) TEST_F(VariantConverterTest, ConstantDataRule) { - const DataRulePtr daqDataRule = ConstantDataRule(2.0); - const DataRulePtr daqDataRuleWrong = ConstantDataRule(1.0); + const DataRulePtr daqDataRule = ConstantDataRule(); const auto variant = VariantConverter::ToVariant(daqDataRule); const auto daqDataRuleOut = VariantConverter::ToDaqObject(variant); ASSERT_TRUE(daqDataRuleOut.equals(daqDataRule)); - ASSERT_FALSE(daqDataRuleOut.equals(daqDataRuleWrong)); } TEST_F(VariantConverterTest, ExplicitDataRule) diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_variant_list_converter.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_variant_list_converter.cpp index 9156181..40544b7 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/test_variant_list_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/tests/test_variant_list_converter.cpp @@ -240,7 +240,7 @@ TEST_F(VariantListConverterTest, DataRule) { auto list = List(); list.pushBack(LinearDataRule(2.0, 3.0)); - list.pushBack(ConstantDataRule(100.0)); + list.pushBack(ConstantDataRule()); list.pushBack(ExplicitDataRule()); const auto variant = VariantConverter::ToArrayVariant(list); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp index e53c73f..eae9363 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp @@ -43,7 +43,7 @@ class TmsSignalTest : public TmsObjectIntegrationTest .setSampleType(SampleType::Float32) .setName("Value Name") .setDimensions(List()) - .setRule(ConstantDataRule(1.0)) + .setRule(ConstantDataRule()) .setUnit(Unit("symbol", 1, "name", "quantity")) // Optional .setOrigin("Origin") // Optional .setValueRange(Range(0.0, 100.0)) // Optional @@ -350,7 +350,7 @@ TEST_F(TmsSignalTest, AttrDescriptor) auto serverDataDescriptor = DataDescriptorBuilder() .setSampleType(SampleType::Float32) .setDimensions(List()) - .setRule(ConstantDataRule(1.0)) + .setRule(ConstantDataRule()) .setUnit(Unit("symbol", 1, "name", "quantity")) // Optional .setOrigin("Origin") // Optional .setValueRange(Range(0.0, 100.0)) // Optional @@ -399,13 +399,7 @@ TEST_F(TmsSignalTest, AttrDescriptor) auto clientRule = clientDataDescriptor.getRule(); ASSERT_EQ(clientRule.getType(), DataRuleType::Constant); auto clientRuleParameters = clientRule.getParameters(); - ASSERT_EQ(clientRuleParameters.getCount(), 1u); - auto clientKeyList = clientRuleParameters.getKeyList(); - auto clientValueList = clientRuleParameters.getValueList(); - auto k = clientKeyList.getItemAt(0); - ASSERT_EQ(clientKeyList.getItemAt(0), "constant"); - auto v = clientValueList.getItemAt(0); - ASSERT_EQ(clientValueList.getItemAt(0), 1.0); + ASSERT_EQ(clientRuleParameters.getCount(), 0u); auto clientUnit = clientDataDescriptor.getUnit(); ASSERT_EQ(clientUnit.getQuantity(), "quantity"); From f8b716d7593fb630fdd955eeb54d921b39287f6d Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Fri, 5 Apr 2024 15:35:09 +0200 Subject: [PATCH 112/217] [TBBAS-1291] Grouping of discovered devices via serial number (openDAQ/openDAQ#196) - Rework device discovery to group devices via manufacturer and serial number - Add server capabilities to device information - Allow connection to devices with "daq://" prefix to automatically select best connection parameters --- .../opcua_client_module_impl.h | 2 +- .../src/opcua_client_module_impl.cpp | 104 ++++++++++++------ .../tests/test_opcua_client_module.cpp | 16 +-- .../opcua_server_module/opcua_server_impl.h | 1 + .../src/opcua_server_impl.cpp | 13 ++- .../objects/tms_client_device_impl.h | 2 +- .../objects/tms_client_property_object_impl.h | 13 ++- ...=> tms_client_server_capability_factory.h} | 11 +- ....h => tms_client_server_capability_impl.h} | 12 +- .../opcuatms_client/src/CMakeLists.txt | 8 +- .../src/objects/tms_client_device_impl.cpp | 71 +++++++----- .../tms_client_property_object_impl.cpp | 9 +- .../tms_client_server_capability_impl.cpp | 18 +++ .../tms_client_streaming_info_impl.cpp | 15 --- .../objects/tms_server_device.h | 4 +- .../src/objects/tms_server_device.cpp | 26 ++--- .../opcuatms_server/src/tms_server.cpp | 9 +- .../test_streaming_integration.cpp | 8 +- .../opcuatms_integration/test_tms_device.cpp | 42 ++++++- 19 files changed, 250 insertions(+), 134 deletions(-) rename shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/{tms_client_streaming_info_factory.h => tms_client_server_capability_factory.h} (73%) rename shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/{tms_client_streaming_info_impl.h => tms_client_server_capability_impl.h} (61%) create mode 100644 shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_server_capability_impl.cpp delete mode 100644 shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_streaming_info_impl.cpp diff --git a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h index d6449a5..83c5d68 100644 --- a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h +++ b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h @@ -34,7 +34,7 @@ class OpcUaClientModule final : public Module bool onAcceptsConnectionParameters(const StringPtr& connectionString, const PropertyObjectPtr& config) override; private: - static std::string GetUrlFromConnectionString(const StringPtr& connectionString); + static std::tuple ParseConnectionString(const StringPtr& connectionString); static bool acceptDeviceProperties(const PropertyObjectPtr& config); static PropertyObjectPtr createDeviceDefaultConfig(); static void configureStreamingSources(const PropertyObjectPtr& deviceConfig, const DevicePtr& device); diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 79fa98b..0a9fad4 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -12,7 +12,7 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_CLIENT_MODULE -static const char* DaqOpcUaDeviceTypeId = "daq.opcua"; +static const char* DaqOpcUaDeviceTypeId = "opendaq_opcua_config"; static const char* DaqOpcUaDevicePrefix = "daq.opcua://"; static const char* OpcUaScheme = "opc.tcp://"; @@ -26,9 +26,13 @@ OpcUaClientModule::OpcUaClientModule(ContextPtr context) "OpcUaClient") , discoveryClient( { - [](const MdnsDiscoveredDevice& discoveredDevice) + [context = this->context](const MdnsDiscoveredDevice& discoveredDevice) { - return DaqOpcUaDevicePrefix + discoveredDevice.ipv4Address + "/"; + auto connectionString = DaqOpcUaDevicePrefix + discoveredDevice.ipv4Address + "/"; + auto cap = ServerCapability("opendaq_opcua_config", "openDAQ OpcUa", ProtocolType::Configuration).addConnectionString(connectionString) + .setConnectionType("Ipv4") + .setPrefix("daq.opcua"); + return cap; } }, {"OPENDAQ"} @@ -74,52 +78,63 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, if (!context.assigned()) throw InvalidParameterException{"Context is not available."}; - const auto deviceUrl = GetUrlFromConnectionString(connectionString); - StringPtr rootDeviceAddress; - std::smatch match; - auto regexHostname = std::regex("^(.*:\\/\\/)?([^:\\/\\s]+)"); - if (std::regex_search(deviceUrl, match, regexHostname)) - rootDeviceAddress = String(match[2]); + auto parsedConnection = ParseConnectionString(connectionString); + auto prefix = std::get<0>(parsedConnection); + auto host = std::get<1>(parsedConnection); + auto path = std::get<2>(parsedConnection); + if (prefix != DaqOpcUaDevicePrefix) + throw InvalidParameterException("OpcUa does not support connection string with prefix"); - FunctionPtr createStreamingCallback = [&](const StreamingInfoPtr& streamingInfo, + FunctionPtr createStreamingCallback = [&](const ServerCapabilityPtr& capability, bool isRootDevice) -> StreamingPtr { + if (capability.getProtocolType() != ProtocolType::Streaming) + return nullptr; + if (isRootDevice) - streamingInfo.template asPtr().setPrimaryAddress(rootDeviceAddress); + capability.setPropertyValue("address", host); const StringPtr streamingHeuristic = deviceConfig.getPropertySelectionValue("StreamingConnectionHeuristic"); const ListPtr allowedStreamingProtocols = deviceConfig.getPropertyValue("AllowedStreamingProtocols"); - if (const auto it = std::find(allowedStreamingProtocols.begin(), - allowedStreamingProtocols.end(), - streamingInfo.getProtocolId()); - it == allowedStreamingProtocols.end()) - return nullptr; + const StringPtr protocolId = capability.getPropertyValue("protocolId"); + + if (protocolId != nullptr) + if (const auto it = std::find(allowedStreamingProtocols.begin(), + allowedStreamingProtocols.end(), + protocolId); + it == allowedStreamingProtocols.end()) + return nullptr; if (streamingHeuristic == "MinHops" || streamingHeuristic == "Fallbacks" || streamingHeuristic == "MinConnections" && isRootDevice) - return this->createStreamingFromAnotherModule(nullptr, streamingInfo); + return this->createStreamingFromAnotherModule(nullptr, capability); else return nullptr; }; std::scoped_lock lock(sync); - TmsClient client(context, parent, OpcUaScheme + deviceUrl, createStreamingCallback); + TmsClient client(context, parent, OpcUaScheme + host + path, createStreamingCallback); auto device = client.connect(); this->configureStreamingSources(deviceConfig, device); return device; } -std::string OpcUaClientModule::GetUrlFromConnectionString(const StringPtr& connectionString) +std::tuple OpcUaClientModule::ParseConnectionString(const StringPtr& connectionString) { - std::string connStr = connectionString; - std::string prefixWithDeviceStr = DaqOpcUaDevicePrefix; - auto found = connStr.find(prefixWithDeviceStr); - if (found != 0) - throw InvalidParameterException(); + std::string urlString = connectionString.toStdString(); - return connStr.substr(prefixWithDeviceStr.size(), std::string::npos); + auto regexIpv6Hostname = std::regex("^(.*:\\/\\/)(\\[[a-fA-F0-9:]+\\])(.*)"); + auto regexIpv4Hostname = std::regex("^(.*:\\/\\/)([^:\\/\\s]+)(.*)"); + std::smatch match; + + if (std::regex_search(urlString, match, regexIpv6Hostname)) + return {match[1],match[2],match[3]}; + if (std::regex_search(urlString, match, regexIpv4Hostname)) + return {match[1],match[2],match[3]}; + + throw InvalidParameterException("Host name not found in url: {}", connectionString); } bool OpcUaClientModule::onAcceptsConnectionParameters(const StringPtr& connectionString, const PropertyObjectPtr& config) @@ -175,16 +190,16 @@ PropertyObjectPtr OpcUaClientModule::createDeviceDefaultConfig() StringPtr primaryStreamingProtocol = "none"; #if defined(OPENDAQ_ENABLE_NATIVE_STREAMING) - allowedStreamingProtocols.pushBack("daq.ns"); - primaryStreamingProtocol = "daq.ns"; + allowedStreamingProtocols.pushBack("opendaq_native_streaming"); + primaryStreamingProtocol = "opendaq_native_streaming"; // TODO add websocket streaming to default list of allowed protocols // when it will have subscribe/unsubscribe support //#if defined(OPENDAQ_ENABLE_WEBSOCKET_STREAMING) -// allowedStreamingProtocols.pushBack("daq.wss"); +// allowedStreamingProtocols.pushBack("opendaq_lt_streaming"); #endif #if defined(OPENDAQ_ENABLE_WEBSOCKET_STREAMING) - allowedStreamingProtocols.pushBack("daq.wss"); -// primaryStreamingProtocol = "daq.wss"; + allowedStreamingProtocols.pushBack("opendaq_lt_streaming"); +// primaryStreamingProtocol = "opendaq_lt_streaming"; #endif defaultConfig.addProperty(ListProperty("AllowedStreamingProtocols", allowedStreamingProtocols)); @@ -217,6 +232,21 @@ void OpcUaClientModule::configureStreamingSources(const PropertyObjectPtr& devic const StringPtr primaryStreamingProtocol = deviceConfig.getPropertyValue("PrimaryStreamingProtocol"); const ListPtr allowedStreamingProtocols = deviceConfig.getPropertyValue("AllowedStreamingProtocols"); + std::unordered_map idPrefixMap; + + { + auto devices = device.getDevices(search::Recursive(search::Any())); + devices.pushBack(device); + + for (const auto& dev : devices) + { + const auto capabilities = dev.getInfo().getServerCapabilities(); + for (const auto & cap : capabilities) + { + idPrefixMap.insert(std::make_pair(cap.getProtocolId(), cap.getPrefix())); + } + } + } for (const auto& signal : device.getSignals(search::Recursive(search::Any()))) { @@ -236,7 +266,12 @@ void OpcUaClientModule::configureStreamingSources(const PropertyObjectPtr& devic for (const auto& streamingConnectionString : streamingSources) { std::string connectionString = streamingConnectionString.toStdString(); - std::string protocolPrefix = primaryStreamingProtocol.toStdString(); + std::string streamingProtocolId = primaryStreamingProtocol.toStdString(); + + if (!idPrefixMap.count(streamingProtocolId)) + continue; + + std::string protocolPrefix = idPrefixMap.at(streamingProtocolId); if (connectionString.find(protocolPrefix) == 0) { // save the first streaming source as the leaf streaming @@ -253,9 +288,12 @@ void OpcUaClientModule::configureStreamingSources(const PropertyObjectPtr& devic for (const auto& streamingConnectionString : streamingSources) { std::string connectionString = streamingConnectionString.toStdString(); - for (const auto& protocol : allowedStreamingProtocols) + for (const auto& streamingProtocolId : allowedStreamingProtocols) { - std::string protocolPrefix = protocol.toStdString(); + if (!idPrefixMap.count(streamingProtocolId)) + continue; + + std::string protocolPrefix = idPrefixMap.at(streamingProtocolId); if (connectionString.find(protocolPrefix) == 0) { // save the first streaming source as the leaf streaming diff --git a/modules/opcua_client_module/tests/test_opcua_client_module.cpp b/modules/opcua_client_module/tests/test_opcua_client_module.cpp index bd0c6a1..08908c0 100644 --- a/modules/opcua_client_module/tests/test_opcua_client_module.cpp +++ b/modules/opcua_client_module/tests/test_opcua_client_module.cpp @@ -138,8 +138,8 @@ TEST_F(OpcUaClientModuleTest, GetAvailableComponentTypes) DictPtr deviceTypes; ASSERT_NO_THROW(deviceTypes = module.getAvailableDeviceTypes()); ASSERT_EQ(deviceTypes.getCount(), 1u); - ASSERT_TRUE(deviceTypes.hasKey("daq.opcua")); - ASSERT_EQ(deviceTypes.get("daq.opcua").getId(), "daq.opcua"); + ASSERT_TRUE(deviceTypes.hasKey("opendaq_opcua_config")); + ASSERT_EQ(deviceTypes.get("opendaq_opcua_config").getId(), "opendaq_opcua_config"); DictPtr serverTypes; ASSERT_NO_THROW(serverTypes = module.getAvailableServerTypes()); @@ -153,8 +153,8 @@ TEST_F(OpcUaClientModuleTest, DefaultDeviceConfig) DictPtr deviceTypes; ASSERT_NO_THROW(deviceTypes = module.getAvailableDeviceTypes()); ASSERT_EQ(deviceTypes.getCount(), 1u); - ASSERT_TRUE(deviceTypes.hasKey("daq.opcua")); - auto config = deviceTypes.get("daq.opcua").createDefaultConfig(); + ASSERT_TRUE(deviceTypes.hasKey("opendaq_opcua_config")); + auto config = deviceTypes.get("opendaq_opcua_config").createDefaultConfig(); ASSERT_TRUE(config.assigned()); ASSERT_TRUE(config.hasProperty("StreamingConnectionHeuristic")); @@ -162,16 +162,16 @@ TEST_F(OpcUaClientModuleTest, DefaultDeviceConfig) #if defined(OPENDAQ_ENABLE_NATIVE_STREAMING) ASSERT_TRUE(config.hasProperty("AllowedStreamingProtocols")); - ASSERT_EQ(config.getPropertyValue("AllowedStreamingProtocols"), List("daq.ns", "daq.wss")); + ASSERT_EQ(config.getPropertyValue("AllowedStreamingProtocols"), List("opendaq_native_streaming", "opendaq_lt_streaming")); ASSERT_TRUE(config.hasProperty("PrimaryStreamingProtocol")); - ASSERT_EQ(config.getPropertyValue("PrimaryStreamingProtocol"), "daq.ns"); + ASSERT_EQ(config.getPropertyValue("PrimaryStreamingProtocol"), "opendaq_native_streaming"); #elif defined(OPENDAQ_ENABLE_WEBSOCKET_STREAMING) && !defined(OPENDAQ_ENABLE_NATIVE_STREAMING) ASSERT_TRUE(config.hasProperty("AllowedStreamingProtocols")); - ASSERT_EQ(config.getPropertyValue("AllowedStreamingProtocols"), List("daq.wss")); + ASSERT_EQ(config.getPropertyValue("AllowedStreamingProtocols"), List("opendaq_lt_streaming")); ASSERT_TRUE(config.hasProperty("PrimaryStreamingProtocol")); - ASSERT_EQ(config.getPropertyValue("PrimaryStreamingProtocol"), "daq.wss"); + ASSERT_EQ(config.getPropertyValue("PrimaryStreamingProtocol"), "opendaq_lt_streaming"); #endif } diff --git a/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h b/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h index 5cbb3ad..7564f15 100644 --- a/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h +++ b/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h @@ -28,6 +28,7 @@ class OpcUaServerImpl : public daq::Server { public: explicit OpcUaServerImpl(daq::DevicePtr rootDevice, PropertyObjectPtr config, const ContextPtr& context); + ~OpcUaServerImpl(); static PropertyObjectPtr createDefaultConfig(); static ServerTypePtr createType(); diff --git a/modules/opcua_server_module/src/opcua_server_impl.cpp b/modules/opcua_server_module/src/opcua_server_impl.cpp index dfa9a55..ea968a9 100644 --- a/modules/opcua_server_module/src/opcua_server_impl.cpp +++ b/modules/opcua_server_module/src/opcua_server_impl.cpp @@ -3,9 +3,10 @@ #include #include #include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_SERVER_MODULE - using namespace daq; using namespace daq::opcua; @@ -21,6 +22,10 @@ OpcUaServerImpl::OpcUaServerImpl(DevicePtr rootDevice, PropertyObjectPtr config, server.start(); } +OpcUaServerImpl::~OpcUaServerImpl() +{ +} + PropertyObjectPtr OpcUaServerImpl::createDefaultConfig() { constexpr Int minPortValue = 0; @@ -53,6 +58,12 @@ ServerTypePtr OpcUaServerImpl::createType() void OpcUaServerImpl::onStopServer() { server.stop(); + if (this->rootDevice.assigned()) + { + const auto info = this->rootDevice.getInfo().asPtr(); + if (info.hasServerCapability("opendaq_opcua_config")) + info.removeServerCapability("opendaq_opcua_config"); + } } OPENDAQ_DEFINE_CLASS_FACTORY_WITH_INTERFACE( diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h index e6cc117..ba75526 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h @@ -50,7 +50,7 @@ class TmsClientDeviceImpl : public TmsClientComponentBaseImpl #include "opcuaclient/opcuaclient.h" #include "opcuatms/opcuatms.h" #include "opcuatms_client/objects/tms_client_object_impl.h" -#include "opendaq/channel_impl.h" -#include "opendaq/streaming_info_impl.h" +#include #include "opcuatms_client/objects/tms_client_component.h" +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -52,18 +52,19 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl init(); } - template = 0> + template = 0> TmsClientPropertyObjectBaseImpl(const ContextPtr& daqContext, + const StringPtr& protocolName, const StringPtr& protocolId, const TmsClientContextPtr& clientContext, const opcua::OpcUaNodeId& nodeId) : TmsClientObjectImpl(daqContext, clientContext, nodeId) - , Impl(protocolId) + , Impl(protocolId, protocolName, ProtocolType::Streaming) { init(); } - template, ChannelImpl, PropertyObjectImpl, StreamingInfoConfigImpl> = 0> + template, ChannelImpl, PropertyObjectImpl, ServerCapabilityConfigImpl> = 0> TmsClientPropertyObjectBaseImpl(const ContextPtr& ctx, const ComponentPtr& parent, const StringPtr& localId, diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_streaming_info_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_factory.h similarity index 73% rename from shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_streaming_info_factory.h rename to shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_factory.h index a6015fd..aea843b 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_streaming_info_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_factory.h @@ -15,17 +15,18 @@ */ #pragma once #include "opcuatms_client/objects/tms_client_context.h" -#include "opcuatms_client/objects/tms_client_streaming_info_impl.h" -#include +#include "opcuatms_client/objects/tms_client_server_capability_impl.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS -inline StreamingInfoConfigPtr TmsClientStreamingInfo(const ContextPtr& daqContext, + +inline ServerCapabilityPtr TmsClientServerCapability(const ContextPtr& daqContext, const StringPtr& protocolId, + const StringPtr& protocolName, const daq::opcua::tms::TmsClientContextPtr& clientContext, const opcua::OpcUaNodeId& nodeId) { - StreamingInfoConfigPtr obj( - createWithImplementation(daqContext, protocolId, clientContext, nodeId) + ServerCapabilityPtr obj( + createWithImplementation(daqContext, protocolId, protocolName, clientContext, nodeId) ); return obj; } diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_streaming_info_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_impl.h similarity index 61% rename from shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_streaming_info_impl.h rename to shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_impl.h index 3dfe46e..2c05068 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_streaming_info_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_impl.h @@ -16,17 +16,17 @@ #pragma once #include "opcuatms_client/objects/tms_client_property_object_impl.h" -#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS -class TmsClientStreamingInfoImpl : public TmsClientPropertyObjectBaseImpl +class TmsClientServerCapabilityImpl : public TmsClientPropertyObjectBaseImpl { public: - explicit TmsClientStreamingInfoImpl(const ContextPtr& daqContext, - const StringPtr& protocolId, - const TmsClientContextPtr& clientContext, - const opcua::OpcUaNodeId& nodeId); + explicit TmsClientServerCapabilityImpl(const ContextPtr& daqContext, + const StringPtr& protocolId, + const StringPtr& protocolName, + const TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId); }; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt index e06abc3..3f68140 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt @@ -52,8 +52,8 @@ set(SRC_Objects_Headers ${OBJECT_SRC_DIR}/tms_client_object_impl.h ${OBJECT_SRC_DIR}/tms_client_component_impl.h ${OBJECT_SRC_DIR}/tms_client_component_factory.h - ${OBJECT_SRC_DIR}/tms_client_streaming_info_impl.h - ${OBJECT_SRC_DIR}/tms_client_streaming_info_factory.h + ${OBJECT_SRC_DIR}/tms_client_server_capability_impl.h + ${OBJECT_SRC_DIR}/tms_client_server_capability_factory.h ${OBJECT_SRC_DIR}/tms_client_function_impl.h ${OBJECT_SRC_DIR}/tms_client_function_factory.h @@ -77,7 +77,7 @@ set(SRC_Objects ${OBJECT_SRC_DIR}/tms_client_object_impl.cpp ${OBJECT_SRC_DIR}/tms_client_folder_impl.cpp ${OBJECT_SRC_DIR}/tms_client_io_folder_impl.cpp ${OBJECT_SRC_DIR}/tms_client_component_impl.cpp - ${OBJECT_SRC_DIR}/tms_client_streaming_info_impl.cpp + ${OBJECT_SRC_DIR}/tms_client_server_capability_impl.cpp ${OBJECT_SRC_DIR}/tms_client_function_impl.cpp ${OBJECT_SRC_DIR}/tms_client_procedure_impl.cpp ${OBJECT_SRC_DIR}/tms_client_tags_impl.cpp @@ -98,7 +98,7 @@ source_group("objects\\device" "${OBJECT_SRC_DIR}/tms_client_device.*") source_group("objects\\folder" "${OBJECT_SRC_DIR}/tms_client_folder.*") source_group("objects\\component" "${OBJECT_SRC_DIR}/tms_client_component.*") source_group("objects\\io_folder" "${OBJECT_SRC_DIR}/tms_client_io_folder.*") -source_group("objects\\streaming_info" "${OBJECT_SRC_DIR}/tms_client_streaming_info.*") +source_group("objects\\server_capability" "${OBJECT_SRC_DIR}/tms_client_server_capability.*") source_group("objects\\tags" "${OBJECT_SRC_DIR}/tms_client_tags.*") source_group("objects\\function" "${OBJECT_SRC_DIR}/(tms_client_function_impl.*|tms_client_function_factory.h|tms_client_procedure.*)") diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 97825a4..afe7ef7 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -10,12 +10,13 @@ #include #include "opcuatms_client/objects/tms_client_component_factory.h" #include "opcuatms_client/objects/tms_client_io_folder_factory.h" -#include "opcuatms_client/objects/tms_client_streaming_info_factory.h" +#include "opcuatms_client/objects/tms_client_server_capability_factory.h" #include #include "open62541/daqbt_nodeids.h" #include #include #include +#include #include #include "opcuatms/core_types_utils.h" #include "opcuatms/exceptions.h" @@ -29,7 +30,7 @@ using namespace daq::opcua; namespace detail { - static std::unordered_set defaultComponents = {"Sig", "FB", "IO", "StreamingOptions"}; + static std::unordered_set defaultComponents = {"Sig", "FB", "IO", "ServerCapabilities"}; static std::unordered_map> deviceInfoSetterMap = { {"AssetId", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setAssetId(v.toString()); }}, @@ -75,14 +76,13 @@ TmsClientDeviceImpl::TmsClientDeviceImpl(const ContextPtr& ctx, if (isRootDevice) clientContext->registerRootDevice(thisInterface()); - + findAndCreateSubdevices(); findAndCreateFunctionBlocks(); findAndCreateSignals(); findAndCreateInputsOutputs(); findAndCreateCustomComponents(); - findAndCreateStreamingOptions(); connectToStreamings(); setUpStreamings(); } @@ -137,10 +137,7 @@ void TmsClientDeviceImpl::onRemoveDevice(const DevicePtr& /*device*/) DeviceInfoPtr TmsClientDeviceImpl::onGetInfo() { - if (deviceInfo.assigned()) - return deviceInfo; - - deviceInfo = DeviceInfo(""); + auto deviceInfo = DeviceInfo("", "OpcUa Client"); auto browseFilter = BrowseFilter(); browseFilter.nodeClass = UA_NODECLASS_VARIABLE; @@ -186,6 +183,8 @@ DeviceInfoPtr TmsClientDeviceImpl::onGetInfo() LOG_W("Failed to read device info attribute on OpcUa client device \"{}\": {}", this->globalId, e.what()); } } + + findAndCreateServerCapabilities(deviceInfo); deviceInfo.freeze(); return deviceInfo; @@ -201,6 +200,9 @@ void TmsClientDeviceImpl::fetchTimeDomain() if (!deviceDomain) return; + if (deviceDomain == nullptr) + return; + auto numerator = deviceDomain->resolution.numerator; auto denominator = deviceDomain->resolution.denominator; if (denominator == 0) @@ -355,40 +357,50 @@ void TmsClientDeviceImpl::findAndCreateInputsOutputs() this->ioFolder.addItem(val); } -void TmsClientDeviceImpl::findAndCreateStreamingOptions() +void TmsClientDeviceImpl::findAndCreateServerCapabilities(const DeviceInfoPtr& deviceInfo) { - std::map orderedStreamings; - std::vector unorderedStreamings; + std::map orderedCaps; + std::vector unorderedCaps; - this->streamingOptions.clear(); - auto streamingOptionsNodeId = getNodeId("StreamingOptions"); + auto serverCapabilitiesNodeId = getNodeId("ServerCapabilities"); try { - const auto& streamingOptionsReferences = - getChildReferencesOfType(streamingOptionsNodeId, OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_VARIABLEBLOCKTYPE)); + const auto& serverCapabilitiesReferences = + getChildReferencesOfType(serverCapabilitiesNodeId, OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_VARIABLEBLOCKTYPE)); - for (const auto& [browseName, ref] : streamingOptionsReferences.byBrowseName) + for (const auto& [browseName, ref] : serverCapabilitiesReferences.byBrowseName) { const auto optionNodeId = OpcUaNodeId(ref->nodeId.nodeId); - auto clientStreamingInfo = TmsClientStreamingInfo(daqContext, browseName, clientContext, optionNodeId); + auto clientServerCapability = TmsClientServerCapability(daqContext, browseName, "", clientContext, optionNodeId); + + auto capabilityCopy = ServerCapability("", "", ProtocolType::Unknown); + for (const auto& prop : clientServerCapability.getAllProperties()) + { + const auto name = prop.getName(); + if (!capabilityCopy.hasProperty(name)) + capabilityCopy.addProperty(prop.asPtr().clone()); + capabilityCopy.setPropertyValue(name, clientServerCapability.getPropertyValue(name)); + } auto numberInList = this->tryReadChildNumberInList(optionNodeId); if (numberInList != std::numeric_limits::max()) - orderedStreamings.insert(std::pair(numberInList, clientStreamingInfo)); + orderedCaps.insert(std::pair(numberInList, capabilityCopy)); else - unorderedStreamings.emplace_back(clientStreamingInfo); + unorderedCaps.emplace_back(capabilityCopy); } } catch (const std::exception& e) { - LOG_W("Failed to find 'StreamingOptions' OpcUA node on OpcUA client device \"{}\": {}", this->globalId, e.what()); + LOG_W("Failed to find 'ServerCapabilities' OpcUA node on OpcUA client device \"{}\": {}", this->globalId, e.what()); } - for (const auto& val : orderedStreamings) - this->streamingOptions.push_back(val.second); - for (const auto& val : unorderedStreamings) - this->streamingOptions.push_back(val); + auto deviceInfoInternal = deviceInfo.asPtr(); + deviceInfoInternal.clearServerStreamingCapabilities(); + for (const auto& [_, val] : orderedCaps) + deviceInfoInternal.addServerCapability(val); + for (const auto& val : unorderedCaps) + deviceInfoInternal.addServerCapability(val); } void TmsClientDeviceImpl::findAndCreateCustomComponents() @@ -530,16 +542,21 @@ void TmsClientDeviceImpl::setUpStreamings() void TmsClientDeviceImpl::connectToStreamings() { + DeviceInfoPtr info; + this->getInfo(&info); if (createStreamingCallback.assigned()) { - for (const auto& option : streamingOptions) + for (const auto& capability : info.getServerCapabilities()) { + if (capability.getProtocolType() != ProtocolType::Streaming) + continue; + StreamingPtr streaming; - ErrCode errCode = wrapHandlerReturn(createStreamingCallback, streaming, option, isRootDevice); + ErrCode errCode = wrapHandlerReturn(createStreamingCallback, streaming, capability, isRootDevice); if (OPENDAQ_FAILED(errCode) || !streaming.assigned()) { - LOG_W("Device \"{}\" had not connected to published streaming protocol \"{}\".", globalId, option.getProtocolId()); + LOG_W("Device \"{}\" had not connected to published streaming protocol \"{}\".", globalId, capability.getPropertyValue("protocolId").asPtr()); } else { diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index f697400..82410d7 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -19,6 +19,11 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS using namespace opcua; +namespace detail +{ + std::unordered_set ignoredPropertyNames{"ServerCapabilities"}; +} + template ErrCode TmsClientPropertyObjectBaseImpl::setPropertyValueInternal(IString* propertyName, IBaseObject* value, bool protectedWrite) { @@ -257,6 +262,8 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par { const auto typeId = OpcUaNodeId(ref->typeDefinition.nodeId); const auto propName = String(utils::ToStdString(ref->browseName.name)); + if (detail::ignoredPropertyNames.count(propName)) + continue; Bool hasProp; daq::checkErrorInfo(Impl::hasProperty(propName, &hasProp)); @@ -493,7 +500,7 @@ template class TmsClientPropertyObjectBaseImpl>; template class TmsClientPropertyObjectBaseImpl>; template class TmsClientPropertyObjectBaseImpl>; -template class TmsClientPropertyObjectBaseImpl; +template class TmsClientPropertyObjectBaseImpl; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_server_capability_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_server_capability_impl.cpp new file mode 100644 index 0000000..87e28e9 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_server_capability_impl.cpp @@ -0,0 +1,18 @@ +#include "opcuatms_client/objects/tms_client_server_capability_impl.h" +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace daq::opcua; + +TmsClientServerCapabilityImpl::TmsClientServerCapabilityImpl(const ContextPtr& daqContext, + const StringPtr& protocolName, + const StringPtr& protocolId, + const TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId) + : TmsClientPropertyObjectBaseImpl(daqContext, protocolId, protocolName, clientContext, nodeId) +{ + +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_streaming_info_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_streaming_info_impl.cpp deleted file mode 100644 index c80bdc9..0000000 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_streaming_info_impl.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "opcuatms_client/objects/tms_client_streaming_info_impl.h" -#include - -BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS - -using namespace daq::opcua; - -TmsClientStreamingInfoImpl::TmsClientStreamingInfoImpl(const ContextPtr& daqContext, - const StringPtr& protocolId, - const TmsClientContextPtr& clientContext, - const opcua::OpcUaNodeId& nodeId) - : TmsClientPropertyObjectBaseImpl(daqContext, protocolId, clientContext, nodeId) -{ -} -END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h index f02af7c..902396b 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h @@ -47,7 +47,7 @@ class TmsServerDevice : public TmsServerComponent protected: opcua::OpcUaNodeId getTmsTypeId() override; void populateDeviceInfo(); - void populateStreamingOptions(); + void populateServerCapabilities(); void addFunctionBlockFolderNodes(); void createFunctionBlockTypesFolder(const OpcUaNodeId& parentId); void createAddFunctionBlockNode(const OpcUaNodeId& parentId); @@ -66,7 +66,7 @@ class TmsServerDevice : public TmsServerComponent std::list functionBlocks; std::list folders; std::list components; - std::list streamingOptions; + std::list serverCapabilities; std::list functionBlockTypes; }; diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index 77ec116..bb41603 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -9,7 +9,6 @@ #include "opcuatms/converters/struct_converter.h" #include #include -#include #include #include #include @@ -221,26 +220,17 @@ void TmsServerDevice::populateDeviceInfo() } } -void TmsServerDevice::populateStreamingOptions() +void TmsServerDevice::populateServerCapabilities() { - auto params = AddObjectNodeParams(UA_NODEID_NULL, nodeId); - params.setBrowseName("StreamingOptions"); - auto streamingOptionsNodeId = server->addObjectNode(params); - - auto devicePrivatePtr = object.asPtrOrNull(); - if (devicePrivatePtr == nullptr) // Instance does not implement IDevicePrivate + const auto deviceInfo = object.getInfo(); + if (deviceInfo == nullptr) return; - ListPtr streamingOptions; - devicePrivatePtr->getStreamingOptions(&streamingOptions); + const PropertyObjectPtr serverCapabilitiesObj = deviceInfo.getPropertyValue("serverCapabilities"); - uint32_t numberInList = 0; - for (const auto& streamingOption : streamingOptions) - { - auto tmsStreamingOption = registerTmsObjectOrAddReference( - streamingOptionsNodeId, streamingOption.asPtr(), numberInList++, streamingOption.getProtocolId()); - this->streamingOptions.push_back(std::move(tmsStreamingOption)); - } + auto tmsServerCapability = registerTmsObjectOrAddReference( + nodeId, serverCapabilitiesObj.asPtr(), numberInList++, "ServerCapabilities"); + this->serverCapabilities.push_back(std::move(tmsServerCapability)); } void TmsServerDevice::addFunctionBlockFolderNodes() @@ -432,7 +422,7 @@ void TmsServerDevice::removeFunctionBlock(const StringPtr& localId) void TmsServerDevice::addChildNodes() { populateDeviceInfo(); - populateStreamingOptions(); + populateServerCapabilities(); auto methodSetNodeId = getChildNodeId("MethodSet"); tmsPropertyObject->setMethodParentNodeId(methodSetNodeId); diff --git a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp index 1b83a44..bcb878a 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include using namespace daq::opcua; using namespace daq::opcua::tms; @@ -45,6 +47,11 @@ void TmsServer::start() tmsContext = std::make_shared(context, device); auto signals = device.getSignals(); + auto serverCapability = ServerCapability("opendaq_opcua_config", "openDAQ OpcUa", ProtocolType::Configuration); + serverCapability.setPrefix("daq.opcua"); + serverCapability.setConnectionType("Ipv4"); + device.getInfo().asPtr().addServerCapability(serverCapability); + tmsDevice = std::make_unique(device, server, context, tmsContext); tmsDevice->registerOpcUaNode(OpcUaNodeId(NAMESPACE_DI, UA_DIID_DEVICESET)); tmsDevice->createNonhierarchicalReferences(); @@ -56,7 +63,7 @@ void TmsServer::stop() { if (server) server->stop(); - + server.reset(); tmsDevice.reset(); } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp index 52d1fc5..564905c 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp @@ -33,7 +33,7 @@ class StreamingIntegrationTest : public testing::Test const uint16_t STREAMING_PORT = 7414; const uint16_t STREAMING_CONTROL_PORT = 7438; const std::string OPCUA_URL = "opc.tcp://127.0.0.1/"; - const std::string STREAMING_URL = "daq.wss://127.0.0.1/"; + const std::string STREAMING_URL = "daq.lt://127.0.0.1/"; using ReadCallback = std::function& readPackets)>; @@ -42,10 +42,10 @@ class StreamingIntegrationTest : public testing::Test logger = Logger(); loggerComponent = logger.getOrAddComponent("StreamingIntegrationTest"); auto clientLogger = Logger(); - clientContext = Context(Scheduler(clientLogger, 1), clientLogger, nullptr, nullptr); + clientContext = Context(Scheduler(clientLogger, 1), clientLogger, TypeManager(), nullptr); instance = createDevice(); - createStreamingCallback = Function([this](const StreamingInfoPtr& /*streamingConfig*/, + createStreamingCallback = Function([this](const ServerCapabilityPtr& /*capability*/, bool /*isRootDevice*/) { return createStreaming(); @@ -442,7 +442,7 @@ TEST_F(StreamingIntegrationTest, StreamingDeactivate) server.start(); auto streaming = createStreaming(); - auto createStreamingCb = Function([&](const StreamingInfoPtr& /*streamingConfig*/, + auto createStreamingCb = Function([&](const ServerCapabilityPtr& /*capability*/, bool /*isRootDevice*/) { return streaming; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp index 8537155..a2c91cc 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp @@ -12,6 +12,7 @@ #include #include #include "tms_object_integration_test.h" +#include "opendaq/device_info_internal_ptr.h" using namespace daq; using namespace opcua::tms; @@ -33,7 +34,11 @@ class TmsDeviceTest : public TmsObjectIntegrationTest auto instance = InstanceCustom(context, "localInstance"); instance.addDevice("daq_client_device"); - instance.addDevice("mock_phys_device"); + const auto device = instance.addDevice("mock_phys_device"); + const auto infoInternal = device.getInfo().asPtr(); + infoInternal.addServerCapability(ServerCapability("protocol_1", "protocol 1", ProtocolType::Streaming)); + infoInternal.addServerCapability(ServerCapability("protocol_2", "protocol 2", ProtocolType::Configuration)); + instance.addFunctionBlock("mock_fb_uid"); return instance; @@ -219,6 +224,41 @@ TEST_F(TmsDeviceTest, DeviceInfo) ASSERT_EQ(clientDeviceInfo.getPropertyValue("custom_int"), 1); } +TEST_F(TmsDeviceTest, DeviceInfoServerCapabilities) +{ + auto ctx = NullContext(); + DevicePtr serverDevice = createDevice(); + + auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); + auto nodeId = serverTmsDevice.registerOpcUaNode(); + + auto serverSubDevices = serverDevice.getDevices(); + ASSERT_EQ(serverSubDevices.getCount(), 2u); + auto serverSubDevice = serverSubDevices[1]; + auto serverDeviceInfo = serverSubDevice.getInfo(); + + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + + auto clientSubDevices = clientDevice.getDevices(); + ASSERT_EQ(clientSubDevices.getCount(), 2u); + auto clientSubDevice = clientSubDevices[1]; + auto clientDeviceInfo = clientSubDevice.getInfo(); + ASSERT_EQ(serverDeviceInfo.getServerCapabilities().getCount(), 2); + ASSERT_EQ(clientDeviceInfo.getServerCapabilities().getCount(), 2); + auto name = clientDeviceInfo.getServerCapabilities()[1].getProtocolName(); + auto id = clientDeviceInfo.getServerCapabilities()[1].getProtocolId(); + ASSERT_EQ(clientDeviceInfo.getServerCapabilities()[0].getProtocolId(), serverDeviceInfo.getServerCapabilities()[0].getProtocolId()); + ASSERT_EQ(clientDeviceInfo.getServerCapabilities()[1].getProtocolId(), serverDeviceInfo.getServerCapabilities()[1].getProtocolId()); + ASSERT_EQ(clientDeviceInfo.getServerCapabilities()[0].getProtocolName(), serverDeviceInfo.getServerCapabilities()[0].getProtocolName()); + ASSERT_EQ(clientDeviceInfo.getServerCapabilities()[1].getProtocolName(), serverDeviceInfo.getServerCapabilities()[1].getProtocolName()); + ASSERT_EQ(clientDeviceInfo.getServerCapabilities()[0].getProtocolType(), serverDeviceInfo.getServerCapabilities()[0].getProtocolType()); + ASSERT_EQ(clientDeviceInfo.getServerCapabilities()[1].getProtocolType(), serverDeviceInfo.getServerCapabilities()[1].getProtocolType()); + ASSERT_EQ(clientDeviceInfo.getServerCapabilities()[0].getConnectionType(), serverDeviceInfo.getServerCapabilities()[0].getConnectionType()); + ASSERT_EQ(clientDeviceInfo.getServerCapabilities()[1].getConnectionType(), serverDeviceInfo.getServerCapabilities()[1].getConnectionType()); + ASSERT_EQ(clientDeviceInfo.getServerCapabilities()[0].getCoreEventsEnabled(), serverDeviceInfo.getServerCapabilities()[0].getCoreEventsEnabled()); + ASSERT_EQ(clientDeviceInfo.getServerCapabilities()[1].getCoreEventsEnabled(), serverDeviceInfo.getServerCapabilities()[1].getCoreEventsEnabled()); +} + TEST_F(TmsDeviceTest, DeviceGetTicksSinceOrigin) { auto ctx = NullContext(); From df5994393d8a3c68f3357fdb9262ea27b9b80967 Mon Sep 17 00:00:00 2001 From: Martin Kraner Date: Mon, 8 Apr 2024 13:42:21 +0200 Subject: [PATCH 113/217] Fix MSVC Win32 build --- .../opcuatms/tests/opcuatms_integration/test_tms_device.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp index a2c91cc..005773b 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp @@ -243,8 +243,8 @@ TEST_F(TmsDeviceTest, DeviceInfoServerCapabilities) ASSERT_EQ(clientSubDevices.getCount(), 2u); auto clientSubDevice = clientSubDevices[1]; auto clientDeviceInfo = clientSubDevice.getInfo(); - ASSERT_EQ(serverDeviceInfo.getServerCapabilities().getCount(), 2); - ASSERT_EQ(clientDeviceInfo.getServerCapabilities().getCount(), 2); + ASSERT_EQ(serverDeviceInfo.getServerCapabilities().getCount(), 2u); + ASSERT_EQ(clientDeviceInfo.getServerCapabilities().getCount(), 2u); auto name = clientDeviceInfo.getServerCapabilities()[1].getProtocolName(); auto id = clientDeviceInfo.getServerCapabilities()[1].getProtocolId(); ASSERT_EQ(clientDeviceInfo.getServerCapabilities()[0].getProtocolId(), serverDeviceInfo.getServerCapabilities()[0].getProtocolId()); From 4acd6993f4f2d1123568fdf89ed375c2d7a6c6cf Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Wed, 10 Apr 2024 16:33:55 +0200 Subject: [PATCH 114/217] [Bug]: websocket mdns discovery backward competitivity (openDAQ/openDAQ#247) - mdns service can handle list of serviceNames - backward competitivity of old lt prefix "daq.ws://" and mdns service name "_streaming-ws._tcp.local." --- .../opcua_client_module/src/opcua_client_module_impl.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 0a9fad4..f2ac8ca 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -29,16 +29,17 @@ OpcUaClientModule::OpcUaClientModule(ContextPtr context) [context = this->context](const MdnsDiscoveredDevice& discoveredDevice) { auto connectionString = DaqOpcUaDevicePrefix + discoveredDevice.ipv4Address + "/"; - auto cap = ServerCapability("opendaq_opcua_config", "openDAQ OpcUa", ProtocolType::Configuration).addConnectionString(connectionString) - .setConnectionType("Ipv4") - .setPrefix("daq.opcua"); + auto cap = ServerCapability("opendaq_opcua_config", "openDAQ OpcUa", ProtocolType::Configuration); + cap.addConnectionString(connectionString); + cap.setConnectionType("Ipv4"); + cap.setPrefix("daq.opcua"); return cap; } }, {"OPENDAQ"} ) { - discoveryClient.initMdnsClient("_opcua-tcp._tcp.local."); + discoveryClient.initMdnsClient(List("_opcua-tcp._tcp.local.")); } ListPtr OpcUaClientModule::onGetAvailableDevices() From 019c5ad6acee854967eb5ce69e5e8479f950aee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Wed, 10 Apr 2024 11:03:03 +0200 Subject: [PATCH 115/217] Update module and library versions to 3.0.0 --- modules/opcua_client_module/CMakeLists.txt | 2 +- modules/opcua_server_module/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/opcua_client_module/CMakeLists.txt b/modules/opcua_client_module/CMakeLists.txt index 6f984e3..01d0f0d 100644 --- a/modules/opcua_client_module/CMakeLists.txt +++ b/modules/opcua_client_module/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(ClientModule VERSION 2.0.0 LANGUAGES C CXX) +project(ClientModule VERSION 3.0.0 LANGUAGES C CXX) add_subdirectory(src) diff --git a/modules/opcua_server_module/CMakeLists.txt b/modules/opcua_server_module/CMakeLists.txt index fdcc620..ffa5990 100644 --- a/modules/opcua_server_module/CMakeLists.txt +++ b/modules/opcua_server_module/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(ServerModule VERSION 2.0.0 LANGUAGES CXX) +project(ServerModule VERSION 3.0.0 LANGUAGES CXX) add_subdirectory(src) diff --git a/shared/libraries/opcuatms/opcuatms/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms/CMakeLists.txt index 2a5287e..f86bc4a 100644 --- a/shared/libraries/opcuatms/opcuatms/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(opcuatms VERSION 2.0.0 LANGUAGES CXX) +project(opcuatms VERSION 3.0.0 LANGUAGES CXX) add_subdirectory(src) diff --git a/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt index 61c03e9..be9acd8 100644 --- a/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(opcuatms_client VERSION 2.0.0 LANGUAGES CXX) +project(opcuatms_client VERSION 3.0.0 LANGUAGES CXX) add_subdirectory(src) diff --git a/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt index a608979..48f03b7 100644 --- a/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(opcuatms_server VERSION 2.0.0 LANGUAGES CXX) +project(opcuatms_server VERSION 3.0.0 LANGUAGES CXX) add_subdirectory(src) From ce5019d2806cc125179caea1f347c5daa67c0db8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Fri, 8 Mar 2024 15:29:36 +0100 Subject: [PATCH 116/217] Prepare interfaces for core role management --- .../test_tms_integration.cpp | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index 239e914..deb43a3 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -403,3 +403,23 @@ TEST_F(TmsIntegrationTest, BeginEndUpdateDevice) ASSERT_NO_THROW(clientDevice.beginUpdate()); ASSERT_NO_THROW(clientDevice.endUpdate()); } + +TEST_F(TmsIntegrationTest, TmpAccessControl) +{ + // this is a temporary test, it should be removed + + InstancePtr device = createDevice(); + + // /localInstance/FB/mock_fb_uid_0 + auto fb = device.findComponent("FB/mock_fb_uid_0"); + // fb.getPermissionManager().inherit(true).allow("user", "RWX") + + TmsServer tmsServer(device); + tmsServer.start(); + + std::cin.get(); + + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + auto clientDevice = tmsClient.connect(); + ASSERT_TRUE(clientDevice.assigned()); +} From 1f8f9508c7658828169d88ee3f3882ac0a18bfa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Tue, 19 Mar 2024 16:27:00 +0100 Subject: [PATCH 117/217] Implement permisison manager and integrate it into property object and component --- .../test_tms_integration.cpp | 21 +------------------ 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index deb43a3..00767cf 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -8,6 +8,7 @@ #include #include #include +#include using namespace daq; using namespace daq::opcua; @@ -403,23 +404,3 @@ TEST_F(TmsIntegrationTest, BeginEndUpdateDevice) ASSERT_NO_THROW(clientDevice.beginUpdate()); ASSERT_NO_THROW(clientDevice.endUpdate()); } - -TEST_F(TmsIntegrationTest, TmpAccessControl) -{ - // this is a temporary test, it should be removed - - InstancePtr device = createDevice(); - - // /localInstance/FB/mock_fb_uid_0 - auto fb = device.findComponent("FB/mock_fb_uid_0"); - // fb.getPermissionManager().inherit(true).allow("user", "RWX") - - TmsServer tmsServer(device); - tmsServer.start(); - - std::cin.get(); - - TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); - auto clientDevice = tmsClient.connect(); - ASSERT_TRUE(clientDevice.assigned()); -} From ebd3741f45fb793a882cf71c11744625559d7045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Fri, 29 Mar 2024 13:11:29 +0100 Subject: [PATCH 118/217] Rename IPermissionConfig to IPermissions --- .../tests/opcuatms_integration/test_tms_integration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index 00767cf..f45a2fb 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include using namespace daq; using namespace daq::opcua; From 93417d771a7a591694997e8938541cb25ba2a2cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Tue, 2 Apr 2024 13:11:19 +0200 Subject: [PATCH 119/217] Move security files into coreobjects --- .../tests/opcuatms_integration/test_tms_integration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index f45a2fb..f1c550a 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include using namespace daq; using namespace daq::opcua; From baf9c806ede287e5b6c2e451d4a48ec4180843f9 Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Fri, 12 Apr 2024 15:41:46 +0200 Subject: [PATCH 120/217] rename server capability protocol type rename server capability protocol type from ipv4 to tcp/ip --- modules/opcua_client_module/src/opcua_client_module_impl.cpp | 2 +- shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index f2ac8ca..989abfc 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -31,7 +31,7 @@ OpcUaClientModule::OpcUaClientModule(ContextPtr context) auto connectionString = DaqOpcUaDevicePrefix + discoveredDevice.ipv4Address + "/"; auto cap = ServerCapability("opendaq_opcua_config", "openDAQ OpcUa", ProtocolType::Configuration); cap.addConnectionString(connectionString); - cap.setConnectionType("Ipv4"); + cap.setConnectionType("TCP/IP"); cap.setPrefix("daq.opcua"); return cap; } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp index bcb878a..cd3a19b 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp @@ -49,7 +49,7 @@ void TmsServer::start() auto serverCapability = ServerCapability("opendaq_opcua_config", "openDAQ OpcUa", ProtocolType::Configuration); serverCapability.setPrefix("daq.opcua"); - serverCapability.setConnectionType("Ipv4"); + serverCapability.setConnectionType("TCP/IP"); device.getInfo().asPtr().addServerCapability(serverCapability); tmsDevice = std::make_unique(device, server, context, tmsContext); From 79f3dd7d9d4e9025f90a56ee5b2e6cdf7b6baf24 Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Thu, 25 Apr 2024 16:41:19 +0200 Subject: [PATCH 121/217] Supporting connection with ipv6 connection string (openDAQ/openDAQ#281) --- .../src/opcua_client_module_impl.cpp | 16 +++++++++++----- .../tests/test_opcua_client_module.cpp | 2 ++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 989abfc..a6ffffe 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -28,9 +28,15 @@ OpcUaClientModule::OpcUaClientModule(ContextPtr context) { [context = this->context](const MdnsDiscoveredDevice& discoveredDevice) { - auto connectionString = DaqOpcUaDevicePrefix + discoveredDevice.ipv4Address + "/"; + auto connectionStringIpv4 = DaqOpcUaDevicePrefix + discoveredDevice.ipv4Address + "/"; + auto connectionStringIpv6 = fmt::format("{}[{}]/", + DaqOpcUaDevicePrefix, + discoveredDevice.ipv6Address); auto cap = ServerCapability("opendaq_opcua_config", "openDAQ OpcUa", ProtocolType::Configuration); - cap.addConnectionString(connectionString); + cap.addConnectionString(connectionStringIpv4); + cap.addAddress(discoveredDevice.ipv4Address); + cap.addConnectionString(connectionStringIpv6); + cap.addAddress("[" + discoveredDevice.ipv6Address + "]"); cap.setConnectionType("TCP/IP"); cap.setPrefix("daq.opcua"); return cap; @@ -86,19 +92,19 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, if (prefix != DaqOpcUaDevicePrefix) throw InvalidParameterException("OpcUa does not support connection string with prefix"); - FunctionPtr createStreamingCallback = [&](const ServerCapabilityPtr& capability, + FunctionPtr createStreamingCallback = [&](const ServerCapabilityConfigPtr& capability, bool isRootDevice) -> StreamingPtr { if (capability.getProtocolType() != ProtocolType::Streaming) return nullptr; if (isRootDevice) - capability.setPropertyValue("address", host); + capability.addAddress(host); const StringPtr streamingHeuristic = deviceConfig.getPropertySelectionValue("StreamingConnectionHeuristic"); const ListPtr allowedStreamingProtocols = deviceConfig.getPropertyValue("AllowedStreamingProtocols"); - const StringPtr protocolId = capability.getPropertyValue("protocolId"); + const StringPtr protocolId = capability.getProtocolId(); if (protocolId != nullptr) if (const auto it = std::find(allowedStreamingProtocols.begin(), diff --git a/modules/opcua_client_module/tests/test_opcua_client_module.cpp b/modules/opcua_client_module/tests/test_opcua_client_module.cpp index 08908c0..fcf3be9 100644 --- a/modules/opcua_client_module/tests/test_opcua_client_module.cpp +++ b/modules/opcua_client_module/tests/test_opcua_client_module.cpp @@ -88,6 +88,8 @@ TEST_F(OpcUaClientModuleTest, AcceptsConnectionStringCorrect) auto module = CreateModule(); ASSERT_TRUE(module.acceptsConnectionParameters("daq.opcua://device8")); + ASSERT_TRUE(module.acceptsConnectionParameters("daq.opcua://[::1]")); + ASSERT_TRUE(module.acceptsConnectionParameters("daq.opcua://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]")); } TEST_F(OpcUaClientModuleTest, CreateDeviceConnectionStringNull) From 3f8d101a022317f69b62f9f991bbab44e8759099 Mon Sep 17 00:00:00 2001 From: Nikolai Shipilov Date: Thu, 25 Apr 2024 13:27:51 +0200 Subject: [PATCH 122/217] Move streaming creation from device impl to the module manager: * the opcua client module no longer manages streaming heuristic configuration; this responsibility has shifted to the module manager. * opcua device implementation no longer handles server capabilities or creates streaming objects, as it is done by the module manager * new interfaces added, IMirroredDevice and IMirroredDeviceConfig, to manage streaming sources on per-device basis for configuration-enabled devices. * streaming heuristic config is supported only when connecting via device info "daq://" prefix * fix the device type created for native configuration device --- .../opcua_client_module_impl.h | 4 +- .../src/opcua_client_module_impl.cpp | 226 ++---------------- .../tests/test_opcua_client_module.cpp | 34 +-- .../objects/tms_client_device_factory.h | 10 +- .../objects/tms_client_device_impl.h | 14 +- .../include/opcuatms_client/tms_client.h | 5 +- .../src/objects/tms_client_component_impl.cpp | 4 +- .../src/objects/tms_client_device_impl.cpp | 49 +--- .../tms_client_property_object_impl.cpp | 4 +- .../opcuatms_client/src/tms_client.cpp | 7 +- .../test_streaming_integration.cpp | 44 ++-- .../opcuatms_integration/test_tms_device.cpp | 40 ++-- .../test_tms_integration.cpp | 26 +- 13 files changed, 91 insertions(+), 376 deletions(-) diff --git a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h index 83c5d68..a8ef7ec 100644 --- a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h +++ b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h @@ -35,10 +35,8 @@ class OpcUaClientModule final : public Module private: static std::tuple ParseConnectionString(const StringPtr& connectionString); - static bool acceptDeviceProperties(const PropertyObjectPtr& config); - static PropertyObjectPtr createDeviceDefaultConfig(); - static void configureStreamingSources(const PropertyObjectPtr& deviceConfig, const DevicePtr& device); static DeviceTypePtr createDeviceType(); + static void completeDeviceServerCapabilities(const DevicePtr& device, const StringPtr& deviceAddress); discovery::DiscoveryClient discoveryClient; std::mutex sync; diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index a6ffffe..a29f76b 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_CLIENT_MODULE @@ -75,11 +77,7 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, if (!connectionString.assigned()) throw ArgumentNullException(); - PropertyObjectPtr deviceConfig = config; - if (!deviceConfig.assigned()) - deviceConfig = createDeviceDefaultConfig(); - - if (!onAcceptsConnectionParameters(connectionString, deviceConfig)) + if (!onAcceptsConnectionParameters(connectionString, config)) throw InvalidParameterException(); if (!context.assigned()) @@ -92,42 +90,25 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, if (prefix != DaqOpcUaDevicePrefix) throw InvalidParameterException("OpcUa does not support connection string with prefix"); - FunctionPtr createStreamingCallback = [&](const ServerCapabilityConfigPtr& capability, - bool isRootDevice) -> StreamingPtr - { - if (capability.getProtocolType() != ProtocolType::Streaming) - return nullptr; - - if (isRootDevice) - capability.addAddress(host); - - const StringPtr streamingHeuristic = deviceConfig.getPropertySelectionValue("StreamingConnectionHeuristic"); - const ListPtr allowedStreamingProtocols = deviceConfig.getPropertyValue("AllowedStreamingProtocols"); - - const StringPtr protocolId = capability.getProtocolId(); - - if (protocolId != nullptr) - if (const auto it = std::find(allowedStreamingProtocols.begin(), - allowedStreamingProtocols.end(), - protocolId); - it == allowedStreamingProtocols.end()) - return nullptr; - - if (streamingHeuristic == "MinHops" || - streamingHeuristic == "Fallbacks" || - streamingHeuristic == "MinConnections" && isRootDevice) - return this->createStreamingFromAnotherModule(nullptr, capability); - else - return nullptr; - }; - std::scoped_lock lock(sync); - TmsClient client(context, parent, OpcUaScheme + host + path, createStreamingCallback); + TmsClient client(context, parent, OpcUaScheme + host + path); auto device = client.connect(); - this->configureStreamingSources(deviceConfig, device); + completeDeviceServerCapabilities(device, host); return device; } +void OpcUaClientModule::completeDeviceServerCapabilities(const DevicePtr& device, const StringPtr& deviceAddress) +{ + auto deviceInfo = device.getInfo(); + if (deviceInfo.assigned()) + { + for (const auto& capability : deviceInfo.getServerCapabilities()) + { + capability.asPtr().addAddress(deviceAddress); + } + } +} + std::tuple OpcUaClientModule::ParseConnectionString(const StringPtr& connectionString) { std::string urlString = connectionString.toStdString(); @@ -148,184 +129,17 @@ bool OpcUaClientModule::onAcceptsConnectionParameters(const StringPtr& connectio { std::string connStr = connectionString; auto found = connStr.find(DaqOpcUaDevicePrefix); - if (found != 0) - return false; - - if (config.assigned() && !acceptDeviceProperties(config)) - { - LOG_W("Connection string \"{}\" is accepted but config is incomplete", connectionString); - return false; - } - else - { + if (found == 0) return true; - } -} - -bool OpcUaClientModule::acceptDeviceProperties(const PropertyObjectPtr& config) -{ - bool hasRequiredProperties = config.hasProperty("StreamingConnectionHeuristic") && - config.hasProperty("AllowedStreamingProtocols") && - config.hasProperty("PrimaryStreamingProtocol"); - if (!hasRequiredProperties) - return false; - - const StringPtr primaryStreamingProtocol = config.getPropertyValue("PrimaryStreamingProtocol"); - const ListPtr allowedStreamingProtocols = config.getPropertyValue("AllowedStreamingProtocols"); - if (const auto it = std::find(allowedStreamingProtocols.begin(), - allowedStreamingProtocols.end(), - primaryStreamingProtocol); - it == allowedStreamingProtocols.end()) + else return false; - - return true; -} - -PropertyObjectPtr OpcUaClientModule::createDeviceDefaultConfig() -{ - auto defaultConfig = PropertyObject(); - - const auto streamingConnectionHeuristicProp = SelectionProperty("StreamingConnectionHeuristic", - List("MinConnections", - "MinHops", - "Fallbacks", - "NotConnected"), - 0); - defaultConfig.addProperty(streamingConnectionHeuristicProp); - - auto allowedStreamingProtocols = List(); - StringPtr primaryStreamingProtocol = "none"; - -#if defined(OPENDAQ_ENABLE_NATIVE_STREAMING) - allowedStreamingProtocols.pushBack("opendaq_native_streaming"); - primaryStreamingProtocol = "opendaq_native_streaming"; -// TODO add websocket streaming to default list of allowed protocols -// when it will have subscribe/unsubscribe support -//#if defined(OPENDAQ_ENABLE_WEBSOCKET_STREAMING) -// allowedStreamingProtocols.pushBack("opendaq_lt_streaming"); -#endif -#if defined(OPENDAQ_ENABLE_WEBSOCKET_STREAMING) - allowedStreamingProtocols.pushBack("opendaq_lt_streaming"); -// primaryStreamingProtocol = "opendaq_lt_streaming"; -#endif - - defaultConfig.addProperty(ListProperty("AllowedStreamingProtocols", allowedStreamingProtocols)); - defaultConfig.addProperty(StringProperty("PrimaryStreamingProtocol", primaryStreamingProtocol)); - - return defaultConfig; } DeviceTypePtr OpcUaClientModule::createDeviceType() { - auto configurationCallback = [](IBaseObject* input, IBaseObject** output) -> ErrCode - { - PropertyObjectPtr propObjPtr; - ErrCode errCode = wrapHandlerReturn(&OpcUaClientModule::createDeviceDefaultConfig, propObjPtr); - *output = propObjPtr.detach(); - return errCode; - }; - return DeviceType(DaqOpcUaDeviceTypeId, "OpcUa enabled device", - "Network device connected over OpcUa protocol", - configurationCallback); -} - -void OpcUaClientModule::configureStreamingSources(const PropertyObjectPtr& deviceConfig, const DevicePtr& device) -{ - const StringPtr streamingHeuristic = deviceConfig.getPropertySelectionValue("StreamingConnectionHeuristic"); - if (streamingHeuristic == "NotConnected") - return; - - const StringPtr primaryStreamingProtocol = deviceConfig.getPropertyValue("PrimaryStreamingProtocol"); - const ListPtr allowedStreamingProtocols = deviceConfig.getPropertyValue("AllowedStreamingProtocols"); - std::unordered_map idPrefixMap; - - { - auto devices = device.getDevices(search::Recursive(search::Any())); - devices.pushBack(device); - - for (const auto& dev : devices) - { - const auto capabilities = dev.getInfo().getServerCapabilities(); - for (const auto & cap : capabilities) - { - idPrefixMap.insert(std::make_pair(cap.getProtocolId(), cap.getPrefix())); - } - } - } - - for (const auto& signal : device.getSignals(search::Recursive(search::Any()))) - { - MirroredSignalConfigPtr mirroredSignalConfigPtr = signal.template asPtr(); - - auto streamingSources = mirroredSignalConfigPtr.getStreamingSources(); - - if (streamingSources.empty()) - continue; - - // TODO this may raise bugs - // since sub-devices are being created recursively it is expected that - // the leaf device direct streaming is the first-one of available sources - // and root streaming is the last-one - StringPtr leafStreaming; - StringPtr rootStreaming; - for (const auto& streamingConnectionString : streamingSources) - { - std::string connectionString = streamingConnectionString.toStdString(); - std::string streamingProtocolId = primaryStreamingProtocol.toStdString(); - - if (!idPrefixMap.count(streamingProtocolId)) - continue; - - std::string protocolPrefix = idPrefixMap.at(streamingProtocolId); - if (connectionString.find(protocolPrefix) == 0) - { - // save the first streaming source as the leaf streaming - if (!leafStreaming.assigned()) - leafStreaming = streamingConnectionString; - - // save the last streaming source as the root streaming - rootStreaming = streamingConnectionString; - } - } - - if (!leafStreaming.assigned() || !rootStreaming.assigned()) - { - for (const auto& streamingConnectionString : streamingSources) - { - std::string connectionString = streamingConnectionString.toStdString(); - for (const auto& streamingProtocolId : allowedStreamingProtocols) - { - if (!idPrefixMap.count(streamingProtocolId)) - continue; - - std::string protocolPrefix = idPrefixMap.at(streamingProtocolId); - if (connectionString.find(protocolPrefix) == 0) - { - // save the first streaming source as the leaf streaming - if (!leafStreaming.assigned()) - leafStreaming = streamingConnectionString; - - // save the last streaming source as the root streaming - rootStreaming = streamingConnectionString; - } - } - } - } - - if (!leafStreaming.assigned() || !rootStreaming.assigned()) - continue; - - if (streamingHeuristic == "MinConnections" || streamingHeuristic == "Fallbacks") - { - mirroredSignalConfigPtr.setActiveStreamingSource(rootStreaming); - } - else if (streamingHeuristic == "MinHops") - { - mirroredSignalConfigPtr.setActiveStreamingSource(leafStreaming); - } - } + "Network device connected over OpcUa protocol"); } END_NAMESPACE_OPENDAQ_OPCUA_CLIENT_MODULE diff --git a/modules/opcua_client_module/tests/test_opcua_client_module.cpp b/modules/opcua_client_module/tests/test_opcua_client_module.cpp index fcf3be9..b5a80e4 100644 --- a/modules/opcua_client_module/tests/test_opcua_client_module.cpp +++ b/modules/opcua_client_module/tests/test_opcua_client_module.cpp @@ -121,14 +121,6 @@ TEST_F(OpcUaClientModuleTest, CreateDeviceConnectionStringInvalidId) ASSERT_THROW(module.createDevice("daqref://devicett3axxr1", nullptr), InvalidParameterException); } -TEST_F(OpcUaClientModuleTest, CreateDeviceConfigInvalid) -{ - auto module = CreateModule(); - auto config = PropertyObject(); - - ASSERT_THROW(module.createDevice("daq.opcua://device8", nullptr, config), InvalidParameterException); -} - TEST_F(OpcUaClientModuleTest, GetAvailableComponentTypes) { const auto module = CreateModule(); @@ -158,31 +150,7 @@ TEST_F(OpcUaClientModuleTest, DefaultDeviceConfig) ASSERT_TRUE(deviceTypes.hasKey("opendaq_opcua_config")); auto config = deviceTypes.get("opendaq_opcua_config").createDefaultConfig(); ASSERT_TRUE(config.assigned()); - - ASSERT_TRUE(config.hasProperty("StreamingConnectionHeuristic")); - ASSERT_EQ(config.getPropertySelectionValue("StreamingConnectionHeuristic"), "MinConnections"); - -#if defined(OPENDAQ_ENABLE_NATIVE_STREAMING) - ASSERT_TRUE(config.hasProperty("AllowedStreamingProtocols")); - ASSERT_EQ(config.getPropertyValue("AllowedStreamingProtocols"), List("opendaq_native_streaming", "opendaq_lt_streaming")); - - ASSERT_TRUE(config.hasProperty("PrimaryStreamingProtocol")); - ASSERT_EQ(config.getPropertyValue("PrimaryStreamingProtocol"), "opendaq_native_streaming"); -#elif defined(OPENDAQ_ENABLE_WEBSOCKET_STREAMING) && !defined(OPENDAQ_ENABLE_NATIVE_STREAMING) - ASSERT_TRUE(config.hasProperty("AllowedStreamingProtocols")); - ASSERT_EQ(config.getPropertyValue("AllowedStreamingProtocols"), List("opendaq_lt_streaming")); - - ASSERT_TRUE(config.hasProperty("PrimaryStreamingProtocol")); - ASSERT_EQ(config.getPropertyValue("PrimaryStreamingProtocol"), "opendaq_lt_streaming"); -#endif -} - -TEST_F(OpcUaClientModuleTest, InvalidDeviceConfig) -{ - auto module = CreateModule(); - auto config = PropertyObject(); - - ASSERT_FALSE(module.acceptsConnectionParameters("daq.opcua://device8", config)); + ASSERT_EQ(config.getAllProperties().getCount(), 0u); } TEST_F(OpcUaClientModuleTest, CreateFunctionBlockIdNull) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_factory.h index f1894e1..066387b 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_factory.h @@ -24,10 +24,9 @@ inline DevicePtr TmsClientDevice(const ContextPtr& context, const ComponentPtr& parent, const StringPtr& localId, const daq::opcua::tms::TmsClientContextPtr& clientContext, - const opcua::OpcUaNodeId& nodeId, - const FunctionPtr& createStreamingCallback) + const opcua::OpcUaNodeId& nodeId) { - DevicePtr obj(createWithImplementation(context, parent, localId, clientContext, nodeId, createStreamingCallback, false)); + DevicePtr obj(createWithImplementation(context, parent, localId, clientContext, nodeId, false)); return obj; } @@ -35,10 +34,9 @@ inline DevicePtr TmsClientRootDevice(const ContextPtr& context, const ComponentPtr& parent, const StringPtr& localId, const daq::opcua::tms::TmsClientContextPtr& clientContext, - const opcua::OpcUaNodeId& nodeId, - const FunctionPtr& createStreamingCallback) + const opcua::OpcUaNodeId& nodeId) { - DevicePtr obj(createWithImplementation(context, parent, localId, clientContext, nodeId, createStreamingCallback, true)); + DevicePtr obj(createWithImplementation(context, parent, localId, clientContext, nodeId, true)); return obj; } diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h index ba75526..f428758 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h @@ -16,13 +16,12 @@ #pragma once #include "opcuatms_client/objects/tms_client_component_impl.h" -#include "opendaq/device_impl.h" +#include "opendaq/mirrored_device_impl.h" #include "opendaq/device_ptr.h" -#include "opendaq/streaming_ptr.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS -class TmsClientDeviceImpl : public TmsClientComponentBaseImpl> +class TmsClientDeviceImpl : public TmsClientComponentBaseImpl> { public: explicit TmsClientDeviceImpl(const ContextPtr& ctx, @@ -30,7 +29,6 @@ class TmsClientDeviceImpl : public TmsClientComponentBaseImpl streamings; - FunctionPtr createStreamingCallback; - bool isRootDevice; private: void fetchTimeDomain(); diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h index 13f37e7..890c701 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h @@ -18,7 +18,6 @@ #include #include "opcuatms/opcuatms.h" #include "opcuaclient/opcuaclient.h" -#include "opcuatms_client/objects/tms_client_device_factory.h" #include "opcuatms_client/objects/tms_client_context.h" #include @@ -29,8 +28,7 @@ class TmsClient final public: TmsClient(const ContextPtr& context, const ComponentPtr& parent, - const std::string& opcUaUrl, - const FunctionPtr& createStreamingCallback); + const std::string& opcUaUrl); daq::DevicePtr connect(); @@ -42,7 +40,6 @@ class TmsClient final ContextPtr context; daq::opcua::OpcUaClientPtr client; std::string opcUaUrl; - FunctionPtr createStreamingCallback; ComponentPtr parent; LoggerComponentPtr loggerComponent; }; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp index 2c7ab06..74792c5 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp @@ -1,5 +1,5 @@ #include "opcuatms_client/objects/tms_client_component_impl.h" -#include "opendaq/device_impl.h" +#include "opendaq/mirrored_device_impl.h" #include "opendaq/folder_impl.h" #include "opendaq/io_folder_impl.h" #include "opendaq/mirrored_signal_impl.h" @@ -210,7 +210,7 @@ bool TmsClientComponentBaseImpl::isChildComponent(const ComponentPtr& comp template class TmsClientComponentBaseImpl>; template class TmsClientComponentBaseImpl>; template class TmsClientComponentBaseImpl>; -template class TmsClientComponentBaseImpl>; +template class TmsClientComponentBaseImpl>; template class TmsClientComponentBaseImpl>; template class TmsClientComponentBaseImpl>; template class TmsClientComponentBaseImpl>; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index afe7ef7..c4b63ee 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -62,11 +62,8 @@ TmsClientDeviceImpl::TmsClientDeviceImpl(const ContextPtr& ctx, const StringPtr& localId, const TmsClientContextPtr& clientContext, const opcua::OpcUaNodeId& nodeId, - const FunctionPtr& createStreamingCallback, bool isRootDevice) : TmsClientComponentBaseImpl(ctx, parent, localId, clientContext, nodeId) - , createStreamingCallback(createStreamingCallback) - , isRootDevice(isRootDevice) , logger(ctx.getLogger()) , loggerComponent( this->logger.assigned() ? this->logger.getOrAddComponent("TmsClientDevice") @@ -82,15 +79,12 @@ TmsClientDeviceImpl::TmsClientDeviceImpl(const ContextPtr& ctx, findAndCreateSignals(); findAndCreateInputsOutputs(); findAndCreateCustomComponents(); - - connectToStreamings(); - setUpStreamings(); } ErrCode TmsClientDeviceImpl::getDomain(IDeviceDomain** deviceDomain) { fetchTimeDomain(); - return TmsClientComponentBaseImpl>::getDomain(deviceDomain); + return TmsClientComponentBaseImpl>::getDomain(deviceDomain); } void TmsClientDeviceImpl::findAndCreateSubdevices() @@ -105,7 +99,7 @@ void TmsClientDeviceImpl::findAndCreateSubdevices() try { auto subdeviceNodeId = OpcUaNodeId(ref->nodeId.nodeId); - auto clientSubdevice = TmsClientDevice(context, devices, browseName, clientContext, subdeviceNodeId, createStreamingCallback); + auto clientSubdevice = TmsClientDevice(context, devices, browseName, clientContext, subdeviceNodeId); auto numberInList = this->tryReadChildNumberInList(subdeviceNodeId); if (numberInList != std::numeric_limits::max() && !orderedDevices.count(numberInList)) @@ -527,43 +521,4 @@ void TmsClientDeviceImpl::onRemoveFunctionBlock(const FunctionBlockPtr& function removeNestedFunctionBlock(functionBlock); } -void TmsClientDeviceImpl::setUpStreamings() -{ - auto self = this->borrowPtr(); - const auto signals = self.getSignals(search::Recursive(search::Any())); - LOG_I("Device \"{}\" has established {} streaming connections", globalId, streamings.size()); - for (const auto& streaming : streamings) - { - LOG_I("Device \"{}\" adding signals to a streaming connection on url: {}", globalId, streaming.getConnectionString()); - streaming.addSignals(signals); - streaming.setActive(true); - } -} - -void TmsClientDeviceImpl::connectToStreamings() -{ - DeviceInfoPtr info; - this->getInfo(&info); - if (createStreamingCallback.assigned()) - { - for (const auto& capability : info.getServerCapabilities()) - { - if (capability.getProtocolType() != ProtocolType::Streaming) - continue; - - StreamingPtr streaming; - ErrCode errCode = wrapHandlerReturn(createStreamingCallback, streaming, capability, isRootDevice); - - if (OPENDAQ_FAILED(errCode) || !streaming.assigned()) - { - LOG_W("Device \"{}\" had not connected to published streaming protocol \"{}\".", globalId, capability.getPropertyValue("protocolId").asPtr()); - } - else - { - streamings.push_back(streaming); - } - } - } -} - END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index 82410d7..a4e2725 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -12,7 +12,7 @@ #include "opendaq/mirrored_signal_impl.h" #include "opendaq/input_port_impl.h" #include "opendaq/channel_impl.h" -#include "opendaq/device_impl.h" +#include "opendaq/mirrored_device_impl.h" #include "opendaq/io_folder_impl.h" BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -495,7 +495,7 @@ template class TmsClientPropertyObjectBaseImpl; template class TmsClientPropertyObjectBaseImpl>; template class TmsClientPropertyObjectBaseImpl>; template class TmsClientPropertyObjectBaseImpl>; -template class TmsClientPropertyObjectBaseImpl>; +template class TmsClientPropertyObjectBaseImpl>; template class TmsClientPropertyObjectBaseImpl>; template class TmsClientPropertyObjectBaseImpl>; template class TmsClientPropertyObjectBaseImpl>; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp index d9ff37c..a02a981 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp @@ -13,6 +13,7 @@ #include #include +#include using namespace daq::opcua; using namespace daq::opcua::tms; @@ -21,11 +22,9 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA TmsClient::TmsClient(const ContextPtr& context, const ComponentPtr& parent, - const std::string& opcUaUrl, - const FunctionPtr& createStreamingCallback) + const std::string& opcUaUrl) : context(context) , opcUaUrl(opcUaUrl) - , createStreamingCallback(createStreamingCallback) , parent(parent) , loggerComponent(context.getLogger().assigned() ? context.getLogger().getOrAddComponent("OpcUaClient") : throw ArgumentNullException("Logger must not be null")) @@ -62,7 +61,7 @@ daq::DevicePtr TmsClient::connect() std::string rootDeviceBrowseName; getRootDeviceNodeAttributes(rootDeviceNodeId, rootDeviceBrowseName); - auto device = TmsClientRootDevice(context, parent, rootDeviceBrowseName, tmsClientContext, rootDeviceNodeId, createStreamingCallback); + auto device = TmsClientRootDevice(context, parent, rootDeviceBrowseName, tmsClientContext, rootDeviceNodeId); const auto deviceInfo = device.getInfo(); if (deviceInfo.hasProperty("OpenDaqPackageVersion")) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp index 564905c..e274189 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp @@ -19,6 +19,7 @@ #include #include #include +#include using namespace daq; using namespace daq::opcua; @@ -44,12 +45,6 @@ class StreamingIntegrationTest : public testing::Test auto clientLogger = Logger(); clientContext = Context(Scheduler(clientLogger, 1), clientLogger, TypeManager(), nullptr); instance = createDevice(); - - createStreamingCallback = Function([this](const ServerCapabilityPtr& /*capability*/, - bool /*isRootDevice*/) - { - return createStreaming(); - }); } void TearDown() override @@ -188,12 +183,19 @@ class StreamingIntegrationTest : public testing::Test return WebsocketStreaming(STREAMING_URL, clientContext); } - void setActiveStreamingSource(const DevicePtr& device) + void setStreamingSource(const DevicePtr& device) { - for (const auto& signal : device.getSignals(search::Recursive(search::Visible()))) + streaming = createStreaming(); + streaming.setActive(true); + + auto mirroredDeviceConfig = device.template asPtr(); + mirroredDeviceConfig.addStreamingSource(streaming); + auto signals = device.getSignals(search::Recursive(search::Visible())); + streaming.addSignals(signals); + for (const auto& signal : signals) { auto mirroredSignalConfigPtr = signal.template asPtr(); - mirroredSignalConfigPtr.setActiveStreamingSource(STREAMING_URL); + mirroredSignalConfigPtr.setActiveStreamingSource(streaming.getConnectionString()); } } @@ -201,7 +203,7 @@ class StreamingIntegrationTest : public testing::Test LoggerComponentPtr loggerComponent; ContextPtr clientContext; InstancePtr instance; - FunctionPtr createStreamingCallback; + StreamingPtr streaming; }; TEST_F(StreamingIntegrationTest, Connect) @@ -272,9 +274,9 @@ TEST_F(StreamingIntegrationTest, ByteStep) auto server = TmsServer(instance); server.start(); - auto client = TmsClient(clientContext, nullptr, OPCUA_URL, createStreamingCallback); + auto client = TmsClient(clientContext, nullptr, OPCUA_URL); auto clientDevice = client.connect(); - setActiveStreamingSource(clientDevice); + setStreamingSource(clientDevice); auto mirroredSignalPtr = getSignal(clientDevice, "ByteStep").template asPtr(); std::promise subscribeCompletePromise; @@ -317,9 +319,9 @@ TEST_F(StreamingIntegrationTest, ChangingSignal) auto server = TmsServer(instance); server.start(); - auto client = TmsClient(clientContext, nullptr, OPCUA_URL, createStreamingCallback); + auto client = TmsClient(clientContext, nullptr, OPCUA_URL); auto clientDevice = client.connect(); - setActiveStreamingSource(clientDevice); + setStreamingSource(clientDevice); auto mirroredSignalPtr = getSignal(clientDevice, "ChangingSignal").template asPtr(); std::promise subscribeCompletePromise; @@ -368,9 +370,9 @@ TEST_F(StreamingIntegrationTest, AllSignalsAsync) auto server = TmsServer(instance); server.start(); - auto client = TmsClient(clientContext, nullptr, OPCUA_URL, createStreamingCallback); + auto client = TmsClient(clientContext, nullptr, OPCUA_URL); auto clientDevice = client.connect(); - setActiveStreamingSource(clientDevice); + setStreamingSource(clientDevice); for (const auto& signal : signals) { @@ -441,15 +443,9 @@ TEST_F(StreamingIntegrationTest, StreamingDeactivate) auto server = TmsServer(instance); server.start(); - auto streaming = createStreaming(); - auto createStreamingCb = Function([&](const ServerCapabilityPtr& /*capability*/, - bool /*isRootDevice*/) - { - return streaming; - }); - auto client = TmsClient(clientContext, nullptr, OPCUA_URL, createStreamingCb); + auto client = TmsClient(clientContext, nullptr, OPCUA_URL); auto clientDevice = client.connect(); - setActiveStreamingSource(clientDevice); + setStreamingSource(clientDevice); streaming.setActive(False); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp index 005773b..6d3aae6 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp @@ -52,7 +52,7 @@ TEST_F(TmsDeviceTest, CreateClientDevice) auto tmsPropertyObject = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = tmsPropertyObject.registerOpcUaNode(); auto ctx = NullContext(); - ASSERT_NO_THROW(TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr)); + ASSERT_NO_THROW(TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId)); } TEST_F(TmsDeviceTest, SubDevices) @@ -63,7 +63,7 @@ TEST_F(TmsDeviceTest, SubDevices) auto nodeId = tmsPropertyObject.registerOpcUaNode(); auto ctx = NullContext(); - auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId); ASSERT_EQ(clientDevice.getDevices().getCount(), 2u); } @@ -75,7 +75,7 @@ TEST_F(TmsDeviceTest, FunctionBlocks) auto tmsPropertyObject = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = tmsPropertyObject.registerOpcUaNode(); - auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId); ListPtr functionBlocks; ASSERT_NO_THROW(functionBlocks = clientDevice.getFunctionBlocks()); ASSERT_EQ(functionBlocks.getCount(), 1u); @@ -92,7 +92,7 @@ TEST_F(TmsDeviceTest, GetSignals) auto nodeId = tmsPropertyObject.registerOpcUaNode(); auto ctx = NullContext(); - auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId); ListPtr signals; ASSERT_NO_THROW(signals = clientDevice.getSignals()); @@ -122,7 +122,7 @@ TEST_F(TmsDeviceTest, GetChannels) auto nodeId = tmsPropertyObject.registerOpcUaNode(); auto ctx = NullContext(); - auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId); ListPtr channels; ASSERT_NO_THROW(channels = clientDevice.getChannels()); ASSERT_EQ(channels.getCount(), serverDevice.getChannels().getCount()); @@ -144,7 +144,7 @@ TEST_F(TmsDeviceTest, DISABLED_Property) auto nodeId = serverTmsDevice.registerOpcUaNode(); auto ctx = NullContext(); - auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId); auto serverVisibleProps = serverDevice.getVisibleProperties(); auto visibleProperties = clientDevice.getVisibleProperties(); @@ -179,7 +179,7 @@ TEST_F(TmsDeviceTest, DeviceInfo) auto serverSubDevice = serverSubDevices[1]; auto serverDeviceInfo = serverSubDevice.getInfo(); - auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId); auto clientSubDevices = clientDevice.getDevices(); ASSERT_EQ(clientSubDevices.getCount(), 2u); @@ -237,7 +237,7 @@ TEST_F(TmsDeviceTest, DeviceInfoServerCapabilities) auto serverSubDevice = serverSubDevices[1]; auto serverDeviceInfo = serverSubDevice.getInfo(); - auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId); auto clientSubDevices = clientDevice.getDevices(); ASSERT_EQ(clientSubDevices.getCount(), 2u); @@ -267,7 +267,7 @@ TEST_F(TmsDeviceTest, DeviceGetTicksSinceOrigin) auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = serverTmsDevice.registerOpcUaNode(); - auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId); auto clientSubDevices = clientDevice.getDevices(); auto clientSubDevice = clientSubDevices[1]; @@ -288,7 +288,7 @@ TEST_F(TmsDeviceTest, DeviceDomain) auto serverSubDevice = serverSubDevices[1]; auto serverDeviceInfo = serverSubDevice.getInfo(); - auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId, nullptr); + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId); auto clientSubDevices = clientDevice.getDevices(); ASSERT_EQ(clientSubDevices.getCount(), 2u); @@ -323,7 +323,7 @@ TEST_F(TmsDeviceTest, CustomComponents) auto nodeId = serverTmsDevice.registerOpcUaNode(); auto serverSubDevice = serverDevice.getDevices()[1]; - auto clientDevice = TmsClientRootDevice(ctx, nullptr, "Dev", clientContext, nodeId, nullptr); + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "Dev", clientContext, nodeId); auto clientSubDevice = clientDevice.getDevices()[1]; ASSERT_EQ(serverSubDevice.getItems().getCount(), clientSubDevice.getItems().getCount()); @@ -345,7 +345,7 @@ TEST_F(TmsDeviceTest, CustomComponentsProperties) auto nodeId = serverTmsDevice.registerOpcUaNode(); auto serverSubDevice = serverDevice.getDevices()[1]; - auto clientDevice = TmsClientRootDevice(ctx, nullptr, "Dev", clientContext, nodeId, nullptr); + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "Dev", clientContext, nodeId); auto clientSubDevice = clientDevice.getDevices()[1]; ASSERT_EQ(serverSubDevice.getItems().getCount(), clientSubDevice.getItems().getCount()); @@ -368,7 +368,7 @@ TEST_F(TmsDeviceTest, ComponentMethods) auto nodeId = serverTmsDevice.registerOpcUaNode(); auto serverSubDevice = serverDevice.getDevices()[1]; - auto clientDevice = TmsClientRootDevice(ctx, nullptr, "Dev", clientContext, nodeId, nullptr); + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "Dev", clientContext, nodeId); auto clientSubDevice = clientDevice.getDevices()[1]; ASSERT_EQ(serverSubDevice.getName(), clientSubDevice.getName()); @@ -393,7 +393,7 @@ TEST_F(TmsDeviceTest, DeviceProcedureProperty) auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = serverTmsDevice.registerOpcUaNode(); - auto clientDevice = TmsClientRootDevice(ctx, nullptr, "Dev", clientContext, nodeId, nullptr); + auto clientDevice = TmsClientRootDevice(ctx, nullptr, "Dev", clientContext, nodeId); auto clientSubDevice = clientDevice.getDevices()[1]; auto procProp = clientSubDevice.getProperty("stop"); @@ -412,7 +412,7 @@ TEST_F(TmsDeviceTest, SignalOrder) auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = tmsServerDevice.registerOpcUaNode(); - DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "Dev", clientContext, nodeId, nullptr); + DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "Dev", clientContext, nodeId); const auto serverSignals = serverDevice.getSignals(); const auto clientSignals = clientDevice.getSignals(); @@ -430,7 +430,7 @@ TEST_F(TmsDeviceTest, DeviceOrder) auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = tmsServerDevice.registerOpcUaNode(); - DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "Dev", clientContext, nodeId, nullptr); + DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "Dev", clientContext, nodeId); const auto serverDevices = serverDevice.getDevices(); const auto clientDevices = clientDevice.getDevices(); @@ -448,7 +448,7 @@ TEST_F(TmsDeviceTest, FunctionBlockOrder) auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = tmsServerDevice.registerOpcUaNode(); - DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "Dev", clientContext, nodeId, nullptr); + DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "Dev", clientContext, nodeId); const auto serverFbs = serverDevice.getFunctionBlocks(); const auto clientFbs = clientDevice.getFunctionBlocks(); @@ -469,7 +469,7 @@ TEST_F(TmsDeviceTest, IOFolderOrder) auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = tmsServerDevice.registerOpcUaNode(); - DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "Dev", clientContext, nodeId, nullptr); + DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "Dev", clientContext, nodeId); const auto serverIO = serverDevice.getInputsOutputsFolder().getItems(); const auto clientIO = clientDevice.getInputsOutputsFolder().getItems(); @@ -487,7 +487,7 @@ TEST_F(TmsDeviceTest, CustomComponentOrder) auto tmsServerDevice = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); auto nodeId = tmsServerDevice.registerOpcUaNode(); - DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "Dev", clientContext, nodeId, nullptr); + DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "Dev", clientContext, nodeId); const auto serverCmps = serverDevice.getCustomComponents(); const auto clientCmps = clientDevice.getCustomComponents(); @@ -501,7 +501,7 @@ TEST_F(TmsDeviceTest, SdkPackageVersion) auto serverDevice = createDevice(); auto tmsServerDevice = TmsServerDevice(serverDevice.getRootDevice(), this->getServer(), ctx, serverContext); auto nodeId = tmsServerDevice.registerOpcUaNode(); - DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "Dev", clientContext, nodeId, nullptr); + DevicePtr clientDevice = TmsClientRootDevice(NullContext(), nullptr, "Dev", clientContext, nodeId); ASSERT_EQ(clientDevice.getInfo().getSdkVersion(), OPENDAQ_PACKAGE_VERSION); } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index f1c550a..fd3c24e 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -55,7 +55,7 @@ TEST_F(TmsIntegrationTest, Connect) TmsServer tmsServer(device); tmsServer.start(); - TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL); DevicePtr clientDevice; ASSERT_NO_THROW(clientDevice = tmsClient.connect()); ASSERT_TRUE(clientDevice.assigned()); @@ -68,7 +68,7 @@ TEST_F(TmsIntegrationTest, Devices) TmsServer tmsServer(device); tmsServer.start(); - TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL); DevicePtr clientDevice = tmsClient.connect(); auto devices = clientDevice.getDevices(); ASSERT_EQ(devices.getCount(), 2u); @@ -81,7 +81,7 @@ TEST_F(TmsIntegrationTest, DeviceInfo) TmsServer tmsServer(device); tmsServer.start(); - TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL); DevicePtr clientDevice = tmsClient.connect(); auto devices = clientDevice.getDevices(); @@ -96,7 +96,7 @@ TEST_F(TmsIntegrationTest, FunctionBlocks) TmsServer tmsServer(device); tmsServer.start(); - TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL); DevicePtr clientDevice = tmsClient.connect(); auto functionBlocks = clientDevice.getFunctionBlocks(); @@ -110,7 +110,7 @@ TEST_F(TmsIntegrationTest, FunctionBlockType) TmsServer tmsServer(device); tmsServer.start(); - TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL); DevicePtr clientDevice = tmsClient.connect(); auto functionBlocks = clientDevice.getFunctionBlocks(); @@ -125,7 +125,7 @@ TEST_F(TmsIntegrationTest, GetSignals) TmsServer tmsServer(device); tmsServer.start(); - TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL); DevicePtr clientDevice = tmsClient.connect(); ListPtr signals; @@ -226,7 +226,7 @@ TEST_F(TmsIntegrationTest, GetDomainSignal) DevicePtr clientDevice; { - TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); // The device should work after we delete the builder + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL); // The device should work after we delete the builder clientDevice = tmsClient.connect(); } @@ -248,7 +248,7 @@ TEST_F(TmsIntegrationTest, GetAvailableFunctionBlockTypes) auto serverFbTypes = device.getAvailableFunctionBlockTypes(); - TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL); auto clientDevice = tmsClient.connect(); const auto clientFbTypes = clientDevice.getAvailableFunctionBlockTypes(); @@ -264,7 +264,7 @@ TEST_F(TmsIntegrationTest, AddFunctionBlock) TmsServer tmsServer(device); tmsServer.start(); - TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL); auto clientDevice = tmsClient.connect(); ASSERT_EQ("mock_fb_uid_1", clientDevice.getFunctionBlocks()[0].getLocalId()); @@ -285,7 +285,7 @@ TEST_F(TmsIntegrationTest, AddFunctionBlockWitchConfig) TmsServer tmsServer(device); tmsServer.start(); - TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL); auto clientDevice = tmsClient.connect(); const auto clientFbTypes = clientDevice.getAvailableFunctionBlockTypes(); @@ -308,7 +308,7 @@ TEST_F(TmsIntegrationTest, RemoveFunctionBlock) TmsServer tmsServer(device); tmsServer.start(); - TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL); auto clientDevice = tmsClient.connect(); auto fb1 = clientDevice.addFunctionBlock("mock_fb_uid"); @@ -328,7 +328,7 @@ TEST_F(TmsIntegrationTest, InputPortConnect) TmsServer tmsServer(device); tmsServer.start(); - TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL); auto clientDevice = tmsClient.connect(); auto inputPort = clientDevice.getChannelsRecursive().getItemAt(0).getInputPorts().getItemAt(0); @@ -398,7 +398,7 @@ TEST_F(TmsIntegrationTest, BeginEndUpdateDevice) TmsServer tmsServer(device); tmsServer.start(); - TmsClient tmsClient(device.getContext(), nullptr, OPC_URL, nullptr); + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL); auto clientDevice = tmsClient.connect(); ASSERT_NO_THROW(clientDevice.beginUpdate()); From 426324f53866916313d182a507c19392931669cb Mon Sep 17 00:00:00 2001 From: Denis Erokhin Date: Tue, 30 Apr 2024 10:51:35 +0200 Subject: [PATCH 123/217] init --- .../src/objects/tms_client_device_impl.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index c4b63ee..50e56d9 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -180,6 +180,14 @@ DeviceInfoPtr TmsClientDeviceImpl::onGetInfo() findAndCreateServerCapabilities(deviceInfo); + for (const auto & cap : deviceInfo.getServerCapabilities()) + { + if (cap.getProtocolId() == "opendaq_opcua_config") + { + deviceInfo.setConnectionString(cap.getConnectionString()); + } + } + deviceInfo.freeze(); return deviceInfo; } From 48485240f8aef1ae331a78a93043854f472b2334 Mon Sep 17 00:00:00 2001 From: Nikolai Shipilov Date: Thu, 25 Apr 2024 14:56:00 +0200 Subject: [PATCH 124/217] Clone property object to create default config from type --- .../src/opcua_server_impl.cpp | 10 +---- .../test_tms_function_block_type.cpp | 40 +++++++------------ 2 files changed, 15 insertions(+), 35 deletions(-) diff --git a/modules/opcua_server_module/src/opcua_server_impl.cpp b/modules/opcua_server_module/src/opcua_server_impl.cpp index ea968a9..4c9bcf5 100644 --- a/modules/opcua_server_module/src/opcua_server_impl.cpp +++ b/modules/opcua_server_module/src/opcua_server_impl.cpp @@ -41,18 +41,10 @@ PropertyObjectPtr OpcUaServerImpl::createDefaultConfig() ServerTypePtr OpcUaServerImpl::createType() { - auto configurationCallback = [](IBaseObject* input, IBaseObject** output) -> ErrCode - { - PropertyObjectPtr propObjPtr; - ErrCode errCode = wrapHandlerReturn(&OpcUaServerImpl::createDefaultConfig, propObjPtr); - *output = propObjPtr.detach(); - return errCode; - }; - return ServerType("openDAQ OpcUa", "openDAQ OpcUa server", "Publishes device structure over OpcUa protocol", - configurationCallback); + OpcUaServerImpl::createDefaultConfig()); } void OpcUaServerImpl::onStopServer() diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block_type.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block_type.cpp index 68c1777..fdadb17 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block_type.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block_type.cpp @@ -16,18 +16,12 @@ class TmsFunctionBlockTypeTest : public TmsObjectIntegrationTest public: FunctionBlockTypePtr createFunctionBlockType() { - auto createDefaultConfig = [](IBaseObject* /*params*/, IBaseObject** result) - { - auto config = PropertyObject(); - config.addProperty(IntProperty("port", 1000)); - config.addProperty(StringProperty("name", "vlado")); - config.addProperty(ListProperty("scaling", List(1.0, 2.0, 3.0))); - - *result = config.detach(); - return OPENDAQ_SUCCESS; - }; - - return FunctionBlockType("ref_fb", "Reference function block", "Description", createDefaultConfig); + auto defaultConfig = PropertyObject(); + defaultConfig.addProperty(IntProperty("port", 1000)); + defaultConfig.addProperty(StringProperty("name", "vlado")); + defaultConfig.addProperty(ListProperty("scaling", List(1.0, 2.0, 3.0))); + + return FunctionBlockType("ref_fb", "Reference function block", "Description", defaultConfig); } }; @@ -61,9 +55,9 @@ TEST_F(TmsFunctionBlockTypeTest, Values) ASSERT_TRUE(TestComparators::FunctionBlockTypeEquals(fbType, clientFbType)); } -TEST_F(TmsFunctionBlockTypeTest, NullConfig) +TEST_F(TmsFunctionBlockTypeTest, DefaultConfig) { - auto fbType = FunctionBlockType("id", "", "", nullptr); + auto fbType = FunctionBlockType("id", "", ""); auto serverFbType = std::make_shared(fbType, server, ctx, serverContext); auto nodeId = serverFbType->registerOpcUaNode(); auto clientFbType = TmsClientFunctionBlockType(ctx, clientContext, nodeId); @@ -114,20 +108,14 @@ TEST_F(TmsFunctionBlockTypeTest, DISABLED_NonDefaultValues) { // This should work, but it doesnt, because of an error in client property object. - auto createDefaultConfig = [](IBaseObject* /*params*/, IBaseObject** result) - { - auto config = PropertyObject(); - config.addProperty(IntProperty("port", 0)); - config.addProperty(StringProperty("name", "")); - - config.setPropertyValue("port", 1000); - config.setPropertyValue("name", "vlado"); + auto defaultConfig = PropertyObject(); + defaultConfig.addProperty(IntProperty("port", 0)); + defaultConfig.addProperty(StringProperty("name", "")); - *result = config.detach(); - return OPENDAQ_SUCCESS; - }; + defaultConfig.setPropertyValue("port", 1000); + defaultConfig.setPropertyValue("name", "vlado"); - auto fbType = FunctionBlockType("ref_fb", "Reference function block", "Description", createDefaultConfig); + auto fbType = FunctionBlockType("ref_fb", "Reference function block", "Description", defaultConfig); auto serverFbType = std::make_shared(fbType, server, ctx, serverContext); auto nodeId = serverFbType->registerOpcUaNode(); From 75f8c4d1582add06884ea568bbe2265f2f38d47a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE?= Date: Tue, 7 May 2024 10:11:48 +0200 Subject: [PATCH 125/217] Bump version from 3.0.0 to 3.1.0 --- modules/opcua_client_module/CMakeLists.txt | 2 +- modules/opcua_server_module/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/opcua_client_module/CMakeLists.txt b/modules/opcua_client_module/CMakeLists.txt index 01d0f0d..7cea83a 100644 --- a/modules/opcua_client_module/CMakeLists.txt +++ b/modules/opcua_client_module/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(ClientModule VERSION 3.0.0 LANGUAGES C CXX) +project(ClientModule VERSION 3.1.0 LANGUAGES C CXX) add_subdirectory(src) diff --git a/modules/opcua_server_module/CMakeLists.txt b/modules/opcua_server_module/CMakeLists.txt index ffa5990..d8628e3 100644 --- a/modules/opcua_server_module/CMakeLists.txt +++ b/modules/opcua_server_module/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(ServerModule VERSION 3.0.0 LANGUAGES CXX) +project(ServerModule VERSION 3.1.0 LANGUAGES CXX) add_subdirectory(src) diff --git a/shared/libraries/opcuatms/opcuatms/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms/CMakeLists.txt index f86bc4a..22acec2 100644 --- a/shared/libraries/opcuatms/opcuatms/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(opcuatms VERSION 3.0.0 LANGUAGES CXX) +project(opcuatms VERSION 3.1.0 LANGUAGES CXX) add_subdirectory(src) diff --git a/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt index be9acd8..2feff54 100644 --- a/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(opcuatms_client VERSION 3.0.0 LANGUAGES CXX) +project(opcuatms_client VERSION 3.1.0 LANGUAGES CXX) add_subdirectory(src) diff --git a/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt index 48f03b7..9e81467 100644 --- a/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(opcuatms_server VERSION 3.0.0 LANGUAGES CXX) +project(opcuatms_server VERSION 3.1.0 LANGUAGES CXX) add_subdirectory(src) From c251bdb8978eb77db35f601894d8133751af285e Mon Sep 17 00:00:00 2001 From: Dejan Crnila Date: Mon, 6 May 2024 22:52:40 +0200 Subject: [PATCH 126/217] Fix unit tests --- .../objects/tms_client_property_object_impl.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h index fd2411d..f290822 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h @@ -22,6 +22,7 @@ #include #include "opcuatms_client/objects/tms_client_component.h" #include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -64,7 +65,19 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl init(); } - template, ChannelImpl, PropertyObjectImpl, ServerCapabilityConfigImpl> = 0> + template > = 0> + TmsClientPropertyObjectBaseImpl(const ContextPtr& ctx, + const ComponentPtr& parent, + const StringPtr& localId, + const TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId) + : TmsClientObjectImpl(ctx, clientContext, nodeId) + , Impl(ctx, parent, localId) + { + init(); + } + + template, ChannelImpl, PropertyObjectImpl, ServerCapabilityConfigImpl, GenericInputPortImpl> = 0> TmsClientPropertyObjectBaseImpl(const ContextPtr& ctx, const ComponentPtr& parent, const StringPtr& localId, From 9a6fd9c24b73522aba883a7815a89497db4cf24d Mon Sep 17 00:00:00 2001 From: roettger Date: Thu, 2 May 2024 12:24:07 +0000 Subject: [PATCH 127/217] NodeId as String not as numeric for Properties In opendaq only objects had a nodeID as string. With this PR also Properties / Variables have a numeric node id. --- .../include/opcuaserver/opcuaaddnodeparams.h | 3 ++ .../include/opcuaserver/opcuaserver.h | 1 + .../opcuaserver/src/opcuaaddnodeparams.cpp | 25 ++++++++++++++++ .../opcua/opcuaserver/src/opcuaserver.cpp | 29 +++++++++++++++++++ .../objects/tms_server_property_object.cpp | 3 +- .../src/objects/tms_server_variable.cpp | 2 +- 6 files changed, 60 insertions(+), 3 deletions(-) diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h index dbfc869..d960cc6 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h @@ -62,6 +62,7 @@ class AddVariableNodeParams : public GenericAddNodeParams public: AddVariableNodeParams(const OpcUaNodeId& requestedNewNodeId); AddVariableNodeParams(const OpcUaNodeId& requestedNewNodeId, const OpcUaNodeId& parentNodeId); + AddVariableNodeParams(const std::string& name, const OpcUaNodeId& parentNodeId); void setDataType(const OpcUaNodeId& dataTypeId); @@ -73,6 +74,8 @@ class AddMethodNodeParams : public GenericAddNodeParams public: AddMethodNodeParams(const OpcUaNodeId& requestedNewNodeId); AddMethodNodeParams(const OpcUaNodeId& requestedNewNodeId, const OpcUaNodeId& parentNodeId); + AddMethodNodeParams(const std::string& name, const OpcUaNodeId& parentNodeId); + ~AddMethodNodeParams(); UA_MethodCallback method{}; diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h index e531b9c..1d51269 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h @@ -137,6 +137,7 @@ class OpcUaServer final : public daq::utils::ThreadEx const UA_ExtensionObject* userIdentityToken, void** sessionContext); static void closeSession(UA_Server* server, UA_AccessControl* ac, const UA_NodeId* sessionId, void* sessionContext); + static UA_StatusCode generateChildId(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, const UA_NodeId *sourceNodeId, const UA_NodeId *targetParentNodeId, const UA_NodeId *referenceTypeId, UA_NodeId *targetNodeId); static UA_StatusCode authenticateUser(OpcUaServer* serverInstance, const UA_ExtensionObject* userIdentityToken); // missing UA_Server void* member workaround... diff --git a/shared/libraries/opcua/opcuaserver/src/opcuaaddnodeparams.cpp b/shared/libraries/opcua/opcuaserver/src/opcuaaddnodeparams.cpp index c2b7df5..64c8537 100644 --- a/shared/libraries/opcua/opcuaserver/src/opcuaaddnodeparams.cpp +++ b/shared/libraries/opcua/opcuaserver/src/opcuaaddnodeparams.cpp @@ -2,6 +2,19 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA +/*RequestedNodeIdBaseOnName*/ + +static daq::opcua::OpcUaNodeId RequestedNodeIdBaseOnName(const std::string& name, const OpcUaNodeId& parentNodeId) +{ + if (parentNodeId.getValue().identifierType == UA_NODEIDTYPE_STRING) + { + std::string newNodeIdStr = utils::ToStdString(parentNodeId.getValue().identifier.string) + "/" + name; + return OpcUaNodeId(parentNodeId.getNamespaceIndex(), newNodeIdStr); + } + return UA_NODEID_NULL; +} + + /*AddNodeParams*/ AddNodeParams::AddNodeParams(const OpcUaNodeId& requestedNewNodeId, const OpcUaNodeId& parentNodeId, const OpcUaNodeId& referenceTypeId) @@ -41,6 +54,12 @@ AddObjectNodeParams::AddObjectNodeParams(const OpcUaNodeId& requestedNewNodeId, { } +AddVariableNodeParams::AddVariableNodeParams(const std::string& name, const OpcUaNodeId& parentNodeId) + : GenericAddNodeParams( + RequestedNodeIdBaseOnName(name, parentNodeId), parentNodeId, OpcUaNodeId(UA_NS0ID_HASPROPERTY), UA_VariableAttributes_default) +{ +} + /*AddVariableNodeParams*/ AddVariableNodeParams::AddVariableNodeParams(const OpcUaNodeId& requestedNewNodeId) @@ -72,6 +91,12 @@ AddMethodNodeParams::AddMethodNodeParams(const OpcUaNodeId& requestedNewNodeId, { } +AddMethodNodeParams::AddMethodNodeParams(const std::string& name, const OpcUaNodeId& parentNodeId) + : GenericAddNodeParams( + RequestedNodeIdBaseOnName(name, parentNodeId), parentNodeId, OpcUaNodeId(UA_NS0ID_HASPROPERTY), UA_MethodAttributes_default) +{ +} + AddMethodNodeParams::~AddMethodNodeParams() { if(outputArguments) diff --git a/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp b/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp index 0690c75..65f53d4 100644 --- a/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp +++ b/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp @@ -129,6 +129,7 @@ void OpcUaServer::prepareServer() activateSession_default = config->accessControl.activateSession; config->accessControl.activateSession = activateSession; config->accessControl.closeSession = closeSession; + config->nodeLifecycle.generateChildNodeId = generateChildId; eventManager->registerEvents(); } @@ -598,6 +599,34 @@ void OpcUaServer::closeSession(UA_Server* server, UA_AccessControl* ac, const UA serverInstance->deleteSessionContextCallback(sessionContext); } + +UA_StatusCode OpcUaServer::generateChildId(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, const UA_NodeId *sourceNodeId, const UA_NodeId *targetParentNodeId, const UA_NodeId *referenceTypeId, UA_NodeId *targetNodeId) +{ + if (targetParentNodeId->identifierType == UA_NODEIDTYPE_STRING) { + std::string newNodeIdStr; + std::string parentNodeIdStr = utils::ToStdString(targetParentNodeId->identifier.string); + std::string objectTypeIdStr; + if (sourceNodeId->identifierType == UA_NODEIDTYPE_STRING) + { + objectTypeIdStr = opcua::utils::ToStdString(sourceNodeId->identifier.string); + } + else if (sourceNodeId->identifierType == UA_NODEIDTYPE_NUMERIC) + { + UA_QualifiedName* browseName = UA_QualifiedName_new();; + UA_Server_readBrowseName(server, *sourceNodeId, browseName); + objectTypeIdStr = opcua::utils::ToStdString(browseName->name); + UA_QualifiedName_delete(browseName); + } + + parentNodeIdStr.append("/"); + newNodeIdStr = parentNodeIdStr + objectTypeIdStr; + *targetNodeId = UA_NODEID_STRING_ALLOC(targetParentNodeId->namespaceIndex, const_cast(newNodeIdStr.c_str())); + } + + return UA_STATUSCODE_GOOD; +} + + bool OpcUaServer::passwordLock(const std::string& password) { return serverLock.passwordLock(password); diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp index afbf352..d32f7f3 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp @@ -229,8 +229,7 @@ void TmsServerPropertyObject::addMethodPropertyNode(const PropertyPtr& prop, uin { const auto name = prop.getName(); OpcUaNodeId parentId = methodParentNodeId.isNull() ? nodeId : methodParentNodeId; - OpcUaNodeId newNodeId(0); - AddMethodNodeParams params(newNodeId, parentId); + AddMethodNodeParams params(name, parentId); params.referenceTypeId = OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT)); const auto callableInfo = prop.getCallableInfo(); diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp index f2458de..53b2bb9 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp @@ -21,7 +21,7 @@ opcua::OpcUaNodeId TmsServerVariable::createNode(const opcua::OpcUaNod this->typeBrowseName = this->readTypeBrowseName(); std::string name = this->getBrowseName(); - auto params = AddVariableNodeParams(UA_NODEID_NULL, parentNodeId); + auto params = AddVariableNodeParams(name, parentNodeId); configureVariableNodeAttributes(params.attr); params.setBrowseName(name); params.typeDefinition = this->getTmsTypeId(); From 9ac8e611dd72eceb648b7ae18d94037786049e03 Mon Sep 17 00:00:00 2001 From: Nils Roettger <99480819+nilsRoettgerAtBB@users.noreply.github.com> Date: Fri, 10 May 2024 10:03:14 +0200 Subject: [PATCH 128/217] Update shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp Co-authored-by: Jaka Mohorko <96818661+JakaMohorkoDS@users.noreply.github.com> --- .../opcua/opcuaserver/src/opcuaserver.cpp | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp b/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp index 65f53d4..c36eb83 100644 --- a/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp +++ b/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp @@ -600,27 +600,36 @@ void OpcUaServer::closeSession(UA_Server* server, UA_AccessControl* ac, const UA } -UA_StatusCode OpcUaServer::generateChildId(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, const UA_NodeId *sourceNodeId, const UA_NodeId *targetParentNodeId, const UA_NodeId *referenceTypeId, UA_NodeId *targetNodeId) +UA_StatusCode OpcUaServer::generateChildId(UA_Server* server, + const UA_NodeId*/*sessionId*/, + void*/*sessionContext*/, + const UA_NodeId* sourceNodeId, + const UA_NodeId* targetParentNodeId, + const UA_NodeId*/*referenceTypeId*/, + UA_NodeId* targetNodeId) { if (targetParentNodeId->identifierType == UA_NODEIDTYPE_STRING) { - std::string newNodeIdStr; - std::string parentNodeIdStr = utils::ToStdString(targetParentNodeId->identifier.string); + const std::string parentNodeIdStr = utils::ToStdString(targetParentNodeId->identifier.string); std::string objectTypeIdStr; + if (sourceNodeId->identifierType == UA_NODEIDTYPE_STRING) { - objectTypeIdStr = opcua::utils::ToStdString(sourceNodeId->identifier.string); + objectTypeIdStr = utils::ToStdString(sourceNodeId->identifier.string); } else if (sourceNodeId->identifierType == UA_NODEIDTYPE_NUMERIC) { - UA_QualifiedName* browseName = UA_QualifiedName_new();; + UA_QualifiedName* browseName = UA_QualifiedName_new(); UA_Server_readBrowseName(server, *sourceNodeId, browseName); - objectTypeIdStr = opcua::utils::ToStdString(browseName->name); + objectTypeIdStr = utils::ToStdString(browseName->name); UA_QualifiedName_delete(browseName); } + else + { + return UA_STATUSCODE_GOOD; + } - parentNodeIdStr.append("/"); - newNodeIdStr = parentNodeIdStr + objectTypeIdStr; - *targetNodeId = UA_NODEID_STRING_ALLOC(targetParentNodeId->namespaceIndex, const_cast(newNodeIdStr.c_str())); + const auto newNodeIdStr = parentNodeIdStr + "/" + objectTypeIdStr; + *targetNodeId = UA_NODEID_STRING_ALLOC(targetParentNodeId->namespaceIndex, newNodeIdStr.c_str()); } return UA_STATUSCODE_GOOD; From c553724ea9e12dfb701b78205e378dd7de3a6cc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Mon, 22 Apr 2024 14:58:59 +0200 Subject: [PATCH 129/217] Add support for username authentication to OpcUa server and client --- .../include/opcuaclient/opcuaclient.h | 1 - .../opcua/opcuaclient/src/opcuaclient.cpp | 26 +-- .../include/opcuaserver/opcuaserver.h | 17 +- .../opcua/opcuaserver/src/CMakeLists.txt | 3 +- .../opcua/opcuaserver/src/opcuaserver.cpp | 210 ++++++++---------- .../include/opcuashared/opcuaendpoint.h | 26 ++- .../opcua/opcuashared/src/opcuaendpoint.cpp | 47 ++-- .../opcuashared/tests/test_opcuaendpoint.cpp | 58 ++++- .../opcua/tests/testopcua/CMakeLists.txt | 1 + .../testopcua/test_opcua_authentication.cpp | 60 +++++ .../tests/testopcua/test_opcua_security.cpp | 4 +- .../opcuatms_client/src/tms_client.cpp | 2 +- .../tests/test_utils/tms_object_test.cpp | 2 +- 13 files changed, 271 insertions(+), 186 deletions(-) create mode 100644 shared/libraries/opcua/tests/testopcua/test_opcua_authentication.cpp diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h index a3a0836..bcf44fc 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h @@ -108,7 +108,6 @@ class OpcUaClient UA_Client* getUaClient(); ClientLockGuard getLockedUaClient(); const OpcUaEndpoint& getEndpoint() const; - void setUrl(const std::string& url); void setTimeout(uint32_t timoutMs); uint32_t getTimeout() const; void setConnectivityCheckInterval(uint32_t connectivityCheckInterval); diff --git a/shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp b/shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp index f355b7c..18f4576 100644 --- a/shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp +++ b/shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp @@ -55,7 +55,7 @@ OpcUaClient::OpcUaClient(const OpcUaEndpoint& endpoint) } OpcUaClient::OpcUaClient(const std::string& url) - : OpcUaClient(OpcUaEndpoint("", url)) + : OpcUaClient(OpcUaEndpoint(url)) { } @@ -70,7 +70,7 @@ void OpcUaClient::initialize() { std::lock_guard guard(getLock()); - uaclient = UaClientFactory::Create(endpoint.getSecurityConfig(), endpoint.getLogLevel(), endpoint.getCustomDataTypes()); + uaclient = UaClientFactory::Create(nullptr, UA_LOGLEVEL_WARNING, endpoint.getCustomDataTypes()); UA_Client_getConfig(uaclient)->clientContext = this; @@ -199,22 +199,17 @@ UA_Client* UaClientFactory::build() bool OpcUaClient::connect() { std::lock_guard guard(getLock()); + if (!uaclient) initialize(); - const OpcUaClientSecurityConfig* securityConfig = endpoint.getSecurityConfig(); - - UA_StatusCode status; + UA_StatusCode status = UA_STATUSCODE_GOOD; - if (securityConfig == NULL || securityConfig->isAnonymous()) + if (endpoint.isAnonymous()) status = UA_Client_connect(uaclient, endpoint.getUrl().c_str()); else - { - status = UA_Client_connectUsername(uaclient, - endpoint.getUrl().c_str(), - securityConfig->username.value_or("").c_str(), - securityConfig->password.value_or("").c_str()); - } + status = + UA_Client_connectUsername(uaclient, endpoint.getUrl().c_str(), endpoint.getUsername().c_str(), endpoint.getPassword().c_str()); return OPCUA_STATUSCODE_SUCCEEDED(status); } @@ -270,13 +265,6 @@ const OpcUaEndpoint& OpcUaClient::getEndpoint() const return endpoint; } -void OpcUaClient::setUrl(const std::string& url) -{ - if (isConnected()) - throw std::runtime_error("Cannot setUrl. Disconnect connection broker first."); - endpoint.setUrl(url); -} - void OpcUaClient::setTimeout(uint32_t timeoutMs) { std::lock_guard guard(getLock()); diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h index 1d51269..4f778ea 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h @@ -28,8 +28,8 @@ #include #include #include - #include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA @@ -43,6 +43,8 @@ class OpcUaServer final : public daq::utils::ThreadEx uint16_t& getPort(); void setPort(uint16_t port); + void setAllowAnonymous(bool allowAnonymous); + void setAuthenticationProvider(const AuthenticationProviderPtr& authenticationProvider); void setSecurityConfig(OpcUaServerSecurityConfig* config); const OpcUaServerSecurityConfig* getSecurityConfig() const; @@ -123,11 +125,12 @@ class OpcUaServer final : public daq::utils::ThreadEx UA_Server* createServer(); void prepareServer(); void prepareServerMinimal(UA_ServerConfig* config); - void prepareServerSecured(UA_ServerConfig* config); - void prepareEncryption(UA_ServerConfig* config); void prepareAccessControl(UA_ServerConfig* config); - void configureAppUri(UA_ServerConfig* config); void shutdownServer(); + UA_StatusCode validateIdentityToken(const UA_ExtensionObject* token); + bool isUsernameIdentityTokenValid(const UA_UserNameIdentityToken* token); + bool isAnonymousIdentityTokenValid(const UA_AnonymousIdentityToken* token); + void createSession(const OpcUaNodeId& sessionId, void** sessionContext); static UA_StatusCode activateSession(UA_Server* server, UA_AccessControl* ac, @@ -138,7 +141,6 @@ class OpcUaServer final : public daq::utils::ThreadEx void** sessionContext); static void closeSession(UA_Server* server, UA_AccessControl* ac, const UA_NodeId* sessionId, void* sessionContext); static UA_StatusCode generateChildId(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, const UA_NodeId *sourceNodeId, const UA_NodeId *targetParentNodeId, const UA_NodeId *referenceTypeId, UA_NodeId *targetNodeId); - static UA_StatusCode authenticateUser(OpcUaServer* serverInstance, const UA_ExtensionObject* userIdentityToken); // missing UA_Server void* member workaround... static OpcUaServer* getServer(UA_Server* server); @@ -154,11 +156,10 @@ class OpcUaServer final : public daq::utils::ThreadEx OpcUaServerLock serverLock; uint16_t port{OPCUA_DEFAULT_PORT}; UA_Server* server{}; - std::optional securityConfig; std::unordered_set sessionContext; ServerEventManagerPtr eventManager; - static std::mutex serverMappingMutex; - static std::map serverMapping; + bool allowAnonymous; + AuthenticationProviderPtr authenticationProvider; }; END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/src/CMakeLists.txt b/shared/libraries/opcua/opcuaserver/src/CMakeLists.txt index 67ca02c..4e62311 100644 --- a/shared/libraries/opcua/opcuaserver/src/CMakeLists.txt +++ b/shared/libraries/opcua/opcuaserver/src/CMakeLists.txt @@ -46,6 +46,7 @@ target_include_directories(${MODULE_NAME} PUBLIC $ #include #include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA OpcUaServer::OpcUaServer() : eventManager(std::make_shared(this)) + , allowAnonymous(true) { setPort(OPCUA_DEFAULT_PORT); createSessionContextCallback = [this](const OpcUaNodeId& sessionId) { return createSessionContextCallbackImp(sessionId); }; deleteSessionContextCallback = [this](void* context) { deleteSessionContextCallbackImp(context); }; + authenticationProvider = AuthenticationProvider(); } void* OpcUaServer::createSessionContextCallbackImp(const OpcUaNodeId& sessionId) @@ -46,17 +50,24 @@ void OpcUaServer::setPort(uint16_t port) this->port = port; } +void OpcUaServer::setAllowAnonymous(bool allowAnonymous) +{ + this->allowAnonymous = allowAnonymous; +} + +void OpcUaServer::setAuthenticationProvider(const AuthenticationProviderPtr& authenticationProvider) +{ + this->authenticationProvider = authenticationProvider; +} + void OpcUaServer::setSecurityConfig(OpcUaServerSecurityConfig* config) { - if (config == nullptr) - this->securityConfig.reset(); - else - this->securityConfig = *config; + throw std::exception("method setSecurityConfig() is deprecated"); } const OpcUaServerSecurityConfig* OpcUaServer::getSecurityConfig() const { - return this->securityConfig.has_value() ? &this->securityConfig.value() : nullptr; + throw std::exception("method getSecurityConfig() is deprecated"); } void OpcUaServer::start() @@ -90,9 +101,6 @@ void OpcUaServer::prepare() shutdownServer(); prepareServer(); - - std::lock_guard guard(serverMappingMutex); - serverMapping[server] = this; } catch (const OpcUaException&) { @@ -120,16 +128,13 @@ void OpcUaServer::prepareServer() server = createServer(); UA_ServerConfig* config = UA_Server_getConfig(server); - if (!securityConfig.has_value()) - prepareServerMinimal(config); - else - prepareServerSecured(config); + prepareServerMinimal(config); + config->context = this; + config->nodeLifecycle.generateChildNodeId = generateChildId; + prepareAccessControl(config); addTmsTypes(server); - activateSession_default = config->accessControl.activateSession; - config->accessControl.activateSession = activateSession; - config->accessControl.closeSession = closeSession; - config->nodeLifecycle.generateChildNodeId = generateChildId; + eventManager->registerEvents(); } @@ -139,81 +144,89 @@ void OpcUaServer::prepareServerMinimal(UA_ServerConfig* config) CheckStatusCodeException(retval, "Failed to configure server minimal."); } -void OpcUaServer::prepareServerSecured(UA_ServerConfig* config) +void OpcUaServer::prepareAccessControl(UA_ServerConfig* config) { - securityConfig->validate(); + config->accessControl.clear(&config->accessControl); - if (!securityConfig->hasCertificate()) - prepareServerMinimal(config); - else - prepareEncryption(config); + auto status = + UA_AccessControl_default(config, false, NULL, &config->securityPolicies[config->securityPoliciesSize - 1].policyUri, 0, nullptr); - configureAppUri(config); - prepareAccessControl(config); + CheckStatusCodeException(status, "Failed to configure access control."); + + activateSession_default = config->accessControl.activateSession; + config->accessControl.activateSession = activateSession; + config->accessControl.closeSession = closeSession; } -void OpcUaServer::prepareEncryption(UA_ServerConfig* config) +void OpcUaServer::shutdownServer() { -#ifdef OPCUA_ENABLE_ENCRYPTION - UA_StatusCode retval = - UA_ServerConfig_setDefaultWithSecurityPolicies(config, - portUsed, - &securityConfig->certificate.getValue(), - &securityConfig->privateKey.getValue(), - (securityConfig->trustAll) ? NULL : securityConfig->trustList.data(), - (securityConfig->trustAll) ? 0 : securityConfig->trustList.size(), - NULL, - 0, - securityConfig->revocationList.data(), - securityConfig->revocationList.size()); + if (getStarted()) + { + UA_StatusCode status = UA_Server_run_shutdown(server); + CheckStatusCodeException(status); + } - if (!securityConfig->trustAll && securityConfig->trustList.size() == 0) - config->certificateVerification.verifyCertificate = OpcUaSecurityCommon::verifyCertificateRejectAll; + if (isPrepared()) + { + UA_Server_delete(server); + server = nullptr; + } - if (retval != UA_STATUSCODE_GOOD) - throw OpcUaException(retval, "Failed to configure security policies."); -#else - throw OpcUaException(UA_STATUSCODE_BADINTERNALERROR, "Encryption was not enabled when building the project."); -#endif + assert(sessionContext.size() == 0); } -void OpcUaServer::prepareAccessControl(UA_ServerConfig* config) +UA_StatusCode OpcUaServer::validateIdentityToken(const UA_ExtensionObject* token) { - config->accessControl.clear(&config->accessControl); - UA_StatusCode retval = - UA_AccessControl_default(config, true, NULL, &config->securityPolicies[config->securityPoliciesSize - 1].policyUri, 0, NULL); + if (token->content.decoded.type == &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]) + { + if (isUsernameIdentityTokenValid((UA_UserNameIdentityToken*) token->content.decoded.data)) + return UA_STATUSCODE_GOOD; + } + else if (token->content.decoded.type == &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]) + { + if (isAnonymousIdentityTokenValid((UA_AnonymousIdentityToken*) token->content.decoded.data)) + return UA_STATUSCODE_GOOD; + } + else + { + return UA_STATUSCODE_BADIDENTITYTOKENINVALID; + } - if (retval != UA_STATUSCODE_GOOD) - throw OpcUaException(retval, "Failed to configure server access control."); + return UA_STATUSCODE_BADUSERACCESSDENIED; } -void OpcUaServer::configureAppUri(UA_ServerConfig* config) +bool OpcUaServer::isUsernameIdentityTokenValid(const UA_UserNameIdentityToken* token) { - std::optional appUri = securityConfig->getAppUriOrParseFromCertificate(); - if (appUri.has_value()) + const auto username = utils::ToStdString(token->userName); + const auto password = utils::ToStdString(token->password); + + try { - UA_String_clear(&config->applicationDescription.applicationUri); - config->applicationDescription.applicationUri = UA_STRING_ALLOC(appUri.value().c_str()); + authenticationProvider.authenticate(username, password); } + catch (const DaqException&) + { + return false; + } + + return true; } -void OpcUaServer::shutdownServer() +bool OpcUaServer::isAnonymousIdentityTokenValid(const UA_AnonymousIdentityToken* /*token*/) { - if (getStarted()) - { - UA_StatusCode status = UA_Server_run_shutdown(server); - CheckStatusCodeException(status); - } + return allowAnonymous; +} - if (isPrepared()) +void OpcUaServer::createSession(const OpcUaNodeId& sessionId, void** sessionContext) +{ + bool sessionContextAlreadyCreated = *sessionContext != nullptr; + + if (createSessionContextCallback && !sessionContextAlreadyCreated) { - UA_Server_delete(server); - std::lock_guard guard(serverMappingMutex); - serverMapping.erase(server); - server = nullptr; + *sessionContext = createSessionContextCallback(sessionId); + if (*sessionContext != nullptr) + this->sessionContext.insert(*sessionContext); } - - assert(sessionContext.size() == 0); } void OpcUaServer::execute() @@ -518,33 +531,11 @@ bool OpcUaServer::referenceExists(const OpcUaNodeId& sourceId, const OpcUaNodeId return false; } -std::mutex OpcUaServer::serverMappingMutex; -std::map OpcUaServer::serverMapping; - OpcUaServer* OpcUaServer::getServer(UA_Server* server) { - std::lock_guard guard(serverMappingMutex); - auto it = serverMapping.find(server); - if (it != serverMapping.end()) - return (*it).second; - return nullptr; -} - -UA_StatusCode OpcUaServer::authenticateUser(OpcUaServer* serverInstance, const UA_ExtensionObject* userIdentityToken) -{ - UA_StatusCode status = UA_STATUSCODE_BADUSERACCESSDENIED; - - if (userIdentityToken->content.decoded.type == &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]) - status = serverInstance->securityConfig->authenticateUser(true, "", ""); - else if (userIdentityToken->content.decoded.type == &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]) - { - const UA_UserNameIdentityToken* userToken = (UA_UserNameIdentityToken*) userIdentityToken->content.decoded.data; - std::string username = utils::ToStdString(userToken->userName); - std::string password = utils::ToStdString(userToken->password); - status = serverInstance->securityConfig->authenticateUser(false, username, password); - } - - return status; + auto config = UA_Server_getConfig(server); + assert(config != nullptr && config->context != nullptr); + return (OpcUaServer*) config->context; } UA_StatusCode OpcUaServer::activateSession(UA_Server* server, @@ -556,32 +547,27 @@ UA_StatusCode OpcUaServer::activateSession(UA_Server* server, void** sessionContext) { OpcUaServer* serverInstance = getServer(server); - OpcUaSecurityConfig* securityConfig = serverInstance->securityConfig.has_value() ? &serverInstance->securityConfig.value() : nullptr; - - if (securityConfig != nullptr && securityConfig->securityMode != endpointDescription->securityMode) - return UA_STATUSCODE_BADSECURITYMODEREJECTED; - void* unusedSessionContext = nullptr; // activateSession_default resets sessionContext. Subsequent calls should keep the session - // context + // activateSession_default resets sessionContext. Subsequent calls should keep the context + void* unusedSessionContext = nullptr; UA_StatusCode status = serverInstance->activateSession_default( server, ac, endpointDescription, secureChannelRemoteCertificate, sessionId, userIdentityToken, &unusedSessionContext); assert(unusedSessionContext == nullptr); - if (securityConfig != nullptr && (status == UA_STATUSCODE_GOOD || status == UA_STATUSCODE_BADUSERACCESSDENIED)) - status = authenticateUser(serverInstance, userIdentityToken); - - if (status != UA_STATUSCODE_GOOD) - return status; - - bool sessionContextAlreadyCreated = *sessionContext != nullptr; - if (serverInstance->createSessionContextCallback && !sessionContextAlreadyCreated) + switch (status) { - OpcUaNodeId sessionNodeId(*sessionId, true); - *sessionContext = serverInstance->createSessionContextCallback(sessionNodeId); - if (*sessionContext != nullptr) - serverInstance->sessionContext.insert(*sessionContext); + case UA_STATUSCODE_GOOD: + case UA_STATUSCODE_BADUSERACCESSDENIED: + case UA_STATUSCODE_BADIDENTITYTOKENINVALID: + { + status = serverInstance->validateIdentityToken(userIdentityToken); + break; + } } + if (status == UA_STATUSCODE_GOOD) + serverInstance->createSession(*sessionId, sessionContext); + return status; } @@ -611,7 +597,7 @@ UA_StatusCode OpcUaServer::generateChildId(UA_Server* server, if (targetParentNodeId->identifierType == UA_NODEIDTYPE_STRING) { const std::string parentNodeIdStr = utils::ToStdString(targetParentNodeId->identifier.string); std::string objectTypeIdStr; - + if (sourceNodeId->identifierType == UA_NODEIDTYPE_STRING) { objectTypeIdStr = utils::ToStdString(sourceNodeId->identifier.string); diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaendpoint.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaendpoint.h index 001d8dd..bd9d985 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaendpoint.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaendpoint.h @@ -40,30 +40,32 @@ using OpcUaEndpointPtr = std::shared_ptr; class OpcUaEndpoint { public: - OpcUaEndpoint(const std::string& name, const std::string& url); - OpcUaEndpoint(); + OpcUaEndpoint(const std::string& url); + OpcUaEndpoint(const std::string& url, const std::string& username, const std::string& password); void setName(const std::string& name); - const std::string& getName() const; + const std::string getName() const; void setUrl(const std::string& url); - const std::string& getUrl() const; + const std::string getUrl() const; - void setSecurityConfig(OpcUaClientSecurityConfig* securityConfig); - const OpcUaClientSecurityConfig* getSecurityConfig() const; + void setUsername(const std::string& username); + const std::string getUsername() const; + + void setPassword(const std::string& password); + const std::string getPassword() const; void registerCustomTypes(const size_t typesSize, const UA_DataType* types); const UA_DataTypeArray* getCustomDataTypes() const; - void setLogLevel(const UA_LogLevel logLevel); - UA_LogLevel getLogLevel() const; + bool isAnonymous(); private: - std::string name{}; - std::string url{}; - std::optional securityConfig; + std::string name; + std::string url; + std::string username; + std::string password; OpcUaDataTypeArrayList customDataTypeList; - UA_LogLevel logLevel = UA_LOGLEVEL_WARNING; }; END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/src/opcuaendpoint.cpp b/shared/libraries/opcua/opcuashared/src/opcuaendpoint.cpp index 1ca18a6..3d7e83e 100644 --- a/shared/libraries/opcua/opcuashared/src/opcuaendpoint.cpp +++ b/shared/libraries/opcua/opcuashared/src/opcuaendpoint.cpp @@ -2,13 +2,15 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA -OpcUaEndpoint::OpcUaEndpoint(const std::string& name, const std::string& url) - : name(name) - , url(url) +OpcUaEndpoint::OpcUaEndpoint(const std::string& url) + : url(url) { } -OpcUaEndpoint::OpcUaEndpoint() +OpcUaEndpoint::OpcUaEndpoint(const std::string& url, const std::string& username, const std::string& password) + : url(url) + , username(username) + , password(password) { } @@ -17,7 +19,7 @@ void OpcUaEndpoint::setName(const std::string& name) this->name = name; } -const std::string& OpcUaEndpoint::getName() const +const std::string OpcUaEndpoint::getName() const { return name; } @@ -27,43 +29,44 @@ void OpcUaEndpoint::setUrl(const std::string& url) this->url = url; } -const std::string& OpcUaEndpoint::getUrl() const +const std::string OpcUaEndpoint::getUrl() const { return url; } -void OpcUaEndpoint::setSecurityConfig(OpcUaClientSecurityConfig* securityConfig) +void OpcUaEndpoint::setUsername(const std::string& username) { - if (securityConfig == NULL) - this->securityConfig.reset(); - else - this->securityConfig = *securityConfig; + this->username = username; } -const OpcUaClientSecurityConfig* OpcUaEndpoint::getSecurityConfig() const +const std::string OpcUaEndpoint::getUsername() const { - return this->securityConfig.has_value() ? &this->securityConfig.value() : NULL; + return username; } -const UA_DataTypeArray* OpcUaEndpoint::getCustomDataTypes()const +void OpcUaEndpoint::setPassword(const std::string& password) { - return customDataTypeList.getCustomDataTypes(); + this->password = password; } -void OpcUaEndpoint::registerCustomTypes(const size_t typesSize, const UA_DataType* types) +const std::string OpcUaEndpoint::getPassword() const { - customDataTypeList.add(typesSize, types); - + return password; } -void OpcUaEndpoint::setLogLevel(const UA_LogLevel logLevel) +const UA_DataTypeArray* OpcUaEndpoint::getCustomDataTypes()const { - this->logLevel = logLevel; + return customDataTypeList.getCustomDataTypes(); } -UA_LogLevel OpcUaEndpoint::getLogLevel() const +bool OpcUaEndpoint::isAnonymous() { - return this->logLevel; + return username.empty(); +} + +void OpcUaEndpoint::registerCustomTypes(const size_t typesSize, const UA_DataType* types) +{ + customDataTypeList.add(typesSize, types); } END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuashared/tests/test_opcuaendpoint.cpp b/shared/libraries/opcua/opcuashared/tests/test_opcuaendpoint.cpp index b5dd702..968a1d0 100644 --- a/shared/libraries/opcua/opcuashared/tests/test_opcuaendpoint.cpp +++ b/shared/libraries/opcua/opcuashared/tests/test_opcuaendpoint.cpp @@ -1,20 +1,64 @@ #include -#include "opcuashared/opcuaendpoint.h" +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA using OpcUaEndpointTest = testing::Test; -TEST_F(OpcUaEndpointTest, CreateEmptyEndpoint) +TEST_F(OpcUaEndpointTest, Create) { - ASSERT_NO_THROW(OpcUaEndpoint ep{}); + auto endpoint = OpcUaEndpoint("opc.tcp://localhost:4840"); + ASSERT_EQ(endpoint.getUrl(), "opc.tcp://localhost:4840"); } -TEST_F(OpcUaEndpointTest, CreateEndpoint) +TEST_F(OpcUaEndpointTest, CreateUsernamePassword) { - OpcUaEndpoint ep{"name", "opc.tcp://localhost:4840"}; - ASSERT_EQ(ep.getName(), "name"); - ASSERT_EQ(ep.getUrl(), "opc.tcp://localhost:4840"); + auto endpoint = OpcUaEndpoint("opc.tcp://127.0.0.1", "un", "pass"); + + ASSERT_EQ(endpoint.getUrl(), "opc.tcp://127.0.0.1"); + ASSERT_EQ(endpoint.getUsername(), "un"); + ASSERT_EQ(endpoint.getPassword(), "pass"); +} + +TEST_F(OpcUaEndpointTest, SettersAndGetters) +{ + auto endpoint = OpcUaEndpoint("opc.tcp://localhost:4840"); + + endpoint.setUrl("opc.tcp://localhost:2000"); + ASSERT_EQ(endpoint.getUrl(), "opc.tcp://localhost:2000"); + + endpoint.setName("name"); + ASSERT_EQ(endpoint.getName(), "name"); + + endpoint.setUsername("username"); + ASSERT_EQ(endpoint.getUsername(), "username"); + + endpoint.setPassword("123"); + ASSERT_EQ(endpoint.getPassword(), "123"); +} + +TEST_F(OpcUaEndpointTest, RegisterCustomTypes) +{ + auto endpoint = OpcUaEndpoint("opc.tcp://127.0.0.1:4840"); + + endpoint.registerCustomTypes(UA_TYPES_COUNT, UA_TYPES); + auto typeList = endpoint.getCustomDataTypes(); + + ASSERT_EQ(typeList[0].typesSize, UA_TYPES_COUNT); + ASSERT_EQ(typeList[0].types, UA_TYPES); +} + +TEST_F(OpcUaEndpointTest, IsAnonymous) +{ + auto endpoint = OpcUaEndpoint("opc.tcp://127.0.0.1:4840"); + ASSERT_TRUE(endpoint.isAnonymous()); + + endpoint.setUsername("u"); + ASSERT_FALSE(endpoint.isAnonymous()); + + endpoint.setUsername(""); + endpoint.setPassword("u"); + ASSERT_TRUE(endpoint.isAnonymous()); } END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/tests/testopcua/CMakeLists.txt b/shared/libraries/opcua/tests/testopcua/CMakeLists.txt index a842d5c..11579fb 100644 --- a/shared/libraries/opcua/tests/testopcua/CMakeLists.txt +++ b/shared/libraries/opcua/tests/testopcua/CMakeLists.txt @@ -4,6 +4,7 @@ set(TEST_APP test_${MODULE_NAME}) set(TEST_SOURCES main.cpp test_opcua_security.cpp + test_opcua_authentication.cpp ) add_executable(${TEST_APP} ${TEST_SOURCES}) diff --git a/shared/libraries/opcua/tests/testopcua/test_opcua_authentication.cpp b/shared/libraries/opcua/tests/testopcua/test_opcua_authentication.cpp new file mode 100644 index 0000000..f012b19 --- /dev/null +++ b/shared/libraries/opcua/tests/testopcua/test_opcua_authentication.cpp @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include + +using namespace daq; +using namespace daq::opcua; + +using OpcUaAuthenticationTest = testing::Test; + +TEST_F(OpcUaAuthenticationTest, DefaultConnect) +{ + auto server = OpcUaServer(); + server.start(); + + auto client = OpcUaClient("opc.tcp://127.0.0.1"); + client.connect(); + ASSERT_TRUE(client.isConnected()); +} + +TEST_F(OpcUaAuthenticationTest, NoAnonymous) +{ + auto server = OpcUaServer(); + server.setPort(4840); + server.setAllowAnonymous(false); + server.start(); + + auto client = OpcUaClient("opc.tcp://127.0.0.1"); + client.connect(); + ASSERT_FALSE(client.isConnected()); +} + +TEST_F(OpcUaAuthenticationTest, AuthenticationProvider) +{ + auto users = List(); + users.pushBack(User("jure", "jure123")); + users.pushBack(User("tomaz", "tomaz123")); + auto authenticationProvider = StaticAuthenticationProvider(users); + + auto server = OpcUaServer(); + server.setPort(4840); + server.setAllowAnonymous(true); + server.setAuthenticationProvider(authenticationProvider); + server.start(); + + OpcUaClientPtr client; + + client = std::make_shared("opc.tcp://127.0.0.1"); + ASSERT_TRUE(client->connect()); + + client = std::make_shared(OpcUaEndpoint("opc.tcp://127.0.0.1", "jure", "wrongPass")); + ASSERT_FALSE(client->connect()); + + client = std::make_shared(OpcUaEndpoint("opc.tcp://127.0.0.1", "jure", "jure123")); + ASSERT_TRUE(client->connect()); + + client = std::make_shared(OpcUaEndpoint("opc.tcp://127.0.0.1", "tomaz", "tomaz123")); + ASSERT_TRUE(client->connect()); +} diff --git a/shared/libraries/opcua/tests/testopcua/test_opcua_security.cpp b/shared/libraries/opcua/tests/testopcua/test_opcua_security.cpp index ef33ad3..4ad9700 100644 --- a/shared/libraries/opcua/tests/testopcua/test_opcua_security.cpp +++ b/shared/libraries/opcua/tests/testopcua/test_opcua_security.cpp @@ -105,8 +105,8 @@ class TestClient void connect() { - OpcUaEndpoint endpoint("test", "opc.tcp://localhost:4840/"); - endpoint.setSecurityConfig(securityConfig); + OpcUaEndpoint endpoint("opc.tcp://localhost:4840/"); + //endpoint.setSecurityConfig(securityConfig); client = std::make_shared(endpoint); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp index a02a981..3b0366c 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp @@ -35,7 +35,7 @@ daq::DevicePtr TmsClient::connect() { const auto startTime = std::chrono::steady_clock::now(); - OpcUaEndpoint endpoint("TmsClient", opcUaUrl); + OpcUaEndpoint endpoint(opcUaUrl); client = std::make_shared(endpoint); if (!client->connect()) throw NotFoundException(); diff --git a/shared/libraries/opcuatms/tests/test_utils/tms_object_test.cpp b/shared/libraries/opcuatms/tests/test_utils/tms_object_test.cpp index 3cbd8e6..82993aa 100644 --- a/shared/libraries/opcuatms/tests/test_utils/tms_object_test.cpp +++ b/shared/libraries/opcuatms/tests/test_utils/tms_object_test.cpp @@ -92,7 +92,7 @@ daq::opcua::OpcUaServerPtr TmsObjectTest::CreateAndStartTestServer() daq::opcua::OpcUaClientPtr TmsObjectTest::CreateAndConnectTestClient() { - OpcUaEndpoint endpoint("Test", "opc.tcp://127.0.0.1:4840"); + OpcUaEndpoint endpoint("opc.tcp://127.0.0.1:4840"); endpoint.registerCustomTypes(UA_TYPES_DI_COUNT, UA_TYPES_DI); endpoint.registerCustomTypes(UA_TYPES_DAQBT_COUNT, UA_TYPES_DAQBT); endpoint.registerCustomTypes(UA_TYPES_DAQBSP_COUNT, UA_TYPES_DAQBSP); From 2d3bc8cb94e15a64b919ada84417a8499dd542dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Tue, 23 Apr 2024 16:11:50 +0200 Subject: [PATCH 130/217] Add authentication provider to Context object --- .../opcua_server_module/tests/test_opcua_server_module.cpp | 4 +++- .../opcuatms/tests/test_generic_struct_converter.cpp | 2 +- .../libraries/opcuatms/opcuatms_server/tests/test_helpers.h | 4 +++- .../opcuatms/opcuatms_server/tests/test_tms_input_port.cpp | 4 +++- .../opcuatms_integration/test_property_object_advanced.cpp | 6 +++--- .../opcuatms_integration/test_streaming_integration.cpp | 5 +++-- .../tests/opcuatms_integration/test_tms_amplifier.cpp | 4 ++-- .../opcuatms/tests/opcuatms_integration/test_tms_device.cpp | 2 +- .../tests/opcuatms_integration/test_tms_fusion_device.cpp | 2 +- .../tests/opcuatms_integration/test_tms_input_port.cpp | 2 +- .../tests/opcuatms_integration/test_tms_integration.cpp | 2 +- 11 files changed, 22 insertions(+), 15 deletions(-) diff --git a/modules/opcua_server_module/tests/test_opcua_server_module.cpp b/modules/opcua_server_module/tests/test_opcua_server_module.cpp index 938842f..646589c 100644 --- a/modules/opcua_server_module/tests/test_opcua_server_module.cpp +++ b/modules/opcua_server_module/tests/test_opcua_server_module.cpp @@ -11,6 +11,7 @@ #include #include #include +#include class OpcUaServerModuleTest : public testing::Test @@ -35,7 +36,8 @@ static InstancePtr CreateTestInstance() { const auto logger = Logger(); const auto moduleManager = ModuleManager("[[none]]"); - const auto context = Context(Scheduler(logger), logger, TypeManager(), moduleManager); + const auto authenticationProvider = AuthenticationProvider(); + const auto context = Context(Scheduler(logger), logger, TypeManager(), moduleManager, authenticationProvider); const ModulePtr deviceModule(MockDeviceModule_Create(context)); moduleManager.addModule(deviceModule); diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_generic_struct_converter.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_generic_struct_converter.cpp index d78c930..6be31c8 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/test_generic_struct_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/tests/test_generic_struct_converter.cpp @@ -50,7 +50,7 @@ namespace test_helpers List("Key", "Value"), List(SimpleType(ctString), SimpleType(ctUndefined)))); - return Context(nullptr, Logger(), typeManager, nullptr); + return Context(nullptr, Logger(), typeManager, nullptr, nullptr); } } diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h b/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h index 17bd1c3..0c94282 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h @@ -25,6 +25,7 @@ #include "opendaq/mock/mock_fb_module.h" #include "opendaq/mock/mock_physical_device.h" #include "open62541/daqbsp_nodeids.h" +#include namespace test_helpers { @@ -33,7 +34,8 @@ namespace test_helpers using namespace daq; const auto logger = Logger(); const auto moduleManager = ModuleManager("[[none]]"); - const auto context = Context(nullptr, logger, TypeManager(), moduleManager); + const auto authenticationProvider = AuthenticationProvider(); + const auto context = Context(nullptr, logger, TypeManager(), moduleManager, authenticationProvider); const ModulePtr deviceModule(MockDeviceModule_Create(context)); moduleManager.addModule(deviceModule); diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp index 7bb5949..c516c39 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp @@ -13,6 +13,7 @@ #include #include #include +#include using namespace daq; using namespace opcua::tms; @@ -48,7 +49,8 @@ TEST_F(TmsInputPortTest, ConnectedToReference) { const auto logger = Logger(); const auto scheduler = Scheduler(logger); - const auto context = Context(scheduler, logger, nullptr, nullptr); + const auto authenticationProvider = AuthenticationProvider(); + const auto context = Context(scheduler, logger, nullptr, nullptr, authenticationProvider); SignalPtr signal = Signal(context, nullptr, "sig"); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp index fafe132..7d12471 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp @@ -179,11 +179,11 @@ class TmsPropertyObjectAdvancedTest : public TmsObjectIntegrationTest RegisteredPropertyObject registerPropertyObject(const PropertyObjectPtr& prop) { - const auto context = Context(nullptr, logger, manager, nullptr); + const auto context = Context(nullptr, logger, manager, nullptr, nullptr); const auto serverProp = std::make_shared(prop, server, context, std::make_shared(context, nullptr)); const auto nodeId = serverProp->registerOpcUaNode(); - const auto clientProp = TmsClientPropertyObject(Context(nullptr, logger, manager,nullptr), clientContext, nodeId); + const auto clientProp = TmsClientPropertyObject(Context(nullptr, logger, manager,nullptr, nullptr), clientContext, nodeId); return {serverProp, clientProp}; } @@ -802,7 +802,7 @@ TEST_F(TmsPropertyObjectAdvancedTest, GainScalingStructure) const auto logger = Logger(); const auto serverProp = - std::make_shared(obj, server, Context(nullptr, logger, manager, nullptr), serverContext); + std::make_shared(obj, server, Context(nullptr, logger, manager, nullptr, nullptr), serverContext); const auto nodeId = serverProp->registerOpcUaNode(); auto [serverObj, clientObj] = registerPropertyObject(obj); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp index e274189..0127bad 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp @@ -20,6 +20,7 @@ #include #include #include +#include using namespace daq; using namespace daq::opcua; @@ -43,7 +44,7 @@ class StreamingIntegrationTest : public testing::Test logger = Logger(); loggerComponent = logger.getOrAddComponent("StreamingIntegrationTest"); auto clientLogger = Logger(); - clientContext = Context(Scheduler(clientLogger, 1), clientLogger, TypeManager(), nullptr); + clientContext = Context(Scheduler(clientLogger, 1), clientLogger, TypeManager(), nullptr, nullptr); instance = createDevice(); } @@ -165,7 +166,7 @@ class StreamingIntegrationTest : public testing::Test { const auto moduleManager = ModuleManager("[[none]]"); - auto context = Context(Scheduler(logger, 1), logger, TypeManager(), moduleManager); + auto context = Context(Scheduler(logger, 1), logger, TypeManager(), moduleManager, AuthenticationProvider()); const ModulePtr deviceModule(MockDeviceModule_Create(context)); moduleManager.addModule(deviceModule); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp index a9f55ad..0ec0de0 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp @@ -281,11 +281,11 @@ class TMSAmplifierTest : public TmsObjectIntegrationTest RegisteredPropertyObject registerPropertyObject(const PropertyObjectPtr& prop) { - const auto context = Context(nullptr, logger, TypeManager(), nullptr); + const auto context = Context(nullptr, logger, TypeManager(), nullptr, nullptr); const auto serverProp = std::make_shared(prop, server, context, std::make_shared(context, nullptr)); const auto nodeId = serverProp->registerOpcUaNode(); - const auto clientProp = TmsClientPropertyObject(Context(nullptr, logger, TypeManager(), nullptr), clientContext, nodeId); + const auto clientProp = TmsClientPropertyObject(Context(nullptr, logger, TypeManager(), nullptr, nullptr), clientContext, nodeId); return {serverProp, clientProp}; } }; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp index 6d3aae6..33c66f3 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp @@ -25,7 +25,7 @@ class TmsDeviceTest : public TmsObjectIntegrationTest InstancePtr createDevice() { const auto moduleManager = ModuleManager("[[none]]"); - auto context = Context(nullptr, Logger(), nullptr, moduleManager); + auto context = Context(nullptr, Logger(), nullptr, moduleManager, nullptr); const ModulePtr deviceModule(MockDeviceModule_Create(context)); moduleManager.addModule(deviceModule); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp index eedd26c..860b3a8 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp @@ -86,7 +86,7 @@ class TmsFusionDevice : public TmsObjectIntegrationTest RegisteredPropertyObject registerPropertyObject(const PropertyObjectPtr& prop) { const auto logger = Logger(); - const auto context = Context(nullptr, logger, objManager, nullptr); + const auto context = Context(nullptr, logger, objManager, nullptr, nullptr); const auto serverProp = std::make_shared(prop, server, context, std::make_shared(context, nullptr)); const auto nodeId = serverProp->registerOpcUaNode(); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp index 9b137f7..a01d544 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp @@ -119,7 +119,7 @@ TEST_F(TmsInputPortTest, ConnectedToReference) { const auto logger = Logger(); const auto scheduler = Scheduler(logger); - const auto context = Context(scheduler, logger, nullptr, nullptr); + const auto context = Context(scheduler, logger, nullptr, nullptr, nullptr); SignalPtr signal = Signal(context, nullptr, "sig"); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index fd3c24e..d74beaa 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -23,7 +23,7 @@ class TmsIntegrationTest : public testing::Test { const auto moduleManager = ModuleManager("[[none]]"); auto logger = Logger(); - auto context = Context(Scheduler(logger, 1), logger, TypeManager(), moduleManager); + auto context = Context(Scheduler(logger, 1), logger, TypeManager(), moduleManager, nullptr); const ModulePtr deviceModule(MockDeviceModule_Create(context)); moduleManager.addModule(deviceModule); From 475fe1fda5bb778ae1a1bdcef82b1c12b8320afc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Thu, 25 Apr 2024 11:32:32 +0200 Subject: [PATCH 131/217] Move allow anonymous flag to authentication provider --- .../opcua/opcuaserver/include/opcuaserver/opcuaserver.h | 2 -- shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp | 8 +------- .../opcua/tests/testopcua/test_opcua_authentication.cpp | 5 ++--- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h index 4f778ea..c1f990d 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h @@ -43,7 +43,6 @@ class OpcUaServer final : public daq::utils::ThreadEx uint16_t& getPort(); void setPort(uint16_t port); - void setAllowAnonymous(bool allowAnonymous); void setAuthenticationProvider(const AuthenticationProviderPtr& authenticationProvider); void setSecurityConfig(OpcUaServerSecurityConfig* config); @@ -158,7 +157,6 @@ class OpcUaServer final : public daq::utils::ThreadEx UA_Server* server{}; std::unordered_set sessionContext; ServerEventManagerPtr eventManager; - bool allowAnonymous; AuthenticationProviderPtr authenticationProvider; }; diff --git a/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp b/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp index 13011dd..81abc76 100644 --- a/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp +++ b/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp @@ -12,7 +12,6 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA OpcUaServer::OpcUaServer() : eventManager(std::make_shared(this)) - , allowAnonymous(true) { setPort(OPCUA_DEFAULT_PORT); createSessionContextCallback = [this](const OpcUaNodeId& sessionId) { return createSessionContextCallbackImp(sessionId); }; @@ -50,11 +49,6 @@ void OpcUaServer::setPort(uint16_t port) this->port = port; } -void OpcUaServer::setAllowAnonymous(bool allowAnonymous) -{ - this->allowAnonymous = allowAnonymous; -} - void OpcUaServer::setAuthenticationProvider(const AuthenticationProviderPtr& authenticationProvider) { this->authenticationProvider = authenticationProvider; @@ -214,7 +208,7 @@ bool OpcUaServer::isUsernameIdentityTokenValid(const UA_UserNameIdentityToken* t bool OpcUaServer::isAnonymousIdentityTokenValid(const UA_AnonymousIdentityToken* /*token*/) { - return allowAnonymous; + return authenticationProvider.isAnonymousAllowed(); } void OpcUaServer::createSession(const OpcUaNodeId& sessionId, void** sessionContext) diff --git a/shared/libraries/opcua/tests/testopcua/test_opcua_authentication.cpp b/shared/libraries/opcua/tests/testopcua/test_opcua_authentication.cpp index f012b19..eb84e1b 100644 --- a/shared/libraries/opcua/tests/testopcua/test_opcua_authentication.cpp +++ b/shared/libraries/opcua/tests/testopcua/test_opcua_authentication.cpp @@ -23,7 +23,7 @@ TEST_F(OpcUaAuthenticationTest, NoAnonymous) { auto server = OpcUaServer(); server.setPort(4840); - server.setAllowAnonymous(false); + server.setAuthenticationProvider(AuthenticationProvider(false)); server.start(); auto client = OpcUaClient("opc.tcp://127.0.0.1"); @@ -36,11 +36,10 @@ TEST_F(OpcUaAuthenticationTest, AuthenticationProvider) auto users = List(); users.pushBack(User("jure", "jure123")); users.pushBack(User("tomaz", "tomaz123")); - auto authenticationProvider = StaticAuthenticationProvider(users); + auto authenticationProvider = StaticAuthenticationProvider(true, users); auto server = OpcUaServer(); server.setPort(4840); - server.setAllowAnonymous(true); server.setAuthenticationProvider(authenticationProvider); server.start(); From 60929575a10bf8c4bc9adb0dc85ee2ac2cf44cc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Thu, 25 Apr 2024 11:43:39 +0200 Subject: [PATCH 132/217] Pass authentication provider to TmsServer --- shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp index cd3a19b..0c2ba8a 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp @@ -42,6 +42,7 @@ void TmsServer::start() server = std::make_shared(); server->setPort(opcUaPort); + server->setAuthenticationProvider(context.getAuthenticationProvider()); server->prepare(); tmsContext = std::make_shared(context, device); From 3d8a2980918fd48539b47fb2c64c74f3ef950079 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Thu, 25 Apr 2024 15:28:33 +0200 Subject: [PATCH 133/217] Add authentication parameters to opcua client module --- .../src/opcua_client_module_impl.cpp | 13 ++++++++++++- .../include/opcuatms_client/tms_client.h | 7 ++++++- .../opcuatms_client/src/tms_client.cpp | 18 +++++++++++++----- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index a29f76b..6e49665 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -91,7 +91,18 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, throw InvalidParameterException("OpcUa does not support connection string with prefix"); std::scoped_lock lock(sync); - TmsClient client(context, parent, OpcUaScheme + host + path); + + auto endpoint = OpcUaEndpoint(OpcUaScheme + host + path); + + if (config.assigned()) + { + if (config.hasProperty("Username")) + endpoint.setUsername(config.getPropertyValue("Username")); + if (config.hasProperty("Password")) + endpoint.setPassword(config.getPropertyValue("Password")); + } + + TmsClient client(context, parent, endpoint, createStreamingCallback); auto device = client.connect(); completeDeviceServerCapabilities(device, host); return device; diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h index 890c701..98dc243 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h @@ -30,6 +30,11 @@ class TmsClient final const ComponentPtr& parent, const std::string& opcUaUrl); + TmsClient(const ContextPtr& context, + const ComponentPtr& parent, + const OpcUaEndpoint& endpoint, + const FunctionPtr& createStreamingCallback); + daq::DevicePtr connect(); @@ -39,7 +44,7 @@ class TmsClient final tms::TmsClientContextPtr tmsClientContext; ContextPtr context; daq::opcua::OpcUaClientPtr client; - std::string opcUaUrl; + OpcUaEndpoint endpoint; ComponentPtr parent; LoggerComponentPtr loggerComponent; }; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp index 3b0366c..0c8556a 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp @@ -10,7 +10,6 @@ #include #include - #include #include #include @@ -22,9 +21,19 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA TmsClient::TmsClient(const ContextPtr& context, const ComponentPtr& parent, - const std::string& opcUaUrl) + const std::string& opcUaUrl, + const FunctionPtr& createStreamingCallback) + : TmsClient(context, parent, OpcUaEndpoint(opcUaUrl), createStreamingCallback) +{ +} + +TmsClient::TmsClient(const ContextPtr& context, + const ComponentPtr& parent, + const OpcUaEndpoint& endpoint, + const FunctionPtr& createStreamingCallback) : context(context) - , opcUaUrl(opcUaUrl) + , endpoint(endpoint) + , createStreamingCallback(createStreamingCallback) , parent(parent) , loggerComponent(context.getLogger().assigned() ? context.getLogger().getOrAddComponent("OpcUaClient") : throw ArgumentNullException("Logger must not be null")) @@ -35,7 +44,6 @@ daq::DevicePtr TmsClient::connect() { const auto startTime = std::chrono::steady_clock::now(); - OpcUaEndpoint endpoint(opcUaUrl); client = std::make_shared(endpoint); if (!client->connect()) throw NotFoundException(); @@ -78,7 +86,7 @@ daq::DevicePtr TmsClient::connect() const auto endTime = std::chrono::steady_clock::now(); const auto connectTime = std::chrono::duration(endTime - startTime); - LOG_D("Connected to openDAQ OPC UA server {}. Connect took {:.2f} s.", opcUaUrl, connectTime.count()); + LOG_D("Connected to openDAQ OPC UA server {}. Connect took {:.2f} s.", endpoint.getUrl(), connectTime.count()); return device; } From a6ccecbec108b613d36840c35f5901db4ae0d6e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Mon, 13 May 2024 10:19:37 +0200 Subject: [PATCH 134/217] Refactor opcua client connect() method to throw an exception on failed exception --- .../tests/test_opcua_server_module.cpp | 8 ++--- .../include/opcuaclient/opcuaclient.h | 2 +- .../opcua/opcuaclient/src/opcuaclient.cpp | 5 ++-- .../src/taskprocessor/opcuataskprocessor.cpp | 17 ++++++++++- .../tests/src/test_opcuaclient.cpp | 10 +++---- .../opcuaserver/tests/common_test_functions.h | 4 +-- .../testopcua/test_opcua_authentication.cpp | 11 ++++--- .../include/opcuatms_client/tms_client.h | 1 + .../opcuatms_client/src/tms_client.cpp | 29 +++++++++++++++---- 9 files changed, 60 insertions(+), 27 deletions(-) diff --git a/modules/opcua_server_module/tests/test_opcua_server_module.cpp b/modules/opcua_server_module/tests/test_opcua_server_module.cpp index 646589c..c9eba38 100644 --- a/modules/opcua_server_module/tests/test_opcua_server_module.cpp +++ b/modules/opcua_server_module/tests/test_opcua_server_module.cpp @@ -152,7 +152,7 @@ TEST_F(OpcUaServerModuleTest, TestConnection) device.addServer("openDAQ OpcUa", config); OpcUaClient client("opc.tcp://localhost/"); - ASSERT_TRUE(client.connect()); + ASSERT_NO_THROW(client.connect()); } TEST_F(OpcUaServerModuleTest, TestConnectionDifferentPort) @@ -166,7 +166,7 @@ TEST_F(OpcUaServerModuleTest, TestConnectionDifferentPort) auto serverPtr = module.createServer("openDAQ OpcUa", device.getRootDevice(), config); OpcUaClient client("opc.tcp://localhost:4841/"); - ASSERT_TRUE(client.connect()); + ASSERT_NO_THROW(client.connect()); } TEST_F(OpcUaServerModuleTest, StopServer) @@ -178,9 +178,9 @@ TEST_F(OpcUaServerModuleTest, StopServer) auto serverPtr = module.createServer("openDAQ OpcUa", device.getRootDevice(), config); OpcUaClient client("opc.tcp://localhost/"); - ASSERT_TRUE(client.connect()); + ASSERT_NO_THROW(client.connect()); client.disconnect(); serverPtr.stop(); - ASSERT_FALSE(client.connect()); + ASSERT_THROW(client.connect(), OpcUaException); } diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h index bcf44fc..cbe3fed 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h @@ -101,7 +101,7 @@ class OpcUaClient static constexpr size_t CONNECTION_TIMEOUT_SECONDS = 10; void initialize(); - bool connect(); + void connect(); void disconnect(); void clear(); bool isConnected(); diff --git a/shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp b/shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp index 18f4576..424b562 100644 --- a/shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp +++ b/shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp @@ -196,7 +196,7 @@ UA_Client* UaClientFactory::build() return client; } -bool OpcUaClient::connect() +void OpcUaClient::connect() { std::lock_guard guard(getLock()); @@ -211,7 +211,8 @@ bool OpcUaClient::connect() status = UA_Client_connectUsername(uaclient, endpoint.getUrl().c_str(), endpoint.getUsername().c_str(), endpoint.getPassword().c_str()); - return OPCUA_STATUSCODE_SUCCEEDED(status); + if (!OPCUA_STATUSCODE_SUCCEEDED(status)) + throw OpcUaException(status, "Failed to connect to OpcUa server"); } void OpcUaClient::disconnect() diff --git a/shared/libraries/opcua/opcuaclient/src/taskprocessor/opcuataskprocessor.cpp b/shared/libraries/opcua/opcuaclient/src/taskprocessor/opcuataskprocessor.cpp index 51e007d..0909116 100644 --- a/shared/libraries/opcua/opcuaclient/src/taskprocessor/opcuataskprocessor.cpp +++ b/shared/libraries/opcua/opcuaclient/src/taskprocessor/opcuataskprocessor.cpp @@ -65,7 +65,22 @@ void OpcUaTaskProcessor::executeTask(std::promise& promise, const OpcUaTas bool OpcUaTaskProcessor::connect() { bool result = false; - executeTask([&result](OpcUaClient& client) { result = client.connect(); }); + + auto connectTask = [&result](OpcUaClient& client) + { + try + { + client.connect(); + } + catch (const OpcUaException& /*e*/) + { + // ignored + } + + result = client.isConnected(); + }; + + executeTask(connectTask); return result; } diff --git a/shared/libraries/opcua/opcuaclient/tests/src/test_opcuaclient.cpp b/shared/libraries/opcua/opcuaclient/tests/src/test_opcuaclient.cpp index 0c8bc53..d2d6fd7 100644 --- a/shared/libraries/opcua/opcuaclient/tests/src/test_opcuaclient.cpp +++ b/shared/libraries/opcua/opcuaclient/tests/src/test_opcuaclient.cpp @@ -51,7 +51,7 @@ TEST_F(OpcUaClientTest, Connect) { OpcUaClient client(getServerUrl()); - ASSERT_TRUE(client.connect()); + client.connect(); ASSERT_TRUE(client.isConnected()); client.disconnect(); ASSERT_FALSE(client.isConnected()); @@ -65,13 +65,13 @@ TEST_F_OPTIONAL(OpcUaClientTest, FirstConnectFails) client.setTimeout(500); - ASSERT_FALSE(client.connect()); + ASSERT_THROW(client.connect(), OpcUaException); ASSERT_FALSE(client.isConnected()); testHelper.startServer(); client.disconnect(); - ASSERT_TRUE(client.connect()); + ASSERT_THROW(client.connect(), OpcUaException); ASSERT_TRUE(client.isConnected()); client.disconnect(); @@ -118,7 +118,7 @@ TEST_F_OPTIONAL(OpcUaClientTest, ConnectTimeout) OpcUaClient client(getServerUrl()); - ASSERT_TRUE(client.connect()); + ASSERT_THROW(client.connect(), OpcUaException); ASSERT_TRUE(client.isConnected()); auto uaNode = OpcUaNodeId(1, ".d"); @@ -130,7 +130,7 @@ TEST_F_OPTIONAL(OpcUaClientTest, ConnectTimeout) ASSERT_THROW(client.nodeExists(uaNode), OpcUaException); client.disconnect(); - ASSERT_TRUE(client.connect()); + ASSERT_THROW(client.connect(), OpcUaException); ASSERT_TRUE(client.isConnected()); ASSERT_TRUE(client.nodeExists(uaNode)); diff --git a/shared/libraries/opcua/opcuaserver/tests/common_test_functions.h b/shared/libraries/opcua/opcuaserver/tests/common_test_functions.h index e71c065..aba7a5b 100644 --- a/shared/libraries/opcua/opcuaserver/tests/common_test_functions.h +++ b/shared/libraries/opcua/opcuaserver/tests/common_test_functions.h @@ -37,8 +37,8 @@ inline UA_Client* CreateClient() inline std::shared_ptr CreateClientAndConnect() { auto client = std::make_shared(SERVER_URL); - if (!client->connect()) - throw std::runtime_error("Fail to connect"); + client->connect(); + assert(client->isConnected()); return client; } diff --git a/shared/libraries/opcua/tests/testopcua/test_opcua_authentication.cpp b/shared/libraries/opcua/tests/testopcua/test_opcua_authentication.cpp index eb84e1b..ac54d36 100644 --- a/shared/libraries/opcua/tests/testopcua/test_opcua_authentication.cpp +++ b/shared/libraries/opcua/tests/testopcua/test_opcua_authentication.cpp @@ -27,8 +27,7 @@ TEST_F(OpcUaAuthenticationTest, NoAnonymous) server.start(); auto client = OpcUaClient("opc.tcp://127.0.0.1"); - client.connect(); - ASSERT_FALSE(client.isConnected()); + ASSERT_THROW(client.connect(), OpcUaException); } TEST_F(OpcUaAuthenticationTest, AuthenticationProvider) @@ -46,14 +45,14 @@ TEST_F(OpcUaAuthenticationTest, AuthenticationProvider) OpcUaClientPtr client; client = std::make_shared("opc.tcp://127.0.0.1"); - ASSERT_TRUE(client->connect()); + ASSERT_NO_THROW(client->connect()); client = std::make_shared(OpcUaEndpoint("opc.tcp://127.0.0.1", "jure", "wrongPass")); - ASSERT_FALSE(client->connect()); + ASSERT_THROW(client->connect(), OpcUaException); client = std::make_shared(OpcUaEndpoint("opc.tcp://127.0.0.1", "jure", "jure123")); - ASSERT_TRUE(client->connect()); + ASSERT_NO_THROW(client->connect()); client = std::make_shared(OpcUaEndpoint("opc.tcp://127.0.0.1", "tomaz", "tomaz123")); - ASSERT_TRUE(client->connect()); + ASSERT_NO_THROW(client->connect()); } diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h index 98dc243..5a803f8 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h @@ -40,6 +40,7 @@ class TmsClient final protected: void getRootDeviceNodeAttributes(OpcUaNodeId& nodeIdOut, std::string& browseNameOut); + void createAndConectClient(); tms::TmsClientContextPtr tmsClientContext; ContextPtr context; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp index 0c8556a..e68a5c3 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp @@ -44,9 +44,7 @@ daq::DevicePtr TmsClient::connect() { const auto startTime = std::chrono::steady_clock::now(); - client = std::make_shared(endpoint); - if (!client->connect()) - throw NotFoundException(); + createAndConectClient(); client->runIterate(); // A first connect is needed to read from the server the available namespaces out from the server @@ -57,9 +55,8 @@ daq::DevicePtr TmsClient::connect() // After a disconnect, we need to register the data types, but only these which are available on server side. registerDaqTypes(endpoint, namespaces); - client = std::make_shared(endpoint); - if (!client->connect()) - throw NotFoundException(); + + createAndConectClient(); client->runIterate(); tmsClientContext = std::make_shared(client, context); @@ -107,4 +104,24 @@ void TmsClient::getRootDeviceNodeAttributes(OpcUaNodeId& nodeIdOut, std::string& browseNameOut = references.byBrowseName.begin().key(); } +void TmsClient::createAndConectClient() +{ + try + { + client = std::make_shared(endpoint); + client->connect(); + } + catch (const OpcUaException& e) + { + switch (e.getStatusCode()) + { + case UA_STATUSCODE_BADUSERACCESSDENIED: + case UA_STATUSCODE_BADIDENTITYTOKENINVALID: + throw AuthenticationFailedException(e.what()); + default: + throw NotFoundException(e.what()); + } + } +} + END_NAMESPACE_OPENDAQ_OPCUA From d64a6367128460d430574b53428b6e984a7dd51e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Mon, 13 May 2024 12:54:56 +0200 Subject: [PATCH 135/217] Fix merge conflicts --- .../opcua_client_module_impl.h | 1 + .../src/opcua_client_module_impl.cpp | 25 ++++++++++++++----- .../tests/test_opcua_client_module.cpp | 2 +- .../include/opcuatms_client/tms_client.h | 3 +-- .../opcuatms_client/src/tms_client.cpp | 9 +++---- 5 files changed, 25 insertions(+), 15 deletions(-) diff --git a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h index a8ef7ec..072af08 100644 --- a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h +++ b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h @@ -36,6 +36,7 @@ class OpcUaClientModule final : public Module private: static std::tuple ParseConnectionString(const StringPtr& connectionString); static DeviceTypePtr createDeviceType(); + static PropertyObjectPtr createDefaultConfig(); static void completeDeviceServerCapabilities(const DevicePtr& device, const StringPtr& deviceAddress); discovery::DiscoveryClient discoveryClient; diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 6e49665..0b7815d 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -11,6 +11,7 @@ #include #include #include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_CLIENT_MODULE @@ -66,17 +67,20 @@ DictPtr OpcUaClientModule::onGetAvailableDeviceTypes() auto deviceType = createDeviceType(); result.set(deviceType.getId(), deviceType); - return result; } DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, const ComponentPtr& parent, - const PropertyObjectPtr& config) + const PropertyObjectPtr& aConfig) { if (!connectionString.assigned()) throw ArgumentNullException(); + PropertyObjectPtr config = aConfig; + if (!config.assigned()) + config = createDefaultConfig(); + if (!onAcceptsConnectionParameters(connectionString, config)) throw InvalidParameterException(); @@ -102,7 +106,7 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, endpoint.setPassword(config.getPropertyValue("Password")); } - TmsClient client(context, parent, endpoint, createStreamingCallback); + TmsClient client(context, parent, endpoint); auto device = client.connect(); completeDeviceServerCapabilities(device, host); return device; @@ -148,9 +152,18 @@ bool OpcUaClientModule::onAcceptsConnectionParameters(const StringPtr& connectio DeviceTypePtr OpcUaClientModule::createDeviceType() { - return DeviceType(DaqOpcUaDeviceTypeId, - "OpcUa enabled device", - "Network device connected over OpcUa protocol"); + const auto config = createDefaultConfig(); + return DeviceType(DaqOpcUaDeviceTypeId, "OpcUa enabled device", "Network device connected over OpcUa protocol", config); +} + +PropertyObjectPtr OpcUaClientModule::createDefaultConfig() +{ + auto config = PropertyObject(); + + config.addProperty(StringProperty("Username", "")); + config.addProperty(StringProperty("Password", "")); + + return config; } END_NAMESPACE_OPENDAQ_OPCUA_CLIENT_MODULE diff --git a/modules/opcua_client_module/tests/test_opcua_client_module.cpp b/modules/opcua_client_module/tests/test_opcua_client_module.cpp index b5a80e4..657ee6b 100644 --- a/modules/opcua_client_module/tests/test_opcua_client_module.cpp +++ b/modules/opcua_client_module/tests/test_opcua_client_module.cpp @@ -150,7 +150,7 @@ TEST_F(OpcUaClientModuleTest, DefaultDeviceConfig) ASSERT_TRUE(deviceTypes.hasKey("opendaq_opcua_config")); auto config = deviceTypes.get("opendaq_opcua_config").createDefaultConfig(); ASSERT_TRUE(config.assigned()); - ASSERT_EQ(config.getAllProperties().getCount(), 0u); + ASSERT_EQ(config.getAllProperties().getCount(), 2u); } TEST_F(OpcUaClientModuleTest, CreateFunctionBlockIdNull) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h index 5a803f8..0dbe915 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h @@ -32,8 +32,7 @@ class TmsClient final TmsClient(const ContextPtr& context, const ComponentPtr& parent, - const OpcUaEndpoint& endpoint, - const FunctionPtr& createStreamingCallback); + const OpcUaEndpoint& endpoint); daq::DevicePtr connect(); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp index e68a5c3..a421775 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp @@ -21,19 +21,16 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA TmsClient::TmsClient(const ContextPtr& context, const ComponentPtr& parent, - const std::string& opcUaUrl, - const FunctionPtr& createStreamingCallback) - : TmsClient(context, parent, OpcUaEndpoint(opcUaUrl), createStreamingCallback) + const std::string& opcUaUrl) + : TmsClient(context, parent, OpcUaEndpoint(opcUaUrl)) { } TmsClient::TmsClient(const ContextPtr& context, const ComponentPtr& parent, - const OpcUaEndpoint& endpoint, - const FunctionPtr& createStreamingCallback) + const OpcUaEndpoint& endpoint) : context(context) , endpoint(endpoint) - , createStreamingCallback(createStreamingCallback) , parent(parent) , loggerComponent(context.getLogger().assigned() ? context.getLogger().getOrAddComponent("OpcUaClient") : throw ArgumentNullException("Logger must not be null")) From a9dcbcb2f392bf60a2da0dbd5342fc70fb168332 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Mon, 13 May 2024 15:16:20 +0200 Subject: [PATCH 136/217] Fix gcc build errors --- shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp b/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp index 81abc76..bdddcbd 100644 --- a/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp +++ b/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp @@ -56,12 +56,12 @@ void OpcUaServer::setAuthenticationProvider(const AuthenticationProviderPtr& aut void OpcUaServer::setSecurityConfig(OpcUaServerSecurityConfig* config) { - throw std::exception("method setSecurityConfig() is deprecated"); + throw std::runtime_error("method setSecurityConfig() is deprecated"); } const OpcUaServerSecurityConfig* OpcUaServer::getSecurityConfig() const { - throw std::exception("method getSecurityConfig() is deprecated"); + throw std::runtime_error("method getSecurityConfig() is deprecated"); } void OpcUaServer::start() From 1d52b153648b465e437c80ea5f7ad75660f57d77 Mon Sep 17 00:00:00 2001 From: Dejan Crnila Date: Thu, 16 May 2024 11:41:45 +0200 Subject: [PATCH 137/217] Fix MSVC 2017 compilation --- shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp b/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp index bdddcbd..1a6490e 100644 --- a/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp +++ b/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp @@ -581,11 +581,11 @@ void OpcUaServer::closeSession(UA_Server* server, UA_AccessControl* ac, const UA UA_StatusCode OpcUaServer::generateChildId(UA_Server* server, - const UA_NodeId*/*sessionId*/, - void*/*sessionContext*/, + const UA_NodeId* /*sessionId*/, + void* /*sessionContext*/, const UA_NodeId* sourceNodeId, const UA_NodeId* targetParentNodeId, - const UA_NodeId*/*referenceTypeId*/, + const UA_NodeId* /*referenceTypeId*/, UA_NodeId* targetNodeId) { if (targetParentNodeId->identifierType == UA_NODEIDTYPE_STRING) { From 905c9ebc9d6a2defa0f69a3739b5e7876ebd4951 Mon Sep 17 00:00:00 2001 From: Nikolai Shipilov Date: Mon, 29 Apr 2024 20:18:31 +0200 Subject: [PATCH 138/217] Streaming connection/configuration updates: * Enable support of any streaming protocol type for native-config device * order streaming sources of mirrored device by protocols priority set up by user config * test MIN_HOPS/MIN_CONNECTIONS streaming heuristics with native-config device * use streaming heuristic config for "daq://", "daq.nd://", "daq.opcua://" connection prefixes * add addStreaming method on IDevice interface * remove "FALLBACKS" streaming heuristic * use separate connections for native streaming and native configuration * extend IModule interface to create connection string from ServerCapability instead of creating streaming directly from capability * support config object with connection parameters when creating streaming from module * rework module integration tests for subdevices testing --- .../opcua_client_module_impl.h | 1 + .../src/opcua_client_module_impl.cpp | 24 ++++++++++++++++++ .../tests/test_opcua_client_module.cpp | 25 +++++++++++++++++++ .../opcuatms_server/src/tms_server.cpp | 2 ++ 4 files changed, 52 insertions(+) diff --git a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h index 072af08..c5784a9 100644 --- a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h +++ b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h @@ -32,6 +32,7 @@ class OpcUaClientModule final : public Module const ComponentPtr& parent, const PropertyObjectPtr& config) override; bool onAcceptsConnectionParameters(const StringPtr& connectionString, const PropertyObjectPtr& config) override; + StringPtr onCreateConnectionString(const ServerCapabilityPtr& serverCapability) override; private: static std::tuple ParseConnectionString(const StringPtr& connectionString); diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 0b7815d..984583c 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -166,4 +166,28 @@ PropertyObjectPtr OpcUaClientModule::createDefaultConfig() return config; } +StringPtr OpcUaClientModule::onCreateConnectionString(const ServerCapabilityPtr& serverCapability) +{ + if (serverCapability.getProtocolId() != "opendaq_opcua_config") + return nullptr; + + StringPtr connectionString = serverCapability.getConnectionString(); + if (connectionString.getLength() != 0) + return connectionString; + + StringPtr address; + if (ListPtr addresses = serverCapability.getAddresses(); addresses.getCount() > 0) + { + address = addresses[0]; + } + if (!address.assigned() || address.toStdString().empty()) + throw InvalidParameterException("Address is not set"); + + if (!serverCapability.hasProperty("Port")) + throw InvalidParameterException("Port is not set"); + auto port = serverCapability.getPropertyValue("Port").template asPtr(); + + return fmt::format("{}{}:{}", DaqOpcUaDevicePrefix, address, port); +} + END_NAMESPACE_OPENDAQ_OPCUA_CLIENT_MODULE diff --git a/modules/opcua_client_module/tests/test_opcua_client_module.cpp b/modules/opcua_client_module/tests/test_opcua_client_module.cpp index 657ee6b..718ebb0 100644 --- a/modules/opcua_client_module/tests/test_opcua_client_module.cpp +++ b/modules/opcua_client_module/tests/test_opcua_client_module.cpp @@ -5,7 +5,9 @@ #include #include +#include #include +#include #include @@ -59,6 +61,29 @@ TEST_F(OpcUaClientModuleTest, EnumerateDevices) ASSERT_NO_THROW(deviceInfo = module.getAvailableDevices()); } +TEST_F(OpcUaClientModuleTest, CreateConnectionString) +{ + auto context = NullContext(); + ModulePtr module; + createModule(&module, context); + + StringPtr connectionString; + + ServerCapabilityConfigPtr serverCapabilityIgnored = ServerCapability("test", "test", ProtocolType::Unknown); + ASSERT_NO_THROW(connectionString = module.createConnectionString(serverCapabilityIgnored)); + ASSERT_FALSE(connectionString.assigned()); + + ServerCapabilityConfigPtr serverCapability = ServerCapability("opendaq_opcua_config", "openDAQ OpcUa", ProtocolType::Configuration); + ASSERT_THROW(module.createConnectionString(serverCapability), InvalidParameterException); + + serverCapability.addAddress("123.123.123.123"); + ASSERT_THROW(module.createConnectionString(serverCapability), InvalidParameterException); + + serverCapability.addProperty(IntProperty("Port", 1234)); + ASSERT_NO_THROW(connectionString = module.createConnectionString(serverCapability)); + ASSERT_EQ(connectionString, "daq.opcua://123.123.123.123:1234"); +} + TEST_F(OpcUaClientModuleTest, AcceptsConnectionStringNull) { auto module = CreateModule(); diff --git a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp index 0c2ba8a..a4b47e3 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp @@ -5,6 +5,7 @@ #include #include #include +#include using namespace daq::opcua; using namespace daq::opcua::tms; @@ -51,6 +52,7 @@ void TmsServer::start() auto serverCapability = ServerCapability("opendaq_opcua_config", "openDAQ OpcUa", ProtocolType::Configuration); serverCapability.setPrefix("daq.opcua"); serverCapability.setConnectionType("TCP/IP"); + serverCapability.addProperty(IntProperty("Port", opcUaPort)); device.getInfo().asPtr().addServerCapability(serverCapability); tmsDevice = std::make_unique(device, server, context, tmsContext); From 9871ddd12e66d6b2bd9d670005eed6e9cdd1df8e Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Fri, 10 May 2024 12:39:14 +0200 Subject: [PATCH 139/217] Sync location and name between device and device info --- .../src/opcua_client_module_impl.cpp | 23 +++++++++------ .../src/objects/tms_client_device_impl.cpp | 2 +- .../tms_client_property_object_impl.cpp | 14 +++++----- .../opcuatms_integration/test_tms_device.cpp | 28 ++++++++++++++++++- 4 files changed, 50 insertions(+), 17 deletions(-) diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 984583c..f07bb61 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -31,15 +31,22 @@ OpcUaClientModule::OpcUaClientModule(ContextPtr context) { [context = this->context](const MdnsDiscoveredDevice& discoveredDevice) { - auto connectionStringIpv4 = DaqOpcUaDevicePrefix + discoveredDevice.ipv4Address + "/"; - auto connectionStringIpv6 = fmt::format("{}[{}]/", - DaqOpcUaDevicePrefix, - discoveredDevice.ipv6Address); auto cap = ServerCapability("opendaq_opcua_config", "openDAQ OpcUa", ProtocolType::Configuration); - cap.addConnectionString(connectionStringIpv4); - cap.addAddress(discoveredDevice.ipv4Address); - cap.addConnectionString(connectionStringIpv6); - cap.addAddress("[" + discoveredDevice.ipv6Address + "]"); + + if (!discoveredDevice.ipv4Address.empty()) + { + auto connectionStringIpv4 = DaqOpcUaDevicePrefix + discoveredDevice.ipv4Address + "/"; + cap.addConnectionString(connectionStringIpv4); + cap.addAddress(discoveredDevice.ipv4Address); + } + + if(!discoveredDevice.ipv6Address.empty()) + { + auto connectionStringIpv6 = fmt::format("{}[{}]/", DaqOpcUaDevicePrefix, discoveredDevice.ipv6Address); + cap.addConnectionString(connectionStringIpv6); + cap.addAddress("[" + discoveredDevice.ipv6Address + "]"); + } + cap.setConnectionType("TCP/IP"); cap.setPrefix("daq.opcua"); return cap; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 50e56d9..4a696ff 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -131,7 +131,7 @@ void TmsClientDeviceImpl::onRemoveDevice(const DevicePtr& /*device*/) DeviceInfoPtr TmsClientDeviceImpl::onGetInfo() { - auto deviceInfo = DeviceInfo("", "OpcUa Client"); + auto deviceInfo = DeviceInfo("", this->client->readDisplayName(this->nodeId)); auto browseFilter = BrowseFilter(); browseFilter.nodeClass = UA_NODECLASS_VARIABLE; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index a4e2725..c314256 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -34,7 +34,7 @@ ErrCode TmsClientPropertyObjectBaseImpl::setPropertyValueInternal(IString* } auto propertyNamePtr = StringPtr::Borrow(propertyName); - StringPtr lastProccessDescription = ""; + StringPtr lastProcessDescription = ""; ErrCode errCode = daqTry( [&]() { @@ -44,7 +44,7 @@ ErrCode TmsClientPropertyObjectBaseImpl::setPropertyValueInternal(IString* checkErrorInfo(getProperty(propertyName, &prop)); if (protectedWrite) { - lastProccessDescription = "Checking exisiting property is read-only"; + lastProcessDescription = "Checking existing property is read-only"; const bool readOnly = prop.getReadOnly(); if (readOnly) return OPENDAQ_SUCCESS; @@ -56,7 +56,7 @@ ErrCode TmsClientPropertyObjectBaseImpl::setPropertyValueInternal(IString* if (ct != valueCt) valuePtr = valuePtr.convertTo(ct); - lastProccessDescription = "Writing property value"; + lastProcessDescription = "Writing property value"; const auto variant = VariantConverter::ToVariant(valuePtr, nullptr, daqContext); client->writeValue(it->second, variant); return OPENDAQ_SUCCESS; @@ -64,21 +64,21 @@ ErrCode TmsClientPropertyObjectBaseImpl::setPropertyValueInternal(IString* if (const auto& it = referenceVariableIdMap.find(propertyNamePtr); it != referenceVariableIdMap.cend()) { - lastProccessDescription = "Setting property value"; + lastProcessDescription = "Setting property value"; const auto refProp = this->objPtr.getProperty(propertyName).getReferencedProperty(); return setPropertyValue(refProp.getName(), value); } if (const auto& it = objectTypeIdMap.find((propertyNamePtr)); it != objectTypeIdMap.cend()) { - lastProccessDescription = "Object type properties cannot be set over OpcUA"; + lastProcessDescription = "Object type properties cannot be set over OpcUA"; return OPENDAQ_ERR_NOTIMPLEMENTED; } - lastProccessDescription = "Property not found"; + lastProcessDescription = "Property not found"; return OPENDAQ_ERR_NOTFOUND; }); if (OPENDAQ_FAILED(errCode)) - LOG_W("Failed to set value for property \"{}\" on OpcUA client property object: {}", propertyNamePtr, lastProccessDescription); + LOG_W("Failed to set value for property \"{}\" on OpcUA client property object: {}", propertyNamePtr, lastProcessDescription); if (errCode == OPENDAQ_ERR_NOTFOUND) return errCode; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp index 33c66f3..eedbe97 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp @@ -103,7 +103,7 @@ TEST_F(TmsDeviceTest, GetSignals) { auto name = subDevice.getName(); ASSERT_NO_THROW(signals = subDevice.getSignals()); - if (name == "mockdev") + if (name == "MockPhysicalDevice") ASSERT_EQ(signals.getCount(), 1u); else ASSERT_EQ(signals.getCount(), 0u); @@ -505,3 +505,29 @@ TEST_F(TmsDeviceTest, SdkPackageVersion) ASSERT_EQ(clientDevice.getInfo().getSdkVersion(), OPENDAQ_PACKAGE_VERSION); } + +TEST_F(TmsDeviceTest, DeviceInfoChanges) +{ + const auto ctx = NullContext(); + const DevicePtr serverDevice = createDevice(); + + auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); + const auto nodeId = serverTmsDevice.registerOpcUaNode(); + const auto serverDeviceInfo = serverDevice.getDevices()[1].getInfo(); + + const auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId); + const auto clientSubDevice = clientDevice.getDevices()[1]; + const auto clientDeviceInfo = clientSubDevice.getInfo(); + + ASSERT_EQ(serverDeviceInfo.getName(), clientDeviceInfo.getName()); + ASSERT_EQ(serverDeviceInfo.getLocation(), clientDeviceInfo.getLocation()); + + clientSubDevice.setName("new_name"); + clientSubDevice.setPropertyValue("location", "new_location"); + + ASSERT_EQ("new_name", clientDeviceInfo.getName()); + ASSERT_EQ("new_location", clientDeviceInfo.getLocation()); + + ASSERT_EQ(serverDeviceInfo.getName(), clientDeviceInfo.getName()); + ASSERT_EQ(serverDeviceInfo.getLocation(), clientDeviceInfo.getLocation()); +} From e8db04905e7f2d8423fae89af45d5cc7dc774dc9 Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Tue, 28 May 2024 14:51:04 +0200 Subject: [PATCH 140/217] [TBBAS-1313] mDNS discovery service in SDK (openDAQ/openDAQ#294) -add ability to make server discovered by mdns -support overriding default server configs from config provider (for native/opcua/streaming lt) -support setting path for opcua server -fix reading port from connection string in opcua client -update quick_start_simulator and device simulator to use discovery -update doc --- .../opcua_client_module_impl.h | 2 +- .../src/opcua_client_module_impl.cpp | 53 ++++++++++++------- .../opcua_server_module/opcua_server_impl.h | 7 +-- .../src/opcua_server_impl.cpp | 44 ++++++++++++--- .../src/opcua_server_module_impl.cpp | 4 +- 5 files changed, 80 insertions(+), 30 deletions(-) diff --git a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h index c5784a9..765c223 100644 --- a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h +++ b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h @@ -35,7 +35,7 @@ class OpcUaClientModule final : public Module StringPtr onCreateConnectionString(const ServerCapabilityPtr& serverCapability) override; private: - static std::tuple ParseConnectionString(const StringPtr& connectionString); + static std::tuple ParseConnectionString(const StringPtr& connectionString); static DeviceTypePtr createDeviceType(); static PropertyObjectPtr createDefaultConfig(); static void completeDeviceServerCapabilities(const DevicePtr& device, const StringPtr& deviceAddress); diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index f07bb61..1a89136 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -29,24 +29,29 @@ OpcUaClientModule::OpcUaClientModule(ContextPtr context) "OpcUaClient") , discoveryClient( { - [context = this->context](const MdnsDiscoveredDevice& discoveredDevice) + [context = this->context](MdnsDiscoveredDevice discoveredDevice) { auto cap = ServerCapability("opendaq_opcua_config", "openDAQ OpcUa", ProtocolType::Configuration); - if (!discoveredDevice.ipv4Address.empty()) { - auto connectionStringIpv4 = DaqOpcUaDevicePrefix + discoveredDevice.ipv4Address + "/"; + auto connectionStringIpv4 = fmt::format("{}{}:{}{}", + DaqOpcUaDevicePrefix, + discoveredDevice.ipv4Address, + discoveredDevice.servicePort, + discoveredDevice.getPropertyOrDefault("path", "/")); cap.addConnectionString(connectionStringIpv4); cap.addAddress(discoveredDevice.ipv4Address); } - if(!discoveredDevice.ipv6Address.empty()) { - auto connectionStringIpv6 = fmt::format("{}[{}]/", DaqOpcUaDevicePrefix, discoveredDevice.ipv6Address); + auto connectionStringIpv6 = fmt::format("{}[{}]:{}{}", + DaqOpcUaDevicePrefix, + discoveredDevice.ipv6Address, + discoveredDevice.servicePort, + discoveredDevice.getPropertyOrDefault("path", "/")); cap.addConnectionString(connectionStringIpv6); cap.addAddress("[" + discoveredDevice.ipv6Address + "]"); } - cap.setConnectionType("TCP/IP"); cap.setPrefix("daq.opcua"); return cap; @@ -97,13 +102,14 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, auto parsedConnection = ParseConnectionString(connectionString); auto prefix = std::get<0>(parsedConnection); auto host = std::get<1>(parsedConnection); - auto path = std::get<2>(parsedConnection); + auto port = std::get<2>(parsedConnection); + auto path = std::get<3>(parsedConnection); if (prefix != DaqOpcUaDevicePrefix) - throw InvalidParameterException("OpcUa does not support connection string with prefix"); + throw InvalidParameterException("OpcUa does not support connection string with prefix " + prefix); std::scoped_lock lock(sync); - auto endpoint = OpcUaEndpoint(OpcUaScheme + host + path); + auto endpoint = OpcUaEndpoint(OpcUaScheme + host + ":" + port + path); if (config.assigned()) { @@ -131,20 +137,31 @@ void OpcUaClientModule::completeDeviceServerCapabilities(const DevicePtr& device } } -std::tuple OpcUaClientModule::ParseConnectionString(const StringPtr& connectionString) +// {prefix://}{hostname}:{port}{/path} +std::tuple OpcUaClientModule::ParseConnectionString(const StringPtr& connectionString) { + std::string port = "4840"; + std::string target = "/"; std::string urlString = connectionString.toStdString(); - auto regexIpv6Hostname = std::regex("^(.*:\\/\\/)(\\[[a-fA-F0-9:]+\\])(.*)"); - auto regexIpv4Hostname = std::regex("^(.*:\\/\\/)([^:\\/\\s]+)(.*)"); + auto regexIpv6Hostname = std::regex(R"(^(.*://)?(\[[a-fA-F0-9:]+\])(?::(\d+))?(/.*)?$)"); + auto regexIpv4Hostname = std::regex(R"(^(.*://)?([^:/\s]+)(?::(\d+))?(/.*)?$)"); std::smatch match; - if (std::regex_search(urlString, match, regexIpv6Hostname)) - return {match[1],match[2],match[3]}; - if (std::regex_search(urlString, match, regexIpv4Hostname)) - return {match[1],match[2],match[3]}; - - throw InvalidParameterException("Host name not found in url: {}", connectionString); + bool parsed = false; + parsed = std::regex_search(urlString, match, regexIpv6Hostname); + if (!parsed) + parsed = std::regex_search(urlString, match, regexIpv4Hostname); + + if (!parsed) + throw InvalidParameterException("Host name not found in url: {}", connectionString); + + if (match[3].matched) + port = match[3]; + if (match[4].matched) + target = match[4]; + + return {match[1], match[2], port, target}; } bool OpcUaClientModule::onAcceptsConnectionParameters(const StringPtr& connectionString, const PropertyObjectPtr& config) diff --git a/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h b/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h index 7564f15..56405c3 100644 --- a/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h +++ b/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h @@ -29,14 +29,15 @@ class OpcUaServerImpl : public daq::Server public: explicit OpcUaServerImpl(daq::DevicePtr rootDevice, PropertyObjectPtr config, const ContextPtr& context); ~OpcUaServerImpl(); - static PropertyObjectPtr createDefaultConfig(); - static ServerTypePtr createType(); + static PropertyObjectPtr createDefaultConfig(const ContextPtr& context); + static ServerTypePtr createType(const ContextPtr& context); protected: + PropertyObjectPtr getDiscoveryConfig() override; void onStopServer() override; + static void populateDefaultConfigFromProvider(const ContextPtr& context, const PropertyObjectPtr& config); daq::opcua::TmsServer server; - PropertyObjectPtr config; ContextPtr context; }; diff --git a/modules/opcua_server_module/src/opcua_server_impl.cpp b/modules/opcua_server_module/src/opcua_server_impl.cpp index 4c9bcf5..32d31cc 100644 --- a/modules/opcua_server_module/src/opcua_server_impl.cpp +++ b/modules/opcua_server_module/src/opcua_server_impl.cpp @@ -11,9 +11,8 @@ using namespace daq; using namespace daq::opcua; OpcUaServerImpl::OpcUaServerImpl(DevicePtr rootDevice, PropertyObjectPtr config, const ContextPtr& context) - : Server(nullptr, rootDevice, nullptr, nullptr) + : Server("OpcUaServer", config, rootDevice, context, nullptr) , server(rootDevice, context) - , config(config) , context(context) { const uint16_t port = config.getPropertyValue("Port"); @@ -26,25 +25,58 @@ OpcUaServerImpl::~OpcUaServerImpl() { } -PropertyObjectPtr OpcUaServerImpl::createDefaultConfig() +void OpcUaServerImpl::populateDefaultConfigFromProvider(const ContextPtr& context, const PropertyObjectPtr& config) +{ + if (!context.assigned()) + return; + if (!config.assigned()) + return; + + auto options = context.getModuleOptions("OpcUaServer"); + for (const auto& [key, value] : options) + { + if (config.hasProperty(key)) + { + config->setPropertyValue(key, value); + } + } +} + +PropertyObjectPtr OpcUaServerImpl::createDefaultConfig(const ContextPtr& context) { constexpr Int minPortValue = 0; constexpr Int maxPortValue = 65535; auto defaultConfig = PropertyObject(); - const auto portProp = IntPropertyBuilder("Port", 4840).setMinValue(minPortValue).setMaxValue(maxPortValue).build(); + const auto portProp = IntPropertyBuilder("Port", 4840) + .setMinValue(minPortValue) + .setMaxValue(maxPortValue) + .build(); defaultConfig.addProperty(portProp); + defaultConfig.addProperty(StringProperty("Path", "/")); + + populateDefaultConfigFromProvider(context, defaultConfig); return defaultConfig; } -ServerTypePtr OpcUaServerImpl::createType() +PropertyObjectPtr OpcUaServerImpl::getDiscoveryConfig() +{ + auto discoveryConfig = PropertyObject(); + discoveryConfig.addProperty(StringProperty("ServiceName", "_opcua-tcp._tcp.local.")); + discoveryConfig.addProperty(StringProperty("ServiceCap", "OPENDAQ")); + discoveryConfig.addProperty(StringProperty("Path", config.getPropertyValue("Path"))); + discoveryConfig.addProperty(IntProperty("Port", config.getPropertyValue("Port"))); + return discoveryConfig; +} + +ServerTypePtr OpcUaServerImpl::createType(const ContextPtr& context) { return ServerType("openDAQ OpcUa", "openDAQ OpcUa server", "Publishes device structure over OpcUa protocol", - OpcUaServerImpl::createDefaultConfig()); + OpcUaServerImpl::createDefaultConfig(context)); } void OpcUaServerImpl::onStopServer() diff --git a/modules/opcua_server_module/src/opcua_server_module_impl.cpp b/modules/opcua_server_module/src/opcua_server_module_impl.cpp index a8d7c3b..939f350 100644 --- a/modules/opcua_server_module/src/opcua_server_module_impl.cpp +++ b/modules/opcua_server_module/src/opcua_server_module_impl.cpp @@ -18,7 +18,7 @@ DictPtr OpcUaServerModule::onGetAvailableServerTypes() { auto result = Dict(); - auto serverType = OpcUaServerImpl::createType(); + auto serverType = OpcUaServerImpl::createType(context); result.set(serverType.getId(), serverType); return result; @@ -32,7 +32,7 @@ ServerPtr OpcUaServerModule::onCreateServer(StringPtr serverType, throw InvalidParameterException{"Context parameter cannot be null."}; if (!serverConfig.assigned()) - serverConfig = OpcUaServerImpl::createDefaultConfig(); + serverConfig = OpcUaServerImpl::createDefaultConfig(context); ServerPtr server(OpcUaServer_Create(rootDevice, serverConfig, context)); return server; From 8f12c7a61a2c59aba9e6c6dad67959130f2292ea Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Fri, 31 May 2024 13:08:34 +0200 Subject: [PATCH 141/217] Add client connection configuration info in the device info (openDAQ/openDAQ#329) --- .../src/opcua_client_module_impl.cpp | 19 ++++++++++++++++--- .../tests/test_opcua_client_module.cpp | 2 +- .../opcuatms_server/src/tms_server.cpp | 2 +- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 1a89136..349f831 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -31,7 +31,7 @@ OpcUaClientModule::OpcUaClientModule(ContextPtr context) { [context = this->context](MdnsDiscoveredDevice discoveredDevice) { - auto cap = ServerCapability("opendaq_opcua_config", "openDAQ OpcUa", ProtocolType::Configuration); + auto cap = ServerCapability(DaqOpcUaDeviceTypeId, "openDAQ OpcUa", ProtocolType::Configuration); if (!discoveredDevice.ipv4Address.empty()) { auto connectionStringIpv4 = fmt::format("{}{}:{}{}", @@ -122,6 +122,19 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, TmsClient client(context, parent, endpoint); auto device = client.connect(); completeDeviceServerCapabilities(device, host); + + // Set the connection info for the device + ServerCapabilityConfigPtr connectionInfo = device.getInfo().getConfigurationConnectionInfo(); + + connectionInfo.setProtocolId(DaqOpcUaDeviceTypeId); + connectionInfo.setProtocolName("openDAQ OpcUa"); + connectionInfo.setProtocolType(ProtocolType::Configuration); + connectionInfo.setConnectionType("TCP/IP"); + connectionInfo.addAddress(host); + connectionInfo.setPort(std::stoi(port)); + connectionInfo.setPrefix("daq.opcua"); + connectionInfo.setConnectionString(connectionString); + return device; } @@ -207,9 +220,9 @@ StringPtr OpcUaClientModule::onCreateConnectionString(const ServerCapabilityPtr& if (!address.assigned() || address.toStdString().empty()) throw InvalidParameterException("Address is not set"); - if (!serverCapability.hasProperty("Port")) + auto port = serverCapability.getPort(); + if (port == -1) throw InvalidParameterException("Port is not set"); - auto port = serverCapability.getPropertyValue("Port").template asPtr(); return fmt::format("{}{}:{}", DaqOpcUaDevicePrefix, address, port); } diff --git a/modules/opcua_client_module/tests/test_opcua_client_module.cpp b/modules/opcua_client_module/tests/test_opcua_client_module.cpp index 718ebb0..984d27b 100644 --- a/modules/opcua_client_module/tests/test_opcua_client_module.cpp +++ b/modules/opcua_client_module/tests/test_opcua_client_module.cpp @@ -79,7 +79,7 @@ TEST_F(OpcUaClientModuleTest, CreateConnectionString) serverCapability.addAddress("123.123.123.123"); ASSERT_THROW(module.createConnectionString(serverCapability), InvalidParameterException); - serverCapability.addProperty(IntProperty("Port", 1234)); + serverCapability.setPort(1234); ASSERT_NO_THROW(connectionString = module.createConnectionString(serverCapability)); ASSERT_EQ(connectionString, "daq.opcua://123.123.123.123:1234"); } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp index a4b47e3..20d9884 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp @@ -52,7 +52,7 @@ void TmsServer::start() auto serverCapability = ServerCapability("opendaq_opcua_config", "openDAQ OpcUa", ProtocolType::Configuration); serverCapability.setPrefix("daq.opcua"); serverCapability.setConnectionType("TCP/IP"); - serverCapability.addProperty(IntProperty("Port", opcUaPort)); + serverCapability.setPort(opcUaPort); device.getInfo().asPtr().addServerCapability(serverCapability); tmsDevice = std::make_unique(device, server, context, tmsContext); From 903d586333c81cc1aae2d242f48e4afc633d1955 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Wed, 15 May 2024 12:08:56 +0200 Subject: [PATCH 142/217] opendaq component merge - Merge of all openDAQ targets into a singular target --- .../libraries/opcuatms/opcuatms_client/src/CMakeLists.txt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt index 3f68140..5ba6707 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt @@ -130,11 +130,8 @@ target_link_libraries(${LIB_NAME} PUBLIC daq::opcuatms daq::opcuaclient - PRIVATE - daq::signal_dev - daq::streaming_dev - daq::device_dev - daq::component_dev + PRIVATE + daq::opendaq_dev ) target_include_directories(${LIB_NAME} PUBLIC $ From b5c2f0f8a5699a55e6222d09d121f276c35ada12 Mon Sep 17 00:00:00 2001 From: Nikolai Shipilov Date: Thu, 30 May 2024 14:43:31 +0200 Subject: [PATCH 143/217] Close all connections on device removal: * Release streaming object on pseudo device removal * Close streaming connections on config-enabled mirrored device removal * Invalidate operations on a removed device * Close config connection on native device removal * Invalidate attributes managing for removed component * Disconnect OpcUa client on device removal * Fix - retrieve the connection string before removing the device in the Python GUI application --- .../include/opcuaclient/opcuaclient.h | 2 +- .../opcua/opcuaclient/src/opcuaclient.cpp | 5 +++-- .../objects/tms_client_device_impl.h | 3 +++ .../src/objects/tms_client_device_impl.cpp | 17 +++++++++++++++-- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h index cbe3fed..1338147 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h @@ -102,7 +102,7 @@ class OpcUaClient void initialize(); void connect(); - void disconnect(); + void disconnect(bool doClear = true); void clear(); bool isConnected(); UA_Client* getUaClient(); diff --git a/shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp b/shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp index 424b562..84e5da3 100644 --- a/shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp +++ b/shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp @@ -215,7 +215,7 @@ void OpcUaClient::connect() throw OpcUaException(status, "Failed to connect to OpcUa server"); } -void OpcUaClient::disconnect() +void OpcUaClient::disconnect(bool doClear) { std::lock_guard guard(getLock()); if (!uaclient) @@ -225,7 +225,8 @@ void OpcUaClient::disconnect() UA_Client_disconnect(uaclient); - clear(); // to clear all internal states + if (doClear) + clear(); // to clear all internal states } void OpcUaClient::clear() diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h index f428758..a39d656 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h @@ -24,6 +24,7 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS class TmsClientDeviceImpl : public TmsClientComponentBaseImpl> { public: + using Super = TmsClientComponentBaseImpl>; explicit TmsClientDeviceImpl(const ContextPtr& ctx, const ComponentPtr& parent, const StringPtr& localId, @@ -49,6 +50,8 @@ class TmsClientDeviceImpl : public TmsClientComponentBaseImplisComponentRemoved) + return OPENDAQ_ERR_COMPONENT_REMOVED; + fetchTimeDomain(); - return TmsClientComponentBaseImpl>::getDomain(deviceDomain); + return Super::getDomain(deviceDomain); } void TmsClientDeviceImpl::findAndCreateSubdevices() @@ -233,6 +236,7 @@ void TmsClientDeviceImpl::fetchTicksSinceOrigin() deviceDomain = (UA_DeviceDomainStructure*) variant.getValue().data; ticksSinceOrigin = deviceDomain->ticksSinceOrigin; } + uint64_t TmsClientDeviceImpl::onGetTicksSinceOrigin() { fetchTicksSinceOrigin(); @@ -241,7 +245,6 @@ uint64_t TmsClientDeviceImpl::onGetTicksSinceOrigin() void TmsClientDeviceImpl::findAndCreateFunctionBlocks() { - std::map orderedFunctionBlocks; std::vector unorderedFunctionBlocks; @@ -405,6 +408,16 @@ void TmsClientDeviceImpl::findAndCreateServerCapabilities(const DeviceInfoPtr& d deviceInfoInternal.addServerCapability(val); } +void TmsClientDeviceImpl::removed() +{ + if (this->clientContext->getRootDevice() == this->thisPtr()) + { + this->client->disconnect(false); + } + + Super::removed(); +} + void TmsClientDeviceImpl::findAndCreateCustomComponents() { std::map orderedComponents; From 520660c3a186454867b422a926119365f9972155 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko <96818661+JakaMohorkoDS@users.noreply.github.com> Date: Thu, 20 Jun 2024 07:50:42 +0200 Subject: [PATCH 144/217] Other/config object rework (openDAQ/openDAQ#326) - Adds a default config that is used to configure both device (config) connection, streaming, and general settings at once - Add StreamingType - Add new general add-device-config settings --- .../opcua_client_module_impl.h | 4 +- .../src/opcua_client_module_impl.cpp | 78 +++++++++++++------ .../tests/test_opcua_client_module.cpp | 2 +- .../objects/tms_client_device_impl.h | 2 + .../src/objects/tms_client_device_impl.cpp | 10 +++ 5 files changed, 72 insertions(+), 24 deletions(-) diff --git a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h index 765c223..de024b8 100644 --- a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h +++ b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h @@ -18,6 +18,7 @@ #include #include #include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_CLIENT_MODULE @@ -35,10 +36,11 @@ class OpcUaClientModule final : public Module StringPtr onCreateConnectionString(const ServerCapabilityPtr& serverCapability) override; private: - static std::tuple ParseConnectionString(const StringPtr& connectionString); + StringPtr formConnectionString(const StringPtr& connectionString, const PropertyObjectPtr& config, std::string& host, int& port); static DeviceTypePtr createDeviceType(); static PropertyObjectPtr createDefaultConfig(); static void completeDeviceServerCapabilities(const DevicePtr& device, const StringPtr& deviceAddress); + static PropertyObjectPtr populateDefaultConfig(const PropertyObjectPtr& config); discovery::DiscoveryClient discoveryClient; std::mutex sync; diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 349f831..0a36982 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -92,6 +92,8 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, PropertyObjectPtr config = aConfig; if (!config.assigned()) config = createDefaultConfig(); + else + config = populateDefaultConfig(config); if (!onAcceptsConnectionParameters(connectionString, config)) throw InvalidParameterException(); @@ -99,17 +101,13 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, if (!context.assigned()) throw InvalidParameterException{"Context is not available."}; - auto parsedConnection = ParseConnectionString(connectionString); - auto prefix = std::get<0>(parsedConnection); - auto host = std::get<1>(parsedConnection); - auto port = std::get<2>(parsedConnection); - auto path = std::get<3>(parsedConnection); - if (prefix != DaqOpcUaDevicePrefix) - throw InvalidParameterException("OpcUa does not support connection string with prefix " + prefix); + std::string host; + int port; + auto formedConnectionString = formConnectionString(connectionString, config, host, port); std::scoped_lock lock(sync); - auto endpoint = OpcUaEndpoint(OpcUaScheme + host + ":" + port + path); + auto endpoint = OpcUaEndpoint(formedConnectionString); if (config.assigned()) { @@ -131,7 +129,7 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, connectionInfo.setProtocolType(ProtocolType::Configuration); connectionInfo.setConnectionType("TCP/IP"); connectionInfo.addAddress(host); - connectionInfo.setPort(std::stoi(port)); + connectionInfo.setPort(port); connectionInfo.setPrefix("daq.opcua"); connectionInfo.setConnectionString(connectionString); @@ -150,31 +148,61 @@ void OpcUaClientModule::completeDeviceServerCapabilities(const DevicePtr& device } } -// {prefix://}{hostname}:{port}{/path} -std::tuple OpcUaClientModule::ParseConnectionString(const StringPtr& connectionString) +PropertyObjectPtr OpcUaClientModule::populateDefaultConfig(const PropertyObjectPtr& config) { - std::string port = "4840"; - std::string target = "/"; + const auto defConfig = createDefaultConfig(); + for (const auto& prop : defConfig.getAllProperties()) + { + const auto name = prop.getName(); + if (config.hasProperty(name)) + defConfig.setPropertyValue(name, config.getPropertyValue(name)); + } + + return defConfig; +} + +StringPtr OpcUaClientModule::formConnectionString(const StringPtr& connectionString, const PropertyObjectPtr& config, std::string& host, int& port) +{ + if (config.assigned() && config.hasProperty("Port")) + { + port = config.getPropertyValue("Port"); + } + std::string urlString = connectionString.toStdString(); - auto regexIpv6Hostname = std::regex(R"(^(.*://)?(\[[a-fA-F0-9:]+\])(?::(\d+))?(/.*)?$)"); + auto regexIpv6Hostname = std::regex(R"(^(.*://)(\[[a-fA-F0-9:]+\])(?::(\d+))?(/.*)?$)"); auto regexIpv4Hostname = std::regex(R"(^(.*://)?([^:/\s]+)(?::(\d+))?(/.*)?$)"); std::smatch match; + std::string target = "/"; + std::string prefix = ""; + std::string path = ""; + bool parsed = false; parsed = std::regex_search(urlString, match, regexIpv6Hostname); if (!parsed) + { parsed = std::regex_search(urlString, match, regexIpv4Hostname); + } - if (!parsed) + if (parsed) + { + prefix = match[1]; + host = match[2]; + + if (match[3].matched && port == 4840) + port = std::stoi(match[3]); + + if (match[4].matched) + path = match[4]; + } + else throw InvalidParameterException("Host name not found in url: {}", connectionString); - if (match[3].matched) - port = match[3]; - if (match[4].matched) - target = match[4]; + if (prefix != DaqOpcUaDevicePrefix) + throw InvalidParameterException("OpcUa does not support connection string with prefix {}", prefix); - return {match[1], match[2], port, target}; + return OpcUaScheme + host + ":" + std::to_string(port) + "/" + path; } bool OpcUaClientModule::onAcceptsConnectionParameters(const StringPtr& connectionString, const PropertyObjectPtr& config) @@ -189,8 +217,13 @@ bool OpcUaClientModule::onAcceptsConnectionParameters(const StringPtr& connectio DeviceTypePtr OpcUaClientModule::createDeviceType() { - const auto config = createDefaultConfig(); - return DeviceType(DaqOpcUaDeviceTypeId, "OpcUa enabled device", "Network device connected over OpcUa protocol", config); + return DeviceTypeBuilder() + .setId(DaqOpcUaDeviceTypeId) + .setName("OpcUa enabled device") + .setDescription("Network device connected over OpcUa protocol") + .setConnectionStringPrefix("daq.opcua") + .setDefaultConfig(createDefaultConfig()) + .build(); } PropertyObjectPtr OpcUaClientModule::createDefaultConfig() @@ -199,6 +232,7 @@ PropertyObjectPtr OpcUaClientModule::createDefaultConfig() config.addProperty(StringProperty("Username", "")); config.addProperty(StringProperty("Password", "")); + config.addProperty(IntProperty("Port", 4840)); return config; } diff --git a/modules/opcua_client_module/tests/test_opcua_client_module.cpp b/modules/opcua_client_module/tests/test_opcua_client_module.cpp index 984d27b..6cca7fe 100644 --- a/modules/opcua_client_module/tests/test_opcua_client_module.cpp +++ b/modules/opcua_client_module/tests/test_opcua_client_module.cpp @@ -175,7 +175,7 @@ TEST_F(OpcUaClientModuleTest, DefaultDeviceConfig) ASSERT_TRUE(deviceTypes.hasKey("opendaq_opcua_config")); auto config = deviceTypes.get("opendaq_opcua_config").createDefaultConfig(); ASSERT_TRUE(config.assigned()); - ASSERT_EQ(config.getAllProperties().getCount(), 2u); + ASSERT_EQ(config.getAllProperties().getCount(), 3u); } TEST_F(OpcUaClientModuleTest, CreateFunctionBlockIdNull) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h index a39d656..6935ab4 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h @@ -40,6 +40,8 @@ class TmsClientDeviceImpl : public TmsClientComponentBaseImpl onGetAvailableDeviceTypes() override; + PropertyObjectPtr onCreateDefaultAddDeviceConfig() override; void findAndCreateFunctionBlocks(); void findAndCreateSignals(); void findAndCreateInputsOutputs(); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 515e60f..d7ad24b 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -243,6 +243,16 @@ uint64_t TmsClientDeviceImpl::onGetTicksSinceOrigin() return ticksSinceOrigin; } +DictPtr TmsClientDeviceImpl::onGetAvailableDeviceTypes() +{ + return Dict(); +} + +PropertyObjectPtr TmsClientDeviceImpl::onCreateDefaultAddDeviceConfig() +{ + return PropertyObject(); +} + void TmsClientDeviceImpl::findAndCreateFunctionBlocks() { std::map orderedFunctionBlocks; From 7dc90caf6f77d4ea36398fad81bd908b2c6e7078 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Fri, 21 Jun 2024 11:01:33 +0200 Subject: [PATCH 145/217] Modify discovery capability merge - Take device caps as source of truth - Add port to discovery caps - Fall back to default port if not specified in cap --- .../opcua_client_module_impl.h | 2 +- .../src/opcua_client_module_impl.cpp | 15 +++++++++++---- .../tests/test_opcua_client_module.cpp | 2 +- .../opcua_server_module/src/opcua_server_impl.cpp | 5 +++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h index de024b8..19ad160 100644 --- a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h +++ b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h @@ -39,7 +39,7 @@ class OpcUaClientModule final : public Module StringPtr formConnectionString(const StringPtr& connectionString, const PropertyObjectPtr& config, std::string& host, int& port); static DeviceTypePtr createDeviceType(); static PropertyObjectPtr createDefaultConfig(); - static void completeDeviceServerCapabilities(const DevicePtr& device, const StringPtr& deviceAddress); + static void completeServerCapabilities(const DevicePtr& device, const StringPtr& deviceAddress); static PropertyObjectPtr populateDefaultConfig(const PropertyObjectPtr& config); discovery::DiscoveryClient discoveryClient; diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 0a36982..61e9c57 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -54,12 +54,15 @@ OpcUaClientModule::OpcUaClientModule(ContextPtr context) } cap.setConnectionType("TCP/IP"); cap.setPrefix("daq.opcua"); + if (discoveredDevice.servicePort > 0) + cap.setPort(discoveredDevice.servicePort); return cap; } }, {"OPENDAQ"} ) { + loggerComponent = this->context.getLogger().getOrAddComponent("OpcUaClient"); discoveryClient.initMdnsClient(List("_opcua-tcp._tcp.local.")); } @@ -119,7 +122,7 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, TmsClient client(context, parent, endpoint); auto device = client.connect(); - completeDeviceServerCapabilities(device, host); + completeServerCapabilities(device, host); // Set the connection info for the device ServerCapabilityConfigPtr connectionInfo = device.getInfo().getConfigurationConnectionInfo(); @@ -136,14 +139,15 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, return device; } -void OpcUaClientModule::completeDeviceServerCapabilities(const DevicePtr& device, const StringPtr& deviceAddress) +void OpcUaClientModule::completeServerCapabilities(const DevicePtr& device, const StringPtr& deviceAddress) { auto deviceInfo = device.getInfo(); if (deviceInfo.assigned()) { for (const auto& capability : deviceInfo.getServerCapabilities()) { - capability.asPtr().addAddress(deviceAddress); + if (capability.getConnectionType() == "TCP/IP") + capability.asPtr().addAddress(deviceAddress); } } } @@ -256,7 +260,10 @@ StringPtr OpcUaClientModule::onCreateConnectionString(const ServerCapabilityPtr& auto port = serverCapability.getPort(); if (port == -1) - throw InvalidParameterException("Port is not set"); + { + port = 4840; + LOG_W("OPC UA server capability is missing port. Defaulting to 4840.") + } return fmt::format("{}{}:{}", DaqOpcUaDevicePrefix, address, port); } diff --git a/modules/opcua_client_module/tests/test_opcua_client_module.cpp b/modules/opcua_client_module/tests/test_opcua_client_module.cpp index 6cca7fe..271e0e9 100644 --- a/modules/opcua_client_module/tests/test_opcua_client_module.cpp +++ b/modules/opcua_client_module/tests/test_opcua_client_module.cpp @@ -77,7 +77,7 @@ TEST_F(OpcUaClientModuleTest, CreateConnectionString) ASSERT_THROW(module.createConnectionString(serverCapability), InvalidParameterException); serverCapability.addAddress("123.123.123.123"); - ASSERT_THROW(module.createConnectionString(serverCapability), InvalidParameterException); + ASSERT_EQ(module.createConnectionString(serverCapability), "daq.opcua://123.123.123.123:4840"); serverCapability.setPort(1234); ASSERT_NO_THROW(connectionString = module.createConnectionString(serverCapability)); diff --git a/modules/opcua_server_module/src/opcua_server_impl.cpp b/modules/opcua_server_module/src/opcua_server_impl.cpp index 32d31cc..8f8ef45 100644 --- a/modules/opcua_server_module/src/opcua_server_impl.cpp +++ b/modules/opcua_server_module/src/opcua_server_impl.cpp @@ -84,9 +84,10 @@ void OpcUaServerImpl::onStopServer() server.stop(); if (this->rootDevice.assigned()) { - const auto info = this->rootDevice.getInfo().asPtr(); + const auto info = this->rootDevice.getInfo(); + const auto infoInternal = info.asPtr(); if (info.hasServerCapability("opendaq_opcua_config")) - info.removeServerCapability("opendaq_opcua_config"); + infoInternal.removeServerCapability("opendaq_opcua_config"); } } From e0e842a4e9f9545062eccae126f0c6fffaeef316 Mon Sep 17 00:00:00 2001 From: Nikolai Shipilov Date: Tue, 25 Jun 2024 15:38:16 +0200 Subject: [PATCH 146/217] Enable streaming for signals of FB added via OpcUa: * link streaming sources available per the device with the signals from added function block * fix - create non-hierarchical references for added function block * Python gui app - input port view - retrieve the connected signal directly from input port instead of getting it from connection to bypass OpcUa implementation limitations --- .../src/objects/tms_client_device_impl.cpp | 17 +++++++++++++++++ .../src/objects/tms_server_device.cpp | 1 + 2 files changed, 18 insertions(+) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index d7ad24b..7fea325 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -24,6 +24,7 @@ #include "opcuatms/converters/property_object_conversion_utils.h" #include #include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS using namespace daq::opcua; @@ -527,6 +528,22 @@ FunctionBlockPtr TmsClientDeviceImpl::onAddFunctionBlock(const StringPtr& typeId auto clientFunctionBlock = TmsClientFunctionBlock(context, this->functionBlocks, localId, clientContext, fbNodeId); addNestedFunctionBlock(clientFunctionBlock); + + auto fbSignals = clientFunctionBlock.getSignals(search::Recursive(search::Any())); + auto deviceStreamingSources = this->thisPtr().getStreamingSources(); + for (const auto& streaming : deviceStreamingSources) + { + streaming.addSignals(fbSignals); + } + if (deviceStreamingSources.getCount() > 0) + { + for (const auto& signal : fbSignals) + { + if (signal.getPublic()) + signal.asPtr().setActiveStreamingSource(deviceStreamingSources[0].getConnectionString()); + } + } + return clientFunctionBlock; } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index bb41603..123abcd 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -390,6 +390,7 @@ TmsServerFunctionBlockPtr TmsServerDevice::addFunctionBlock(const StringPtr& fbT auto functionBlock = object.addFunctionBlock(fbTypeId, config); auto tmsFunctionBlock = registerTmsObjectOrAddReference>(fbFolderNodeId, functionBlock, functionBlocks.size()); functionBlocks.push_back(tmsFunctionBlock); + tmsFunctionBlock->createNonhierarchicalReferences(); return tmsFunctionBlock; } From 04ab4c5377cc49e5855fa338bc7cf06163dd0f49 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Thu, 4 Jul 2024 11:03:04 +0200 Subject: [PATCH 147/217] Re-add check for signal parent component --- .../opcuatms/opcuatms_server/tests/test_tms_function_block.cpp | 2 +- .../tests/opcuatms_integration/test_tms_function_block.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp index d12f318..f095bb7 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp @@ -72,7 +72,7 @@ TEST_F(TmsFunctionBlockTest, BrowseSignals) OpcUaServerNode serverNodeFB(*this->getServer(), nodeId); auto signalServerNode = serverNodeFB.getChildNode(UA_QUALIFIEDNAME_ALLOC(NAMESPACE_DAQBSP, "Sig")); auto signalReferences = signalServerNode->browse(OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASVALUESIGNAL)); - ASSERT_EQ(signalReferences.size(), 5u); + ASSERT_EQ(signalReferences.size(), 4u); } // TODO: Enable once name and description are no longer props diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp index f1af544..d4316d7 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp @@ -124,12 +124,11 @@ TEST_F(TmsFunctionBlockTest, MethodGetSignals) ASSERT_NO_THROW(signals = clientFunctionBlock.getSignals()); ASSERT_TRUE(signals.assigned()); - ASSERT_EQ(signals.getCount(), 5u); + ASSERT_EQ(signals.getCount(), 4u); ASSERT_EQ(signals[0].getDescriptor().getName(), "Signal1"); ASSERT_EQ(signals[1].getDescriptor().getName(), "Signal2"); ASSERT_EQ(signals[2].getDescriptor().getName(), "Signal3"); ASSERT_EQ(signals[3].getDescriptor().getName(), "Signal4"); - ASSERT_EQ(signals[4].getDescriptor().getName(), "NestedSignal1"); } TEST_F(TmsFunctionBlockTest, SignalCheckGlobalId) From c8a79f4628b5d43afde7b78ad478e1aeb80b0bb9 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Thu, 4 Jul 2024 10:24:12 +0200 Subject: [PATCH 148/217] Remove acceptsConnectionParameters from module --- .../opcua_client_module_impl.h | 2 +- .../src/opcua_client_module_impl.cpp | 4 +-- .../tests/test_opcua_client_module.cpp | 33 ------------------- .../opcuatms_server/tests/test_helpers.h | 4 +-- .../test_streaming_integration.cpp | 2 +- .../opcuatms_integration/test_tms_device.cpp | 4 +-- .../test_tms_integration.cpp | 4 +-- 7 files changed, 10 insertions(+), 43 deletions(-) diff --git a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h index 19ad160..8fc2037 100644 --- a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h +++ b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h @@ -32,7 +32,7 @@ class OpcUaClientModule final : public Module DevicePtr onCreateDevice(const StringPtr& connectionString, const ComponentPtr& parent, const PropertyObjectPtr& config) override; - bool onAcceptsConnectionParameters(const StringPtr& connectionString, const PropertyObjectPtr& config) override; + bool acceptsConnectionParameters(const StringPtr& connectionString, const PropertyObjectPtr& config); StringPtr onCreateConnectionString(const ServerCapabilityPtr& serverCapability) override; private: diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 61e9c57..03bc544 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -98,7 +98,7 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, else config = populateDefaultConfig(config); - if (!onAcceptsConnectionParameters(connectionString, config)) + if (!acceptsConnectionParameters(connectionString, config)) throw InvalidParameterException(); if (!context.assigned()) @@ -209,7 +209,7 @@ StringPtr OpcUaClientModule::formConnectionString(const StringPtr& connectionStr return OpcUaScheme + host + ":" + std::to_string(port) + "/" + path; } -bool OpcUaClientModule::onAcceptsConnectionParameters(const StringPtr& connectionString, const PropertyObjectPtr& config) +bool OpcUaClientModule::acceptsConnectionParameters(const StringPtr& connectionString, const PropertyObjectPtr& config) { std::string connStr = connectionString; auto found = connStr.find(DaqOpcUaDevicePrefix); diff --git a/modules/opcua_client_module/tests/test_opcua_client_module.cpp b/modules/opcua_client_module/tests/test_opcua_client_module.cpp index 271e0e9..ddac714 100644 --- a/modules/opcua_client_module/tests/test_opcua_client_module.cpp +++ b/modules/opcua_client_module/tests/test_opcua_client_module.cpp @@ -84,39 +84,6 @@ TEST_F(OpcUaClientModuleTest, CreateConnectionString) ASSERT_EQ(connectionString, "daq.opcua://123.123.123.123:1234"); } -TEST_F(OpcUaClientModuleTest, AcceptsConnectionStringNull) -{ - auto module = CreateModule(); - ASSERT_THROW(module.acceptsConnectionParameters(nullptr), ArgumentNullException); -} - -TEST_F(OpcUaClientModuleTest, AcceptsConnectionStringEmpty) -{ - auto module = CreateModule(); - - bool accepts = true; - ASSERT_NO_THROW(accepts = module.acceptsConnectionParameters("")); - ASSERT_FALSE(accepts); -} - -TEST_F(OpcUaClientModuleTest, AcceptsConnectionStringInvalid) -{ - auto module = CreateModule(); - - bool accepts = true; - ASSERT_NO_THROW(accepts = module.acceptsConnectionParameters("drfrfgt")); - ASSERT_FALSE(accepts); -} - -TEST_F(OpcUaClientModuleTest, AcceptsConnectionStringCorrect) -{ - auto module = CreateModule(); - - ASSERT_TRUE(module.acceptsConnectionParameters("daq.opcua://device8")); - ASSERT_TRUE(module.acceptsConnectionParameters("daq.opcua://[::1]")); - ASSERT_TRUE(module.acceptsConnectionParameters("daq.opcua://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]")); -} - TEST_F(OpcUaClientModuleTest, CreateDeviceConnectionStringNull) { auto module = CreateModule(); diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h b/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h index 0c94282..a0f6cbd 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h @@ -44,8 +44,8 @@ namespace test_helpers moduleManager.addModule(fbModule); auto instance = InstanceCustom(context, "localInstance"); - instance.addDevice("daq_client_device"); - instance.addDevice("mock_phys_device"); + instance.addDevice("daqmock://client_device"); + instance.addDevice("daqmock://phys_device"); instance.addFunctionBlock("mock_fb_uid"); return instance; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp index 0127bad..015aff9 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp @@ -174,7 +174,7 @@ class StreamingIntegrationTest : public testing::Test auto instance = InstanceCustom(context, "localInstance"); - instance.addDevice("mock_phys_device"); + instance.addDevice("daqmock://phys_device"); return instance; } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp index eedbe97..4d5ae7f 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp @@ -33,8 +33,8 @@ class TmsDeviceTest : public TmsObjectIntegrationTest moduleManager.addModule(fbModule); auto instance = InstanceCustom(context, "localInstance"); - instance.addDevice("daq_client_device"); - const auto device = instance.addDevice("mock_phys_device"); + instance.addDevice("daqmock://client_device"); + const auto device = instance.addDevice("daqmock://phys_device"); const auto infoInternal = device.getInfo().asPtr(); infoInternal.addServerCapability(ServerCapability("protocol_1", "protocol 1", ProtocolType::Streaming)); infoInternal.addServerCapability(ServerCapability("protocol_2", "protocol 2", ProtocolType::Configuration)); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index d74beaa..61b5945 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -32,8 +32,8 @@ class TmsIntegrationTest : public testing::Test moduleManager.addModule(fbModule); auto instance = InstanceCustom(context, localId); - instance.addDevice("daq_client_device"); - instance.addDevice("mock_phys_device"); + instance.addDevice("daqmock://client_device"); + instance.addDevice("daqmock://phys_device"); instance.addFunctionBlock("mock_fb_uid"); return instance; From 240ca83acbd7e9dbc6fa0caf561a223f5ef3059b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE?= Date: Wed, 10 Jul 2024 09:05:13 +0200 Subject: [PATCH 149/217] Change company name from `Blueberry d.o.o.` to `openDAQ d.o.o.` (openDAQ/openDAQ#374) --- .../opcua_client_module/include/opcua_client_module/common.h | 2 +- .../include/opcua_client_module/module_dll.h | 2 +- .../include/opcua_client_module/opcua_client_module_impl.h | 2 +- .../opcua_server_module/include/opcua_server_module/common.h | 2 +- .../include/opcua_server_module/module_dll.h | 2 +- .../include/opcua_server_module/opcua_server_impl.h | 2 +- .../include/opcua_server_module/opcua_server_module_impl.h | 2 +- .../opcua/opcuaclient/include/opcuaclient/attribute_reader.h | 2 +- .../opcua/opcuaclient/include/opcuaclient/browse_request.h | 2 +- .../opcuaclient/include/opcuaclient/browser/opcuabrowser.h | 2 +- .../include/opcuaclient/browser/opcuanodefactorybrowser.h | 2 +- .../opcuaclient/include/opcuaclient/browser/opcuanodevisitor.h | 2 +- .../include/opcuaclient/browser/opcuatransactionbrowser.h | 2 +- .../opcuaclient/include/opcuaclient/cached_reference_browser.h | 2 +- .../include/opcuaclient/chdatagather/_alignsyncchdatagather.h | 2 +- .../include/opcuaclient/chdatagather/_chdatagather.h | 2 +- .../opcua/opcuaclient/include/opcuaclient/event_filter.h | 2 +- .../include/opcuaclient/monitored_item_create_request.h | 2 +- .../opcuaclient/include/opcuaclient/opcuaasyncexecthread.h | 2 +- .../opcuaclient/include/opcuaclient/opcuacallmethodrequest.h | 2 +- .../opcua/opcuaclient/include/opcuaclient/opcuaclient.h | 2 +- .../opcua/opcuaclient/include/opcuaclient/opcuanodefactory.h | 2 +- .../opcua/opcuaclient/include/opcuaclient/opcuareadvalueid.h | 2 +- .../include/opcuaclient/opcuatimertaskcontextcollection.h | 2 +- .../opcuaclient/include/opcuaclient/opcuatimertaskhelper.h | 2 +- .../opcua/opcuaclient/include/opcuaclient/request_handler.h | 2 +- .../opcua/opcuaclient/include/opcuaclient/subscriptions.h | 2 +- .../include/opcuaclient/taskprocessor/opcuataskprocessor.h | 2 +- .../opcua/opcuaclient/tests/include/opcuaservertesthelper.h | 2 +- shared/libraries/opcua/opcuaserver/include/opcuaserver/common.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/event_attributes.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/node_event_manager.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/opcuaserver.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/opcuaserverlock.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/opcuaservernode.h | 2 +- .../opcuaserver/include/opcuaserver/opcuaservernodefactory.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/opcuasession.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/opcuataskqueue.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/opcuatmstypes.h | 2 +- .../opcuaserver/include/opcuaserver/server_event_manager.h | 2 +- .../libraries/opcua/opcuaserver/tests/common_test_functions.h | 2 +- shared/libraries/opcua/opcuashared/include/opcuashared/bcrypt.h | 2 +- .../opcua/opcuashared/include/opcuashared/node/opcuadatatype.h | 2 +- .../opcua/opcuashared/include/opcuashared/node/opcuanode.h | 2 +- .../opcuashared/include/opcuashared/node/opcuanodemethod.h | 2 +- .../opcuashared/include/opcuashared/node/opcuanodeobject.h | 2 +- .../opcuashared/include/opcuashared/node/opcuanodevariable.h | 2 +- .../opcuashared/include/opcuashared/node/opcuaobjecttype.h | 2 +- .../opcua/opcuashared/include/opcuashared/node/opcuatype.h | 2 +- .../opcuashared/include/opcuashared/node/opcuavariabletype.h | 2 +- shared/libraries/opcua/opcuashared/include/opcuashared/opcua.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcua_attribute.h | 2 +- .../opcuashared/include/opcuashared/opcuacallmethodresult.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuacollection.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuacommon.h | 2 +- .../opcuashared/include/opcuashared/opcuadatatypearraylist.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuadatavalue.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuaendpoint.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuaexception.h | 2 +- .../libraries/opcua/opcuashared/include/opcuashared/opcualog.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuanodecollection.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuanodeid.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuaobject.h | 2 +- .../opcuashared/include/opcuashared/opcuasecurity_config.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuasecuritycommon.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuavariant.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuavector.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuaversion.h | 2 +- .../opcuatms/opcuatms/include/opcuatms/converter_maps.h | 2 +- .../include/opcuatms/converters/list_conversion_utils.h | 2 +- .../opcuatms/converters/property_object_conversion_utils.h | 2 +- .../opcuatms/include/opcuatms/converters/selection_converter.h | 2 +- .../opcuatms/include/opcuatms/converters/struct_converter.h | 2 +- .../opcuatms/include/opcuatms/converters/variant_converter.h | 2 +- .../opcuatms/opcuatms/include/opcuatms/core_types_utils.h | 2 +- shared/libraries/opcuatms/opcuatms/include/opcuatms/errors.h | 2 +- .../libraries/opcuatms/opcuatms/include/opcuatms/exceptions.h | 2 +- .../opcuatms/opcuatms/include/opcuatms/extension_object.h | 2 +- shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h | 2 +- .../opcuatms/opcuatms/include/opcuatms/type_mappings.h | 2 +- .../opcuatms_client/objects/tms_client_channel_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_channel_impl.h | 2 +- .../include/opcuatms_client/objects/tms_client_component.h | 2 +- .../opcuatms_client/objects/tms_client_component_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_component_impl.h | 2 +- .../include/opcuatms_client/objects/tms_client_context.h | 2 +- .../include/opcuatms_client/objects/tms_client_device_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_device_impl.h | 2 +- .../include/opcuatms_client/objects/tms_client_folder_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_folder_impl.h | 2 +- .../opcuatms_client/objects/tms_client_function_block_factory.h | 2 +- .../opcuatms_client/objects/tms_client_function_block_impl.h | 2 +- .../objects/tms_client_function_block_type_factory.h | 2 +- .../objects/tms_client_function_block_type_impl.h | 2 +- .../opcuatms_client/objects/tms_client_function_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_function_impl.h | 2 +- .../opcuatms_client/objects/tms_client_input_port_factory.h | 2 +- .../opcuatms_client/objects/tms_client_input_port_impl.h | 2 +- .../opcuatms_client/objects/tms_client_io_folder_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_io_folder_impl.h | 2 +- .../include/opcuatms_client/objects/tms_client_object_impl.h | 2 +- .../opcuatms_client/objects/tms_client_procedure_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_procedure_impl.h | 2 +- .../opcuatms_client/objects/tms_client_property_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_property_impl.h | 2 +- .../objects/tms_client_property_object_factory.h | 2 +- .../opcuatms_client/objects/tms_client_property_object_impl.h | 2 +- .../objects/tms_client_server_capability_factory.h | 2 +- .../opcuatms_client/objects/tms_client_server_capability_impl.h | 2 +- .../include/opcuatms_client/objects/tms_client_signal_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_signal_impl.h | 2 +- .../include/opcuatms_client/objects/tms_client_tags_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_tags_impl.h | 2 +- .../include/opcuatms_client/tms_attribute_collector.h | 2 +- .../opcuatms_client/include/opcuatms_client/tms_client.h | 2 +- .../include/opcuatms_server/objects/tms_server_channel.h | 2 +- .../include/opcuatms_server/objects/tms_server_component.h | 2 +- .../include/opcuatms_server/objects/tms_server_device.h | 2 +- .../include/opcuatms_server/objects/tms_server_eval_value.h | 2 +- .../include/opcuatms_server/objects/tms_server_folder.h | 2 +- .../include/opcuatms_server/objects/tms_server_function_block.h | 2 +- .../opcuatms_server/objects/tms_server_function_block_type.h | 2 +- .../include/opcuatms_server/objects/tms_server_input_port.h | 2 +- .../include/opcuatms_server/objects/tms_server_object.h | 2 +- .../include/opcuatms_server/objects/tms_server_property.h | 2 +- .../opcuatms_server/objects/tms_server_property_object.h | 2 +- .../include/opcuatms_server/objects/tms_server_signal.h | 2 +- .../include/opcuatms_server/objects/tms_server_variable.h | 2 +- .../opcuatms_server/include/opcuatms_server/tms_server.h | 2 +- .../include/opcuatms_server/tms_server_context.h | 2 +- shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h | 2 +- .../libraries/opcuatms/opcuatms_server/tests/tms_server_test.h | 2 +- .../tests/opcuatms_integration/tms_object_integration_test.h | 2 +- .../opcuatms/tests/test_utils/test_input_port_notifications.h | 2 +- shared/libraries/opcuatms/tests/test_utils/tms_object_test.h | 2 +- 136 files changed, 136 insertions(+), 136 deletions(-) diff --git a/modules/opcua_client_module/include/opcua_client_module/common.h b/modules/opcua_client_module/include/opcua_client_module/common.h index 318794d..cfb43ff 100644 --- a/modules/opcua_client_module/include/opcua_client_module/common.h +++ b/modules/opcua_client_module/include/opcua_client_module/common.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/modules/opcua_client_module/include/opcua_client_module/module_dll.h b/modules/opcua_client_module/include/opcua_client_module/module_dll.h index ea56e47..239f7bf 100644 --- a/modules/opcua_client_module/include/opcua_client_module/module_dll.h +++ b/modules/opcua_client_module/include/opcua_client_module/module_dll.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h index 8fc2037..d45dc0d 100644 --- a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h +++ b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/modules/opcua_server_module/include/opcua_server_module/common.h b/modules/opcua_server_module/include/opcua_server_module/common.h index 1a53c8e..55425f3 100644 --- a/modules/opcua_server_module/include/opcua_server_module/common.h +++ b/modules/opcua_server_module/include/opcua_server_module/common.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/modules/opcua_server_module/include/opcua_server_module/module_dll.h b/modules/opcua_server_module/include/opcua_server_module/module_dll.h index 6ba4ef4..539477b 100644 --- a/modules/opcua_server_module/include/opcua_server_module/module_dll.h +++ b/modules/opcua_server_module/include/opcua_server_module/module_dll.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h b/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h index 56405c3..fdef2d6 100644 --- a/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h +++ b/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/modules/opcua_server_module/include/opcua_server_module/opcua_server_module_impl.h b/modules/opcua_server_module/include/opcua_server_module/opcua_server_module_impl.h index 81f51b8..64c9ede 100644 --- a/modules/opcua_server_module/include/opcua_server_module/opcua_server_module_impl.h +++ b/modules/opcua_server_module/include/opcua_server_module/opcua_server_module_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/attribute_reader.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/attribute_reader.h index 4e26cac..bece48d 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/attribute_reader.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/attribute_reader.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browse_request.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browse_request.h index 9347db6..96d39a2 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browse_request.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browse_request.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuabrowser.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuabrowser.h index 0e74f14..f27f52a 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuabrowser.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuabrowser.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodefactorybrowser.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodefactorybrowser.h index d77aa9f..4b1b35f 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodefactorybrowser.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodefactorybrowser.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodevisitor.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodevisitor.h index da3638a..1c559f1 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodevisitor.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodevisitor.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuatransactionbrowser.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuatransactionbrowser.h index 87b38d1..e546401 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuatransactionbrowser.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuatransactionbrowser.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h index 297911e..da8887f 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_alignsyncchdatagather.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_alignsyncchdatagather.h index 52abb55..56b2521 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_alignsyncchdatagather.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_alignsyncchdatagather.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_chdatagather.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_chdatagather.h index cf82b57..9222435 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_chdatagather.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_chdatagather.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/event_filter.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/event_filter.h index 050449d..812a6e4 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/event_filter.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/event_filter.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/monitored_item_create_request.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/monitored_item_create_request.h index bf8faf1..071ca5d 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/monitored_item_create_request.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/monitored_item_create_request.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaasyncexecthread.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaasyncexecthread.h index e863f96..70b1d01 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaasyncexecthread.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaasyncexecthread.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuacallmethodrequest.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuacallmethodrequest.h index d94bb44..c4e891d 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuacallmethodrequest.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuacallmethodrequest.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h index 1338147..3a8ac14 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuanodefactory.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuanodefactory.h index 9d43f14..d2e53a8 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuanodefactory.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuanodefactory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuareadvalueid.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuareadvalueid.h index d578633..98af9a7 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuareadvalueid.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuareadvalueid.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskcontextcollection.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskcontextcollection.h index c294058..acc21db 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskcontextcollection.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskcontextcollection.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskhelper.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskhelper.h index 3568f3a..d3f2a0a 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskhelper.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskhelper.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/request_handler.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/request_handler.h index 08245c4..e34170d 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/request_handler.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/request_handler.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/subscriptions.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/subscriptions.h index a39843b..3781cb8 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/subscriptions.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/subscriptions.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/taskprocessor/opcuataskprocessor.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/taskprocessor/opcuataskprocessor.h index 691a54b..4730de7 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/taskprocessor/opcuataskprocessor.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/taskprocessor/opcuataskprocessor.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h b/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h index 3ea2c28..077e560 100644 --- a/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h +++ b/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/common.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/common.h index 024d0d4..51c2ad6 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/common.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/common.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/event_attributes.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/event_attributes.h index 9fa8ac3..306847d 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/event_attributes.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/event_attributes.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/node_event_manager.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/node_event_manager.h index bfbf867..bc0ba5f 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/node_event_manager.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/node_event_manager.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h index d960cc6..613d700 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h index c1f990d..8e89500 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserverlock.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserverlock.h index 354a439..cdc29c3 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserverlock.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserverlock.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernode.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernode.h index 518f8ab..3129082 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernode.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernode.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernodefactory.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernodefactory.h index 9df9cdf..e77b628 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernodefactory.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernodefactory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuasession.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuasession.h index 8287cd8..93c63db 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuasession.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuasession.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuataskqueue.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuataskqueue.h index e96c191..d361ed7 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuataskqueue.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuataskqueue.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuatmstypes.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuatmstypes.h index 45d78e9..ae91ee3 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuatmstypes.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuatmstypes.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/server_event_manager.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/server_event_manager.h index d55c097..cd03ea6 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/server_event_manager.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/server_event_manager.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/tests/common_test_functions.h b/shared/libraries/opcua/opcuaserver/tests/common_test_functions.h index aba7a5b..f996eaf 100644 --- a/shared/libraries/opcua/opcuaserver/tests/common_test_functions.h +++ b/shared/libraries/opcua/opcuaserver/tests/common_test_functions.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/bcrypt.h b/shared/libraries/opcua/opcuashared/include/opcuashared/bcrypt.h index 8d5c253..81539b0 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/bcrypt.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/bcrypt.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuadatatype.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuadatatype.h index d12a79c..edf5f0c 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuadatatype.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuadatatype.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanode.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanode.h index e97b6d4..e749e14 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanode.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanode.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodemethod.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodemethod.h index 7da9dbc..13172f3 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodemethod.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodemethod.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodeobject.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodeobject.h index ad4be69..60b4fab 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodeobject.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodeobject.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodevariable.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodevariable.h index 1656c4e..b43c634 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodevariable.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodevariable.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuaobjecttype.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuaobjecttype.h index faccf67..11d8d4d 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuaobjecttype.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuaobjecttype.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuatype.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuatype.h index 41738fa..bf052e9 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuatype.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuatype.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuavariabletype.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuavariabletype.h index db5b08e..5c63285 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuavariabletype.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuavariabletype.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcua.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcua.h index 060d041..168eb7e 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcua.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcua.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcua_attribute.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcua_attribute.h index fafa188..435e9e0 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcua_attribute.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcua_attribute.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacallmethodresult.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacallmethodresult.h index dcdd123..52cb75d 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacallmethodresult.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacallmethodresult.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacollection.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacollection.h index 37f4a00..3ff7d15 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacollection.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacollection.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacommon.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacommon.h index f298247..e2f3012 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacommon.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacommon.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatatypearraylist.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatatypearraylist.h index 949ed90..ffecd1b 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatatypearraylist.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatatypearraylist.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatavalue.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatavalue.h index 771dd8e..e14ad59 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatavalue.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatavalue.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaendpoint.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaendpoint.h index bd9d985..753b89b 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaendpoint.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaendpoint.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaexception.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaexception.h index 207990e..856bf19 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaexception.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaexception.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcualog.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcualog.h index 7993ba6..74d48c2 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcualog.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcualog.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodecollection.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodecollection.h index 8c2d229..1bc3a27 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodecollection.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodecollection.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodeid.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodeid.h index b2b4e46..bdf8f77 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodeid.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodeid.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaobject.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaobject.h index c692a4c..0cc4699 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaobject.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaobject.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecurity_config.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecurity_config.h index f9ef49d..890d4a7 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecurity_config.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecurity_config.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecuritycommon.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecuritycommon.h index 7edb642..696808d 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecuritycommon.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecuritycommon.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h index cfd1a4f..43d9e0b 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavector.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavector.h index 109a940..b81a99e 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavector.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavector.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaversion.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaversion.h index 3d9bc5d..f5f8be0 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaversion.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaversion.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h index b068c06..7c362d2 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/list_conversion_utils.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/list_conversion_utils.h index 2bb7bfe..8f06a61 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/list_conversion_utils.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/list_conversion_utils.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/property_object_conversion_utils.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/property_object_conversion_utils.h index 8f34c14..cdfdccb 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/property_object_conversion_utils.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/property_object_conversion_utils.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/selection_converter.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/selection_converter.h index d8d8e50..edddb40 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/selection_converter.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/selection_converter.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/struct_converter.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/struct_converter.h index 076514c..cc3bc80 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/struct_converter.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/struct_converter.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/variant_converter.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/variant_converter.h index 4b98b47..dc0f2cf 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/variant_converter.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/variant_converter.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h index 1881af3..c9b29b7 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/errors.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/errors.h index 1eed3ae..9bf2c32 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/errors.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/errors.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/exceptions.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/exceptions.h index 5a0a2bf..423fe8e 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/exceptions.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/exceptions.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/extension_object.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/extension_object.h index 832ba22..d198283 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/extension_object.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/extension_object.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h index 1c07a52..2d56ea1 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h index 43cc041..c5bbcb7 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_factory.h index fb0ea76..5220273 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_impl.h index 60aa107..7440b00 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component.h index 16ec6fd..1bfa61e 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_factory.h index bb3837e..4a04ec2 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h index 60f5bd8..4369ea2 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h index 983144a..8c0a30b 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_factory.h index 066387b..c83f689 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h index 6935ab4..e682a65 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_factory.h index 80f3c7c..0eb6085 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h index d7a414b..aebfa12 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_factory.h index f97385a..1a5cf4a 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h index 385da8b..2502ddd 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_factory.h index 712befb..578d3bd 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_impl.h index 85ada30..de543e8 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_factory.h index 5a39919..bc3f515 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_impl.h index 839a251..54385d0 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_factory.h index 44e53fe..238edc5 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h index c55f701..774f0f1 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_factory.h index 4c73533..74c2532 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h index d8d178a..f4d402a 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h index e48d614..8f65430 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_factory.h index 69b8607..b613642 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_impl.h index 254341a..4bebb83 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_factory.h index ed38185..b6c20c9 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h index 0cb33c4..b4035fb 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_factory.h index 36ab68a..b47a6a3 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h index f290822..5d90adb 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_factory.h index aea843b..c7a16c2 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_impl.h index 2c05068..5866e83 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_factory.h index 48ecf56..a1d7a2c 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h index 3412b8d..a8608e2 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_factory.h index 6ba21e0..c19292d 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h index e655451..f4e807b 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_attribute_collector.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_attribute_collector.h index 512cfc8..5c41ab5 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_attribute_collector.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_attribute_collector.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h index 0dbe915..e0e5254 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_channel.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_channel.h index 1749187..242a2fa 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_channel.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_channel.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h index 16fe448..50719ff 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h index 902396b..24187eb 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_eval_value.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_eval_value.h index 4489b16..c011277 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_eval_value.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_eval_value.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_folder.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_folder.h index 4d23014..5e123f9 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_folder.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_folder.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block.h index 789f841..1cafdd0 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block_type.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block_type.h index b593203..b5fda41 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block_type.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block_type.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h index 3bf360d..097d9b9 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h index 885e1a9..6c1daa6 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h index eba75b4..77e73e9 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h index 6d1b9f2..9c03a8a 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h index c5aa26a..dc87899 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h index 36c3e4f..7f6b046 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h index 17cf075..40c3ea3 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server_context.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server_context.h index f38d8e0..60ce1dc 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server_context.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server_context.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h b/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h index a0f6cbd..602fd9d 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.h b/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.h index 39d2575..03097d7 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.h +++ b/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h index b98825a..6b6f401 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/tests/test_utils/test_input_port_notifications.h b/shared/libraries/opcuatms/tests/test_utils/test_input_port_notifications.h index 1b2bb9b..2faf6b3 100644 --- a/shared/libraries/opcuatms/tests/test_utils/test_input_port_notifications.h +++ b/shared/libraries/opcuatms/tests/test_utils/test_input_port_notifications.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/tests/test_utils/tms_object_test.h b/shared/libraries/opcuatms/tests/test_utils/tms_object_test.h index 66f3af1..cf14d94 100644 --- a/shared/libraries/opcuatms/tests/test_utils/tms_object_test.h +++ b/shared/libraries/opcuatms/tests/test_utils/tms_object_test.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 Blueberry d.o.o. + * Copyright 2022-2024 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 34207fdbc485f6fd9ccf28f80def71c15e09dee1 Mon Sep 17 00:00:00 2001 From: Martin Kraner Date: Tue, 16 Jul 2024 12:39:23 +0200 Subject: [PATCH 150/217] General CMake and testing and discovery fixes (openDAQ/openDAQ#375) * Only set boost target options the target exists * Fix Boost and GTest alias target issues * Fix compiling with Boost 1.85 (add Align to BOOST_INCLUDE_LIBRARIES) * Fix Win32 Visual Studio 2017 compilation * Disable Warnings As Errors for external dependencies fix test warnings * Make ModuleManager ignore invalid paths and just print a warning * Make ModuleManager tests use relative paths instead of fixed/absolute * Fix CTest absolute working directory paths to relative * Set working directory to test runner location for `test_module_manager_internals` * Workaround mDNS discovery no longer providing device IP * Fix finding only IPv6 addresses or multiple ConfigurationAndStreaming capabilities * Fix NativeStreamingDevice protocol adding IPv4 address even if there is none * Add a default argument to changed Context() factory to maintain backwards compatibility * Add fs::proximate() shim for std::experimental::filesystem * Refactor presets so they can be included in vendor ones * Add address type and reachability status --------- Co-authored-by: Jaka Mohorko --- .../opcua_client_module_impl.h | 4 +- .../src/opcua_client_module_impl.cpp | 162 ++++++++++++------ .../tests/test_opcua_client_module.cpp | 44 ++--- .../opcua_server_module/tests/CMakeLists.txt | 4 +- .../opcuashared/tests/test_opcuaendpoint.cpp | 2 +- .../src/objects/tms_client_device_impl.cpp | 30 +++- .../opcuatms_server/tests/CMakeLists.txt | 4 +- .../tests/opcuatms_integration/CMakeLists.txt | 4 +- 8 files changed, 169 insertions(+), 85 deletions(-) diff --git a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h index d45dc0d..8d06915 100644 --- a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h +++ b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h @@ -33,10 +33,10 @@ class OpcUaClientModule final : public Module const ComponentPtr& parent, const PropertyObjectPtr& config) override; bool acceptsConnectionParameters(const StringPtr& connectionString, const PropertyObjectPtr& config); - StringPtr onCreateConnectionString(const ServerCapabilityPtr& serverCapability) override; + Bool onCompleteServerCapability(const ServerCapabilityPtr& source, const ServerCapabilityConfigPtr& target) override; private: - StringPtr formConnectionString(const StringPtr& connectionString, const PropertyObjectPtr& config, std::string& host, int& port); + StringPtr formConnectionString(const StringPtr& connectionString, const PropertyObjectPtr& config, std::string& host, int& port, std::string& hostType); static DeviceTypePtr createDeviceType(); static PropertyObjectPtr createDefaultConfig(); static void completeServerCapabilities(const DevicePtr& device, const StringPtr& deviceAddress); diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 03bc544..6e8bf02 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -11,13 +11,14 @@ #include #include #include +#include #include BEGIN_NAMESPACE_OPENDAQ_OPCUA_CLIENT_MODULE static const char* DaqOpcUaDeviceTypeId = "opendaq_opcua_config"; -static const char* DaqOpcUaDevicePrefix = "daq.opcua://"; -static const char* OpcUaScheme = "opc.tcp://"; +static const char* DaqOpcUaDevicePrefix = "daq.opcua"; +static const char* OpcUaScheme = "opc.tcp"; using namespace discovery; using namespace daq::opcua; @@ -34,26 +35,40 @@ OpcUaClientModule::OpcUaClientModule(ContextPtr context) auto cap = ServerCapability(DaqOpcUaDeviceTypeId, "openDAQ OpcUa", ProtocolType::Configuration); if (!discoveredDevice.ipv4Address.empty()) { - auto connectionStringIpv4 = fmt::format("{}{}:{}{}", + auto connectionStringIpv4 = fmt::format("{}://{}:{}{}", DaqOpcUaDevicePrefix, discoveredDevice.ipv4Address, discoveredDevice.servicePort, discoveredDevice.getPropertyOrDefault("path", "/")); cap.addConnectionString(connectionStringIpv4); cap.addAddress(discoveredDevice.ipv4Address); + + const auto addressInfo = AddressInfoBuilder().setAddress(discoveredDevice.ipv4Address) + .setReachabilityStatus(AddressReachabilityStatus::Unknown) + .setType("IPv4") + .setConnectionString(connectionStringIpv4) + .build(); + cap.addAddressInfo(addressInfo); } if(!discoveredDevice.ipv6Address.empty()) { - auto connectionStringIpv6 = fmt::format("{}[{}]:{}{}", + auto connectionStringIpv6 = fmt::format("{}://[{}]:{}{}", DaqOpcUaDevicePrefix, discoveredDevice.ipv6Address, discoveredDevice.servicePort, discoveredDevice.getPropertyOrDefault("path", "/")); cap.addConnectionString(connectionStringIpv6); cap.addAddress("[" + discoveredDevice.ipv6Address + "]"); + + const auto addressInfo = AddressInfoBuilder().setAddress("[" + discoveredDevice.ipv6Address + "]") + .setReachabilityStatus(AddressReachabilityStatus::Unknown) + .setType("IPv6") + .setConnectionString(connectionStringIpv6) + .build(); + cap.addAddressInfo(addressInfo); } cap.setConnectionType("TCP/IP"); - cap.setPrefix("daq.opcua"); + cap.setPrefix(DaqOpcUaDevicePrefix); if (discoveredDevice.servicePort > 0) cap.setPort(discoveredDevice.servicePort); return cap; @@ -105,8 +120,9 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, throw InvalidParameterException{"Context is not available."}; std::string host; + std::string hostType; int port; - auto formedConnectionString = formConnectionString(connectionString, config, host, port); + auto formedConnectionString = formConnectionString(connectionString, config, host, port, hostType); std::scoped_lock lock(sync); @@ -126,15 +142,24 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, // Set the connection info for the device ServerCapabilityConfigPtr connectionInfo = device.getInfo().getConfigurationConnectionInfo(); - - connectionInfo.setProtocolId(DaqOpcUaDeviceTypeId); - connectionInfo.setProtocolName("openDAQ OpcUa"); - connectionInfo.setProtocolType(ProtocolType::Configuration); - connectionInfo.setConnectionType("TCP/IP"); - connectionInfo.addAddress(host); - connectionInfo.setPort(port); - connectionInfo.setPrefix("daq.opcua"); - connectionInfo.setConnectionString(connectionString); + + + const auto addressInfo = AddressInfoBuilder().setAddress(host) + .setReachabilityStatus(AddressReachabilityStatus::Reachable) + .setType(hostType) + .setConnectionString(connectionString) + .build(); + + connectionInfo.setProtocolId(DaqOpcUaDeviceTypeId) + .setProtocolName("openDAQ OpcUa") + .setProtocolType(ProtocolType::Configuration) + .setConnectionType("TCP/IP") + .addAddress(host) + .setPort(port) + .setPrefix(DaqOpcUaDevicePrefix) + .setConnectionString(connectionString) + .addAddressInfo(addressInfo) + .freeze(); return device; } @@ -165,13 +190,8 @@ PropertyObjectPtr OpcUaClientModule::populateDefaultConfig(const PropertyObjectP return defConfig; } -StringPtr OpcUaClientModule::formConnectionString(const StringPtr& connectionString, const PropertyObjectPtr& config, std::string& host, int& port) +StringPtr OpcUaClientModule::formConnectionString(const StringPtr& connectionString, const PropertyObjectPtr& config, std::string& host, int& port, std::string& hostType) { - if (config.assigned() && config.hasProperty("Port")) - { - port = config.getPropertyValue("Port"); - } - std::string urlString = connectionString.toStdString(); auto regexIpv6Hostname = std::regex(R"(^(.*://)(\[[a-fA-F0-9:]+\])(?::(\d+))?(/.*)?$)"); @@ -182,11 +202,23 @@ StringPtr OpcUaClientModule::formConnectionString(const StringPtr& connectionStr std::string prefix = ""; std::string path = ""; + if (config.assigned() ) + { + if (config.hasProperty("Port")) + port = config.getPropertyValue("Port"); + + if (config.hasProperty("Path")) + path = String(config.getPropertyValue("Path")).toStdString(); + } + bool parsed = false; parsed = std::regex_search(urlString, match, regexIpv6Hostname); + hostType = "IPv6"; + if (!parsed) { parsed = std::regex_search(urlString, match, regexIpv4Hostname); + hostType = "IPv4"; } if (parsed) @@ -203,29 +235,82 @@ StringPtr OpcUaClientModule::formConnectionString(const StringPtr& connectionStr else throw InvalidParameterException("Host name not found in url: {}", connectionString); - if (prefix != DaqOpcUaDevicePrefix) + if (prefix != std::string(DaqOpcUaDevicePrefix) + "://") throw InvalidParameterException("OpcUa does not support connection string with prefix {}", prefix); - return OpcUaScheme + host + ":" + std::to_string(port) + "/" + path; + return std::string(OpcUaScheme) + "://" + host + ":" + std::to_string(port) + "/" + path; } bool OpcUaClientModule::acceptsConnectionParameters(const StringPtr& connectionString, const PropertyObjectPtr& config) { std::string connStr = connectionString; - auto found = connStr.find(DaqOpcUaDevicePrefix); + auto found = connStr.find(std::string(DaqOpcUaDevicePrefix) + "://"); if (found == 0) return true; else return false; } +Bool OpcUaClientModule::onCompleteServerCapability(const ServerCapabilityPtr& source, const ServerCapabilityConfigPtr& target) +{ + if (target.getProtocolId() != "opendaq_opcua_config") + return false; + + if (target.getConnectionString().getLength() != 0) + return true; + + if (source.getConnectionType() != "TCP/IP") + return false; + + if (!source.getAddresses().assigned() || !source.getAddresses().getCount()) + { + LOG_W("Source server capability address is not available when filling in missing OPC UA capability information.") + return false; + } + + const auto addrInfos = source.getAddressInfo(); + if (!addrInfos.assigned() || !addrInfos.getCount()) + { + LOG_W("Source server capability addressInfo is not available when filling in missing OPC UA capability information.") + return false; + } + + auto port = target.getPort(); + if (port == -1) + { + port = 4840; + target.setPort(port); + LOG_W("OPC UA server capability is missing port. Defaulting to 7420.") + } + + const auto path = target.hasProperty("Path") ? target.getPropertyValue("Path") : ""; + for (const auto& addrInfo : addrInfos) + { + const auto address = addrInfo.getAddress(); + + std::string connectionString = fmt::format("{}://{}:{}/{}", DaqOpcUaDevicePrefix, address, port, path); + const auto targetAddrInfo = AddressInfoBuilder() + .setAddress(addrInfo.getAddress()) + .setReachabilityStatus(addrInfo.getReachabilityStatus()) + .setType(addrInfo.getType()) + .setConnectionString(connectionString) + .build(); + + target.addAddressInfo(targetAddrInfo) + .setConnectionString(connectionString) + .addAddress(address); + } + + return true; +} + DeviceTypePtr OpcUaClientModule::createDeviceType() { return DeviceTypeBuilder() .setId(DaqOpcUaDeviceTypeId) .setName("OpcUa enabled device") .setDescription("Network device connected over OpcUa protocol") - .setConnectionStringPrefix("daq.opcua") + .setConnectionStringPrefix(DaqOpcUaDevicePrefix) .setDefaultConfig(createDefaultConfig()) .build(); } @@ -241,31 +326,4 @@ PropertyObjectPtr OpcUaClientModule::createDefaultConfig() return config; } -StringPtr OpcUaClientModule::onCreateConnectionString(const ServerCapabilityPtr& serverCapability) -{ - if (serverCapability.getProtocolId() != "opendaq_opcua_config") - return nullptr; - - StringPtr connectionString = serverCapability.getConnectionString(); - if (connectionString.getLength() != 0) - return connectionString; - - StringPtr address; - if (ListPtr addresses = serverCapability.getAddresses(); addresses.getCount() > 0) - { - address = addresses[0]; - } - if (!address.assigned() || address.toStdString().empty()) - throw InvalidParameterException("Address is not set"); - - auto port = serverCapability.getPort(); - if (port == -1) - { - port = 4840; - LOG_W("OPC UA server capability is missing port. Defaulting to 4840.") - } - - return fmt::format("{}{}:{}", DaqOpcUaDevicePrefix, address, port); -} - END_NAMESPACE_OPENDAQ_OPCUA_CLIENT_MODULE diff --git a/modules/opcua_client_module/tests/test_opcua_client_module.cpp b/modules/opcua_client_module/tests/test_opcua_client_module.cpp index ddac714..771390b 100644 --- a/modules/opcua_client_module/tests/test_opcua_client_module.cpp +++ b/modules/opcua_client_module/tests/test_opcua_client_module.cpp @@ -61,28 +61,28 @@ TEST_F(OpcUaClientModuleTest, EnumerateDevices) ASSERT_NO_THROW(deviceInfo = module.getAvailableDevices()); } -TEST_F(OpcUaClientModuleTest, CreateConnectionString) -{ - auto context = NullContext(); - ModulePtr module; - createModule(&module, context); - - StringPtr connectionString; - - ServerCapabilityConfigPtr serverCapabilityIgnored = ServerCapability("test", "test", ProtocolType::Unknown); - ASSERT_NO_THROW(connectionString = module.createConnectionString(serverCapabilityIgnored)); - ASSERT_FALSE(connectionString.assigned()); - - ServerCapabilityConfigPtr serverCapability = ServerCapability("opendaq_opcua_config", "openDAQ OpcUa", ProtocolType::Configuration); - ASSERT_THROW(module.createConnectionString(serverCapability), InvalidParameterException); - - serverCapability.addAddress("123.123.123.123"); - ASSERT_EQ(module.createConnectionString(serverCapability), "daq.opcua://123.123.123.123:4840"); - - serverCapability.setPort(1234); - ASSERT_NO_THROW(connectionString = module.createConnectionString(serverCapability)); - ASSERT_EQ(connectionString, "daq.opcua://123.123.123.123:1234"); -} +//TEST_F(OpcUaClientModuleTest, CreateConnectionString) +//{ +// auto context = NullContext(); +// ModulePtr module; +// createModule(&module, context); +// +// StringPtr connectionString; +// +// ServerCapabilityConfigPtr serverCapabilityIgnored = ServerCapability("test", "test", ProtocolType::Unknown); +// ASSERT_NO_THROW(connectionString = module.createConnectionString(serverCapabilityIgnored)); +// ASSERT_FALSE(connectionString.assigned()); +// +// ServerCapabilityConfigPtr serverCapability = ServerCapability("opendaq_opcua_config", "openDAQ OpcUa", ProtocolType::Configuration); +// ASSERT_THROW(module.createConnectionString(serverCapability), InvalidParameterException); +// +// serverCapability.addAddress("123.123.123.123"); +// ASSERT_EQ(module.createConnectionString(serverCapability), "daq.opcua://123.123.123.123:4840"); +// +// serverCapability.setPort(1234); +// ASSERT_NO_THROW(connectionString = module.createConnectionString(serverCapability)); +// ASSERT_EQ(connectionString, "daq.opcua://123.123.123.123:1234"); +//} TEST_F(OpcUaClientModuleTest, CreateDeviceConnectionStringNull) { diff --git a/modules/opcua_server_module/tests/CMakeLists.txt b/modules/opcua_server_module/tests/CMakeLists.txt index 860e24c..7228e63 100644 --- a/modules/opcua_server_module/tests/CMakeLists.txt +++ b/modules/opcua_server_module/tests/CMakeLists.txt @@ -16,8 +16,8 @@ target_link_libraries(${TEST_APP} PRIVATE daq::test_utils ) add_test(NAME ${TEST_APP} - COMMAND $ - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND $ + WORKING_DIRECTORY bin ) if (MSVC) # Ignoring warning for the Taskflow diff --git a/shared/libraries/opcua/opcuashared/tests/test_opcuaendpoint.cpp b/shared/libraries/opcua/opcuashared/tests/test_opcuaendpoint.cpp index 968a1d0..67174e9 100644 --- a/shared/libraries/opcua/opcuashared/tests/test_opcuaendpoint.cpp +++ b/shared/libraries/opcua/opcuashared/tests/test_opcuaendpoint.cpp @@ -44,7 +44,7 @@ TEST_F(OpcUaEndpointTest, RegisterCustomTypes) endpoint.registerCustomTypes(UA_TYPES_COUNT, UA_TYPES); auto typeList = endpoint.getCustomDataTypes(); - ASSERT_EQ(typeList[0].typesSize, UA_TYPES_COUNT); + ASSERT_EQ(typeList[0].typesSize, static_cast(UA_TYPES_COUNT)); ASSERT_EQ(typeList[0].types, UA_TYPES); } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 7fea325..8136095 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -25,6 +25,7 @@ #include #include #include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS using namespace daq::opcua; @@ -388,7 +389,7 @@ void TmsClientDeviceImpl::findAndCreateServerCapabilities(const DeviceInfoPtr& d for (const auto& [browseName, ref] : serverCapabilitiesReferences.byBrowseName) { const auto optionNodeId = OpcUaNodeId(ref->nodeId.nodeId); - auto clientServerCapability = TmsClientServerCapability(daqContext, browseName, "", clientContext, optionNodeId); + auto clientServerCapability = TmsClientPropertyObject(daqContext, clientContext, optionNodeId); auto capabilityCopy = ServerCapability("", "", ProtocolType::Unknown); for (const auto& prop : clientServerCapability.getAllProperties()) @@ -396,7 +397,32 @@ void TmsClientDeviceImpl::findAndCreateServerCapabilities(const DeviceInfoPtr& d const auto name = prop.getName(); if (!capabilityCopy.hasProperty(name)) capabilityCopy.addProperty(prop.asPtr().clone()); - capabilityCopy.setPropertyValue(name, clientServerCapability.getPropertyValue(name)); + + // AddressInfo is a special case, add it as a child object property of type IAddressInfo + if (name == "AddressInfo") + { + const auto addrInfoId = clientContext->getReferenceBrowser()->getChildNodeId(optionNodeId, "AddressInfo"); + const auto& addrInfoRefs = getChildReferencesOfType(addrInfoId, OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_VARIABLEBLOCKTYPE)); + + for (const auto& [addrInfoBrowseName, addrInfoRef] : addrInfoRefs.byBrowseName) + { + auto clientAddressInfo = TmsClientPropertyObject(daqContext, clientContext, OpcUaNodeId(addrInfoRef->nodeId.nodeId)); + auto addrInfoCopy = AddressInfo(); + for (const auto& addrProp : clientAddressInfo.getAllProperties()) + { + const auto addrName = addrProp.getName(); + if (!addrInfoCopy.hasProperty(addrName)) + addrInfoCopy.addProperty(addrProp.asPtr().clone()); + addrInfoCopy.asPtr().setProtectedPropertyValue(addrName, clientAddressInfo.getPropertyValue(addrName)); + } + + capabilityCopy.addAddressInfo(addrInfoCopy); + } + } + else + { + capabilityCopy.asPtr().setProtectedPropertyValue(name, clientServerCapability.getPropertyValue(name)); + } } auto numberInList = this->tryReadChildNumberInList(optionNodeId); diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt index 1c4625f..d1af844 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt @@ -30,8 +30,8 @@ target_link_libraries(${TEST_APP} PRIVATE ${SDK_TARGET_NAMESPACE}::${MODULE_NAME ) add_test(NAME ${TEST_APP} - COMMAND $ - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND $ + WORKING_DIRECTORY bin ) if (OPENDAQ_ENABLE_COVERAGE) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt b/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt index 2f34235..9512c84 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt @@ -61,8 +61,8 @@ if(SUPPORTS_ASAN) endif() add_test(NAME ${TEST_APP} - COMMAND $ - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND $ + WORKING_DIRECTORY bin ) if (MSVC) From d917cc33ab43a8187d5e2da6abfa5fc24e5de712 Mon Sep 17 00:00:00 2001 From: Nils Roettger <99480819+nilsRoettgerAtBB@users.noreply.github.com> Date: Tue, 16 Jul 2024 14:02:52 +0200 Subject: [PATCH 151/217] Bugfix: Parameter Object has Numeric Id (openDAQ/openDAQ#384) This bugfix fixes that Parameter Objects have a Numeric NodeId if the parent has a string nodeId. With this fix Parameter Objects have a String NodeId with this pattern / --- .../include/opcuaserver/opcuaaddnodeparams.h | 3 ++- .../opcua/opcuaserver/src/opcuaaddnodeparams.cpp | 10 ++++++++-- .../opcuatms_server/src/objects/tms_server_object.cpp | 8 ++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h index 613d700..b8b5dfa 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h @@ -53,7 +53,8 @@ class AddObjectNodeParams : public GenericAddNodeParams public: AddObjectNodeParams(const OpcUaNodeId& requestedNewNodeId); AddObjectNodeParams(const OpcUaNodeId& requestedNewNodeId, const OpcUaNodeId& parentNodeId); - + AddObjectNodeParams(const std::string& name, const OpcUaNodeId& parentNodeId); + OpcUaNodeId typeDefinition = OpcUaNodeId(UA_NS0ID_BASEOBJECTTYPE); }; diff --git a/shared/libraries/opcua/opcuaserver/src/opcuaaddnodeparams.cpp b/shared/libraries/opcua/opcuaserver/src/opcuaaddnodeparams.cpp index 64c8537..1a801f0 100644 --- a/shared/libraries/opcua/opcuaserver/src/opcuaaddnodeparams.cpp +++ b/shared/libraries/opcua/opcuaserver/src/opcuaaddnodeparams.cpp @@ -54,14 +54,20 @@ AddObjectNodeParams::AddObjectNodeParams(const OpcUaNodeId& requestedNewNodeId, { } +AddObjectNodeParams::AddObjectNodeParams(const std::string& name, const OpcUaNodeId& parentNodeId) + : GenericAddNodeParams( + RequestedNodeIdBaseOnName(name, parentNodeId), parentNodeId, OpcUaNodeId(UA_NS0ID_HASCOMPONENT), UA_ObjectAttributes_default) +{ +} + +/*AddVariableNodeParams*/ + AddVariableNodeParams::AddVariableNodeParams(const std::string& name, const OpcUaNodeId& parentNodeId) : GenericAddNodeParams( RequestedNodeIdBaseOnName(name, parentNodeId), parentNodeId, OpcUaNodeId(UA_NS0ID_HASPROPERTY), UA_VariableAttributes_default) { } -/*AddVariableNodeParams*/ - AddVariableNodeParams::AddVariableNodeParams(const OpcUaNodeId& requestedNewNodeId) : AddVariableNodeParams(requestedNewNodeId, OpcUaNodeId()) { diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp index 60b4aae..187a8a2 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp @@ -133,7 +133,15 @@ OpcUaNodeId TmsServerObject::createNode(const OpcUaNodeId& parentNodeId) browseName = typeBrowseName; } + // Frist try to set via getRequestedNodeId, because NodeID will also be string + // if parent is numeric. However object needs to be GenericComponentPtr or child of it. auto params = AddObjectNodeParams(getRequestedNodeId(), parentNodeId); + + // If object is not GenericComponentPtr or child the id should be set to string if possible. + // Possible means if parent has a string nodeId. + if (params.requestedNewNodeId.isNull()) + params = AddObjectNodeParams(browseName, parentNodeId); + configureNodeAttributes(params.attr); params.referenceTypeId = getReferenceType(); params.setBrowseName(browseName); From e8cbf9c773e5bcbf39ede65a198802a5e348db4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE?= Date: Tue, 23 Jul 2024 10:13:29 +0200 Subject: [PATCH 152/217] Standardize cases to PascalCase (openDAQ/openDAQ#355) Change the following to PascalCase: * Component IDs * Reference Device * Reference Function Blocks (backwards compatible) * Classifier * FFT * Power * Renderer * Scaling * Statistics * Trigger * AudioDeviceModuleWavWriter * Reference device IO components (AI, CAN, RefCh) * Component names * Default client device * Type IDs * Reference modules * Streaming/config clients (backwards compatible) * Server modules * MiniAudio * Type names * Reference modules * Streaming/config clients * Server modules * Server capability protocol ID (backwards compatible) * Server capability protocol name * Struct Type field names * Other Required integration changes: * Generally none, except for where integration depends upon changed strings listed above (in the description) in some way * If relying on string comparison to hardcoded old IDs of things like FB, device, server types, or protocol IDs, those comparisons will need to be updated to match the new IDs. eg. a check like `if (fbType.getId() == "ref_fb_module_renderer")` will never be true * Old IDs can still be used when adding new objects to a device via `addDevice`/`addFunctionBlock` or similar calls --- .../src/opcua_client_module_impl.cpp | 14 +-- .../tests/test_opcua_client_module.cpp | 12 +- .../src/opcua_server_impl.cpp | 14 +-- .../src/opcua_server_module_impl.cpp | 4 +- .../tests/test_opcua_server_module.cpp | 22 ++-- .../opcua/opcuaserver/src/opcuaserver.cpp | 2 +- .../opcuashared/tests/test_opcuaendpoint.cpp | 4 +- .../converters/dimension_rule_converter.cpp | 6 +- .../opcuatms/src/core_types_utils.cpp | 2 +- .../test_property_object_conversion_utils.cpp | 6 +- .../opcuatms/tests/test_variant_converter.cpp | 14 +-- .../tests/test_variant_list_converter.cpp | 6 +- .../src/objects/tms_client_device_impl.cpp | 12 +- .../src/objects/tms_client_property_impl.cpp | 2 +- .../src/objects/tms_client_tags_impl.cpp | 2 +- .../opcuatms_client/src/tms_client.cpp | 2 +- .../objects/tms_server_component.h | 12 +- .../objects/tms_server_property_object.cpp | 3 +- .../opcuatms_server/src/tms_server.cpp | 2 +- .../tests/test_tms_function_block.cpp | 4 +- .../tests/test_tms_input_port.cpp | 4 +- .../test_property_object_advanced.cpp | 22 ++-- .../opcuatms_integration/test_tms_channel.cpp | 12 +- .../test_tms_component.cpp | 4 +- .../opcuatms_integration/test_tms_device.cpp | 12 +- .../opcuatms_integration/test_tms_folder.cpp | 4 +- .../test_tms_function_block.cpp | 2 +- .../test_tms_function_block_type.cpp | 34 ++--- .../test_tms_function_property.cpp | 118 +++++++++--------- .../test_tms_fusion_device.cpp | 2 +- .../test_tms_input_port.cpp | 6 +- .../test_tms_property_object.cpp | 8 +- .../opcuatms_integration/test_tms_signal.cpp | 30 ++--- 33 files changed, 203 insertions(+), 200 deletions(-) diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 6e8bf02..f0dd7ac 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -16,7 +16,7 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_CLIENT_MODULE -static const char* DaqOpcUaDeviceTypeId = "opendaq_opcua_config"; +static const char* DaqOpcUaDeviceTypeId = "OpenDAQOPCUAConfiguration"; static const char* DaqOpcUaDevicePrefix = "daq.opcua"; static const char* OpcUaScheme = "opc.tcp"; @@ -24,15 +24,15 @@ using namespace discovery; using namespace daq::opcua; OpcUaClientModule::OpcUaClientModule(ContextPtr context) - : Module("openDAQ OpcUa client module", + : Module("OpenDAQOPCUAClientModule", daq::VersionInfo(OPCUA_CLIENT_MODULE_MAJOR_VERSION, OPCUA_CLIENT_MODULE_MINOR_VERSION, OPCUA_CLIENT_MODULE_PATCH_VERSION), std::move(context), - "OpcUaClient") + "OpenDAQOPCUAClientModule") , discoveryClient( { [context = this->context](MdnsDiscoveredDevice discoveredDevice) { - auto cap = ServerCapability(DaqOpcUaDeviceTypeId, "openDAQ OpcUa", ProtocolType::Configuration); + auto cap = ServerCapability(DaqOpcUaDeviceTypeId, "OpenDAQOPCUA", ProtocolType::Configuration); if (!discoveredDevice.ipv4Address.empty()) { auto connectionStringIpv4 = fmt::format("{}://{}:{}{}", @@ -77,7 +77,7 @@ OpcUaClientModule::OpcUaClientModule(ContextPtr context) {"OPENDAQ"} ) { - loggerComponent = this->context.getLogger().getOrAddComponent("OpcUaClient"); + loggerComponent = this->context.getLogger().getOrAddComponent("OPCUAClient"); discoveryClient.initMdnsClient(List("_opcua-tcp._tcp.local.")); } @@ -151,7 +151,7 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, .build(); connectionInfo.setProtocolId(DaqOpcUaDeviceTypeId) - .setProtocolName("openDAQ OpcUa") + .setProtocolName("OpenDAQOPCUA") .setProtocolType(ProtocolType::Configuration) .setConnectionType("TCP/IP") .addAddress(host) @@ -253,7 +253,7 @@ bool OpcUaClientModule::acceptsConnectionParameters(const StringPtr& connectionS Bool OpcUaClientModule::onCompleteServerCapability(const ServerCapabilityPtr& source, const ServerCapabilityConfigPtr& target) { - if (target.getProtocolId() != "opendaq_opcua_config") + if (target.getProtocolId() != "OpenDAQOPCUAConfiguration") return false; if (target.getConnectionString().getLength() != 0) diff --git a/modules/opcua_client_module/tests/test_opcua_client_module.cpp b/modules/opcua_client_module/tests/test_opcua_client_module.cpp index 771390b..e7371fe 100644 --- a/modules/opcua_client_module/tests/test_opcua_client_module.cpp +++ b/modules/opcua_client_module/tests/test_opcua_client_module.cpp @@ -34,7 +34,7 @@ TEST_F(OpcUaClientModuleTest, CreateModule) TEST_F(OpcUaClientModuleTest, ModuleName) { auto module = CreateModule(); - ASSERT_EQ(module.getName(), "openDAQ OpcUa client module"); + ASSERT_EQ(module.getName(), "OpenDAQOPCUAClientModule"); } TEST_F(OpcUaClientModuleTest, VersionAvailable) @@ -73,7 +73,7 @@ TEST_F(OpcUaClientModuleTest, EnumerateDevices) // ASSERT_NO_THROW(connectionString = module.createConnectionString(serverCapabilityIgnored)); // ASSERT_FALSE(connectionString.assigned()); // -// ServerCapabilityConfigPtr serverCapability = ServerCapability("opendaq_opcua_config", "openDAQ OpcUa", ProtocolType::Configuration); +// ServerCapabilityConfigPtr serverCapability = ServerCapability("OpenDAQOPCUAConfiguration", "OpenDAQOPCUA", ProtocolType::Configuration); // ASSERT_THROW(module.createConnectionString(serverCapability), InvalidParameterException); // // serverCapability.addAddress("123.123.123.123"); @@ -124,8 +124,8 @@ TEST_F(OpcUaClientModuleTest, GetAvailableComponentTypes) DictPtr deviceTypes; ASSERT_NO_THROW(deviceTypes = module.getAvailableDeviceTypes()); ASSERT_EQ(deviceTypes.getCount(), 1u); - ASSERT_TRUE(deviceTypes.hasKey("opendaq_opcua_config")); - ASSERT_EQ(deviceTypes.get("opendaq_opcua_config").getId(), "opendaq_opcua_config"); + ASSERT_TRUE(deviceTypes.hasKey("OpenDAQOPCUAConfiguration")); + ASSERT_EQ(deviceTypes.get("OpenDAQOPCUAConfiguration").getId(), "OpenDAQOPCUAConfiguration"); DictPtr serverTypes; ASSERT_NO_THROW(serverTypes = module.getAvailableServerTypes()); @@ -139,8 +139,8 @@ TEST_F(OpcUaClientModuleTest, DefaultDeviceConfig) DictPtr deviceTypes; ASSERT_NO_THROW(deviceTypes = module.getAvailableDeviceTypes()); ASSERT_EQ(deviceTypes.getCount(), 1u); - ASSERT_TRUE(deviceTypes.hasKey("opendaq_opcua_config")); - auto config = deviceTypes.get("opendaq_opcua_config").createDefaultConfig(); + ASSERT_TRUE(deviceTypes.hasKey("OpenDAQOPCUAConfiguration")); + auto config = deviceTypes.get("OpenDAQOPCUAConfiguration").createDefaultConfig(); ASSERT_TRUE(config.assigned()); ASSERT_EQ(config.getAllProperties().getCount(), 3u); } diff --git a/modules/opcua_server_module/src/opcua_server_impl.cpp b/modules/opcua_server_module/src/opcua_server_impl.cpp index 8f8ef45..cf1b629 100644 --- a/modules/opcua_server_module/src/opcua_server_impl.cpp +++ b/modules/opcua_server_module/src/opcua_server_impl.cpp @@ -11,7 +11,7 @@ using namespace daq; using namespace daq::opcua; OpcUaServerImpl::OpcUaServerImpl(DevicePtr rootDevice, PropertyObjectPtr config, const ContextPtr& context) - : Server("OpcUaServer", config, rootDevice, context, nullptr) + : Server("OpenDAQOPCUAServerModule", config, rootDevice, context, nullptr) , server(rootDevice, context) , context(context) { @@ -32,7 +32,7 @@ void OpcUaServerImpl::populateDefaultConfigFromProvider(const ContextPtr& contex if (!config.assigned()) return; - auto options = context.getModuleOptions("OpcUaServer"); + auto options = context.getModuleOptions("OpenDAQOPCUAServerModule"); for (const auto& [key, value] : options) { if (config.hasProperty(key)) @@ -73,9 +73,9 @@ PropertyObjectPtr OpcUaServerImpl::getDiscoveryConfig() ServerTypePtr OpcUaServerImpl::createType(const ContextPtr& context) { - return ServerType("openDAQ OpcUa", - "openDAQ OpcUa server", - "Publishes device structure over OpcUa protocol", + return ServerType("OpenDAQOPCUA", + "openDAQ OPC UA server", + "Publishes device structure over OPC UA protocol", OpcUaServerImpl::createDefaultConfig(context)); } @@ -86,8 +86,8 @@ void OpcUaServerImpl::onStopServer() { const auto info = this->rootDevice.getInfo(); const auto infoInternal = info.asPtr(); - if (info.hasServerCapability("opendaq_opcua_config")) - infoInternal.removeServerCapability("opendaq_opcua_config"); + if (info.hasServerCapability("OpenDAQOPCUAConfiguration")) + infoInternal.removeServerCapability("OpenDAQOPCUAConfiguration"); } } diff --git a/modules/opcua_server_module/src/opcua_server_module_impl.cpp b/modules/opcua_server_module/src/opcua_server_module_impl.cpp index 939f350..5c866d8 100644 --- a/modules/opcua_server_module/src/opcua_server_module_impl.cpp +++ b/modules/opcua_server_module/src/opcua_server_module_impl.cpp @@ -7,10 +7,10 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_SERVER_MODULE OpcUaServerModule::OpcUaServerModule(ContextPtr context) - : Module("openDAQ OpcUa server module", + : Module("OpenDAQOPCUAServerModule", daq::VersionInfo(OPCUA_SERVER_MODULE_MAJOR_VERSION, OPCUA_SERVER_MODULE_MINOR_VERSION, OPCUA_SERVER_MODULE_PATCH_VERSION), std::move(context), - "OpcUaServer") + "OpenDAQOPCUAServerModule") { } diff --git a/modules/opcua_server_module/tests/test_opcua_server_module.cpp b/modules/opcua_server_module/tests/test_opcua_server_module.cpp index c9eba38..3c6fe81 100644 --- a/modules/opcua_server_module/tests/test_opcua_server_module.cpp +++ b/modules/opcua_server_module/tests/test_opcua_server_module.cpp @@ -60,7 +60,7 @@ static InstancePtr CreateTestInstance() static PropertyObjectPtr CreateServerConfig(const InstancePtr& instance) { - auto config = instance.getAvailableServerTypes().get("openDAQ OpcUa").createDefaultConfig(); + auto config = instance.getAvailableServerTypes().get("OpenDAQOPCUA").createDefaultConfig(); return config; } @@ -77,7 +77,7 @@ TEST_F(OpcUaServerModuleTest, CreateModule) TEST_F(OpcUaServerModuleTest, ModuleName) { auto module = CreateModule(); - ASSERT_EQ(module.getName(), "openDAQ OpcUa server module"); + ASSERT_EQ(module.getName(), "OpenDAQOPCUAServerModule"); } TEST_F(OpcUaServerModuleTest, VersionAvailable) @@ -111,8 +111,8 @@ TEST_F(OpcUaServerModuleTest, GetAvailableComponentTypes) DictPtr serverTypes; ASSERT_NO_THROW(serverTypes = module.getAvailableServerTypes()); ASSERT_EQ(serverTypes.getCount(), 1u); - ASSERT_TRUE(serverTypes.hasKey("openDAQ OpcUa")); - ASSERT_EQ(serverTypes.get("openDAQ OpcUa").getId(), "openDAQ OpcUa"); + ASSERT_TRUE(serverTypes.hasKey("OpenDAQOPCUA")); + ASSERT_EQ(serverTypes.get("OpenDAQOPCUA").getId(), "OpenDAQOPCUA"); } TEST_F(OpcUaServerModuleTest, ServerConfig) @@ -120,8 +120,8 @@ TEST_F(OpcUaServerModuleTest, ServerConfig) auto module = CreateModule(); DictPtr serverTypes = module.getAvailableServerTypes(); - ASSERT_TRUE(serverTypes.hasKey("openDAQ OpcUa")); - auto config = serverTypes.get("openDAQ OpcUa").createDefaultConfig(); + ASSERT_TRUE(serverTypes.hasKey("OpenDAQOPCUA")); + auto config = serverTypes.get("OpenDAQOPCUA").createDefaultConfig(); ASSERT_TRUE(config.assigned()); ASSERT_TRUE(config.hasProperty("Port")); @@ -134,7 +134,7 @@ TEST_F(OpcUaServerModuleTest, CreateServer) auto module = CreateModule(device.getContext()); auto config = CreateServerConfig(device); - ASSERT_NO_THROW(module.createServer("openDAQ OpcUa", device.getRootDevice(), config)); + ASSERT_NO_THROW(module.createServer("OpenDAQOPCUA", device.getRootDevice(), config)); } TEST_F(OpcUaServerModuleTest, CreateServerFromInstance) @@ -142,14 +142,14 @@ TEST_F(OpcUaServerModuleTest, CreateServerFromInstance) auto device = CreateTestInstance(); auto config = CreateServerConfig(device); - ASSERT_NO_THROW(device.addServer("openDAQ OpcUa", config)); + ASSERT_NO_THROW(device.addServer("OpenDAQOPCUA", config)); } TEST_F(OpcUaServerModuleTest, TestConnection) { auto device = CreateTestInstance(); auto config = CreateServerConfig(device); - device.addServer("openDAQ OpcUa", config); + device.addServer("OpenDAQOPCUA", config); OpcUaClient client("opc.tcp://localhost/"); ASSERT_NO_THROW(client.connect()); @@ -163,7 +163,7 @@ TEST_F(OpcUaServerModuleTest, TestConnectionDifferentPort) config.setPropertyValue("Port", 4841); - auto serverPtr = module.createServer("openDAQ OpcUa", device.getRootDevice(), config); + auto serverPtr = module.createServer("OpenDAQOPCUA", device.getRootDevice(), config); OpcUaClient client("opc.tcp://localhost:4841/"); ASSERT_NO_THROW(client.connect()); @@ -175,7 +175,7 @@ TEST_F(OpcUaServerModuleTest, StopServer) auto module = CreateModule(device.getContext()); auto config = CreateServerConfig(device); - auto serverPtr = module.createServer("openDAQ OpcUa", device.getRootDevice(), config); + auto serverPtr = module.createServer("OpenDAQOPCUA", device.getRootDevice(), config); OpcUaClient client("opc.tcp://localhost/"); ASSERT_NO_THROW(client.connect()); diff --git a/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp b/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp index 1a6490e..a13e10d 100644 --- a/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp +++ b/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp @@ -225,7 +225,7 @@ void OpcUaServer::createSession(const OpcUaNodeId& sessionId, void** sessionCont void OpcUaServer::execute() { - setThreadName("OpcUaServer"); + setThreadName("OpenDAQOPCUAServerModule"); while (!terminated) { UA_Server_run_iterate(server, true); diff --git a/shared/libraries/opcua/opcuashared/tests/test_opcuaendpoint.cpp b/shared/libraries/opcua/opcuashared/tests/test_opcuaendpoint.cpp index 67174e9..d9ef274 100644 --- a/shared/libraries/opcua/opcuashared/tests/test_opcuaendpoint.cpp +++ b/shared/libraries/opcua/opcuashared/tests/test_opcuaendpoint.cpp @@ -27,8 +27,8 @@ TEST_F(OpcUaEndpointTest, SettersAndGetters) endpoint.setUrl("opc.tcp://localhost:2000"); ASSERT_EQ(endpoint.getUrl(), "opc.tcp://localhost:2000"); - endpoint.setName("name"); - ASSERT_EQ(endpoint.getName(), "name"); + endpoint.setName("Name"); + ASSERT_EQ(endpoint.getName(), "Name"); endpoint.setUsername("username"); ASSERT_EQ(endpoint.getUsername(), "username"); diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/dimension_rule_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/dimension_rule_converter.cpp index bded1a7..ee0c886 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/dimension_rule_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/dimension_rule_converter.cpp @@ -91,7 +91,7 @@ template <> DimensionRulePtr StructConverter::ToDaqObject( const UA_ListRuleDescriptionStructure& tmsStruct, const ContextPtr& /*context*/) { - if (tmsStruct.type != "list") + if (tmsStruct.type != "List") throw ConversionFailedException(); const SizeT elementsSize = tmsStruct.elementsSize; @@ -112,12 +112,12 @@ template <> OpcUaObject StructConverter::ToTmsType( const DimensionRulePtr& object, const ContextPtr& /*context*/) { - ListPtr daqList = object.getParameters().get("list"); + ListPtr daqList = object.getParameters().get("List"); OpcUaObject uaRuleDescription; uaRuleDescription->elementsSize = daqList.getCount(); uaRuleDescription->elements = static_cast(UA_Array_new(uaRuleDescription->elementsSize, GetUaDataType())); - uaRuleDescription->type = UA_STRING_ALLOC("list"); + uaRuleDescription->type = UA_STRING_ALLOC("List"); for (SizeT i = 0; i < daqList.getCount(); i++) uaRuleDescription->elements[i] = VariantConverter::ToVariant(daqList[i]).getDetachedValue(); diff --git a/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp b/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp index 6c0b348..380f41b 100644 --- a/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp @@ -34,7 +34,7 @@ static std::unordered_map nodeIdToCoreTypeMap = { {OpcUaNodeId(0, UA_DAQBTID_RATIONALNUMBER64), ctRatio}}; static std::unordered_set convertibleNativeStructs = { - "unit", "range", "argumentInfo", "complexNumber", "functionBlockType"}; + "Unit", "Range", "ArgumentInfo", "ComplexNumber", "FunctionBlockType"}; } StringPtr ConvertToDaqCoreString(const UA_String& uaString) diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_property_object_conversion_utils.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_property_object_conversion_utils.cpp index fa75998..6ea0fde 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/test_property_object_conversion_utils.cpp +++ b/shared/libraries/opcuatms/opcuatms/tests/test_property_object_conversion_utils.cpp @@ -14,7 +14,7 @@ using namespace daq::opcua::tms; static PropertyObjectPtr CreateTestPropertyObject() { auto obj = PropertyObject(); - obj.addProperty(StringProperty("name", "")); + obj.addProperty(StringProperty("Name", "")); obj.addProperty(IntProperty("age", 0)); obj.addProperty(FloatProperty("weight", 0.0)); obj.addProperty(BoolProperty("isTheBest", false)); @@ -25,7 +25,7 @@ static PropertyObjectPtr CreateTestPropertyObject() TEST_F(PropertyObjectConversionUtilsTest, SimpleObject) { auto obj = CreateTestPropertyObject(); - obj.setPropertyValue("name", "Jovanka"); + obj.setPropertyValue("Name", "Jovanka"); obj.setPropertyValue("age", 99); obj.setPropertyValue("weight", 60.5); obj.setPropertyValue("isTheBest", true); @@ -65,7 +65,7 @@ TEST_F(PropertyObjectConversionUtilsTest, CloneDefault) TEST_F(PropertyObjectConversionUtilsTest, Clone) { auto obj = CreateTestPropertyObject(); - obj.setPropertyValue("name", "Jovanka"); + obj.setPropertyValue("Name", "Jovanka"); obj.setPropertyValue("age", 99); obj.setPropertyValue("weight", 60.5); obj.setPropertyValue("isTheBest", true); diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_variant_converter.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_variant_converter.cpp index dc4f050..411f335 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/test_variant_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/tests/test_variant_converter.cpp @@ -47,13 +47,13 @@ static DataDescriptorBuilderPtr CreateTestStructDescriptorBuilder() // Meta meta; // }; - auto id = DataDescriptorBuilder().setSampleType(SampleType::Int32).setName("id").build(); + auto id = DataDescriptorBuilder().setSampleType(SampleType::Int32).setName("Id").build(); auto data = DataDescriptorBuilder().setSampleType(SampleType::UInt8).setName("data").build(); auto desc = DataDescriptorBuilder() .setSampleType(SampleType::String) - .setName("description") - .setUnit(Unit("V", 1, "voltage", "quantity")) + .setName("Description") + .setUnit(Unit("V", 1, "voltage", "Quantity")) .setValueRange(Range(1, 10)) .setRule(ExplicitDataRule()) .setOrigin("2022-11-30T10:53:06") @@ -254,7 +254,7 @@ TEST_F(VariantConverterTest, CustomDataRule) { auto params = Dict(); params.set("count", 1); - params.set("type", "apple"); + params.set("Type", "apple"); params.set("type1", "gala"); params.set("type2", "fuji"); params.set("weight", 1.123); @@ -272,7 +272,7 @@ TEST_F(VariantConverterTest, DataDescriptor) auto descriptor = DataDescriptorBuilder() .setSampleType(SampleType::Float64) .setName("Value 1") - .setUnit(Unit("V", 1, "voltage", "quantity")) + .setUnit(Unit("V", 1, "voltage", "Quantity")) .setValueRange(Range(1, 10)) .setRule(ExplicitDataRule()) .setDimensions(CreateTestDimensions()) @@ -316,7 +316,7 @@ TEST_F(VariantConverterTest, StructDescriptorEmpty) TEST_F(VariantConverterTest, DataDescriptorMetadata) { auto metadata = Dict(); - metadata.set("name", "sine1"); + metadata.set("Name", "sine1"); metadata.set("frequency", "50"); auto descriptor = CreateTestStructDescriptorBuilder().setName("Sine1").setMetadata(metadata).build(); @@ -371,7 +371,7 @@ TEST_F(VariantConverterTest, CustomDimensionRule) { auto params = Dict(); params.set("count", 1); - params.set("type", "apple"); + params.set("Type", "apple"); params.set("type1", "gala"); params.set("type2", "fuji"); params.set("weight", 1.123); diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_variant_list_converter.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_variant_list_converter.cpp index 40544b7..25e5acd 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/test_variant_list_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/tests/test_variant_list_converter.cpp @@ -77,7 +77,7 @@ TEST_F(VariantListConverterTest, Ratio) TEST_F(VariantListConverterTest, Unit) { auto list = List(); - list.pushBack(Unit("symbol", 1, "name", "q")); + list.pushBack(Unit("Symbol", 1, "Name", "q")); list.pushBack(Unit("V", 2)); const auto variant = VariantConverter::ToArrayVariant(list); @@ -184,7 +184,7 @@ TEST_F(VariantListConverterTest, BaseObject) TEST_F(VariantListConverterTest, DataDescriptor) { - auto id = DataDescriptorBuilder().setSampleType(SampleType::Int32).setName("id").build(); + auto id = DataDescriptorBuilder().setSampleType(SampleType::Int32).setName("Id").build(); auto data = DataDescriptorBuilder().setSampleType(SampleType::UInt8).setName("data").build(); auto can = DataDescriptorBuilder() .setSampleType(SampleType::Struct) @@ -218,7 +218,7 @@ TEST_F(VariantListConverterTest, ListDataDescriptor) TEST_F(VariantListConverterTest, DataDescriptorMetadata) { auto metadata = Dict(); - metadata.set("name", "sine1"); + metadata.set("Name", "sine1"); metadata.set("frequency", "50"); auto descriptor1 = DataDescriptorBuilder().setSampleType(SampleType::Float64).setName("Sine1").setMetadata(metadata).build(); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 8136095..57e078e 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -34,9 +34,9 @@ namespace detail { static std::unordered_set defaultComponents = {"Sig", "FB", "IO", "ServerCapabilities"}; - static std::unordered_map> deviceInfoSetterMap = { + static std::unordered_map> deviceInfoSetterMap = { {"AssetId", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setAssetId(v.toString()); }}, - {"ComponentName", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v){ info.setName(v.toString()); }}, + {"ComponentName", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setName(v.toString()); }}, {"DeviceClass", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setDeviceClass(v.toString()); }}, {"DeviceManual", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setDeviceManual(v.toString()); }}, {"DeviceRevision", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setDeviceRevision(v.toString()); }}, @@ -55,9 +55,11 @@ namespace detail {"Position", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setPosition(v.toInteger()); }}, {"SystemType", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setSystemType(v.toString()); }}, {"SystemUUID", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setSystemUuid(v.toString()); }}, - {"OpenDaqPackageVersion",[](const DeviceInfoConfigPtr& info, const OpcUaVariant& v){ info.asPtr().setProtectedPropertyValue("sdkVersion", v.toString()); }}, + {"OpenDaqPackageVersion", + [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) + { info.asPtr().setProtectedPropertyValue("sdkVersion", v.toString()); }}, }; -} + } TmsClientDeviceImpl::TmsClientDeviceImpl(const ContextPtr& ctx, const ComponentPtr& parent, @@ -187,7 +189,7 @@ DeviceInfoPtr TmsClientDeviceImpl::onGetInfo() for (const auto & cap : deviceInfo.getServerCapabilities()) { - if (cap.getProtocolId() == "opendaq_opcua_config") + if (cap.getProtocolId() == "OpenDAQOPCUAConfiguration") { deviceInfo.setConnectionString(cap.getConnectionString()); } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp index 094c953..0db9811 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp @@ -178,7 +178,7 @@ void TmsClientPropertyImpl::configurePropertyFields() value = reader->getValue(nodeId, UA_ATTRIBUTEID_VALUE); this->defaultValue = VariantConverter::ToDaqObject(value, daqContext); LOG_W( - "Failed to read default value of property {} on OpcUa client. Detault value is set to the value at connection time.", + "Failed to read default value of property {} on OpcUa client. Default value is set to the value at connection time.", this->name); } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_tags_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_tags_impl.cpp index 6770cce..295a89c 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_tags_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_tags_impl.cpp @@ -8,7 +8,7 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS TmsClientTagsImpl::TmsClientTagsImpl(const ContextPtr& ctx, const TmsClientContextPtr& clientContext, const opcua::OpcUaNodeId& nodeId) : TmsClientObjectImpl(ctx, clientContext, nodeId) , TagsImpl() - , loggerComponent(ctx.getLogger().getOrAddComponent("OpcUaClient")) + , loggerComponent(ctx.getLogger().getOrAddComponent("OpenDAQOPCUAClientModule")) { } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp index a421775..f5626d7 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp @@ -32,7 +32,7 @@ TmsClient::TmsClient(const ContextPtr& context, : context(context) , endpoint(endpoint) , parent(parent) - , loggerComponent(context.getLogger().assigned() ? context.getLogger().getOrAddComponent("OpcUaClient") + , loggerComponent(context.getLogger().assigned() ? context.getLogger().getOrAddComponent("OpenDAQOPCUAClientModule") : throw ArgumentNullException("Logger must not be null")) { } diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h index 50719ff..5c76bfb 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h @@ -163,12 +163,12 @@ void TmsServerComponent::bindCallbacks() } catch ([[maybe_unused]] const std::exception& e) { - const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClient"); + const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpenDAQOPCUAClientModule"); LOG_D("OPC UA Component {} failed to set component name: {}", this->object.getLocalId(), e.what()); } catch (...) { - const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClient"); + const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpenDAQOPCUAClientModule"); LOG_D("OPC UA Component {} failed to set component name.", this->object.getLocalId()); } @@ -189,12 +189,12 @@ void TmsServerComponent::bindCallbacks() } catch ([[maybe_unused]] const std::exception& e) { - const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClient"); + const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpenDAQOPCUAClientModule"); LOG_D("OPC UA Component {} failed to set component description: {}", this->object.getLocalId(), e.what()); } catch (...) { - const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClient"); + const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpenDAQOPCUAClientModule"); LOG_D("OPC UA Component {} failed to set component description.", this->object.getLocalId()); } @@ -247,12 +247,12 @@ void TmsServerComponent::onCoreEvent(const CoreEventArgsPtr& args) } catch ([[maybe_unused]] const std::exception& e) { - const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClient"); + const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpenDAQOPCUAClientModule"); LOG_D("OPC UA Component {} failed to set node attribute \"{}\": {}", this->object.getLocalId(), attrName, e.what()); } catch (...) { - const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClient"); + const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpenDAQOPCUAClientModule"); LOG_D("OPC UA Component {} failed to set node attribute \"{}\".", this->object.getLocalId(), attrName); } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp index d32f7f3..dbeb729 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp @@ -133,8 +133,9 @@ void TmsServerPropertyObject::addChildNodes() const auto propName = prop.getName(); if (hasChildNode(propName)) { + const auto tempId = getChildNodeId(propName); serverInfo = std::make_shared(prop, server, daqContext, tmsContext, object, propOrder); - childNodeId = serverInfo->registerToExistingOpcUaNode(nodeId); + childNodeId = serverInfo->registerToExistingOpcUaNode(tempId); } else { diff --git a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp index 20d9884..0c03a48 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp @@ -49,7 +49,7 @@ void TmsServer::start() tmsContext = std::make_shared(context, device); auto signals = device.getSignals(); - auto serverCapability = ServerCapability("opendaq_opcua_config", "openDAQ OpcUa", ProtocolType::Configuration); + auto serverCapability = ServerCapability("OpenDAQOPCUAConfiguration", "OpenDAQOPCUA", ProtocolType::Configuration); serverCapability.setPrefix("daq.opcua"); serverCapability.setConnectionType("TCP/IP"); serverCapability.setPort(opcUaPort); diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp index f095bb7..6ac3077 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp @@ -19,7 +19,7 @@ class TmsFunctionBlockTest : public TmsServerObjectTest { public: - FunctionBlockPtr createFunctionBlock(const FunctionBlockTypePtr& type = FunctionBlockType("uid", "name", "desc")) + FunctionBlockPtr createFunctionBlock(const FunctionBlockTypePtr& type = FunctionBlockType("UID", "Name", "Desc")) { return MockFunctionBlock(type, ctx, nullptr, "mockfb"); } @@ -79,7 +79,7 @@ TEST_F(TmsFunctionBlockTest, BrowseSignals) TEST_F(TmsFunctionBlockTest, DISABLED_Property) { // Build functionBlock info: - const FunctionBlockTypePtr type = FunctionBlockType("uid", "name", "desc"); + const FunctionBlockTypePtr type = FunctionBlockType("UID", "Name", "Desc"); // Build server functionBlock auto serverFunctionBlock = createFunctionBlock(type); diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp index c516c39..7232882 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp @@ -24,8 +24,8 @@ class TmsInputPortTest : public TmsServerObjectTest public: InputPortPtr createInputPort() { - auto port = InputPort(ctx, nullptr, "port"); - port.getTags().asPtr().add("port"); + auto port = InputPort(ctx, nullptr, "Port"); + port.getTags().asPtr().add("Port"); return port; } }; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp index 7d12471..bf83b21 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp @@ -61,7 +61,7 @@ class TmsPropertyObjectAdvancedTest : public TmsObjectIntegrationTest auto functionProp = FunctionProperty( - "function", FunctionInfo(ctString, List(ArgumentInfo("int", ctInt), ArgumentInfo("float", ctFloat)))); + "function", FunctionInfo(ctString, List(ArgumentInfo("Int", ctInt), ArgumentInfo("Float", ctFloat)))); FunctionPtr funcCallback = Function( [](ListPtr args) { @@ -77,9 +77,9 @@ class TmsPropertyObjectAdvancedTest : public TmsObjectIntegrationTest auto procProp = FunctionProperty("procedure", ProcedureInfo(List( - ArgumentInfo("ratio", ctRatio), - ArgumentInfo("string", ctString), - ArgumentInfo("bool", ctBool)))); + ArgumentInfo("Ratio", ctRatio), + ArgumentInfo("String", ctString), + ArgumentInfo("Bool", ctBool)))); ProcedurePtr procCallback = Procedure( [&](ListPtr args) { @@ -132,24 +132,24 @@ class TmsPropertyObjectAdvancedTest : public TmsObjectIntegrationTest .addProperty(StructProperty("ArgumentStruct", ArgumentInfo("Arg", ctInt))) .addProperty(StructProperty("RangeStruct", Range(1, 2))) .addProperty(StructProperty("ComplexNumberStruct", ComplexNumber(1, 2))) - .addProperty(StructProperty("FunctionBlockTypeStruct", FunctionBlockType("id", "name", "desc"))) + .addProperty(StructProperty("FunctionBlockTypeStruct", FunctionBlockType("Id", "Name", "Desc"))) .addProperty(StructProperty("DeviceDomainStructure", Struct("DeviceDomainStructure", Dict({{"Resolution", Ratio(10, 20)}, {"TicksSinceOrigin", 1000}, - {"Origin", "origin"}, + {"Origin", "Origin"}, {"Unit", - Unit("symbol", -1, "name", "quantity")}}), + Unit("Symbol", -1, "Name", "Quantity")}}), manager))) .addProperty(StructProperty("ListRuleDescriptionStructure", Struct("ListRuleDescriptionStructure", Dict( - {{"Type", "list"}, {"Elements", List("foo", "bar")}}), + {{"Type", "List"}, {"Elements", List("foo", "bar")}}), manager))) .addProperty(StructProperty("CustomRuleDescriptionStructure", Struct("CustomRuleDescriptionStructure", Dict( - {{"Type", "list"}, + {{"Type", "List"}, {"Parameters", Dict({{"foo", "bar"}, {"foo1", "bar1"}})}}), manager))) @@ -749,11 +749,11 @@ TEST_F(TmsPropertyObjectAdvancedTest, StructureSet) manager)); clientObj.setPropertyValue("ListRuleDescriptionStructure", Struct("ListRuleDescriptionStructure", - Dict({{"Type", "list"}, {"Elements", List("foo1", "bar1")}}), + Dict({{"Type", "List"}, {"Elements", List("foo1", "bar1")}}), manager)); clientObj.setPropertyValue("CustomRuleDescriptionStructure", Struct("CustomRuleDescriptionStructure", - Dict({{"Type", "list"}, + Dict({{"Type", "List"}, {"Parameters", Dict({{"foo", "bar"}, {"foo1", "bar1"}})}}), manager)); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_channel.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_channel.cpp index 34919ed..675a844 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_channel.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_channel.cpp @@ -39,7 +39,7 @@ TEST_F(TmsChannelTest, Register) auto serverChannel = TmsServerChannel(channel, this->getServer(), ctx, serverContext); // Not possible either auto nodeId = serverChannel.registerOpcUaNode(); - ChannelPtr clientChannel = TmsClientChannel(ctx, nullptr, "ch", clientContext, nodeId); + ChannelPtr clientChannel = TmsClientChannel(ctx, nullptr, "Ch", clientContext, nodeId); ASSERT_TRUE(clientChannel.assigned()); } @@ -51,7 +51,7 @@ TEST_F(TmsChannelTest, BrowseName) auto tmsServerChannel = TmsServerChannel(serverChannel, this->getServer(), ctx, serverContext); auto nodeId = tmsServerChannel.registerOpcUaNode(); - ChannelPtr clientChannel = TmsClientChannel(ctx, nullptr, "ch", clientContext, nodeId); + ChannelPtr clientChannel = TmsClientChannel(ctx, nullptr, "Ch", clientContext, nodeId); auto browseName = client->readBrowseName(nodeId); ASSERT_EQ(browseName, "mockch"); @@ -68,7 +68,7 @@ TEST_F(TmsChannelTest, AttrFunctionBlockType) auto tmsServerChannel = TmsServerChannel(serverChannel, this->getServer(), ctx, serverContext); auto nodeId = tmsServerChannel.registerOpcUaNode(); - ChannelPtr clientChannel = TmsClientChannel(ctx, nullptr, "ch", clientContext, nodeId); + ChannelPtr clientChannel = TmsClientChannel(ctx, nullptr, "Ch", clientContext, nodeId); auto type = clientChannel.getFunctionBlockType(); ASSERT_EQ(type.getId(), "mock_ch"); @@ -84,7 +84,7 @@ TEST_F(TmsChannelTest, MethodGetInputPorts) auto tmsServerChannel = TmsServerChannel(serverChannel, this->getServer(), ctx, serverContext); auto channelNodeId = tmsServerChannel.registerOpcUaNode(); - ChannelPtr clientChannel = TmsClientChannel(ctx, nullptr, "ch", clientContext, channelNodeId); + ChannelPtr clientChannel = TmsClientChannel(ctx, nullptr, "Ch", clientContext, channelNodeId); auto inputPorts = clientChannel.getInputPorts(); ASSERT_TRUE(inputPorts != nullptr); @@ -103,7 +103,7 @@ TEST_F(TmsChannelTest, MethodGetSignals) auto tmsServerChannel = TmsServerChannel(serverChannel, this->getServer(), ctx, serverContext); auto channelNodeId = tmsServerChannel.registerOpcUaNode(); - auto clientChannel = TmsClientChannel(ctx, nullptr, "ch", clientContext, channelNodeId); + auto clientChannel = TmsClientChannel(ctx, nullptr, "Ch", clientContext, channelNodeId); ListPtr signals; ASSERT_NO_THROW(signals = clientChannel.getSignals()); @@ -137,7 +137,7 @@ TEST_F(TmsChannelTest, MethodGetStatusSignal) OpcUaNodeId referenceTypeId(NAMESPACE_DAQBSP, UA_DAQBSPID_HASSTATUSSIGNAL); getServer()->addReference(channelNodeId, referenceTypeId, signalNodeId, true); - ChannelPtr clientChannel = TmsClientChannel(ctx, nullptr, "ch", clientContext, channelNodeId); + ChannelPtr clientChannel = TmsClientChannel(ctx, nullptr, "Ch", clientContext, channelNodeId); //EXPECT_THROW(clientChannel.getStatusSignal(), daq::opcua::OpcUaClientCallNotAvailableException); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_component.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_component.cpp index 1fd0d79..d2dc8c3 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_component.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_component.cpp @@ -25,7 +25,7 @@ class TmsComponentTest : public TmsObjectIntegrationTest component.addProperty(StringProperty("foo", "bar")); auto obj = PropertyObject(); - obj.addProperty(IntProperty("int", 0)); + obj.addProperty(IntProperty("Int", 0)); component.addProperty(ObjectProperty("obj", obj)); component.getTags().asPtr().add("tag1"); @@ -113,7 +113,7 @@ TEST_F(TmsComponentTest, Properties) PropertyObjectPtr serverObj = component.serverComponent.getPropertyValue("obj"); PropertyObjectPtr clientObj = component.clientComponent.getPropertyValue("obj"); - ASSERT_EQ(serverObj.getPropertyValue("int"), clientObj.getPropertyValue("int")); + ASSERT_EQ(serverObj.getPropertyValue("Int"), clientObj.getPropertyValue("Int")); ASSERT_EQ(component.serverComponent.getPropertyValue("foo"), component.clientComponent.getPropertyValue("foo")); component.clientComponent.setPropertyValue("foo", "notbar"); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp index 4d5ae7f..02847ef 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp @@ -162,8 +162,8 @@ TEST_F(TmsDeviceTest, DISABLED_Property) ASSERT_EQ(clientDevice.getPropertyValue("SampleRate"), 14.0); ASSERT_EQ(serverDevice.getPropertyValue("SampleRate"), 14.0); - ASSERT_EQ(clientDevice.getPropertyValue("UserName"), ""); - ASSERT_EQ(clientDevice.getPropertyValue("Location"), ""); + ASSERT_EQ(clientDevice.getPropertyValue("userName"), ""); + ASSERT_EQ(clientDevice.getPropertyValue("location"), ""); } TEST_F(TmsDeviceTest, DeviceInfo) @@ -304,13 +304,13 @@ TEST_F(TmsDeviceTest, DeviceDomain) ASSERT_EQ(ticksSinceOrigin, 789); auto origin = deviceDomain.getOrigin(); - ASSERT_EQ(origin, "origin"); + ASSERT_EQ(origin, "Origin"); auto unit = deviceDomain.getUnit(); ASSERT_EQ(unit.getId(), 987); - ASSERT_EQ(unit.getSymbol(), "unit_symbol"); - ASSERT_EQ(unit.getName(), "unit_name"); - ASSERT_EQ(unit.getQuantity(), "unit_quantity"); + ASSERT_EQ(unit.getSymbol(), "UnitSymbol"); + ASSERT_EQ(unit.getName(), "UnitName"); + ASSERT_EQ(unit.getQuantity(), "UnitQuantity"); } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp index ddcf2ce..9400753 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp @@ -31,7 +31,7 @@ class TmsFolderTest : public TmsObjectIntegrationTest folder2.addProperty(StringProperty("foo", "bar")); auto obj = PropertyObject(); - obj.addProperty(IntProperty("int", 0)); + obj.addProperty(IntProperty("Int", 0)); leafFolder.addProperty(ObjectProperty("obj", obj)); folder1.getTags().asPtr().add("tag1"); @@ -127,7 +127,7 @@ TEST_F(TmsFolderTest, Properties) PropertyObjectPtr serverObj = folder.serverFolder.getItems()[0].asPtr().getItems()[0].getPropertyValue("obj"); PropertyObjectPtr clientObj = folder.clientFolder.getItems()[0].asPtr().getItems()[0].getPropertyValue("obj"); - ASSERT_EQ(serverObj.getPropertyValue("int"), clientObj.getPropertyValue("int")); + ASSERT_EQ(serverObj.getPropertyValue("Int"), clientObj.getPropertyValue("Int")); ASSERT_EQ(folder.serverFolder.getItems()[0].getPropertyValue("foo"), folder.clientFolder.getItems()[0].getPropertyValue("foo")); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp index d4316d7..a69f403 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp @@ -27,7 +27,7 @@ using namespace opcua; class TmsFunctionBlockTest : public TmsObjectIntegrationTest { public: - FunctionBlockPtr createFunctionBlock(const FunctionBlockTypePtr& type = FunctionBlockType("uid", "name", "desc")) + FunctionBlockPtr createFunctionBlock(const FunctionBlockTypePtr& type = FunctionBlockType("UID", "Name", "Desc")) { const auto context = NullContext(); return MockFunctionBlock(type, context, nullptr, "mockfb"); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block_type.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block_type.cpp index fdadb17..b6280c6 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block_type.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block_type.cpp @@ -17,11 +17,11 @@ class TmsFunctionBlockTypeTest : public TmsObjectIntegrationTest FunctionBlockTypePtr createFunctionBlockType() { auto defaultConfig = PropertyObject(); - defaultConfig.addProperty(IntProperty("port", 1000)); - defaultConfig.addProperty(StringProperty("name", "vlado")); - defaultConfig.addProperty(ListProperty("scaling", List(1.0, 2.0, 3.0))); + defaultConfig.addProperty(IntProperty("Port", 1000)); + defaultConfig.addProperty(StringProperty("Name", "vlado")); + defaultConfig.addProperty(ListProperty("Scaling", List(1.0, 2.0, 3.0))); - return FunctionBlockType("ref_fb", "Reference function block", "Description", defaultConfig); + return FunctionBlockType("RefFB", "Reference function block", "Description", defaultConfig); } }; @@ -57,7 +57,7 @@ TEST_F(TmsFunctionBlockTypeTest, Values) TEST_F(TmsFunctionBlockTypeTest, DefaultConfig) { - auto fbType = FunctionBlockType("id", "", ""); + auto fbType = FunctionBlockType("Id", "", ""); auto serverFbType = std::make_shared(fbType, server, ctx, serverContext); auto nodeId = serverFbType->registerOpcUaNode(); auto clientFbType = TmsClientFunctionBlockType(ctx, clientContext, nodeId); @@ -74,11 +74,11 @@ TEST_F(TmsFunctionBlockTypeTest, CloneConfig) auto clientConfig1 = clientFbType.createDefaultConfig(); auto clientConfig2 = clientFbType.createDefaultConfig(); - clientConfig1.setPropertyValue("name", "name1"); - clientConfig2.setPropertyValue("name", "name2"); + clientConfig1.setPropertyValue("Name", "name1"); + clientConfig2.setPropertyValue("Name", "name2"); - ASSERT_EQ(clientConfig1.getPropertyValue("name"), "name1"); - ASSERT_EQ(clientConfig2.getPropertyValue("name"), "name2"); + ASSERT_EQ(clientConfig1.getPropertyValue("Name"), "name1"); + ASSERT_EQ(clientConfig2.getPropertyValue("Name"), "name2"); } TEST_F(TmsFunctionBlockTypeTest, ReadOnly) @@ -95,9 +95,9 @@ TEST_F(TmsFunctionBlockTypeTest, ReadOnly) auto browser = CachedReferenceBrowser(client); const auto defaultConfigId = browser.getChildNodeId(nodeId, "DefaultConfig"); - const auto nameId = browser.getChildNodeId(defaultConfigId, "name"); - const auto portId = browser.getChildNodeId(defaultConfigId, "port"); - const auto scalingId = browser.getChildNodeId(defaultConfigId, "scaling"); + const auto nameId = browser.getChildNodeId(defaultConfigId, "Name"); + const auto portId = browser.getChildNodeId(defaultConfigId, "Port"); + const auto scalingId = browser.getChildNodeId(defaultConfigId, "Scaling"); ASSERT_THROW(client->writeValue(nameId, OpcUaVariant("value")), OpcUaException); ASSERT_THROW(client->writeValue(portId, OpcUaVariant(1001)), OpcUaException); @@ -109,13 +109,13 @@ TEST_F(TmsFunctionBlockTypeTest, DISABLED_NonDefaultValues) // This should work, but it doesnt, because of an error in client property object. auto defaultConfig = PropertyObject(); - defaultConfig.addProperty(IntProperty("port", 0)); - defaultConfig.addProperty(StringProperty("name", "")); + defaultConfig.addProperty(IntProperty("Port", 0)); + defaultConfig.addProperty(StringProperty("Name", "")); - defaultConfig.setPropertyValue("port", 1000); - defaultConfig.setPropertyValue("name", "vlado"); + defaultConfig.setPropertyValue("Port", 1000); + defaultConfig.setPropertyValue("Name", "vlado"); - auto fbType = FunctionBlockType("ref_fb", "Reference function block", "Description", defaultConfig); + auto fbType = FunctionBlockType("RefFB", "Reference function block", "Description", defaultConfig); auto serverFbType = std::make_shared(fbType, server, ctx, serverContext); auto nodeId = serverFbType->registerOpcUaNode(); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_property.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_property.cpp index 8b7f32c..6133093 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_property.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_property.cpp @@ -45,13 +45,13 @@ class TmsFunctionTest: public TmsObjectIntegrationTest TEST_F(TmsFunctionTest, ProcedureNoArgs) { auto obj = PropertyObject(); - obj.addProperty(FunctionProperty("proc", ProcedureInfo())); + obj.addProperty(FunctionProperty("Proc", ProcedureInfo())); bool called = false; auto proc = Procedure([&called]() { called = true; }); - obj.setPropertyValue("proc", proc); + obj.setPropertyValue("Proc", proc); auto [serverObj, clientObj] = registerPropertyObject(obj); - ProcedurePtr clientProc = clientObj.getPropertyValue("proc"); + ProcedurePtr clientProc = clientObj.getPropertyValue("Proc"); ASSERT_NO_THROW(clientProc()); ASSERT_EQ(called, true); } @@ -59,25 +59,25 @@ TEST_F(TmsFunctionTest, ProcedureNoArgs) TEST_F(TmsFunctionTest, FunctionNoArgs) { auto obj = PropertyObject(); - obj.addProperty(FunctionProperty("func", FunctionInfo(ctBool))); + obj.addProperty(FunctionProperty("Func", FunctionInfo(ctBool))); auto func = Function([]() { return true; }); - obj.setPropertyValue("func", func); + obj.setPropertyValue("Func", func); auto [serverObj, clientObj] = registerPropertyObject(obj); - FunctionPtr clientFunc = clientObj.getPropertyValue("func"); + FunctionPtr clientFunc = clientObj.getPropertyValue("Func"); ASSERT_TRUE(clientFunc()); } TEST_F(TmsFunctionTest, ProcedureOneArg) { auto obj = PropertyObject(); - obj.addProperty(FunctionProperty("proc", ProcedureInfo(List(ArgumentInfo("int", ctInt))))); + obj.addProperty(FunctionProperty("Proc", ProcedureInfo(List(ArgumentInfo("Int", ctInt))))); Int callValue; auto proc = Procedure([&callValue](const IntegerPtr& arg) { callValue = arg; }); - obj.setPropertyValue("proc", proc); + obj.setPropertyValue("Proc", proc); auto [serverObj, clientObj] = registerPropertyObject(obj); - ProcedurePtr clientProc = clientObj.getPropertyValue("proc"); + ProcedurePtr clientProc = clientObj.getPropertyValue("Proc"); ASSERT_NO_THROW(clientProc(10)); ASSERT_EQ(callValue, 10); @@ -89,13 +89,13 @@ TEST_F(TmsFunctionTest, ProcedureOneArg) TEST_F(TmsFunctionTest, FunctionOneArg) { auto obj = PropertyObject(); - obj.addProperty(FunctionProperty("func", FunctionInfo(ctInt, List(ArgumentInfo("int", ctInt))))); + obj.addProperty(FunctionProperty("Func", FunctionInfo(ctInt, List(ArgumentInfo("Int", ctInt))))); Int callValue; auto func = Function([&callValue](const IntegerPtr& arg) { return arg; }); - obj.setPropertyValue("func", func); + obj.setPropertyValue("Func", func); auto [serverObj, clientObj] = registerPropertyObject(obj); - FunctionPtr clientFunc = clientObj.getPropertyValue("func"); + FunctionPtr clientFunc = clientObj.getPropertyValue("Func"); ASSERT_EQ(clientFunc(10), 10); ASSERT_EQ(clientFunc(100), 100); @@ -105,7 +105,7 @@ TEST_F(TmsFunctionTest, ProcedureMultipleArgs) { auto obj = PropertyObject(); obj.addProperty(FunctionProperty( - "proc", ProcedureInfo(List(ArgumentInfo("int", ctInt), ArgumentInfo("ratio", ctRatio), ArgumentInfo("string", ctString))))); + "Proc", ProcedureInfo(List(ArgumentInfo("Int", ctInt), ArgumentInfo("Ratio", ctRatio), ArgumentInfo("String", ctString))))); Int intArg; RatioPtr ratioArg; @@ -116,10 +116,10 @@ TEST_F(TmsFunctionTest, ProcedureMultipleArgs) ratioArg = args[1]; stringArg = args[2]; }); - obj.setPropertyValue("proc", proc); + obj.setPropertyValue("Proc", proc); auto [serverObj, clientObj] = registerPropertyObject(obj); - ProcedurePtr clientProc = clientObj.getPropertyValue("proc"); + ProcedurePtr clientProc = clientObj.getPropertyValue("Proc"); clientProc(10, Ratio(1, 20), "foo"); @@ -132,8 +132,8 @@ TEST_F(TmsFunctionTest, FunctionMultipleArgs) { auto obj = PropertyObject(); obj.addProperty(FunctionProperty( - "func", - FunctionInfo(ctBool, List(ArgumentInfo("int", ctInt), ArgumentInfo("ratio", ctRatio), ArgumentInfo("string", ctString))))); + "Func", + FunctionInfo(ctBool, List(ArgumentInfo("Int", ctInt), ArgumentInfo("Ratio", ctRatio), ArgumentInfo("String", ctString))))); auto func = Function([](const ListPtr& args) { @@ -142,10 +142,10 @@ TEST_F(TmsFunctionTest, FunctionMultipleArgs) valid = valid && args[2] == "foo"; return valid; }); - obj.setPropertyValue("func", func); + obj.setPropertyValue("Func", func); auto [serverObj, clientObj] = registerPropertyObject(obj); - FunctionPtr clientProc = clientObj.getPropertyValue("func"); + FunctionPtr clientProc = clientObj.getPropertyValue("Func"); ASSERT_EQ(clientProc(10, Ratio(1, 20), "foo"), true); ASSERT_EQ(clientProc(10, Ratio(1, 20), "bar"), false); @@ -155,12 +155,12 @@ TEST_F(TmsFunctionTest, AllArgTypes) { auto obj = PropertyObject(); obj.addProperty(FunctionProperty( - "proc", - ProcedureInfo(List(ArgumentInfo("int", ctInt), - ArgumentInfo("ratio", ctRatio), - ArgumentInfo("string", ctString), - ArgumentInfo("bool", ctBool), - ArgumentInfo("float", ctFloat))))); + "Proc", + ProcedureInfo(List(ArgumentInfo("Int", ctInt), + ArgumentInfo("Ratio", ctRatio), + ArgumentInfo("String", ctString), + ArgumentInfo("Bool", ctBool), + ArgumentInfo("Float", ctFloat))))); Int intArg; RatioPtr ratioArg; @@ -176,10 +176,10 @@ TEST_F(TmsFunctionTest, AllArgTypes) boolArg = args[3]; floatArg = args[4]; }); - obj.setPropertyValue("proc", proc); + obj.setPropertyValue("Proc", proc); auto [serverObj, clientObj] = registerPropertyObject(obj); - ProcedurePtr clientProc = clientObj.getPropertyValue("proc"); + ProcedurePtr clientProc = clientObj.getPropertyValue("Proc"); clientProc(10, Ratio(1, 20), "foo", false, 1.123); @@ -193,13 +193,13 @@ TEST_F(TmsFunctionTest, AllArgTypes) TEST_F(TmsFunctionTest, InvalidArgTypes) { auto obj = PropertyObject(); - obj.addProperty(FunctionProperty("proc", ProcedureInfo(List(ArgumentInfo("int", ctInt))))); + obj.addProperty(FunctionProperty("Proc", ProcedureInfo(List(ArgumentInfo("Int", ctInt))))); Int callValue; auto proc = Procedure([&callValue](const IntegerPtr& arg) { callValue = arg; }); - obj.setPropertyValue("proc", proc); + obj.setPropertyValue("Proc", proc); auto [serverObj, clientObj] = registerPropertyObject(obj); - ProcedurePtr clientProc = clientObj.getPropertyValue("proc"); + ProcedurePtr clientProc = clientObj.getPropertyValue("Proc"); ASSERT_NO_THROW(clientProc("foo")); ASSERT_EQ(getLastMessage(), "Failed to call procedure on OpcUA client. Error: \"Calling procedure\""); @@ -209,12 +209,12 @@ TEST_F(TmsFunctionTest, InvalidArgTypes) TEST_F(TmsFunctionTest, InvalidReturnType) { auto obj = PropertyObject(); - obj.addProperty(FunctionProperty("func", FunctionInfo(ctBool))); + obj.addProperty(FunctionProperty("Func", FunctionInfo(ctBool))); auto func = Function([]() { return "str"; }); - obj.setPropertyValue("func", func); + obj.setPropertyValue("Func", func); auto [serverObj, clientObj] = registerPropertyObject(obj); - FunctionPtr clientFunc = clientObj.getPropertyValue("func"); + FunctionPtr clientFunc = clientObj.getPropertyValue("Func"); ASSERT_EQ(clientFunc(), "str"); } @@ -222,13 +222,13 @@ TEST_F(TmsFunctionTest, InvalidReturnType) TEST_F(TmsFunctionTest, InvalidArgCount) { auto obj = PropertyObject(); - obj.addProperty(FunctionProperty("proc", ProcedureInfo(List(ArgumentInfo("int", ctInt))))); + obj.addProperty(FunctionProperty("Proc", ProcedureInfo(List(ArgumentInfo("Int", ctInt))))); Int callValue; auto proc = Procedure([&callValue](const IntegerPtr& arg) { callValue = arg; }); - obj.setPropertyValue("proc", proc); + obj.setPropertyValue("Proc", proc); auto [serverObj, clientObj] = registerPropertyObject(obj); - ProcedurePtr clientProc = clientObj.getPropertyValue("proc"); + ProcedurePtr clientProc = clientObj.getPropertyValue("Proc"); ASSERT_NO_THROW(clientProc()); ASSERT_EQ(getLastMessage(), "Failed to call procedure on OpcUA client. Error: \"Calling procedure\""); @@ -241,43 +241,43 @@ TEST_F(TmsFunctionTest, ProcedureArgumentInfo) { auto obj = PropertyObject(); obj.addProperty(FunctionProperty( - "proc", - ProcedureInfo(List(ArgumentInfo("int", ctInt), - ArgumentInfo("ratio", ctRatio), - ArgumentInfo("string", ctString), - ArgumentInfo("bool", ctBool), - ArgumentInfo("float", ctFloat))))); + "Proc", + ProcedureInfo(List(ArgumentInfo("Int", ctInt), + ArgumentInfo("Ratio", ctRatio), + ArgumentInfo("String", ctString), + ArgumentInfo("Bool", ctBool), + ArgumentInfo("Float", ctFloat))))); auto [serverObj, clientObj] = registerPropertyObject(obj); - ASSERT_EQ(obj.getProperty("proc").getCallableInfo(), clientObj.getProperty("proc").getCallableInfo()); + ASSERT_EQ(obj.getProperty("Proc").getCallableInfo(), clientObj.getProperty("Proc").getCallableInfo()); } TEST_F(TmsFunctionTest, FunctionArgumentInfo) { auto obj = PropertyObject(); obj.addProperty(FunctionProperty( - "func", - FunctionInfo(ctInt, List(ArgumentInfo("int", ctInt), - ArgumentInfo("ratio", ctRatio), - ArgumentInfo("string", ctString), - ArgumentInfo("bool", ctBool), - ArgumentInfo("float", ctFloat))))); + "Func", + FunctionInfo(ctInt, List(ArgumentInfo("Int", ctInt), + ArgumentInfo("Ratio", ctRatio), + ArgumentInfo("String", ctString), + ArgumentInfo("Bool", ctBool), + ArgumentInfo("Float", ctFloat))))); auto [serverObj, clientObj] = registerPropertyObject(obj); - ASSERT_EQ(obj.getProperty("func").getCallableInfo(), clientObj.getProperty("func").getCallableInfo()); + ASSERT_EQ(obj.getProperty("Func").getCallableInfo(), clientObj.getProperty("Func").getCallableInfo()); } TEST_F(TmsFunctionTest, UnsupportedArgumentInfo) { auto obj = PropertyObject(); - obj.addProperty(FunctionProperty("proc1", ProcedureInfo(List(ArgumentInfo("list", ctList))))); - obj.addProperty(FunctionProperty("proc2", ProcedureInfo(List(ArgumentInfo("dict", ctDict))))); - obj.addProperty(FunctionProperty("proc3", ProcedureInfo(List(ArgumentInfo("proc", ctProc))))); - obj.addProperty(FunctionProperty("proc4", ProcedureInfo(List(ArgumentInfo("object", ctObject))))); + obj.addProperty(FunctionProperty("proc1", ProcedureInfo(List(ArgumentInfo("List", ctList))))); + obj.addProperty(FunctionProperty("proc2", ProcedureInfo(List(ArgumentInfo("Dict", ctDict))))); + obj.addProperty(FunctionProperty("proc3", ProcedureInfo(List(ArgumentInfo("Proc", ctProc))))); + obj.addProperty(FunctionProperty("proc4", ProcedureInfo(List(ArgumentInfo("Object", ctObject))))); obj.addProperty(FunctionProperty("proc5", ProcedureInfo(List(ArgumentInfo("binary_data", ctBinaryData))))); - obj.addProperty(FunctionProperty("proc6", ProcedureInfo(List(ArgumentInfo("func", ctFunc))))); + obj.addProperty(FunctionProperty("proc6", ProcedureInfo(List(ArgumentInfo("Func", ctFunc))))); obj.addProperty(FunctionProperty("proc7", ProcedureInfo(List(ArgumentInfo("complex_number", ctComplexNumber))))); - obj.addProperty(FunctionProperty("proc8", ProcedureInfo(List(ArgumentInfo("undefined", ctUndefined))))); + obj.addProperty(FunctionProperty("proc8", ProcedureInfo(List(ArgumentInfo("Undefined", ctUndefined))))); auto [serverObj, clientObj] = registerPropertyObject(obj); ASSERT_EQ(clientObj.getAllProperties().getCount(), 0u); @@ -302,16 +302,16 @@ TEST_F(TmsFunctionTest, UnsupportedReturnType) TEST_F(TmsFunctionTest, ServerThrow) { auto obj = PropertyObject(); - obj.addProperty(FunctionProperty("func", FunctionInfo(ctBool))); + obj.addProperty(FunctionProperty("Func", FunctionInfo(ctBool))); auto func = Function([]() { throw GeneralErrorException{}; return false; }); - obj.setPropertyValue("func", func); + obj.setPropertyValue("Func", func); auto [serverObj, clientObj] = registerPropertyObject(obj); - FunctionPtr clientFunc = clientObj.getPropertyValue("func"); + FunctionPtr clientFunc = clientObj.getPropertyValue("Func"); ASSERT_NO_THROW(clientFunc()); ASSERT_EQ(getLastMessage(), "Failed to call function on OpcUA client. Error in \"Calling function\""); } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp index 860b3a8..3289ca0 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp @@ -97,7 +97,7 @@ class TmsFusionDevice : public TmsObjectIntegrationTest TEST_F(TmsFusionDevice, SampleRateTest) { - SignalPtr daqServerSignal = createSignal("id"); + SignalPtr daqServerSignal = createSignal("Id"); daqServerSignal.addProperty(FloatProperty("SampleRate", 1.0, false)); auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), ctx, serverContext); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp index a01d544..8b9cce3 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp @@ -28,7 +28,7 @@ class TmsInputPortTest : public TmsObjectIntegrationTest { auto ip = InputPort(NullContext(), nullptr, name); ip.setRequiresSignal(requiresSignal); - ip.getTags().asPtr().add("port"); + ip.getTags().asPtr().add("Port"); return ip; } }; @@ -159,8 +159,8 @@ TEST_F(TmsInputPortTest, ComponentMethods) auto tags = daqServerInputPort.getTags(); auto clientTags = clientInputPort.getTags(); - ASSERT_TRUE(tags.query("port")); - ASSERT_TRUE(clientTags.query("port")); + ASSERT_TRUE(tags.query("Port")); + ASSERT_TRUE(clientTags.query("Port")); clientInputPort.setActive(false); ASSERT_EQ(daqServerInputPort.getActive(), clientInputPort.getActive()); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp index 9ee2bf9..2ceea26 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp @@ -217,14 +217,14 @@ TEST_F(TmsPropertyObjectTest, TestPropertyOrder) { auto obj = PropertyObject(); for (SizeT i = 0; i < 200; ++i) - obj.addProperty(BoolProperty("bool" + std::to_string(i), true)); + obj.addProperty(BoolProperty("Bool" + std::to_string(i), true)); for (SizeT i = 0; i < 200; ++i) - obj.addProperty(StringProperty("string" + std::to_string(i), "test")); + obj.addProperty(StringProperty("String" + std::to_string(i), "test")); for (SizeT i = 0; i < 200; ++i) { - obj.addProperty(FunctionProperty("func" + std::to_string(i), ProcedureInfo())); + obj.addProperty(FunctionProperty("Func" + std::to_string(i), ProcedureInfo())); ProcedurePtr test = Procedure([](){}); - obj.setPropertyValue("func" + std::to_string(i), test); + obj.setPropertyValue("Func" + std::to_string(i), test); } auto [serverObj, clientObj] = registerPropertyObject(obj); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp index eae9363..45e084f 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp @@ -44,7 +44,7 @@ class TmsSignalTest : public TmsObjectIntegrationTest .setName("Value Name") .setDimensions(List()) .setRule(ConstantDataRule()) - .setUnit(Unit("symbol", 1, "name", "quantity")) // Optional + .setUnit(Unit("Symbol", 1, "Name", "Quantity")) // Optional .setOrigin("Origin") // Optional .setValueRange(Range(0.0, 100.0)) // Optional .setMetadata(serverMetadata) @@ -91,7 +91,7 @@ class TmsSignalTest : public TmsObjectIntegrationTest template void testGetLastValue(const SampleType& sampleType, const T& value) { - auto daqServerSignal = Signal(NullContext(), nullptr, "id"); + auto daqServerSignal = Signal(NullContext(), nullptr, "Id"); auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), ctx, serverContext); auto nodeId = serverSignal.registerOpcUaNode(); @@ -121,7 +121,7 @@ class TmsSignalTest : public TmsObjectIntegrationTest template void testGetLastValueComplex(const SampleType& sampleType, const T& realValue, const T& imaginaryValue) { - auto daqServerSignal = Signal(NullContext(), nullptr, "id"); + auto daqServerSignal = Signal(NullContext(), nullptr, "Id"); auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), ctx, serverContext); auto nodeId = serverSignal.registerOpcUaNode(); @@ -150,7 +150,7 @@ TEST_F(TmsSignalTest, Create) TEST_F(TmsSignalTest, Register) { - SignalPtr signal = createSignal("id"); + SignalPtr signal = createSignal("Id"); auto serverSignal = TmsServerSignal(signal, this->getServer(), ctx, serverContext); auto nodeId = serverSignal.registerOpcUaNode(); @@ -160,13 +160,13 @@ TEST_F(TmsSignalTest, Register) TEST_F(TmsSignalTest, AttrUniqueId) { - SignalPtr daqServerSignal = createSignal("id"); + SignalPtr daqServerSignal = createSignal("Id"); daqServerSignal.setActive(true); auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), ctx, serverContext); auto nodeId = serverSignal.registerOpcUaNode(); - SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "id", clientContext, nodeId); + SignalPtr clientSignal = TmsClientSignal(NullContext(), nullptr, "Id", clientContext, nodeId); // UniqueId is set by core, so only test is that it is transferred correctly: ASSERT_EQ(daqServerSignal.getLocalId(), clientSignal.getLocalId()); @@ -174,7 +174,7 @@ TEST_F(TmsSignalTest, AttrUniqueId) TEST_F(TmsSignalTest, AttrActive) { - SignalPtr daqServerSignal = createSignal("id"); + SignalPtr daqServerSignal = createSignal("Id"); daqServerSignal.setActive(true); auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), ctx, serverContext); @@ -198,7 +198,7 @@ TEST_F(TmsSignalTest, AttrActive) TEST_F(TmsSignalTest, AttrPublic) { - SignalPtr daqServerSignal = createSignal("id"); + SignalPtr daqServerSignal = createSignal("Id"); auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), ctx, serverContext); auto nodeId = serverSignal.registerOpcUaNode(); @@ -275,7 +275,7 @@ TEST_F(TmsSignalTest, GetLastValueUInt64) TEST_F(TmsSignalTest, GetLastValueRange) { - auto daqServerSignal = Signal(NullContext(), nullptr, "id"); + auto daqServerSignal = Signal(NullContext(), nullptr, "Id"); auto serverSignal = TmsServerSignal(daqServerSignal, this->getServer(), ctx, serverContext); auto nodeId = serverSignal.registerOpcUaNode(); @@ -297,7 +297,7 @@ TEST_F(TmsSignalTest, GetLastValueRange) TEST_F(TmsSignalTest, GetLastValueListOfInt64) { - auto daqServerSignal = Signal(NullContext(), nullptr, "id"); + auto daqServerSignal = Signal(NullContext(), nullptr, "Id"); auto numbers = List(); numbers.pushBack(1); @@ -351,7 +351,7 @@ TEST_F(TmsSignalTest, AttrDescriptor) .setSampleType(SampleType::Float32) .setDimensions(List()) .setRule(ConstantDataRule()) - .setUnit(Unit("symbol", 1, "name", "quantity")) // Optional + .setUnit(Unit("Symbol", 1, "Name", "Quantity")) // Optional .setOrigin("Origin") // Optional .setValueRange(Range(0.0, 100.0)) // Optional .setName("Signal Name") @@ -402,9 +402,9 @@ TEST_F(TmsSignalTest, AttrDescriptor) ASSERT_EQ(clientRuleParameters.getCount(), 0u); auto clientUnit = clientDataDescriptor.getUnit(); - ASSERT_EQ(clientUnit.getQuantity(), "quantity"); - ASSERT_EQ(clientUnit.getName(), "name"); - ASSERT_EQ(clientUnit.getSymbol(), "symbol"); + ASSERT_EQ(clientUnit.getQuantity(), "Quantity"); + ASSERT_EQ(clientUnit.getName(), "Name"); + ASSERT_EQ(clientUnit.getSymbol(), "Symbol"); auto clientValueRange = clientDataDescriptor.getValueRange(); ASSERT_EQ(clientValueRange.getLowValue(), 0.0); @@ -483,7 +483,7 @@ TEST_F(TmsSignalTest, AttrRelatedSignals) TEST_F(TmsSignalTest, MethodGetConnections) { - SignalPtr daqServerSignal1 = createSignal("id"); + SignalPtr daqServerSignal1 = createSignal("Id"); auto serverSignal1 = TmsServerSignal(daqServerSignal1, this->getServer(), ctx, serverContext); auto nodeId1 = serverSignal1.registerOpcUaNode(); From 896e60e1ea43877645c945b789704bd67ea31678 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Wed, 24 Jul 2024 13:42:44 +0200 Subject: [PATCH 153/217] Bump sdk version to 3.2 --- modules/opcua_client_module/CMakeLists.txt | 2 +- modules/opcua_server_module/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/opcua_client_module/CMakeLists.txt b/modules/opcua_client_module/CMakeLists.txt index 7cea83a..fe98271 100644 --- a/modules/opcua_client_module/CMakeLists.txt +++ b/modules/opcua_client_module/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(ClientModule VERSION 3.1.0 LANGUAGES C CXX) +project(ClientModule VERSION 3.2.0 LANGUAGES C CXX) add_subdirectory(src) diff --git a/modules/opcua_server_module/CMakeLists.txt b/modules/opcua_server_module/CMakeLists.txt index d8628e3..9d2ffb2 100644 --- a/modules/opcua_server_module/CMakeLists.txt +++ b/modules/opcua_server_module/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(ServerModule VERSION 3.1.0 LANGUAGES CXX) +project(ServerModule VERSION 3.2.0 LANGUAGES CXX) add_subdirectory(src) diff --git a/shared/libraries/opcuatms/opcuatms/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms/CMakeLists.txt index 22acec2..492df14 100644 --- a/shared/libraries/opcuatms/opcuatms/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(opcuatms VERSION 3.1.0 LANGUAGES CXX) +project(opcuatms VERSION 3.2.0 LANGUAGES CXX) add_subdirectory(src) diff --git a/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt index 2feff54..39d868a 100644 --- a/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(opcuatms_client VERSION 3.1.0 LANGUAGES CXX) +project(opcuatms_client VERSION 3.2.0 LANGUAGES CXX) add_subdirectory(src) diff --git a/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt index 9e81467..41f5fef 100644 --- a/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(opcuatms_server VERSION 3.1.0 LANGUAGES CXX) +project(opcuatms_server VERSION 3.2.0 LANGUAGES CXX) add_subdirectory(src) From f68e6af0260c03fdaf13d25348b30184134c5600 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Wed, 24 Jul 2024 14:31:49 +0200 Subject: [PATCH 154/217] Bump version to 3.3 --- modules/opcua_client_module/CMakeLists.txt | 2 +- modules/opcua_server_module/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/opcua_client_module/CMakeLists.txt b/modules/opcua_client_module/CMakeLists.txt index fe98271..5bc1519 100644 --- a/modules/opcua_client_module/CMakeLists.txt +++ b/modules/opcua_client_module/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(ClientModule VERSION 3.2.0 LANGUAGES C CXX) +project(ClientModule VERSION 3.3.0 LANGUAGES C CXX) add_subdirectory(src) diff --git a/modules/opcua_server_module/CMakeLists.txt b/modules/opcua_server_module/CMakeLists.txt index 9d2ffb2..a868025 100644 --- a/modules/opcua_server_module/CMakeLists.txt +++ b/modules/opcua_server_module/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(ServerModule VERSION 3.2.0 LANGUAGES CXX) +project(ServerModule VERSION 3.3.0 LANGUAGES CXX) add_subdirectory(src) diff --git a/shared/libraries/opcuatms/opcuatms/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms/CMakeLists.txt index 492df14..24b8411 100644 --- a/shared/libraries/opcuatms/opcuatms/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(opcuatms VERSION 3.2.0 LANGUAGES CXX) +project(opcuatms VERSION 3.3.0 LANGUAGES CXX) add_subdirectory(src) diff --git a/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt index 39d868a..11e5097 100644 --- a/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(opcuatms_client VERSION 3.2.0 LANGUAGES CXX) +project(opcuatms_client VERSION 3.3.0 LANGUAGES CXX) add_subdirectory(src) diff --git a/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt index 41f5fef..162d6f4 100644 --- a/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(opcuatms_server VERSION 3.2.0 LANGUAGES CXX) +project(opcuatms_server VERSION 3.3.0 LANGUAGES CXX) add_subdirectory(src) From 013ed12bd0827e38cdd8cd0f69ae59a77532bc43 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Thu, 8 Aug 2024 08:58:37 +0200 Subject: [PATCH 155/217] Add IProperty get/setValue --- .../test_tms_amplifier.cpp | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp index 0ec0de0..20828e9 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp @@ -356,6 +356,28 @@ TEST_F(TMSAmplifierTest, Measurement0) ASSERT_EQ(rangeValues[0], rangeValue); } +TEST_F(TMSAmplifierTest, Measurement0PropertySEtter) +{ + const auto obj = PropertyObject(objManager, "LvAmp"); + auto [serverObj, lvAmpl] = registerPropertyObject(obj); + + lvAmpl.getProperty("Measurement").setValue(0); + + lvAmpl.getProperty("Range").setValue(0); + Float rangeValue = lvAmpl.getPropertySelectionValue("Range"); + auto rangeProp = lvAmpl.getProperty("Range"); + ListPtr rangeValues = rangeProp.getSelectionValues(); + + ASSERT_EQ(rangeValues[0], rangeValue); + + lvAmpl.getProperty("Measurement").setValue(1); + rangeValue = lvAmpl.getPropertySelectionValue("Range"); + rangeProp = lvAmpl.getProperty("Range"); + rangeValues = rangeProp.getSelectionValues(); + + ASSERT_EQ(rangeValues[0], rangeValue); +} + TEST_F(TMSAmplifierTest, Measurement1) { const auto obj = PropertyObject(objManager, "LvAmp"); @@ -773,3 +795,11 @@ TEST_F(TMSAmplifierTest, PropertyOrder2) for (SizeT i = 0; i < serverProps.getCount(); ++i) ASSERT_EQ(serverProps[i].getName(), clientProps[i].getName()); } + +TEST_F(TMSAmplifierTest, PropertyGetValue) +{ + const auto obj = PropertyObject(objManager, "LvAmp"); + auto [serverObj, lvAmpl] = registerPropertyObject(obj); + for (const auto& prop : lvAmpl.getAllProperties()) + ASSERT_EQ(lvAmpl.getPropertyValue(prop.getName()), prop.getValue()); +} From 106f14e1a6f5150a07d913a3ffed3167f7bb5067 Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Tue, 13 Aug 2024 09:50:32 +0200 Subject: [PATCH 156/217] Sync components Implementation (openDAQ/openDAQ#361) - Populating eval expression with %ChildProperty:PropertyNames to get the list of child properties names where the ChildProperty is an Object-type property - Each device now has a sync component, which is visible in default components as `Sync`. Meantime the sync component transfers over OPC UA by node id `Synchronization`. - Sync component is replacing dummy property object in the ref device. --- .../objects/tms_client_device_impl.h | 7 +- .../tms_client_sync_component_factory.h | 32 ++++ .../objects/tms_client_sync_component_impl.h | 63 ++++++ .../opcuatms_client/src/CMakeLists.txt | 4 + .../src/objects/tms_client_component_impl.cpp | 17 +- .../src/objects/tms_client_device_impl.cpp | 33 +++- .../src/objects/tms_client_property_impl.cpp | 8 +- .../tms_client_property_object_impl.cpp | 34 ++-- .../src/tms_attribute_collector.cpp | 7 +- .../objects/tms_server_device.h | 2 + .../objects/tms_server_property_object.h | 3 +- .../objects/tms_server_sync_component.h | 43 +++++ .../objects/tms_server_sync_interface.h | 83 ++++++++ .../opcuatms_server/src/CMakeLists.txt | 4 + .../src/objects/tms_server_device.cpp | 12 +- .../objects/tms_server_property_object.cpp | 20 +- .../src/objects/tms_server_sync_component.cpp | 60 ++++++ .../test_property_object_advanced.cpp | 4 +- .../test_tms_integration.cpp | 181 ++++++++++++++++++ 19 files changed, 565 insertions(+), 52 deletions(-) create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_sync_component_factory.h create mode 100644 shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_sync_component_impl.h create mode 100644 shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_sync_component.h create mode 100644 shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_sync_interface.h create mode 100644 shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_sync_component.cpp diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h index e682a65..c103e79 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h @@ -15,9 +15,9 @@ */ #pragma once -#include "opcuatms_client/objects/tms_client_component_impl.h" -#include "opendaq/mirrored_device_impl.h" -#include "opendaq/device_ptr.h" +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -46,6 +46,7 @@ class TmsClientDeviceImpl : public TmsClientComponentBaseImpl onGetAvailableFunctionBlockTypes() override; FunctionBlockPtr onAddFunctionBlock(const StringPtr& typeId, const PropertyObjectPtr& config) override; void onRemoveFunctionBlock(const FunctionBlockPtr& functionBlock) override; diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_sync_component_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_sync_component_factory.h new file mode 100644 index 0000000..852d251 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_sync_component_factory.h @@ -0,0 +1,32 @@ +/* + * Copyright 2022-2024 openDAQ d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +inline SyncComponentPtr TmsClientSyncComponent(const ContextPtr& context, + const ComponentPtr& parent, + const StringPtr& localId, + const daq::opcua::tms::TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId) +{ + ComponentPtr obj(createWithImplementation(context, parent, localId, clientContext, nodeId)); + return obj; +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS \ No newline at end of file diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_sync_component_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_sync_component_impl.h new file mode 100644 index 0000000..80634f4 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_sync_component_impl.h @@ -0,0 +1,63 @@ +/* + * Copyright 2022-2024 openDAQ d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class TmsClientSyncComponentImpl : public TmsClientComponentBaseImpl> +{ +public: + + using Impl = GenericSyncComponentImpl; + using Super = TmsClientComponentBaseImpl; + + TmsClientSyncComponentImpl(const ContextPtr& ctx, + const ComponentPtr& parent, + const StringPtr& localId, + const TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId) + : Super(ctx, parent, localId, clientContext, nodeId) + { + StringPtr propertyName = "Interfaces"; + BaseObjectPtr interfacesValue; + checkErrorInfo(getPropertyValue(propertyName, &interfacesValue)); + checkErrorInfo(Impl::setProtectedPropertyValue(propertyName, interfacesValue)); + } + + ErrCode INTERFACE_FUNC getSyncLocked(Bool* synchronizationLocked) override + { + try + { + const auto syncLockNodeId = clientContext->getReferenceBrowser()->getChildNodeId(nodeId, "SynchronizationLocked"); + OpcUaVariant opcUaVariant = client->readValue(*syncLockNodeId); + if (!opcUaVariant.isNull()) + { + BooleanPtr syncLockPtr = VariantConverter::ToDaqObject(opcUaVariant); + return syncLockPtr->getValue(synchronizationLocked); + } + } + catch (...) + { + LOG_W("Failed to get sync locked on OpcUA client sync component \"{}\"", this->globalId); + } + return OPENDAQ_SUCCESS; + } +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt index 5ba6707..d8a25f5 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt @@ -63,6 +63,9 @@ set(SRC_Objects_Headers ${OBJECT_SRC_DIR}/tms_client_object_impl.h ${OBJECT_SRC_DIR}/tms_client_tags_impl.h ${OBJECT_SRC_DIR}/tms_client_tags_factory.h + + ${OBJECT_SRC_DIR}/tms_client_sync_component_impl.h + ${OBJECT_SRC_DIR}/tms_client_sync_component_factory.h ) set(SRC_Objects ${OBJECT_SRC_DIR}/tms_client_object_impl.cpp @@ -101,6 +104,7 @@ source_group("objects\\io_folder" "${OBJECT_SRC_DIR}/tms_client_io_folder.*") source_group("objects\\server_capability" "${OBJECT_SRC_DIR}/tms_client_server_capability.*") source_group("objects\\tags" "${OBJECT_SRC_DIR}/tms_client_tags.*") source_group("objects\\function" "${OBJECT_SRC_DIR}/(tms_client_function_impl.*|tms_client_function_factory.h|tms_client_procedure.*)") +source_group("objects\\sync_component" "${OBJECT_SRC_DIR}tms_client_sync_component.*") # /objects diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp index 74792c5..0a85716 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp @@ -1,10 +1,11 @@ -#include "opcuatms_client/objects/tms_client_component_impl.h" -#include "opendaq/mirrored_device_impl.h" -#include "opendaq/folder_impl.h" -#include "opendaq/io_folder_impl.h" -#include "opendaq/mirrored_signal_impl.h" -#include "opendaq/input_port_impl.h" -#include "opcuatms_client/objects/tms_client_tags_factory.h" +#include +#include +#include +#include +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -45,7 +46,6 @@ ErrCode TmsClientComponentBaseImpl::setActive(Bool active) template void TmsClientComponentBaseImpl::initComponent() { - try { this->tags = TmsClientTags(this->daqContext, this->clientContext, this->getNodeId("Tags")); @@ -215,5 +215,6 @@ template class TmsClientComponentBaseImpl>; template class TmsClientComponentBaseImpl>; template class TmsClientComponentBaseImpl>; +template class TmsClientComponentBaseImpl>; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 57e078e..b5fc6e8 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -1,4 +1,4 @@ -#include "opcuatms_client/objects/tms_client_device_impl.h" +#include #include #include #include @@ -8,20 +8,21 @@ #include #include #include -#include "opcuatms_client/objects/tms_client_component_factory.h" -#include "opcuatms_client/objects/tms_client_io_folder_factory.h" -#include "opcuatms_client/objects/tms_client_server_capability_factory.h" +#include +#include +#include +#include #include -#include "open62541/daqbt_nodeids.h" +#include #include #include #include #include #include -#include "opcuatms/core_types_utils.h" -#include "opcuatms/exceptions.h" -#include "opcuatms/converters/list_conversion_utils.h" -#include "opcuatms/converters/property_object_conversion_utils.h" +#include +#include +#include +#include #include #include #include @@ -32,7 +33,7 @@ using namespace daq::opcua; namespace detail { - static std::unordered_set defaultComponents = {"Sig", "FB", "IO", "ServerCapabilities"}; + static std::unordered_set defaultComponents = {"Sig", "FB", "IO", "ServerCapabilities", "Synchronization"}; static std::unordered_map> deviceInfoSetterMap = { {"AssetId", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setAssetId(v.toString()); }}, @@ -83,6 +84,7 @@ TmsClientDeviceImpl::TmsClientDeviceImpl(const ContextPtr& ctx, findAndCreateSignals(); findAndCreateInputsOutputs(); findAndCreateCustomComponents(); + findAndCreateSyncComponent(); } ErrCode TmsClientDeviceImpl::getDomain(IDeviceDomain** deviceDomain) @@ -231,6 +233,17 @@ void TmsClientDeviceImpl::fetchTimeDomain() ticksSinceOrigin = deviceDomain->ticksSinceOrigin; } +void TmsClientDeviceImpl::findAndCreateSyncComponent() +{ + this->removeComponentById("Sync"); + auto syncComponentNodeId = getNodeId("Synchronization"); + syncComponent = this->addExistingComponent(TmsClientSyncComponent(context, + this->thisPtr(), + "Sync", + clientContext, + syncComponentNodeId)); +} + void TmsClientDeviceImpl::fetchTicksSinceOrigin() { auto timeDomainNodeId = getNodeId("Domain"); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp index 0db9811..98c32f5 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp @@ -89,11 +89,15 @@ void TmsClientPropertyImpl::configurePropertyFields() if (browseName == "CoercionExpression") { - this->coercer = Coercer(VariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE))); + const auto eval = VariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE)); + if (eval.assigned() && eval.getLength() > 0) + this->coercer = Coercer(eval); } else if (browseName == "ValidationExpression") { - this->validator = Validator(VariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE))); + const auto eval = VariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE)); + if (eval.assigned() && eval.getLength() > 0) + this->validator = Validator(eval); } else if (clientContext->getReferenceBrowser()->isSubtypeOf(ref->typeDefinition.nodeId, evaluationVariableTypeId)) { diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index c314256..96ba812 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -1,19 +1,20 @@ -#include "opcuatms_client/objects/tms_client_property_object_impl.h" -#include "coreobjects/callable_info_factory.h" -#include "coreobjects/eval_value_factory.h" -#include "coreobjects/property_object_factory.h" -#include "opcuaclient/browser/opcuabrowser.h" -#include "opcuatms_client/objects/tms_client_property_factory.h" -#include "open62541/daqbt_nodeids.h" -#include "opcuatms/converters/variant_converter.h" -#include "opcuatms_client/objects/tms_client_property_object_factory.h" -#include "opcuatms_client/objects/tms_client_function_factory.h" -#include "opcuatms_client/objects/tms_client_procedure_factory.h" -#include "opendaq/mirrored_signal_impl.h" -#include "opendaq/input_port_impl.h" -#include "opendaq/channel_impl.h" -#include "opendaq/mirrored_device_impl.h" -#include "opendaq/io_folder_impl.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -501,6 +502,7 @@ template class TmsClientPropertyObjectBaseImpl> template class TmsClientPropertyObjectBaseImpl>; template class TmsClientPropertyObjectBaseImpl>; template class TmsClientPropertyObjectBaseImpl; +template class TmsClientPropertyObjectBaseImpl>; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_attribute_collector.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_attribute_collector.cpp index 0e8813b..8b670a7 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_attribute_collector.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_attribute_collector.cpp @@ -83,6 +83,9 @@ void TmsAttributeCollector::collectDeviceAttributes(const OpcUaNodeId& nodeId) const auto methodSetId = browser->getChildNodeId(nodeId, "MethodSet"); collectMethodSetNode(methodSetId); + + const auto synchronizationNoded = browser->getChildNodeId(nodeId, "Synchronization"); + collectComponentAttributes(synchronizationNoded); } void TmsAttributeCollector::collectFunctionBlockAttributes(const OpcUaNodeId& nodeId) @@ -191,8 +194,8 @@ void TmsAttributeCollector::collectBaseObjectAttributes(const OpcUaNodeId& nodeI { attributes.insert({nodeId, UA_ATTRIBUTEID_NODECLASS}); - const auto numberInListId = browser->getChildNodeId(nodeId, "NumberInList"); - attributes.insert({numberInListId, UA_ATTRIBUTEID_VALUE}); + if (browser->hasReference(nodeId, "NumberInList")) + attributes.insert({browser->getChildNodeId(nodeId, "NumberInList"), UA_ATTRIBUTEID_VALUE}); } void TmsAttributeCollector::collectMethodAttributes(const OpcUaNodeId& nodeId) diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h index 24187eb..aa907f4 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h @@ -22,6 +22,7 @@ #include "opcuatms_server/objects/tms_server_component.h" #include "opcuatms_server/objects/tms_server_property_object.h" #include "opcuatms_server/objects/tms_server_function_block_type.h" +#include "opcuatms_server/objects/tms_server_sync_component.h" #include @@ -68,6 +69,7 @@ class TmsServerDevice : public TmsServerComponent std::list components; std::list serverCapabilities; std::list functionBlockTypes; + std::list syncComponents; }; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h index 9c03a8a..b6cefe4 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h @@ -52,6 +52,7 @@ class TmsServerPropertyObject : public TmsServerObjectBaseImpl ignoredProps; protected: void configureNodeAttributes(opcua::OpcUaObject& attr) override; @@ -65,7 +66,6 @@ class TmsServerPropertyObject : public TmsServerObjectBaseImpl childEvalValues; std::unordered_map> methodProps; -private: void registerEvalValueNode(const std::string& nodeName, TmsServerEvalValue::ReadCallback readCallback); void addMethodPropertyNode(const PropertyPtr& prop, uint32_t numberInList); void bindMethodCallbacks(); @@ -75,7 +75,6 @@ class TmsServerPropertyObject : public TmsServerObjectBaseImpl ignoredProps; }; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_sync_component.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_sync_component.h new file mode 100644 index 0000000..7e7644f --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_sync_component.h @@ -0,0 +1,43 @@ +/* + * Copyright 2022-2024 openDAQ d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class TmsServerSyncComponent; +using TmsServerSyncComponentPtr = std::shared_ptr; + +class TmsServerSyncComponent : public TmsServerComponent +{ +public: + using Super = TmsServerComponent; + + TmsServerSyncComponent(const SyncComponentPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext); + + void addChildNodes() override; + void bindCallbacks() override; + +protected: + opcua::OpcUaNodeId getTmsTypeId() override; + void triggerEvent(PropertyObjectPtr& sender, PropertyValueEventArgsPtr& args); + + TmsServerSyncInterfacesPtr interfaces; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_sync_interface.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_sync_interface.h new file mode 100644 index 0000000..79b6f0c --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_sync_interface.h @@ -0,0 +1,83 @@ +/* + * Copyright 2022-2024 openDAQ d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +class TmsServerSyncInterface; +using TmsServerSyncInterfacePtr = std::shared_ptr; + +class TmsServerSyncInterface : public TmsServerPropertyObject +{ +public: + using Super = TmsServerPropertyObject; + using Super::Super; + +protected: + opcua::OpcUaNodeId getTmsTypeId() override + { + if (name == "InterfaceClockSync") + return OpcUaNodeId(NAMESPACE_DAQESP, UA_DAQESPID_INTERNALCLOCKSYNCINTERFACETYPE); + + if (name == "PtpSyncInterface") + return OpcUaNodeId(NAMESPACE_DAQESP, UA_DAQESPID_PTPSYNCINTERFACETYPE); + + return Super::getTmsTypeId(); + } +}; + +class TmsServerSyncInterfaces; +using TmsServerSyncInterfacesPtr = std::shared_ptr; + +class TmsServerSyncInterfaces : public TmsServerPropertyObject +{ +public: + using Super = TmsServerPropertyObject; + using Super::Super; + + bool createOptionalNode(const opcua::OpcUaNodeId& nodeId) override + { + const auto name = server->readBrowseNameString(nodeId); + + if (name == "") + return false; + + return Super::createOptionalNode(nodeId); + } + + void addChildNodes() override + { + uint32_t propNumber = 0; + + for (const auto& prop : object.getAllProperties()) + { + const auto propName = prop.getName(); + ignoredProps.emplace(propName); + PropertyObjectPtr obj = object.getPropertyValue(propName); + auto serverInfo = registerTmsObjectOrAddReference(nodeId, obj, propNumber++, propName, prop); + auto childNodeId = serverInfo->getNodeId(); + childObjects.insert({childNodeId, serverInfo}); + } + + Super::addChildNodes(); + } +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_server/src/CMakeLists.txt index 887553e..218dbc3 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_server/src/CMakeLists.txt @@ -28,6 +28,8 @@ set(SRC_Objects_Headers ${OBJECT_SRC_DIR}/tms_server_object.h ${OBJECT_SRC_DIR}/tms_server_property.h ${OBJECT_SRC_DIR}/tms_server_eval_value.h ${OBJECT_SRC_DIR}/tms_server_function_block_type.h + ${OBJECT_SRC_DIR}/tms_server_sync_component.h + ${OBJECT_SRC_DIR}/tms_server_sync_interface.h ) set(SRC_Objects ${OBJECT_SRC_DIR}/tms_server_object.cpp @@ -43,6 +45,7 @@ set(SRC_Objects ${OBJECT_SRC_DIR}/tms_server_object.cpp ${OBJECT_SRC_DIR}/tms_server_property.cpp ${OBJECT_SRC_DIR}/tms_server_eval_value.cpp ${OBJECT_SRC_DIR}/tms_server_function_block_type.cpp + ${OBJECT_SRC_DIR}/tms_server_sync_component.cpp ) set(SRC_PublicHeaders ${SRC_PublicHeaders} ${SRC_Objects_Headers}) @@ -60,6 +63,7 @@ source_group("objects\\folder" "${OBJECT_SRC_DIR}/tms_server_folder.*") source_group("objects\\component" "${OBJECT_SRC_DIR}/tms_server_component.*") source_group("objects\\property" "${OBJECT_SRC_DIR}/tms_server_property.*") source_group("objects\\eval_value" "${OBJECT_SRC_DIR}/tms_server_eval_value.*") +source_group("objects\\sync_component" "${OBJECT_SRC_DIR}/tms_server_sync_component.*") # /objects diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index 123abcd..4373918 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -81,6 +81,8 @@ bool TmsServerDevice::createOptionalNode(const OpcUaNodeId& nodeId) return true; if (name == "ProductInstanceUri" && object.getInfo().getProductInstanceUri() != "") return true; + if (name == "Synchronization" && object.getSyncComponent().assigned()) + return true; return Super::createOptionalNode(nodeId); } @@ -462,12 +464,20 @@ void TmsServerDevice::addChildNodes() auto inputsOutputsNode = std::make_unique(topFolder, server, daqContext, tmsContext); inputsOutputsNode->registerToExistingOpcUaNode(inputsOutputsNodeId); folders.push_back(std::move(inputsOutputsNode)); + + auto syncComponentNodeId = getChildNodeId("Synchronization"); + assert(!syncComponentNodeId.isNull()); + auto syncComponent = object.getSyncComponent(); + auto syncComponentNode = std::make_unique(syncComponent, server, daqContext, tmsContext); + syncComponentNode->registerToExistingOpcUaNode(syncComponentNodeId); + syncComponents.push_back(std::move(syncComponentNode)); + numberInList = 0; for (auto component : object.getItems(search::Any())) { auto id = component.getLocalId(); - if (id == "Dev" || id == "FB" || id == "IO" || id == "Sig") + if (id == "Dev" || id == "FB" || id == "IO" || id == "Sig" || id == "Sync") continue; if (component.asPtrOrNull().assigned()) diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp index dbeb729..2e5cdb9 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp @@ -22,7 +22,7 @@ TmsServerPropertyObject::TmsServerPropertyObject(const PropertyObjectPtr& object const TmsServerContextPtr& tmsContext, const std::unordered_set& ignoredProps) : Super(object, server, context, tmsContext) - , ignoredProps(ignoredProps) + , ignoredProps(ignoredProps) { } @@ -149,9 +149,19 @@ void TmsServerPropertyObject::addChildNodes() { const auto propName = prop.getName(); PropertyObjectPtr obj = object.getPropertyValue(propName); - auto serverInfo = registerTmsObjectOrAddReference(nodeId, obj, propOrder[propName], propName, prop); - auto childNodeId = serverInfo->getNodeId(); - childObjects.insert({childNodeId, serverInfo}); + if (hasChildNode(propName)) + { + const auto childNodeId = getChildNodeId(propName); + auto childObj = std::make_shared(obj, server, daqContext, tmsContext, propName, prop); + childObj->registerToExistingOpcUaNode(childNodeId); + childObjects.insert({childNodeId, childObj}); + } + else + { + auto serverInfo = registerTmsObjectOrAddReference(nodeId, obj, propOrder[propName], propName, prop); + auto childNodeId = serverInfo->getNodeId(); + childObjects.insert({childNodeId, serverInfo}); + } } } @@ -174,7 +184,7 @@ bool TmsServerPropertyObject::createOptionalNode(const opcua::OpcUaNodeId& nodeI { const auto name = server->readBrowseNameString(nodeId); - if (name == "" || name == "") + if (name == "" || name == "" || name == "") return false; if (!objProp.assigned() && (name == "IsReadOnly" || name == "IsVisible")) diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_sync_component.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_sync_component.cpp new file mode 100644 index 0000000..6595ad2 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_sync_component.cpp @@ -0,0 +1,60 @@ +#include +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +TmsServerSyncComponent::TmsServerSyncComponent(const SyncComponentPtr& object, const OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext) + : Super(object, server, context, tmsContext) +{ +} + +void TmsServerSyncComponent::addChildNodes() +{ + if (object.hasProperty("Interfaces")) + { + const auto prop = object.getProperty("Interfaces"); + const auto propName = prop.getName(); + const auto obj = object.getPropertyValue(propName); + + auto intefacesNodeId = getChildNodeId("Interfaces"); + interfaces = std::make_shared(obj, server, daqContext, tmsContext, propName, prop); + interfaces->setNumberInList(0); + interfaces->registerToExistingOpcUaNode(intefacesNodeId); + } + + tmsPropertyObject->ignoredProps.emplace("Interfaces"); + tmsPropertyObject->ignoredProps.emplace("InterfaceNames"); + tmsPropertyObject->ignoredProps.emplace("SynchronizationLocked"); + + Super::addChildNodes(); +} + +OpcUaNodeId TmsServerSyncComponent::getTmsTypeId() +{ + return OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_SYNCCOMPONENTTYPE); +} + +void TmsServerSyncComponent::triggerEvent(PropertyObjectPtr& sender, PropertyValueEventArgsPtr& args) +{ + if(!this->server->getUaServer()) + return; + + EventAttributes attributes; + attributes.setTime(UA_DateTime_now()); + attributes.setMessage("Property value changed"); + this->server->triggerEvent(OpcUaNodeId(UA_NS0ID_BASEEVENTTYPE), nodeId, attributes); +} + +void TmsServerSyncComponent::bindCallbacks() +{ + // Bind read callback for SynchronizationLocked property + this->addReadCallback("SynchronizationLocked", + [this] { return VariantConverter::ToVariant( this->object.getSyncLocked()); }); + + Super::bindCallbacks(); +} + + +END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp index bf83b21..366dd92 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp @@ -183,9 +183,8 @@ class TmsPropertyObjectAdvancedTest : public TmsObjectIntegrationTest const auto serverProp = std::make_shared(prop, server, context, std::make_shared(context, nullptr)); const auto nodeId = serverProp->registerOpcUaNode(); - const auto clientProp = TmsClientPropertyObject(Context(nullptr, logger, manager,nullptr, nullptr), clientContext, nodeId); + const auto clientProp = TmsClientPropertyObject(Context(nullptr, logger, manager, nullptr, nullptr), clientContext, nodeId); return {serverProp, clientProp}; - } StringPtr getLastMessage() @@ -430,7 +429,6 @@ TEST_F(TmsPropertyObjectAdvancedTest, IntListGetSet) for (SizeT i = 0; i < serverListObj.getCount(); ++i) ASSERT_EQ(serverListObj[i], clientListObj[i]); - } TEST_F(TmsPropertyObjectAdvancedTest, RatioGetSet) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index 61b5945..7c2b1f2 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -9,6 +9,10 @@ #include #include #include +#include +#include +#include +#include using namespace daq; using namespace daq::opcua; @@ -404,3 +408,180 @@ TEST_F(TmsIntegrationTest, BeginEndUpdateDevice) ASSERT_NO_THROW(clientDevice.beginUpdate()); ASSERT_NO_THROW(clientDevice.endUpdate()); } + +TEST_F(TmsIntegrationTest, SyncComponent) +{ + InstancePtr device = createDevice(); + auto serverTypeManager = device.getContext().getTypeManager(); + auto serverSubDevice = device.getDevices()[1]; + auto serverSync = serverSubDevice.getSyncComponent(); + SyncComponentPrivatePtr syncComponentPrivate = serverSync.asPtr(true); + + syncComponentPrivate.addInterface(PropertyObject(serverTypeManager, "PtpSyncInterface")); + syncComponentPrivate.addInterface(PropertyObject(serverTypeManager, "InterfaceClockSync")); + + serverSync.setSelectedSource(1); + + TmsServer tmsServer(device); + tmsServer.start(); + + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL); + DevicePtr clientDevice = tmsClient.connect(); + auto clientSubDevice = clientDevice.getDevices()[1]; + auto clientSync = clientSubDevice.getSyncComponent(); + + ASSERT_EQ(serverSync.getSelectedSource(), clientSync.getSelectedSource()); + ASSERT_EQ(serverSync.getSyncLocked(), clientSync.getSyncLocked()); + + auto serverInterfaces = serverSync.getInterfaces(); + auto clientInterfaces = clientSync.getInterfaces(); + + ASSERT_EQ(serverInterfaces.getCount(), clientInterfaces.getCount()); + ASSERT_EQ(serverInterfaces.getKeyList(), clientInterfaces.getKeyList()); +} + +TEST_F(TmsIntegrationTest, SyncComponentCustomInterfaceValues) +{ + InstancePtr device = createDevice(); + auto serverTypeManager = device.getContext().getTypeManager(); + auto serverSubDevice = device.getDevices()[1]; + auto serverSync = serverSubDevice.getSyncComponent(); + SyncComponentPrivatePtr syncComponentPrivate = serverSync.asPtr(true); + + auto ptpSyncInterface = PropertyObject(serverTypeManager, "PtpSyncInterface"); + ptpSyncInterface.setPropertyValue("Mode", 2); + + PropertyObjectPtr status = ptpSyncInterface.getPropertyValue("Status"); + status.setPropertyValue("State", 2); + status.setPropertyValue("Grandmaster", "1234"); + + PropertyObjectPtr parameters = ptpSyncInterface.getPropertyValue("Parameters"); + + StructPtr configuration = parameters.getPropertyValue("PtpConfigurationStructure"); + + auto newConfiguration = StructBuilder(configuration) + .set("ClockType", Enumeration("PtpClockTypeEnumeration", "OrdinaryBoundary", serverTypeManager)) + .set("TransportProtocol", Enumeration("PtpProtocolEnumeration", "UDP6_SCOPE", serverTypeManager)) + .set("StepFlag", Enumeration("PtpStepFlagEnumeration", "Two", serverTypeManager)) + .set("DomainNumber", 123) + .set("LeapSeconds", 123) + .set("DelayMechanism", Enumeration("PtpDelayMechanismEnumeration", "E2E", serverTypeManager)) + .set("Priority1", 123) + .set("Priority2", 123) + .set("Profiles", Enumeration("PtpProfileEnumeration", "802_1AS", serverTypeManager)) + .build(); + + parameters.setPropertyValue("PtpConfigurationStructure", newConfiguration); + + PropertyObjectPtr ports = parameters.getPropertyValue("Ports"); + ports.addProperty(BoolProperty("Port1", true)); + + syncComponentPrivate.addInterface(ptpSyncInterface); + + syncComponentPrivate.setSyncLocked(true); + + TmsServer tmsServer(device); + tmsServer.start(); + + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL); + DevicePtr clientDevice = tmsClient.connect(); + auto clientSubDevice = clientDevice.getDevices()[1]; + auto clientSync = clientSubDevice.getSyncComponent(); + + auto serveSyncInterface = serverSync.getInterfaces(); + auto clientSyncInterface = clientSync.getInterfaces(); + + ASSERT_EQ(serverSync.getSelectedSource(), clientSync.getSelectedSource()); + ASSERT_EQ(serverSync.getSyncLocked(), clientSync.getSyncLocked()); + + auto serverInterfaces = serverSync.getInterfaces(); + auto clientInterfaces = clientSync.getInterfaces(); + ASSERT_EQ(serverInterfaces.getCount(), clientInterfaces.getCount()); + ASSERT_EQ(serverInterfaces.getKeyList(), clientInterfaces.getKeyList()); + + auto clientPtpSyncInterface = clientInterfaces.get("PtpSyncInterface"); + ASSERT_EQ(clientPtpSyncInterface.getPropertyValue("Mode"), 2); + + PropertyObjectPtr clientStatus = clientPtpSyncInterface.getPropertyValue("Status"); + ASSERT_EQ(clientStatus.getPropertyValue("State"), 2); + ASSERT_EQ(clientStatus.getPropertyValue("Grandmaster"), "1234"); + + PropertyObjectPtr clientParameters = clientPtpSyncInterface.getPropertyValue("Parameters"); + ASSERT_EQ(clientParameters.getPropertyValue("PtpConfigurationStructure"), newConfiguration); + + PropertyObjectPtr clientPorts = clientParameters.getPropertyValue("Ports"); + ASSERT_EQ(clientPorts.getPropertyValue("Port1"), true); +} + +TEST_F(TmsIntegrationTest, SyncComponentCustomInterface) +{ + InstancePtr device = createDevice(); + auto serverTypeManager = device.getContext().getTypeManager(); + auto serverSubDevice = device.getDevices()[1]; + auto serverSync = serverSubDevice.getSyncComponent(); + SyncComponentPrivatePtr syncComponentPrivate = serverSync.asPtr(true); + + { + auto customSyncInterface = PropertyObjectClassBuilder(serverTypeManager, "CustomInterface") + .setParentName("SyncInterfaceBase") + .addProperty(SelectionProperty("CustomState", List("Cool", "Awesome"), 1)) + .build(); + serverTypeManager->addType(customSyncInterface); + syncComponentPrivate.addInterface(PropertyObject(serverTypeManager, "CustomInterface")); + } + + TmsServer tmsServer(device); + tmsServer.start(); + + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL); + DevicePtr clientDevice = tmsClient.connect(); + auto clientSubDevice = clientDevice.getDevices()[1]; + auto clientSync = clientSubDevice.getSyncComponent(); + + auto serverInterfaces = serverSync.getInterfaces(); + auto clientInterfaces = clientSync.getInterfaces(); + + ASSERT_EQ(serverInterfaces.getCount(), clientInterfaces.getCount()); + ASSERT_EQ(serverInterfaces.getKeyList(), clientInterfaces.getKeyList()); + + auto customInterface = clientInterfaces.get("CustomInterface"); + ASSERT_TRUE(customInterface.hasProperty("CustomState")); + ASSERT_EQ(customInterface.getProperty("CustomState").getSelectionValues(), List("Cool", "Awesome")); + ASSERT_EQ(customInterface.getPropertyValue("CustomState"), 1); + ASSERT_EQ(customInterface.getPropertySelectionValue("CustomState"), "Awesome"); +} + +TEST_F(TmsIntegrationTest, SyncComponentCustomModeOptions) +{ + InstancePtr device = createDevice(); + auto serverTypeManager = device.getContext().getTypeManager(); + auto serverSubDevice = device.getDevices()[1]; + auto serverSync = serverSubDevice.getSyncComponent(); + SyncComponentPrivatePtr syncComponentPrivate = serverSync.asPtr(true); + auto modeOptions = Dict({{2, "Auto"}, {3, "Off"}}); + + { + auto interfaceClockSync = PropertyObject(serverTypeManager, "InterfaceClockSync"); + interfaceClockSync.setPropertyValue("ModeOptions", modeOptions); + syncComponentPrivate.addInterface(interfaceClockSync); + } + + TmsServer tmsServer(device); + tmsServer.start(); + + TmsClient tmsClient(device.getContext(), nullptr, OPC_URL); + DevicePtr clientDevice = tmsClient.connect(); + auto clientSubDevice = clientDevice.getDevices()[1]; + auto clientSync = clientSubDevice.getSyncComponent(); + + auto serverInterfaces = serverSync.getInterfaces(); + auto clientInterfaces = clientSync.getInterfaces(); + + ASSERT_EQ(serverInterfaces.getCount(), clientInterfaces.getCount()); + ASSERT_EQ(serverInterfaces.getKeyList(), clientInterfaces.getKeyList()); + + auto interfaceClockSync = clientInterfaces.get("InterfaceClockSync"); + auto modeProperty = interfaceClockSync.getProperty("Mode"); + ASSERT_EQ(modeProperty.getSelectionValues(), modeOptions); + ASSERT_EQ(interfaceClockSync.getPropertySelectionValue("Mode"), "Off"); +} \ No newline at end of file From a52f35faed97a0c879679f3c16b24307ba7c3b0a Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Tue, 13 Aug 2024 10:08:23 +0200 Subject: [PATCH 157/217] Fix opcua warnings --- .../src/objects/tms_client_device_impl.cpp | 30 ++++++++++++++----- .../tms_client_property_object_impl.cpp | 2 +- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index b5fc6e8..082819c 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -171,14 +171,28 @@ DeviceInfoPtr TmsClientDeviceImpl::onGetInfo() { if (value.isScalar()) { - if (value.isString()) - deviceInfo.addProperty(StringProperty(browseName, value.toString())); - else if (value.isBool()) - deviceInfo.addProperty(BoolProperty(browseName, value.toBool())); - else if (value.isDouble()) - deviceInfo.addProperty(FloatProperty(browseName, value.toDouble())); - else if (value.isInteger()) - deviceInfo.addProperty(IntProperty(browseName, value.toInteger())); + if (deviceInfo.hasProperty(browseName)) + { + if (value.isString()) + deviceInfo.asPtr(true).setProtectedPropertyValue(browseName, value.toString()); + else if (value.isBool()) + deviceInfo.asPtr(true).setProtectedPropertyValue(browseName, value.toBool()); + else if (value.isDouble()) + deviceInfo.asPtr(true).setProtectedPropertyValue(browseName, value.toDouble()); + else if (value.isInteger()) + deviceInfo.asPtr(true).setProtectedPropertyValue(browseName, value.toInteger()); + } + else + { + if (value.isString()) + deviceInfo.addProperty(StringProperty(browseName, value.toString())); + else if (value.isBool()) + deviceInfo.addProperty(BoolProperty(browseName, value.toBool())); + else if (value.isDouble()) + deviceInfo.addProperty(FloatProperty(browseName, value.toDouble())); + else if (value.isInteger()) + deviceInfo.addProperty(IntProperty(browseName, value.toInteger())); + } } } catch (const std::exception& e) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index 96ba812..cbc8124 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -489,7 +489,7 @@ void TmsClientPropertyObjectBaseImpl::browseRawProperties() template bool TmsClientPropertyObjectBaseImpl::isIgnoredMethodPeoperty(const std::string& browseName) { - return browseName == "BeginUpdate" || browseName == "EndUpdate"; + return browseName == "BeginUpdate" || browseName == "EndUpdate" || browseName == "GetErrorInformation"; } template class TmsClientPropertyObjectBaseImpl; From 849acc300e03c9a6ec2747408d889adb08d99855 Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Mon, 19 Aug 2024 13:27:45 +0200 Subject: [PATCH 158/217] Sync component improvements - rename component from sync to synchronization - make sync component invisible for client device --- .../opcuatms_client/src/objects/tms_client_device_impl.cpp | 4 ++-- .../src/objects/tms_client_property_impl.cpp | 7 +------ .../opcuatms_server/src/objects/tms_server_device.cpp | 2 +- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 082819c..fd61235 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -249,11 +249,11 @@ void TmsClientDeviceImpl::fetchTimeDomain() void TmsClientDeviceImpl::findAndCreateSyncComponent() { - this->removeComponentById("Sync"); + this->removeComponentById("Synchronization"); auto syncComponentNodeId = getNodeId("Synchronization"); syncComponent = this->addExistingComponent(TmsClientSyncComponent(context, this->thisPtr(), - "Sync", + "Synchronization", clientContext, syncComponentNodeId)); } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp index 98c32f5..f0b2d74 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp @@ -106,13 +106,8 @@ void TmsClientPropertyImpl::configurePropertyFields() StringPtr evalStr = VariantConverter::ToDaqObject(reader->getValue(evalId, UA_ATTRIBUTEID_VALUE)); if (details::stringToPropertyFieldEnum.count(browseName)) { - bool strHasValue = false; const auto propertyField = details::stringToPropertyFieldEnum[browseName]; - if (evalStr.assigned()) - { - if (evalStr.getLength() > 0) - strHasValue = true; - } + bool strHasValue = evalStr.assigned() && evalStr.getLength() > 0; if (strHasValue) { switch (propertyField) diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index 4373918..f7f1afc 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -477,7 +477,7 @@ void TmsServerDevice::addChildNodes() for (auto component : object.getItems(search::Any())) { auto id = component.getLocalId(); - if (id == "Dev" || id == "FB" || id == "IO" || id == "Sig" || id == "Sync") + if (id == "Dev" || id == "FB" || id == "IO" || id == "Sig" || id == "Synchronization") continue; if (component.asPtrOrNull().assigned()) From 53ca62dcbdbf8c5d975eaeda0df0bce08d3a4d10 Mon Sep 17 00:00:00 2001 From: Denis Erokhin Date: Tue, 20 Aug 2024 11:44:13 +0200 Subject: [PATCH 159/217] fix connection string regexp with % and path. fix sync component cmake --- .../opcua_client_module/src/opcua_client_module_impl.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index f0dd7ac..9e7149e 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -194,13 +194,12 @@ StringPtr OpcUaClientModule::formConnectionString(const StringPtr& connectionStr { std::string urlString = connectionString.toStdString(); - auto regexIpv6Hostname = std::regex(R"(^(.*://)(\[[a-fA-F0-9:]+\])(?::(\d+))?(/.*)?$)"); + auto regexIpv6Hostname = std::regex(R"(^(.*://)?(\[[a-fA-F0-9:]+(?:\%\d+)?\])(?::(\d+))?(/.*)?$)"); auto regexIpv4Hostname = std::regex(R"(^(.*://)?([^:/\s]+)(?::(\d+))?(/.*)?$)"); std::smatch match; - std::string target = "/"; std::string prefix = ""; - std::string path = ""; + std::string path = "/"; if (config.assigned() ) { @@ -238,7 +237,7 @@ StringPtr OpcUaClientModule::formConnectionString(const StringPtr& connectionStr if (prefix != std::string(DaqOpcUaDevicePrefix) + "://") throw InvalidParameterException("OpcUa does not support connection string with prefix {}", prefix); - return std::string(OpcUaScheme) + "://" + host + ":" + std::to_string(port) + "/" + path; + return std::string(OpcUaScheme) + "://" + host + ":" + std::to_string(port) + path; } bool OpcUaClientModule::acceptsConnectionParameters(const StringPtr& connectionString, const PropertyObjectPtr& config) From ce924af41407c06cb155260393ed3158a7f4ce65 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Tue, 20 Aug 2024 11:54:46 +0200 Subject: [PATCH 160/217] Add ipv6 link local interface to connection string when available --- .../opcua_client_module/src/opcua_client_module_impl.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 9e7149e..29c4dfe 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -52,15 +52,15 @@ OpcUaClientModule::OpcUaClientModule(ContextPtr context) } if(!discoveredDevice.ipv6Address.empty()) { - auto connectionStringIpv6 = fmt::format("{}://[{}]:{}{}", + auto connectionStringIpv6 = fmt::format("{}://{}:{}{}", DaqOpcUaDevicePrefix, discoveredDevice.ipv6Address, discoveredDevice.servicePort, discoveredDevice.getPropertyOrDefault("path", "/")); cap.addConnectionString(connectionStringIpv6); - cap.addAddress("[" + discoveredDevice.ipv6Address + "]"); + cap.addAddress(discoveredDevice.ipv6Address); - const auto addressInfo = AddressInfoBuilder().setAddress("[" + discoveredDevice.ipv6Address + "]") + const auto addressInfo = AddressInfoBuilder().setAddress(discoveredDevice.ipv6Address) .setReachabilityStatus(AddressReachabilityStatus::Unknown) .setType("IPv6") .setConnectionString(connectionStringIpv6) From 3fe384e0cacb22ff20e8d4bae0556a3c1c3143a4 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Tue, 20 Aug 2024 13:55:52 +0200 Subject: [PATCH 161/217] Fix regex --- modules/opcua_client_module/src/opcua_client_module_impl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 29c4dfe..9e33e58 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -194,7 +194,7 @@ StringPtr OpcUaClientModule::formConnectionString(const StringPtr& connectionStr { std::string urlString = connectionString.toStdString(); - auto regexIpv6Hostname = std::regex(R"(^(.*://)?(\[[a-fA-F0-9:]+(?:\%\d+)?\])(?::(\d+))?(/.*)?$)"); + auto regexIpv6Hostname = std::regex(R"(^(.*://)?(\[[a-fA-F0-9:]+(?:\%[a-zA-Z0-9]+)?\])(?::(\d+))?(/.*)?$)"); auto regexIpv4Hostname = std::regex(R"(^(.*://)?([^:/\s]+)(?::(\d+))?(/.*)?$)"); std::smatch match; From 564e574e72cef51877f6a257399a8ca53e049667 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Fri, 23 Aug 2024 09:52:14 +0200 Subject: [PATCH 162/217] Increase version to 3.4 --- modules/opcua_client_module/CMakeLists.txt | 2 +- modules/opcua_server_module/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/opcua_client_module/CMakeLists.txt b/modules/opcua_client_module/CMakeLists.txt index 5bc1519..4bae971 100644 --- a/modules/opcua_client_module/CMakeLists.txt +++ b/modules/opcua_client_module/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(ClientModule VERSION 3.3.0 LANGUAGES C CXX) +project(ClientModule VERSION 3.4.0 LANGUAGES C CXX) add_subdirectory(src) diff --git a/modules/opcua_server_module/CMakeLists.txt b/modules/opcua_server_module/CMakeLists.txt index a868025..549d2e2 100644 --- a/modules/opcua_server_module/CMakeLists.txt +++ b/modules/opcua_server_module/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(ServerModule VERSION 3.3.0 LANGUAGES CXX) +project(ServerModule VERSION 3.4.0 LANGUAGES CXX) add_subdirectory(src) diff --git a/shared/libraries/opcuatms/opcuatms/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms/CMakeLists.txt index 24b8411..bcbf9ae 100644 --- a/shared/libraries/opcuatms/opcuatms/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(opcuatms VERSION 3.3.0 LANGUAGES CXX) +project(opcuatms VERSION 3.4.0 LANGUAGES CXX) add_subdirectory(src) diff --git a/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt index 11e5097..67bc6d9 100644 --- a/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(opcuatms_client VERSION 3.3.0 LANGUAGES CXX) +project(opcuatms_client VERSION 3.4.0 LANGUAGES CXX) add_subdirectory(src) diff --git a/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt index 162d6f4..b9d3af0 100644 --- a/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(opcuatms_server VERSION 3.3.0 LANGUAGES CXX) +project(opcuatms_server VERSION 3.4.0 LANGUAGES CXX) add_subdirectory(src) From ab71fa29371b5b5372b6ffb31781674977a691b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE=20Fran=C4=8Di=C4=8D?= Date: Fri, 23 Aug 2024 12:08:15 +0200 Subject: [PATCH 163/217] Add Reference Domain Info (openDAQ/openDAQ#411) * Reference Domain Info was added as an interface that gives additional information about the reference domain * Reference Domain Info has getters for: * Reference Domain ID (Signals with the same Reference Domain ID share a common synchronization source and can be read together) * Reference Domain Offset (which must be added to the domain values of the Signal for them to be equal to that of the sync source) * Reference Time Source (which is used to determine if two signals with different Domain IDs can be read together); possible values are: * [Tai](https://en.wikipedia.org/wiki/International_Atomic_Time) * [Gps](https://en.wikipedia.org/wiki/Global_Positioning_System#Timekeeping) * [Utc](https://en.wikipedia.org/wiki/Coordinated_Universal_Time) * Unknown * Uses Offset * There is also a builder available for creating Reference Domain Info * Reference Domain Info is a part of two interfaces: * Device Domain * Data Descriptor * Reference Domain Info is currently only supported over Native, not over OPC UA or LT Streaming protocols (this will cause two data descriptor changed events to be sent when combining supported and unsupported protocols for configuration/streaming - for example OPC UA and Native streaming) --- .../tests/opcuatms_integration/test_tms_integration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index 7c2b1f2..440a17f 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -584,4 +584,4 @@ TEST_F(TmsIntegrationTest, SyncComponentCustomModeOptions) auto modeProperty = interfaceClockSync.getProperty("Mode"); ASSERT_EQ(modeProperty.getSelectionValues(), modeOptions); ASSERT_EQ(interfaceClockSync.getPropertySelectionValue("Mode"), "Off"); -} \ No newline at end of file +} From 1adf37157452803876fce16573763d0601b9efeb Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Wed, 21 Aug 2024 09:57:54 +0200 Subject: [PATCH 164/217] Use correct namespace name for open library, so that find_package works. Correct spdlog dependency. --- external/open62541/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/open62541/CMakeLists.txt b/external/open62541/CMakeLists.txt index 133c3fd..1081547 100644 --- a/external/open62541/CMakeLists.txt +++ b/external/open62541/CMakeLists.txt @@ -21,7 +21,7 @@ opendaq_dependency( GIT_REPOSITORY https://github.com/openDAQ/open62541.git GIT_REF v1.3.6-opendaq-4 GIT_SUBMODULES "" - EXPECT_TARGET open62541 + EXPECT_TARGET open62541::open62541 ) if (open62541_FETCHED) From 55283861aa9fcd0b05bae2c0f5865fd54660d66c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mikoli=C4=8D?= Date: Wed, 28 Aug 2024 11:17:31 +0200 Subject: [PATCH 165/217] Catch exceptions when calling opcua methods --- .../src/objects/tms_server_device.cpp | 16 ++++++++++++---- .../src/objects/tms_server_input_port.cpp | 8 ++++++++ .../src/objects/tms_server_property_object.cpp | 2 +- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index f7f1afc..d7f61a4 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -292,17 +292,21 @@ void TmsServerDevice::createAddFunctionBlockNode(const OpcUaNodeId& parentId) auto methodNodeId = server->addMethodNode(params); - auto callback = [this](NodeEventManager::MethodArgs args) + auto callback = [this](NodeEventManager::MethodArgs args) -> UA_StatusCode { try { this->onAddFunctionBlock(args); - return OPENDAQ_SUCCESS; + return UA_STATUSCODE_GOOD; } catch (const OpcUaException& e) { return e.getStatusCode(); } + catch (...) + { + return UA_STATUSCODE_BADINTERNALERROR; + } }; addEvent(methodNodeId)->onMethodCall(callback); @@ -323,17 +327,21 @@ void TmsServerDevice::createRemoveFunctionBlockNode(const OpcUaNodeId& parentId) auto methodNodeId = server->addMethodNode(params); - auto callback = [this](NodeEventManager::MethodArgs args) + auto callback = [this](NodeEventManager::MethodArgs args) -> UA_StatusCode { try { this->onRemoveFunctionBlock(args); - return OPENDAQ_SUCCESS; + return UA_STATUSCODE_GOOD; } catch (const OpcUaException& e) { return e.getStatusCode(); } + catch (...) + { + return UA_STATUSCODE_BADINTERNALERROR; + } }; addEvent(methodNodeId)->onMethodCall(callback); diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp index cb013dc..cb778ef 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp @@ -59,6 +59,10 @@ void TmsServerInputPort::createConnectMethodNode() { return e.getStatusCode(); } + catch (...) + { + return UA_STATUSCODE_BADINTERNALERROR; + } return UA_STATUSCODE_GOOD; }; @@ -86,6 +90,10 @@ void TmsServerInputPort::createDisconnectMethodNode() { return e.getStatusCode(); } + catch (...) + { + return UA_STATUSCODE_BADINTERNALERROR; + } return UA_STATUSCODE_GOOD; }; diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp index 2e5cdb9..5412063 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp @@ -335,7 +335,7 @@ void TmsServerPropertyObject::bindMethodCallbacks() } catch(...) { - return UA_STATUSCODE_BAD; + return UA_STATUSCODE_BADINTERNALERROR; } }); } From ea8c63e22b4d09733fcd982c3ba055f9c3625f54 Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Thu, 5 Sep 2024 16:22:52 +0200 Subject: [PATCH 166/217] [TBBAS-1592] Instance save/load fixes (openDAQ/openDAQ#450) - make connecting signals while loading in correct order - printing connection circle dependency if they were detected --- .../src/opcua_client_module_impl.cpp | 26 +++++++------------ .../src/opcua_server_impl.cpp | 2 +- .../src/converters/base_object_converter.cpp | 4 +-- .../src/objects/tms_client_context.cpp | 6 ++--- .../src/objects/tms_client_function_impl.cpp | 3 +-- .../src/objects/tms_client_procedure_impl.cpp | 3 +-- .../src/objects/tms_client_property_impl.cpp | 6 ++--- .../objects/tms_server_component.h | 4 +-- .../src/objects/tms_server_device.cpp | 2 +- .../src/objects/tms_server_folder.cpp | 2 +- .../src/objects/tms_server_property.cpp | 2 +- .../opcuatms_integration/test_tms_folder.cpp | 2 +- .../test_tms_integration.cpp | 2 +- 13 files changed, 28 insertions(+), 36 deletions(-) diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 9e33e58..d05bd15 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -102,18 +102,18 @@ DictPtr OpcUaClientModule::onGetAvailableDeviceTypes() DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, const ComponentPtr& parent, - const PropertyObjectPtr& aConfig) + const PropertyObjectPtr& config) { if (!connectionString.assigned()) throw ArgumentNullException(); - PropertyObjectPtr config = aConfig; - if (!config.assigned()) - config = createDefaultConfig(); + PropertyObjectPtr configPtr = config; + if (!configPtr.assigned()) + configPtr = createDefaultConfig(); else - config = populateDefaultConfig(config); + configPtr = populateDefaultConfig(configPtr); - if (!acceptsConnectionParameters(connectionString, config)) + if (!acceptsConnectionParameters(connectionString, configPtr)) throw InvalidParameterException(); if (!context.assigned()) @@ -122,19 +122,14 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, std::string host; std::string hostType; int port; - auto formedConnectionString = formConnectionString(connectionString, config, host, port, hostType); + auto formedConnectionString = formConnectionString(connectionString, configPtr, host, port, hostType); std::scoped_lock lock(sync); auto endpoint = OpcUaEndpoint(formedConnectionString); - if (config.assigned()) - { - if (config.hasProperty("Username")) - endpoint.setUsername(config.getPropertyValue("Username")); - if (config.hasProperty("Password")) - endpoint.setPassword(config.getPropertyValue("Password")); - } + endpoint.setUsername(configPtr.getPropertyValue("Username")); + endpoint.setPassword(configPtr.getPropertyValue("Password")); TmsClient client(context, parent, endpoint); auto device = client.connect(); @@ -143,7 +138,6 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, // Set the connection info for the device ServerCapabilityConfigPtr connectionInfo = device.getInfo().getConfigurationConnectionInfo(); - const auto addressInfo = AddressInfoBuilder().setAddress(host) .setReachabilityStatus(AddressReachabilityStatus::Reachable) .setType(hostType) @@ -279,7 +273,7 @@ Bool OpcUaClientModule::onCompleteServerCapability(const ServerCapabilityPtr& so { port = 4840; target.setPort(port); - LOG_W("OPC UA server capability is missing port. Defaulting to 7420.") + LOG_W("OPC UA server capability is missing port. Defaulting to 4840.") } const auto path = target.hasProperty("Path") ? target.getPropertyValue("Path") : ""; diff --git a/modules/opcua_server_module/src/opcua_server_impl.cpp b/modules/opcua_server_module/src/opcua_server_impl.cpp index cf1b629..08725f0 100644 --- a/modules/opcua_server_module/src/opcua_server_impl.cpp +++ b/modules/opcua_server_module/src/opcua_server_impl.cpp @@ -11,7 +11,7 @@ using namespace daq; using namespace daq::opcua; OpcUaServerImpl::OpcUaServerImpl(DevicePtr rootDevice, PropertyObjectPtr config, const ContextPtr& context) - : Server("OpenDAQOPCUAServerModule", config, rootDevice, context, nullptr) + : Server("OpenDAQOPCUA", config, rootDevice, context) , server(rootDevice, context) , context(context) { diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp index ac3311e..bde31ad 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp @@ -113,7 +113,7 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr(); + const auto elementType = list.asPtr(); IntfID elementId; elementType->getElementInterfaceId(&elementId); @@ -138,7 +138,7 @@ OpcUaVariant VariantConverter::ToVariant(const BaseObjectPtr& objec const auto ids = object.asPtr().getInterfaceIds(); auto wrapConvertedValue = targetType == &UA_TYPES[UA_TYPES_EXTENSIONOBJECT] || targetType == &UA_TYPES[UA_TYPES_VARIANT]; - wrapConvertedValue = wrapConvertedValue && !object.asPtrOrNull().assigned(); + wrapConvertedValue = wrapConvertedValue && !object.supportsInterface(); if (wrapConvertedValue) { diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp index 74d6036..4ce35a0 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp @@ -141,7 +141,7 @@ void TmsClientContext::addEnumerationTypesToTypeManager() const auto DataTypeEnumerationNodeId = OpcUaNodeId(UA_NS0ID_ENUMERATION); const auto& references = referenceBrowser->browse(DataTypeEnumerationNodeId); - StructPtr EnumValuesStruct; + StructPtr enumValuesStruct; std::vector vecEnumerationsNodeIds; for (auto [browseName, ref] : references.byBrowseName) @@ -173,8 +173,8 @@ void TmsClientContext::addEnumerationTypesToTypeManager() { for (const auto& value : childNodeObject.asPtr()) { - if (EnumValuesStruct = value.asPtrOrNull(); EnumValuesStruct.assigned()) - listEnumValues.pushBack(EnumValuesStruct.get("DisplayName")); + if (enumValuesStruct = value.asPtrOrNull(true); enumValuesStruct.assigned()) + listEnumValues.pushBack(enumValuesStruct.get("DisplayName")); } } } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_impl.cpp index 5534a8f..194f3c4 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_impl.cpp @@ -31,10 +31,9 @@ ErrCode TmsClientFunctionImpl::call(IBaseObject* args, IBaseObject** result) lastProccessDescription = "Creating call request with no args"; callRequest = OpcUaCallMethodRequest(methodId, parentId, 0); } - else if (argsPtr.asPtrOrNull().assigned()) + else if (auto argsList = argsPtr.asPtrOrNull(); argsList.assigned()) { lastProccessDescription = "Creating call request with list of arguments"; - auto argsList = argsPtr.asPtrOrNull(); OpcUaVariant varArgs = ListConversionUtils::ToVariantTypeArrayVariant(argsList, daqContext); callRequest = OpcUaCallMethodRequest(methodId, parentId, argsList.getCount(), (UA_Variant*) varArgs->data); } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_procedure_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_procedure_impl.cpp index 084adc5..b60fb75 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_procedure_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_procedure_impl.cpp @@ -32,10 +32,9 @@ ErrCode TmsClientProcedureImpl::dispatch(IBaseObject* args) lastProccessDescription = "Creating call request with no args"; callRequest = OpcUaCallMethodRequest(methodId, parentId, 0); } - else if (argsPtr.asPtrOrNull().assigned()) + else if (auto argsList = argsPtr.asPtrOrNull(); argsList.assigned()) { lastProccessDescription = "Creating call request with list of arguments"; - auto argsList = argsPtr.asPtrOrNull(); OpcUaVariant varArgs = ListConversionUtils::ToVariantTypeArrayVariant(argsList, daqContext); callRequest = OpcUaCallMethodRequest(methodId, parentId, argsList.getCount(), (UA_Variant*) varArgs->data); } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp index f0b2d74..2d7f3e1 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp @@ -199,7 +199,7 @@ void TmsClientPropertyImpl::configurePropertyFields() else this->defaultValue = VariantConverter::ToDaqObject(value, daqContext); - if (this->defaultValue.assigned() && this->defaultValue.asPtrOrNull().assigned()) + if (this->defaultValue.assigned() && this->defaultValue.supportsInterface()) this->defaultValue.freeze(); break; @@ -223,7 +223,7 @@ void TmsClientPropertyImpl::configurePropertyFields() { this->suggestedValues = VariantConverter::ToDaqList(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE), daqContext); - if (this->suggestedValues.assigned() && this->suggestedValues.asPtrOrNull().assigned()) + if (this->suggestedValues.assigned() && this->suggestedValues.supportsInterface()) this->suggestedValues.freeze(); break; } @@ -231,7 +231,7 @@ void TmsClientPropertyImpl::configurePropertyFields() { this->selectionValues = SelectionVariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE)); - if (this->selectionValues.assigned() && this->selectionValues.asPtrOrNull().assigned()) + if (this->selectionValues.assigned() && this->selectionValues.supportsInterface()) this->selectionValues.freeze(); break; } diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h index 5c76bfb..95aba9d 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h @@ -132,7 +132,7 @@ void TmsServerComponent::bindCallbacks() }); this->addReadCallback("Active", [this]() { return VariantConverter::ToVariant( this->object.getActive()); }); - if (!this->object.template asPtrOrNull().assigned() || !this->object.isFrozen()) + if (!this->object.template supportsInterface() || !this->object.isFrozen()) { this->addWriteCallback("Active", [this](const OpcUaVariant& variant){ this->object.setActive(VariantConverter::ToDaqObject(variant)); @@ -142,7 +142,7 @@ void TmsServerComponent::bindCallbacks() this->addReadCallback("Visible", [this]() { return VariantConverter::ToVariant( this->object.getVisible()); }); - if (!this->object.template asPtrOrNull().assigned() || !this->object.isFrozen()) + if (!this->object.template supportsInterface() || !this->object.isFrozen()) { this->addWriteCallback("Visible", [this](const OpcUaVariant& variant){ this->object.setVisible(VariantConverter::ToDaqObject(variant)); diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index d7f61a4..c500dac 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -488,7 +488,7 @@ void TmsServerDevice::addChildNodes() if (id == "Dev" || id == "FB" || id == "IO" || id == "Sig" || id == "Synchronization") continue; - if (component.asPtrOrNull().assigned()) + if (component.supportsInterface()) { auto folderNode = registerTmsObjectOrAddReference(nodeId, component, numberInList++); folders.push_back(std::move(folderNode)); diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp index 7904819..7eab585 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp @@ -49,7 +49,7 @@ void TmsServerFolder::addChildNodes() OpcUaNodeId TmsServerFolder::getTmsTypeId() { - if (object.asPtrOrNull().assigned()) + if (object.supportsInterface()) return OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_IOCOMPONENTTYPE); return OpcUaNodeId(NAMESPACE_DAQDEVICE, UA_DAQDEVICEID_DAQCOMPONENTTYPE); } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp index 3c12fa6..970122a 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp @@ -82,7 +82,7 @@ void TmsServerProperty::bindCallbacks() return VariantConverter::ToVariant(value, nullptr, daqContext); }); - if (!parentObj.asPtrOrNull().assigned() || !parentObj.isFrozen()) + if (!parentObj.supportsInterface() || !parentObj.isFrozen()) { addWriteCallback(name, [this, name](const OpcUaVariant& variant) { const auto value = VariantConverter::ToDaqObject(variant, daqContext); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp index 9400753..7b58e48 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp @@ -58,7 +58,7 @@ class TmsFolderTest : public TmsObjectIntegrationTest folder.serverFolder = testFolder; folder.serverObject = std::make_shared(folder.serverFolder, this->getServer(), ctx, serverContext); auto nodeId = folder.serverObject->registerOpcUaNode(); - if (testFolder.asPtrOrNull().assigned()) + if (testFolder.supportsInterface()) folder.clientFolder = TmsClientIoFolder(NullContext(), nullptr, "test", clientContext, nodeId); else folder.clientFolder = TmsClientFolder(NullContext(), nullptr, "test", clientContext, nodeId); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index 440a17f..87f2dcd 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -257,7 +257,7 @@ TEST_F(TmsIntegrationTest, GetAvailableFunctionBlockTypes) const auto clientFbTypes = clientDevice.getAvailableFunctionBlockTypes(); - ASSERT_EQ(serverFbTypes.getCount(), 1u); + ASSERT_EQ(serverFbTypes.getCount(), 3u); ASSERT_EQ(serverFbTypes.getCount(), clientFbTypes.getCount()); ASSERT_TRUE(TestComparators::FunctionBlockTypeEquals(serverFbTypes.get("mock_fb_uid"), clientFbTypes.get("mock_fb_uid"))); } From b115de08b412f7db5c7cb86b611ef6d5f2e93334 Mon Sep 17 00:00:00 2001 From: Nikolai Shipilov Date: Mon, 26 Aug 2024 08:11:14 +0200 Subject: [PATCH 167/217] Enable openDAQ servers to be added to the component tree under the device: * IServer now inherits from IFolder * The base server implementation now inherits from SignalContainer * Servers are added under the root device rather than directly under the instance. * Store the root device pointer as a weak reference within IServer objects * Add the missing default configuration population mechanism for the OpcUa server Limitations: * Servers are not exposed in the component tree through the OpcUa protocol --- .../opcua_server_module/opcua_server_impl.h | 7 +++++-- .../opcua_server_module_impl.h | 2 +- .../src/opcua_server_impl.cpp | 21 ++++++++++++++++--- .../src/opcua_server_module_impl.cpp | 15 +++++++------ .../src/objects/tms_server_device.cpp | 5 +++-- 5 files changed, 36 insertions(+), 14 deletions(-) diff --git a/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h b/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h index fdef2d6..7fb3d86 100644 --- a/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h +++ b/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h @@ -24,13 +24,16 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_SERVER_MODULE -class OpcUaServerImpl : public daq::Server +class OpcUaServerImpl : public Server { public: - explicit OpcUaServerImpl(daq::DevicePtr rootDevice, PropertyObjectPtr config, const ContextPtr& context); + explicit OpcUaServerImpl(const DevicePtr& rootDevice, + const PropertyObjectPtr& config, + const ContextPtr& context); ~OpcUaServerImpl(); static PropertyObjectPtr createDefaultConfig(const ContextPtr& context); static ServerTypePtr createType(const ContextPtr& context); + static PropertyObjectPtr populateDefaultConfig(const PropertyObjectPtr& config, const ContextPtr& context); protected: PropertyObjectPtr getDiscoveryConfig() override; diff --git a/modules/opcua_server_module/include/opcua_server_module/opcua_server_module_impl.h b/modules/opcua_server_module/include/opcua_server_module/opcua_server_module_impl.h index 64c9ede..3c066bd 100644 --- a/modules/opcua_server_module/include/opcua_server_module/opcua_server_module_impl.h +++ b/modules/opcua_server_module/include/opcua_server_module/opcua_server_module_impl.h @@ -26,7 +26,7 @@ class OpcUaServerModule final : public Module OpcUaServerModule(ContextPtr context); DictPtr onGetAvailableServerTypes() override; - ServerPtr onCreateServer(StringPtr serverType, PropertyObjectPtr serverConfig, DevicePtr rootDevice) override; + ServerPtr onCreateServer(const StringPtr& serverType, const PropertyObjectPtr& serverConfig, const DevicePtr& rootDevice) override; private: std::mutex sync; diff --git a/modules/opcua_server_module/src/opcua_server_impl.cpp b/modules/opcua_server_module/src/opcua_server_impl.cpp index 08725f0..f5e7227 100644 --- a/modules/opcua_server_module/src/opcua_server_impl.cpp +++ b/modules/opcua_server_module/src/opcua_server_impl.cpp @@ -10,7 +10,9 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_SERVER_MODULE using namespace daq; using namespace daq::opcua; -OpcUaServerImpl::OpcUaServerImpl(DevicePtr rootDevice, PropertyObjectPtr config, const ContextPtr& context) +OpcUaServerImpl::OpcUaServerImpl(const DevicePtr& rootDevice, + const PropertyObjectPtr& config, + const ContextPtr& context) : Server("OpenDAQOPCUA", config, rootDevice, context) , server(rootDevice, context) , context(context) @@ -61,6 +63,19 @@ PropertyObjectPtr OpcUaServerImpl::createDefaultConfig(const ContextPtr& context return defaultConfig; } +PropertyObjectPtr OpcUaServerImpl::populateDefaultConfig(const PropertyObjectPtr& config, const ContextPtr& context) +{ + const auto defConfig = createDefaultConfig(context); + for (const auto& prop : defConfig.getAllProperties()) + { + const auto name = prop.getName(); + if (config.hasProperty(name)) + defConfig.setPropertyValue(name, config.getPropertyValue(name)); + } + + return defConfig; +} + PropertyObjectPtr OpcUaServerImpl::getDiscoveryConfig() { auto discoveryConfig = PropertyObject(); @@ -82,9 +97,9 @@ ServerTypePtr OpcUaServerImpl::createType(const ContextPtr& context) void OpcUaServerImpl::onStopServer() { server.stop(); - if (this->rootDevice.assigned()) + if (const DevicePtr rootDevice = this->rootDeviceRef.assigned() ? this->rootDeviceRef.getRef() : nullptr; rootDevice.assigned()) { - const auto info = this->rootDevice.getInfo(); + const auto info = rootDevice.getInfo(); const auto infoInternal = info.asPtr(); if (info.hasServerCapability("OpenDAQOPCUAConfiguration")) infoInternal.removeServerCapability("OpenDAQOPCUAConfiguration"); diff --git a/modules/opcua_server_module/src/opcua_server_module_impl.cpp b/modules/opcua_server_module/src/opcua_server_module_impl.cpp index 5c866d8..75e82a7 100644 --- a/modules/opcua_server_module/src/opcua_server_module_impl.cpp +++ b/modules/opcua_server_module/src/opcua_server_module_impl.cpp @@ -24,17 +24,20 @@ DictPtr OpcUaServerModule::onGetAvailableServerTypes() return result; } -ServerPtr OpcUaServerModule::onCreateServer(StringPtr serverType, - PropertyObjectPtr serverConfig, - DevicePtr rootDevice) +ServerPtr OpcUaServerModule::onCreateServer(const StringPtr& serverType, + const PropertyObjectPtr& serverConfig, + const DevicePtr& rootDevice) { if (!context.assigned()) throw InvalidParameterException{"Context parameter cannot be null."}; - if (!serverConfig.assigned()) - serverConfig = OpcUaServerImpl::createDefaultConfig(context); + PropertyObjectPtr config = serverConfig; + if (!config.assigned()) + config = OpcUaServerImpl::createDefaultConfig(context); + else + config = OpcUaServerImpl::populateDefaultConfig(config, context); - ServerPtr server(OpcUaServer_Create(rootDevice, serverConfig, context)); + ServerPtr server(OpcUaServer_Create(rootDevice, config, context)); return server; } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index c500dac..d5aa1a5 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -480,12 +480,13 @@ void TmsServerDevice::addChildNodes() syncComponentNode->registerToExistingOpcUaNode(syncComponentNodeId); syncComponents.push_back(std::move(syncComponentNode)); - + // TODO add "Srv" as a default node + numberInList = 0; for (auto component : object.getItems(search::Any())) { auto id = component.getLocalId(); - if (id == "Dev" || id == "FB" || id == "IO" || id == "Sig" || id == "Synchronization") + if (id == "Dev" || id == "FB" || id == "IO" || id == "Sig" || id == "Synchronization" || id == "Srv") continue; if (component.supportsInterface()) From 65f316fcae5b58d0b693e05de34b4de11f1a71d2 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko Date: Thu, 3 Oct 2024 14:15:47 +0200 Subject: [PATCH 168/217] Enable protected write calls over OPC UA --- .../objects/tms_client_property_object_impl.h | 1 + .../tms_client_property_object_impl.cpp | 24 +++++++++++------ .../objects/tms_server_property_object.cpp | 9 ++++--- .../opcuatms_server/tests/test_tms_device.cpp | 23 +++++++++++----- .../tests/test_tms_property_object.cpp | 2 +- .../test_tms_property_object.cpp | 27 ++++++++++++++++++- 6 files changed, 66 insertions(+), 20 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h index 5d90adb..d73a822 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h @@ -109,6 +109,7 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl ErrCode INTERFACE_FUNC getPropertyValue(IString* propertyName, IBaseObject** value) override; ErrCode INTERFACE_FUNC getPropertySelectionValue(IString* propertyName, IBaseObject** value) override; ErrCode INTERFACE_FUNC clearPropertyValue(IString* propertyName) override; + ErrCode INTERFACE_FUNC clearProtectedPropertyValue(IString* propertyName) override; ErrCode INTERFACE_FUNC getProperty(IString* propertyName, IProperty** value) override; ErrCode INTERFACE_FUNC addProperty(IProperty* property) override; ErrCode INTERFACE_FUNC removeProperty(IString* propertyName) override; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index cbc8124..aa09b19 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -15,6 +15,7 @@ #include #include #include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -43,12 +44,11 @@ ErrCode TmsClientPropertyObjectBaseImpl::setPropertyValueInternal(IString* { PropertyPtr prop; checkErrorInfo(getProperty(propertyName, &prop)); - if (protectedWrite) + if (!protectedWrite) { lastProcessDescription = "Checking existing property is read-only"; - const bool readOnly = prop.getReadOnly(); - if (readOnly) - return OPENDAQ_SUCCESS; + if (prop.getReadOnly()) + return OPENDAQ_ERR_ACCESSDENIED; } BaseObjectPtr valuePtr = value; @@ -75,13 +75,15 @@ ErrCode TmsClientPropertyObjectBaseImpl::setPropertyValueInternal(IString* lastProcessDescription = "Object type properties cannot be set over OpcUA"; return OPENDAQ_ERR_NOTIMPLEMENTED; } + lastProcessDescription = "Property not found"; return OPENDAQ_ERR_NOTFOUND; }); + if (OPENDAQ_FAILED(errCode)) LOG_W("Failed to set value for property \"{}\" on OpcUA client property object: {}", propertyNamePtr, lastProcessDescription); - - if (errCode == OPENDAQ_ERR_NOTFOUND) + + if (errCode == OPENDAQ_ERR_NOTFOUND || errCode == OPENDAQ_ERR_ACCESSDENIED) return errCode; return OPENDAQ_SUCCESS; @@ -162,6 +164,12 @@ ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::clearPropertyValue return OPENDAQ_ERR_INVALID_OPERATION; } +template +ErrCode TmsClientPropertyObjectBaseImpl::clearProtectedPropertyValue(IString* propertyName) +{ + return OPENDAQ_ERR_INVALID_OPERATION; +} + template ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::getProperty(IString* propertyName, IProperty** value) { @@ -183,13 +191,13 @@ ErrCode TmsClientPropertyObjectBaseImpl::removeProperty(IString* propertyN template ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::getOnPropertyValueWrite(IString* propertyName, IEvent** event) { - return Impl::getOnPropertyValueWrite(propertyName, event); + return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; } template ErrCode TmsClientPropertyObjectBaseImpl::getOnPropertyValueRead(IString* propertyName, IEvent** event) { - return Impl::getOnPropertyValueRead(propertyName, event); + return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; } template diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp index 5412063..e35d005 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp @@ -6,6 +6,7 @@ #include "opcuatms/converters/variant_converter.h" #include "opcuatms_server/objects/tms_server_property.h" #include +#include "coreobjects/property_object_protected_ptr.h" #include "open62541/nodeids.h" #include "open62541/statuscodes.h" #include "open62541/daqbsp_nodeids.h" @@ -49,8 +50,8 @@ TmsServerPropertyObject::TmsServerPropertyObject(const PropertyObjectPtr& object TmsServerPropertyObject::~TmsServerPropertyObject() { - for (auto prop : this->object.getAllProperties()) - this->object.getOnPropertyValueWrite(prop.getName()) -= event(this, &TmsServerPropertyObject::triggerEvent); + //for (auto prop : this->object.getAllProperties()) + // this->object.getOnPropertyValueWrite(prop.getName()) -= event(this, &TmsServerPropertyObject::triggerEvent); } std::string TmsServerPropertyObject::getBrowseName() @@ -173,7 +174,7 @@ void TmsServerPropertyObject::bindCallbacks() { for (const auto& [id, prop] : childProperties) { - this->object.getOnPropertyValueWrite(prop->getBrowseName()) += event(this, &TmsServerPropertyObject::triggerEvent); + //this->object.getOnPropertyValueWrite(prop->getBrowseName()) += event(this, &TmsServerPropertyObject::triggerEvent); bindPropertyCallbacks(prop->getBrowseName()); } @@ -207,7 +208,7 @@ void TmsServerPropertyObject::bindPropertyCallbacks(const std::string& name) { addWriteCallback(name, [this, name](const OpcUaVariant& variant) { const auto value = VariantConverter::ToDaqObject(variant, daqContext); - this->object.setPropertyValue(name, value); + this->object.asPtr().setProtectedPropertyValue(name, value); return UA_STATUSCODE_GOOD; }); } diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_device.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_device.cpp index 50a7fc0..9ce589f 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_device.cpp @@ -20,13 +20,17 @@ using TmsDeviceTest = TmsServerObjectTest; TEST_F(TmsDeviceTest, Create) { - DevicePtr device = test_helpers::SetupInstance(); + auto instance = test_helpers::SetupInstance(); + auto device = instance.getRootDevice(); + auto tmsDevice = TmsServerDevice(device, this->getServer(), ctx, tmsCtx); } TEST_F(TmsDeviceTest, Register) { - DevicePtr device = test_helpers::SetupInstance(); + auto instance = test_helpers::SetupInstance(); + auto device = instance.getRootDevice(); + auto tmsDevice = TmsServerDevice(device, this->getServer(), ctx, tmsCtx); auto nodeId = tmsDevice.registerOpcUaNode(); @@ -35,7 +39,9 @@ TEST_F(TmsDeviceTest, Register) TEST_F(TmsDeviceTest, SubDevices) { - DevicePtr device = test_helpers::SetupInstance(); + auto instance = test_helpers::SetupInstance(); + auto device = instance.getRootDevice(); + auto tmsDevice = TmsServerDevice(device, this->getServer(), ctx, tmsCtx); auto nodeId = tmsDevice.registerOpcUaNode(); @@ -44,7 +50,9 @@ TEST_F(TmsDeviceTest, SubDevices) TEST_F(TmsDeviceTest, FunctionBlock) { - DevicePtr device = test_helpers::SetupInstance(); + auto instance = test_helpers::SetupInstance(); + auto device = instance.getRootDevice(); + auto tmsDevice = TmsServerDevice(device, this->getServer(), ctx, tmsCtx); auto nodeId = tmsDevice.registerOpcUaNode(); @@ -54,7 +62,8 @@ TEST_F(TmsDeviceTest, FunctionBlock) TEST_F(TmsDeviceTest, Property) { - DevicePtr device = test_helpers::SetupInstance(); + auto instance = test_helpers::SetupInstance(); + auto device = instance.getRootDevice(); const auto sampleRateProp = FloatPropertyBuilder("SampleRate", 100.0).setUnit(Unit("Hz")).setMinValue(1.0).setMaxValue(1000000.0).build(); @@ -86,7 +95,9 @@ TEST_F(TmsDeviceTest, Property) TEST_F(TmsDeviceTest, Components) { - DevicePtr device = test_helpers::SetupInstance(); + auto instance = test_helpers::SetupInstance(); + auto device = instance.getRootDevice(); + auto tmsDevice = TmsServerDevice(device, this->getServer(), ctx, tmsCtx); auto nodeId = tmsDevice.registerOpcUaNode(); diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_property_object.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_property_object.cpp index b8f2081..13147ec 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_property_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_property_object.cpp @@ -70,7 +70,7 @@ TEST_F(TmsPropertyObjectTest, Register) ASSERT_TRUE(this->getClient()->nodeExists(nodeId)); } -TEST_F(TmsPropertyObjectTest, OnPropertyValueChangeEvent) +TEST_F(TmsPropertyObjectTest, DISABLED_OnPropertyValueChangeEvent) { PropertyObjectPtr propertyObject = createPropertyObject(); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp index 2ceea26..c4d0033 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp @@ -228,7 +228,7 @@ TEST_F(TmsPropertyObjectTest, TestPropertyOrder) } auto [serverObj, clientObj] = registerPropertyObject(obj); - auto serverProps = obj.getAllProperties(); + auto serverProps = obj.getAllProperties(); auto clientProps = clientObj.getAllProperties(); ASSERT_EQ(serverProps.getCount(), clientProps.getCount()); @@ -237,3 +237,28 @@ TEST_F(TmsPropertyObjectTest, TestPropertyOrder) ASSERT_EQ(serverProps[i].getName(), clientProps[i].getName()); } + +TEST_F(TmsPropertyObjectTest, TestReadOnlyWrite) +{ + auto obj = PropertyObject(); + obj.addProperty(IntPropertyBuilder("ReadOnly", 0).setReadOnly(true).build()); + auto [serverObj, clientObj] = registerPropertyObject(obj); + auto serverProps = obj.getAllProperties(); + auto clientProps = clientObj.getAllProperties(); + + ASSERT_EQ(clientObj.getPropertyValue("ReadOnly"), 0); + clientObj.asPtr().setProtectedPropertyValue("ReadOnly", 100); + ASSERT_EQ(clientObj.getPropertyValue("ReadOnly"), 100); +} + +TEST_F(TmsPropertyObjectTest, TestReadOnlyWriteFail) +{ + auto obj = PropertyObject(); + obj.addProperty(IntPropertyBuilder("ReadOnly", 0).setReadOnly(true).build()); + auto [serverObj, clientObj] = registerPropertyObject(obj); + auto serverProps = obj.getAllProperties(); + auto clientProps = clientObj.getAllProperties(); + + ASSERT_EQ(clientObj.getPropertyValue("ReadOnly"), 0); + ASSERT_THROW(clientObj.setPropertyValue("ReadOnly", 100), AccessDeniedException); +} From 16bdffe9dcd7e7849e0b6c06e6eeb701b0929c7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE=20Fran=C4=8Di=C4=8D?= Date: Fri, 18 Oct 2024 12:49:25 +0200 Subject: [PATCH 169/217] Inject openDAQ version from a single file (openDAQ/openDAQ#550) * Use `OPENDAQ_PACKAGE_VERSION` instead of hard-coded version throughout `CMakeLists.txt` files * Delete whitespace in `opendaq_verison` * Change `antora.yml` to contain a placeholder * Add Python `openda_version` injector * Add version injection to `build_antora_docs.yml` * Add version injection to `deploy.yml` * Inject version into `quick_start_setting_up_python.adoc` and `quick_start_setting_up_cpp.adoc` * `HEAD_DAQ_VERSION` and `HEAD_DOC_VERSION` variables appear to be unused, so this code is obsolete and we can safely delete the whole CI job * Minor fixes --- modules/opcua_client_module/CMakeLists.txt | 2 +- modules/opcua_server_module/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/opcua_client_module/CMakeLists.txt b/modules/opcua_client_module/CMakeLists.txt index 4bae971..0180af3 100644 --- a/modules/opcua_client_module/CMakeLists.txt +++ b/modules/opcua_client_module/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(ClientModule VERSION 3.4.0 LANGUAGES C CXX) +project(ClientModule VERSION ${OPENDAQ_PACKAGE_VERSION} LANGUAGES C CXX) add_subdirectory(src) diff --git a/modules/opcua_server_module/CMakeLists.txt b/modules/opcua_server_module/CMakeLists.txt index 549d2e2..5e3460c 100644 --- a/modules/opcua_server_module/CMakeLists.txt +++ b/modules/opcua_server_module/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(ServerModule VERSION 3.4.0 LANGUAGES CXX) +project(ServerModule VERSION ${OPENDAQ_PACKAGE_VERSION} LANGUAGES CXX) add_subdirectory(src) diff --git a/shared/libraries/opcuatms/opcuatms/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms/CMakeLists.txt index bcbf9ae..35cf34b 100644 --- a/shared/libraries/opcuatms/opcuatms/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(opcuatms VERSION 3.4.0 LANGUAGES CXX) +project(opcuatms VERSION ${OPENDAQ_PACKAGE_VERSION} LANGUAGES CXX) add_subdirectory(src) diff --git a/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt index 67bc6d9..7b0ec16 100644 --- a/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(opcuatms_client VERSION 3.4.0 LANGUAGES CXX) +project(opcuatms_client VERSION ${OPENDAQ_PACKAGE_VERSION} LANGUAGES CXX) add_subdirectory(src) diff --git a/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt index b9d3af0..c587e6e 100644 --- a/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) set_cmake_folder_context(TARGET_FOLDER_NAME) -project(opcuatms_server VERSION 3.4.0 LANGUAGES CXX) +project(opcuatms_server VERSION ${OPENDAQ_PACKAGE_VERSION} LANGUAGES CXX) add_subdirectory(src) From e1d28ea5f2ff8739bc58f63347a64ddae87f7a85 Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Mon, 21 Oct 2024 20:37:36 +0200 Subject: [PATCH 170/217] [TBBAS-1825] Fix device username/location properties case in opcua (openDAQ/openDAQ#518) --- .../include/opcuatms/converter_maps.h | 16 ++-- .../converters/list_conversion_utils.h | 10 +-- .../opcuatms/converters/selection_converter.h | 6 +- .../opcuatms/converters/struct_converter.h | 8 +- .../opcuatms/converters/variant_converter.h | 10 +-- .../include/opcuatms/core_types_utils.h | 2 +- .../include/opcuatms/extension_object.h | 4 +- .../opcuatms/include/opcuatms/type_mappings.h | 2 +- .../src/converters/argument_converter.cpp | 8 +- .../src/converters/base_object_converter.cpp | 12 +-- .../converters/complex_number_converter.cpp | 8 +- .../src/converters/core_types_converter.cpp | 6 +- .../converters/data_descriptor_converter.cpp | 10 +-- .../src/converters/data_rule_converter.cpp | 10 +-- .../src/converters/dict_converter.cpp | 6 +- .../src/converters/dimension_converter.cpp | 10 +-- .../converters/dimension_rule_converter.cpp | 10 +-- .../function_block_type_converter.cpp | 8 +- .../generic_enumeration_converter.cpp | 16 ++-- .../converters/generic_struct_converter.cpp | 18 ++--- .../src/converters/number_converter.cpp | 8 +- .../src/converters/range_converter.cpp | 8 +- .../src/converters/ratio_converter.cpp | 8 +- .../src/converters/scaling_converter.cpp | 12 +-- .../src/converters/selection_converter.cpp | 8 +- .../src/converters/unit_converter.cpp | 8 +- .../opcuatms/src/core_types_utils.cpp | 14 ++-- .../opcuatms/src/extension_object.cpp | 6 +- .../tests/test_dict_conversion_utils.cpp | 2 +- .../opcuatms/tests/test_extension_object.cpp | 8 +- .../tests/test_generic_struct_converter.cpp | 22 +++--- .../test_property_object_conversion_utils.cpp | 2 +- .../opcuatms/tests/test_variant_converter.cpp | 10 +-- .../tests/test_variant_list_converter.cpp | 12 +-- .../objects/tms_client_channel_factory.h | 4 +- .../objects/tms_client_channel_impl.h | 2 +- .../objects/tms_client_component_factory.h | 4 +- .../objects/tms_client_component_impl.h | 6 +- .../objects/tms_client_context.h | 4 +- .../objects/tms_client_device_factory.h | 4 +- .../objects/tms_client_device_impl.h | 1 + .../objects/tms_client_folder_factory.h | 6 +- .../objects/tms_client_folder_impl.h | 4 +- .../tms_client_function_block_factory.h | 4 +- .../objects/tms_client_function_block_impl.h | 2 +- .../objects/tms_client_function_factory.h | 6 +- .../objects/tms_client_function_impl.h | 8 +- .../objects/tms_client_input_port_factory.h | 4 +- .../objects/tms_client_input_port_impl.h | 4 +- .../objects/tms_client_io_folder_factory.h | 4 +- .../objects/tms_client_io_folder_impl.h | 2 +- .../objects/tms_client_object_impl.h | 8 +- .../objects/tms_client_procedure_factory.h | 6 +- .../objects/tms_client_procedure_impl.h | 8 +- .../objects/tms_client_property_factory.h | 4 +- .../objects/tms_client_property_impl.h | 6 +- .../tms_client_property_object_factory.h | 6 +- .../objects/tms_client_property_object_impl.h | 8 +- .../tms_client_server_capability_factory.h | 4 +- .../tms_client_server_capability_impl.h | 2 +- .../objects/tms_client_signal_factory.h | 4 +- .../objects/tms_client_signal_impl.h | 6 +- .../objects/tms_client_tags_factory.h | 4 +- .../objects/tms_client_tags_impl.h | 8 +- .../include/opcuatms_client/tms_client.h | 6 +- .../src/objects/tms_client_channel_impl.cpp | 2 +- .../src/objects/tms_client_context.cpp | 2 +- .../src/objects/tms_client_device_impl.cpp | 15 ++++ .../src/objects/tms_client_folder_impl.cpp | 4 +- .../tms_client_function_block_impl.cpp | 10 +-- .../src/objects/tms_client_function_impl.cpp | 6 +- .../objects/tms_client_input_port_impl.cpp | 8 +- .../src/objects/tms_client_io_folder_impl.cpp | 10 +-- .../src/objects/tms_client_object_impl.cpp | 6 +- .../src/objects/tms_client_procedure_impl.cpp | 8 +- .../src/objects/tms_client_property_impl.cpp | 16 ++-- .../tms_client_server_capability_impl.cpp | 2 +- .../src/objects/tms_client_signal_impl.cpp | 10 +-- .../src/objects/tms_client_tags_impl.cpp | 8 +- .../objects/tms_server_channel.h | 2 +- .../objects/tms_server_component.h | 46 +++++------ .../objects/tms_server_device.h | 14 ++-- .../objects/tms_server_eval_value.h | 4 +- .../objects/tms_server_folder.h | 2 +- .../objects/tms_server_function_block.h | 6 +- .../objects/tms_server_input_port.h | 2 +- .../objects/tms_server_object.h | 6 +- .../objects/tms_server_property.h | 21 +++-- .../objects/tms_server_property_object.h | 11 ++- .../objects/tms_server_signal.h | 2 +- .../objects/tms_server_variable.h | 2 +- .../include/opcuatms_server/tms_server.h | 2 +- .../src/objects/tms_server_channel.cpp | 8 +- .../src/objects/tms_server_device.cpp | 15 ++-- .../src/objects/tms_server_eval_value.cpp | 8 +- .../src/objects/tms_server_folder.cpp | 12 +-- .../src/objects/tms_server_function_block.cpp | 12 +-- .../src/objects/tms_server_input_port.cpp | 12 +-- .../src/objects/tms_server_object.cpp | 6 +- .../src/objects/tms_server_property.cpp | 79 +++++++++++-------- .../objects/tms_server_property_object.cpp | 76 ++++++++++-------- .../src/objects/tms_server_signal.cpp | 8 +- .../src/objects/tms_server_variable.cpp | 8 +- .../opcuatms_server/tests/test_helpers.h | 8 +- .../tests/test_tms_channel.cpp | 12 +-- .../opcuatms_server/tests/test_tms_device.cpp | 6 +- .../tests/test_tms_function_block.cpp | 8 +- .../tests/test_tms_input_port.cpp | 10 +-- .../tests/test_tms_property_object.cpp | 12 +-- .../opcuatms_server/tests/test_tms_signal.cpp | 8 +- .../opcuatms_server/tests/tms_server_test.h | 4 +- .../test_property_object_advanced.cpp | 32 ++++---- .../test_streaming_integration.cpp | 4 +- .../test_tms_amplifier.cpp | 20 ++--- .../opcuatms_integration/test_tms_channel.cpp | 16 ++-- .../test_tms_component.cpp | 10 +-- .../opcuatms_integration/test_tms_device.cpp | 4 +- .../opcuatms_integration/test_tms_folder.cpp | 14 ++-- .../test_tms_function_block.cpp | 20 ++--- .../test_tms_function_block_type.cpp | 2 +- .../test_tms_function_property.cpp | 16 ++-- .../test_tms_fusion_device.cpp | 24 +++--- .../test_tms_input_port.cpp | 16 ++-- .../test_tms_property.cpp | 10 +-- .../test_tms_property_object.cpp | 14 ++-- .../opcuatms_integration/test_tms_signal.cpp | 12 +-- .../tms_object_integration_test.h | 4 +- .../tests/test_utils/tms_object_test.cpp | 4 +- .../tests/test_utils/tms_object_test.h | 4 +- 129 files changed, 637 insertions(+), 585 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h index 7c362d2..cfe34ce 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h @@ -16,14 +16,14 @@ #pragma once -#include "opcuatms/converters/variant_converter.h" -#include "opcuatms/converters/selection_converter.h" -#include "opendaq/data_descriptor_ptr.h" -#include "open62541/daqbt_nodeids.h" -#include "open62541/daqbsp_nodeids.h" -#include "open62541/daqhbk_nodeids.h" -#include "open62541/nodeids.h" -#include "opendaq/function_block_type_ptr.h" +#include +#include +#include +#include +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/list_conversion_utils.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/list_conversion_utils.h index 8f06a61..33df436 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/list_conversion_utils.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/list_conversion_utils.h @@ -15,11 +15,11 @@ */ #pragma once -#include "opcuashared/opcuavariant.h" -#include "opcuatms/opcuatms.h" -#include "opcuatms/extension_object.h" -#include "opcuatms/converters/variant_converter.h" -#include "opcuatms/converters/struct_converter.h" +#include +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/selection_converter.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/selection_converter.h index edddb40..7ec2ea4 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/selection_converter.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/selection_converter.h @@ -16,9 +16,9 @@ #pragma once #include -#include "opcuashared/opcuavariant.h" -#include "opcuatms/opcuatms.h" -#include "opendaq/context_ptr.h" +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/struct_converter.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/struct_converter.h index cc3bc80..38d5f09 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/struct_converter.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/struct_converter.h @@ -15,10 +15,10 @@ */ #pragma once -#include "opcuatms/opcuatms.h" -#include "opcuashared/opcuavariant.h" -#include "opcuashared/opcuaobject.h" -#include "opendaq/context_ptr.h" +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/variant_converter.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/variant_converter.h index dc0f2cf..4274eb2 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/variant_converter.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/variant_converter.h @@ -16,11 +16,11 @@ #pragma once #include -#include "opcuashared/opcuavariant.h" -#include "opcuatms/opcuatms.h" -#include "opcuatms/type_mappings.h" -#include "opcuashared/opcuaobject.h" -#include "opendaq/context_ptr.h" +#include +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h index c9b29b7..00a452f 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h @@ -20,7 +20,7 @@ #include #include #include -#include "opcuashared/opcuavariant.h" +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/extension_object.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/extension_object.h index d198283..4db7d8f 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/extension_object.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/extension_object.h @@ -15,8 +15,8 @@ */ #pragma once -#include "opcuatms/opcuatms.h" -#include "opcuashared/opcuavariant.h" +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h index c5bbcb7..10e913f 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h @@ -15,7 +15,7 @@ */ #pragma once -#include "opcuatms/opcuatms.h" +#include namespace daq::opcua { diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/argument_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/argument_converter.cpp index a5a8362..b5a18a6 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/argument_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/argument_converter.cpp @@ -1,9 +1,9 @@ #include #include -#include "opcuatms/converters/list_conversion_utils.h" -#include "opcuatms/converters/struct_converter.h" -#include "opcuatms/converters/variant_converter.h" -#include "open62541/types_daqbsp_generated.h" +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp index bde31ad..7811cf8 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp @@ -1,6 +1,6 @@ -#include "opcuatms/converters/variant_converter.h" -#include "opcuatms/core_types_utils.h" -#include "opendaq/data_descriptor_ptr.h" +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -25,9 +25,9 @@ OpcUaVariant VariantConverter::ToVariant(const BaseObjectPtr& objec END_NAMESPACE_OPENDAQ_OPCUA_TMS -#include "opcuatms/converters/selection_converter.h" -#include "opcuatms/converter_maps.h" -#include "opcuatms/converters/list_conversion_utils.h" +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/complex_number_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/complex_number_converter.cpp index 66fca59..dbb8970 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/complex_number_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/complex_number_converter.cpp @@ -1,7 +1,7 @@ -#include "opcuatms/converters/list_conversion_utils.h" -#include "opcuatms/converters/struct_converter.h" -#include "opcuatms/converters/variant_converter.h" -#include "opcuatms/core_types_utils.h" +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/core_types_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/core_types_converter.cpp index 7789421..75856ff 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/core_types_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/core_types_converter.cpp @@ -1,6 +1,6 @@ -#include "opcuatms/converters/variant_converter.h" -#include "opcuatms/converters/struct_converter.h" -#include "opcuatms/converters/list_conversion_utils.h" +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/data_descriptor_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/data_descriptor_converter.cpp index e2327f2..523926a 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/data_descriptor_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/data_descriptor_converter.cpp @@ -1,10 +1,10 @@ #include #include -#include "opcuatms/converters/struct_converter.h" -#include "opcuatms/converters/variant_converter.h" -#include "opcuatms/core_types_utils.h" -#include "opcuatms/extension_object.h" -#include "opcuatms/converters/list_conversion_utils.h" +#include +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/data_rule_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/data_rule_converter.cpp index 18c94e6..f7991c0 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/data_rule_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/data_rule_converter.cpp @@ -1,9 +1,9 @@ #include -#include "opcuatms/converters/struct_converter.h" -#include "opcuatms/converters/variant_converter.h" -#include "open62541/types_daqbsp_generated_handling.h" -#include "opcuatms/converters/list_conversion_utils.h" -#include "opcuatms/core_types_utils.h" +#include +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/dict_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/dict_converter.cpp index a1155aa..866df74 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/dict_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/dict_converter.cpp @@ -1,6 +1,6 @@ -#include "opcuatms/core_types_utils.h" -#include "opcuatms/converters/list_conversion_utils.h" -#include "opcuatms/converters/variant_converter.h" +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/dimension_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/dimension_converter.cpp index 47cb2d7..2cf693f 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/dimension_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/dimension_converter.cpp @@ -1,9 +1,9 @@ #include -#include "opcuatms/converters/list_conversion_utils.h" -#include "opcuatms/converters/struct_converter.h" -#include "opcuatms/converters/variant_converter.h" -#include "opcuatms/core_types_utils.h" -#include "opcuatms/extension_object.h" +#include +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/dimension_rule_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/dimension_rule_converter.cpp index ee0c886..d2d5ee2 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/dimension_rule_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/dimension_rule_converter.cpp @@ -1,9 +1,9 @@ #include -#include "opcuatms/core_types_utils.h" -#include "opcuatms/converters/list_conversion_utils.h" -#include "opcuatms/converters/struct_converter.h" -#include "opcuatms/converters/variant_converter.h" -#include "open62541/types_daqbsp_generated_handling.h" +#include +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/function_block_type_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/function_block_type_converter.cpp index 16b5e4c..b1ba942 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/function_block_type_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/function_block_type_converter.cpp @@ -1,9 +1,9 @@ #include #include -#include "opcuatms/converters/list_conversion_utils.h" -#include "opcuatms/converters/struct_converter.h" -#include "opcuatms/converters/variant_converter.h" -#include "open62541/types_daqbsp_generated.h" +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/generic_enumeration_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/generic_enumeration_converter.cpp index 02ac526..649c182 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/generic_enumeration_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/generic_enumeration_converter.cpp @@ -1,11 +1,11 @@ -#include "coretypes/enumeration_factory.h" -#include "coretypes/enumeration_type_factory.h" -#include "coretypes/simple_type_factory.h" -#include "opcuatms/converters/list_conversion_utils.h" -#include "opcuatms/converters/struct_converter.h" -#include "opcuatms/converters/variant_converter.h" -#include "opcuatms/core_types_utils.h" -#include "opcuatms/extension_object.h" +#include +#include +#include +#include +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/generic_struct_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/generic_struct_converter.cpp index 8aeef51..8e6a0c1 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/generic_struct_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/generic_struct_converter.cpp @@ -1,12 +1,12 @@ -#include "opcuatms/core_types_utils.h" -#include "opcuatms/extension_object.h" -#include "opcuatms/converters/struct_converter.h" -#include "opcuatms/converters/variant_converter.h" -#include "coretypes/struct_factory.h" -#include "coretypes/struct_type_factory.h" -#include "coretypes/simple_type_factory.h" -#include "opcuatms/converters/list_conversion_utils.h" -#include "iostream" +#include +#include +#include +#include +#include +#include +#include +#include +#include #include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/number_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/number_converter.cpp index 20be340..45bcdd7 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/number_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/number_converter.cpp @@ -1,7 +1,7 @@ -#include "opcuatms/core_types_utils.h" -#include "opcuatms/converters/struct_converter.h" -#include "opcuatms/converters/variant_converter.h" -#include "opcuatms/converters/list_conversion_utils.h" +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/range_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/range_converter.cpp index 5176e8b..6b3b1bd 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/range_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/range_converter.cpp @@ -1,9 +1,9 @@ #include -#include "opcuatms/core_types_utils.h" -#include "opcuatms/converters/list_conversion_utils.h" -#include "opcuatms/converters/struct_converter.h" -#include "opcuatms/converters/variant_converter.h" +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/ratio_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/ratio_converter.cpp index d38eb88..4629a4c 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/ratio_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/ratio_converter.cpp @@ -1,9 +1,9 @@ #include -#include "opcuatms/core_types_utils.h" -#include "opcuatms/converters/struct_converter.h" -#include "opcuatms/converters/variant_converter.h" -#include "opcuatms/converters/list_conversion_utils.h" +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/scaling_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/scaling_converter.cpp index 44734cc..4526f56 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/scaling_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/scaling_converter.cpp @@ -1,10 +1,10 @@ #include -#include "opcuatms/converters/struct_converter.h" -#include "opcuatms/converters/variant_converter.h" -#include "open62541/types_daqbsp_generated_handling.h" -#include "opcuatms/core_types_utils.h" -#include "opcuatms/extension_object.h" -#include "opcuatms/converters/list_conversion_utils.h" +#include +#include +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/selection_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/selection_converter.cpp index 382d149..16d8337 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/selection_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/selection_converter.cpp @@ -1,7 +1,7 @@ -#include "opcuatms/converters/selection_converter.h" -#include "opcuatms/extension_object.h" -#include "opcuatms/converters/variant_converter.h" -#include "opcuatms/converters/struct_converter.h" +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/unit_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/unit_converter.cpp index c110ed7..323ae5c 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/unit_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/unit_converter.cpp @@ -1,9 +1,9 @@ #include #include -#include "opcuatms/converters/list_conversion_utils.h" -#include "opcuatms/converters/struct_converter.h" -#include "opcuatms/converters/variant_converter.h" -#include "open62541/types_daqbsp_generated.h" +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp b/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp index 380f41b..4d7bc05 100644 --- a/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp @@ -1,12 +1,12 @@ #include -#include "opcuashared/opcuadatatypearraylist.h" -#include "opcuatms/extension_object.h" -#include "open62541/daqbt_nodeids.h" -#include "open62541/nodeids.h" -#include "open62541/types_daqesp_generated.h" -#include "open62541/types_daqhbk_generated.h" -#include "open62541/types_di_generated.h" +#include +#include +#include +#include +#include +#include +#include using namespace daq::opcua; using namespace daq; diff --git a/shared/libraries/opcuatms/opcuatms/src/extension_object.cpp b/shared/libraries/opcuatms/opcuatms/src/extension_object.cpp index df072ec..cc6e175 100644 --- a/shared/libraries/opcuatms/opcuatms/src/extension_object.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/extension_object.cpp @@ -1,7 +1,7 @@ -#include "opcuatms/extension_object.h" -#include "opcuatms/converters/variant_converter.h" +#include +#include #include -#include "opcuatms/exceptions.h" +#include #include #include diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_dict_conversion_utils.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_dict_conversion_utils.cpp index 328778d..53f16f7 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/test_dict_conversion_utils.cpp +++ b/shared/libraries/opcuatms/opcuatms/tests/test_dict_conversion_utils.cpp @@ -1,4 +1,4 @@ -#include "gtest/gtest.h" +#include #include #include #include diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_extension_object.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_extension_object.cpp index 33e1678..a5f4042 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/test_extension_object.cpp +++ b/shared/libraries/opcuatms/opcuatms/tests/test_extension_object.cpp @@ -1,8 +1,8 @@ -#include "gtest/gtest.h" -#include "opcuatms/extension_object.h" +#include +#include #include -#include "opcuashared/opcuaobject.h" -#include "opcuatms/converters/variant_converter.h" +#include +#include using ExtensionObjectTest = testing::Test; diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_generic_struct_converter.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_generic_struct_converter.cpp index 6be31c8..3e8b0df 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/test_generic_struct_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/tests/test_generic_struct_converter.cpp @@ -1,14 +1,14 @@ -#include "gtest/gtest.h" -#include "opcuatms/converters/variant_converter.h" -#include "coretypes/struct_factory.h" -#include "coretypes/struct_type_factory.h" -#include "coretypes/type_manager_factory.h" -#include "coreobjects/unit_factory.h" -#include "opcuatms/extension_object.h" -#include "opendaq/context_factory.h" -#include "opendaq/data_rule_factory.h" -#include "coretypes/simple_type_factory.h" -#include "opendaq/data_descriptor_factory.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include using GenericStructConverterTest = testing::Test; diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_property_object_conversion_utils.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_property_object_conversion_utils.cpp index 6ea0fde..59ad260 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/test_property_object_conversion_utils.cpp +++ b/shared/libraries/opcuatms/opcuatms/tests/test_property_object_conversion_utils.cpp @@ -1,4 +1,4 @@ -#include "gtest/gtest.h" +#include #include #include #include diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_variant_converter.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_variant_converter.cpp index 411f335..6d28893 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/test_variant_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/tests/test_variant_converter.cpp @@ -1,4 +1,4 @@ -#include "gtest/gtest.h" +#include #include #include #include @@ -7,10 +7,10 @@ #include #include #include -#include "coretypes/ratio_factory.h" -#include "opcuatms/converters/variant_converter.h" -#include "opcuatms/converters/struct_converter.h" -#include "opcuashared/opcuavariant.h" +#include +#include +#include +#include using VariantConverterTest = testing::Test; diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_variant_list_converter.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_variant_list_converter.cpp index 25e5acd..296e492 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/test_variant_list_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/tests/test_variant_list_converter.cpp @@ -1,4 +1,4 @@ -#include "gtest/gtest.h" +#include #include #include #include @@ -6,11 +6,11 @@ #include #include #include -#include "coretypes/ratio_factory.h" -#include "opcuatms/converters/variant_converter.h" -#include "opcuatms/converters/struct_converter.h" -#include "opcuashared/opcuavariant.h" -#include "opcuatms/converters/list_conversion_utils.h" +#include +#include +#include +#include +#include using VariantListConverterTest = testing::Test; diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_factory.h index 5220273..e750f97 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_factory.h @@ -15,8 +15,8 @@ */ #pragma once -#include "opcuaclient/opcuaclient.h" -#include "opcuatms_client/objects/tms_client_channel_impl.h" +#include +#include #include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_impl.h index 7440b00..d958670 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_impl.h @@ -15,7 +15,7 @@ */ #pragma once -#include "opcuatms_client/objects/tms_client_function_block_impl.h" +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_factory.h index 4a04ec2..e1617fb 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_factory.h @@ -14,8 +14,8 @@ * limitations under the License. */ #pragma once -#include "opcuatms_client/objects/tms_client_context.h" -#include "opcuatms_client/objects/tms_client_component_impl.h" +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h index 4369ea2..deb4ec9 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h @@ -15,9 +15,9 @@ */ #pragma once -#include "opcuatms_client/objects/tms_client_property_object_impl.h" -#include "opendaq/channel_impl.h" -#include "opcuatms_client/objects/tms_client_component.h" +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h index 8c0a30b..549e9d0 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h @@ -15,8 +15,8 @@ */ #pragma once -#include "opcuatms/opcuatms.h" -#include "opcuaclient/opcuaclient.h" +#include +#include #include #include #include diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_factory.h index c83f689..8998b47 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_factory.h @@ -14,8 +14,8 @@ * limitations under the License. */ #pragma once -#include "opcuatms_client/objects/tms_client_context.h" -#include "opcuatms_client/objects/tms_client_device_impl.h" +#include +#include #include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h index c103e79..0493197 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h @@ -47,6 +47,7 @@ class TmsClientDeviceImpl : public TmsClientComponentBaseImpl onGetAvailableFunctionBlockTypes() override; FunctionBlockPtr onAddFunctionBlock(const StringPtr& typeId, const PropertyObjectPtr& config) override; void onRemoveFunctionBlock(const FunctionBlockPtr& functionBlock) override; diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_factory.h index 0eb6085..f689282 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_factory.h @@ -14,11 +14,11 @@ * limitations under the License. */ #pragma once -#include "opcuatms_client/objects/tms_client_context.h" -#include "opcuatms_client/objects/tms_client_folder_impl.h" +#include +#include #include -#include "open62541/daqdevice_nodeids.h" +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS inline FolderPtr TmsClientFolder(const ContextPtr& context, diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h index aebfa12..c9cf3a4 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h @@ -15,8 +15,8 @@ */ #pragma once -#include "opcuatms_client/objects/tms_client_component_impl.h" -#include "opendaq/folder_impl.h" +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_factory.h index 1a5cf4a..f1bde5b 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_factory.h @@ -15,8 +15,8 @@ */ #pragma once #include -#include "opcuatms_client/objects/tms_client_context.h" -#include "opcuatms_client/objects/tms_client_function_block_impl.h" +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h index 2502ddd..2b82c4c 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h @@ -15,7 +15,7 @@ */ #pragma once -#include "opcuatms_client/objects/tms_client_component_impl.h" +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_factory.h index bc3f515..b0c6817 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_factory.h @@ -14,9 +14,9 @@ * limitations under the License. */ #pragma once -#include "opcuatms_client/objects/tms_client_context.h" -#include "opcuatms_client/objects/tms_client_function_impl.h" -#include "coretypes/function_ptr.h" +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_impl.h index 54385d0..39748ac 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_impl.h @@ -17,10 +17,10 @@ #pragma once #include "tms_client_context.h" -#include "coretypes/function.h" -#include "coretypes/coretype.h" -#include "opcuashared/opcuanodeid.h" -#include "opendaq/context_ptr.h" +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_factory.h index 238edc5..5c151e5 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_factory.h @@ -15,8 +15,8 @@ */ #pragma once #include -#include "opcuatms_client/objects/tms_client_context.h" -#include "opcuatms_client/objects/tms_client_input_port_impl.h" +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h index 774f0f1..a710d8d 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h @@ -15,8 +15,8 @@ */ #pragma once -#include "opcuatms_client/objects/tms_client_component_impl.h" -#include "opendaq/input_port_impl.h" +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_factory.h index 74c2532..118ad09 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_factory.h @@ -14,8 +14,8 @@ * limitations under the License. */ #pragma once -#include "opcuatms_client/objects/tms_client_context.h" -#include "opcuatms_client/objects/tms_client_io_folder_impl.h" +#include +#include #include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h index f4d402a..5cd1cac 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h @@ -16,7 +16,7 @@ #pragma once #include -#include "opcuatms_client/objects/tms_client_folder_impl.h" +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h index 8f65430..84bb4e6 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h @@ -15,10 +15,10 @@ */ #pragma once -#include "opcuaclient/monitored_item_create_request.h" -#include "opcuaclient/opcuaclient.h" -#include "opcuatms/converters/variant_converter.h" -#include "opcuatms/opcuatms.h" +#include +#include +#include +#include #include #include diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_factory.h index b613642..8befce3 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_factory.h @@ -14,9 +14,9 @@ * limitations under the License. */ #pragma once -#include "coretypes/procedure_ptr.h" -#include "opcuatms_client/objects/tms_client_context.h" -#include "opcuatms_client/objects/tms_client_procedure_impl.h" +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_impl.h index 4bebb83..e9b8e13 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_impl.h @@ -16,11 +16,11 @@ #pragma once -#include "coretypes/coretype.h" -#include "coretypes/procedure.h" -#include "opcuashared/opcuanodeid.h" +#include +#include +#include #include "tms_client_context.h" -#include "opendaq/context_ptr.h" +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_factory.h index b6c20c9..f441f56 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_factory.h @@ -14,8 +14,8 @@ * limitations under the License. */ #pragma once -#include "opcuatms_client/objects/tms_client_context.h" -#include "opcuatms_client/objects/tms_client_property_impl.h" +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h index b4035fb..462fade 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h @@ -15,9 +15,9 @@ */ #pragma once -#include "coreobjects/property_impl.h" -#include "opcuatms/opcuatms.h" -#include "opcuatms_client/objects/tms_client_object_impl.h" +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_factory.h index b47a6a3..cd8d7d2 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_factory.h @@ -14,9 +14,9 @@ * limitations under the License. */ #pragma once -#include "opcuatms/opcuatms.h" -#include "opcuatms_client/objects/tms_client_context.h" -#include "opcuatms_client/objects/tms_client_property_object_impl.h" +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h index d73a822..b3ba28e 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h @@ -16,11 +16,11 @@ #pragma once #include -#include "opcuaclient/opcuaclient.h" -#include "opcuatms/opcuatms.h" -#include "opcuatms_client/objects/tms_client_object_impl.h" +#include +#include +#include #include -#include "opcuatms_client/objects/tms_client_component.h" +#include #include #include diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_factory.h index c7a16c2..ff23f14 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_factory.h @@ -14,8 +14,8 @@ * limitations under the License. */ #pragma once -#include "opcuatms_client/objects/tms_client_context.h" -#include "opcuatms_client/objects/tms_client_server_capability_impl.h" +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_impl.h index 5866e83..f7461a4 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_impl.h @@ -15,7 +15,7 @@ */ #pragma once -#include "opcuatms_client/objects/tms_client_property_object_impl.h" +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_factory.h index a1d7a2c..e401e3f 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_factory.h @@ -14,8 +14,8 @@ * limitations under the License. */ #pragma once -#include "opcuatms_client/objects/tms_client_context.h" -#include "opcuatms_client/objects/tms_client_signal_impl.h" +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h index a8608e2..04d63dd 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h @@ -15,9 +15,9 @@ */ #pragma once -#include "opendaq/mirrored_signal_impl.h" -#include "opcuatms_client/objects/tms_client_component_impl.h" -#include "opendaq/data_descriptor_ptr.h" +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_factory.h index c19292d..e1da477 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_factory.h @@ -14,8 +14,8 @@ * limitations under the License. */ #pragma once -#include "opcuatms_client/objects/tms_client_context.h" -#include "opcuatms_client/objects/tms_client_tags_impl.h" +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h index f4e807b..34f6725 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h @@ -15,10 +15,10 @@ */ #pragma once -#include "opendaq/tags_impl.h" -#include "opcuaclient/opcuaclient.h" -#include "opcuatms/opcuatms.h" -#include "opcuatms_client/objects/tms_client_object_impl.h" +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h index e0e5254..9c76dfd 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h @@ -16,9 +16,9 @@ #pragma once #include -#include "opcuatms/opcuatms.h" -#include "opcuaclient/opcuaclient.h" -#include "opcuatms_client/objects/tms_client_context.h" +#include +#include +#include #include BEGIN_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_channel_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_channel_impl.cpp index 0da0900..8c0a40b 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_channel_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_channel_impl.cpp @@ -1,4 +1,4 @@ -#include "opcuatms_client/objects/tms_client_channel_impl.h" +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp index 4ce35a0..f0bb2f9 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_context.cpp @@ -1,4 +1,4 @@ -#include "opcuatms_client/objects/tms_client_context.h" +#include #include #include #include diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index fd61235..06d1b8c 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -85,6 +86,7 @@ TmsClientDeviceImpl::TmsClientDeviceImpl(const ContextPtr& ctx, findAndCreateInputsOutputs(); findAndCreateCustomComponents(); findAndCreateSyncComponent(); + findAndCreateProporties(); } ErrCode TmsClientDeviceImpl::getDomain(IDeviceDomain** deviceDomain) @@ -258,6 +260,19 @@ void TmsClientDeviceImpl::findAndCreateSyncComponent() syncComponentNodeId)); } +void TmsClientDeviceImpl::findAndCreateProporties() +{ + if (auto it = this->introspectionVariableIdMap.find("UserName"); it != this->introspectionVariableIdMap.end()) + { + introspectionVariableIdMap.emplace("userName", it->second); + } + + if (auto it = this->introspectionVariableIdMap.find("Location"); it != this->introspectionVariableIdMap.end()) + { + introspectionVariableIdMap.emplace("location", it->second); + } +} + void TmsClientDeviceImpl::fetchTicksSinceOrigin() { auto timeDomainNodeId = getNodeId("Domain"); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp index d0dd31c..30cb476 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_folder_impl.cpp @@ -1,7 +1,7 @@ #include #include -#include "opcuatms_client/objects/tms_client_folder_impl.h" -#include "opendaq/io_folder_impl.h" +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp index 8ffd370..05fa2c3 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp @@ -1,10 +1,10 @@ #include #include -#include "opcuatms_client/objects/tms_client_function_block_impl.h" -#include "opcuatms_client/objects/tms_client_signal_factory.h" -#include "opcuatms_client/objects/tms_client_function_block_factory.h" -#include "opcuatms_client/objects/tms_client_input_port_factory.h" -#include "open62541/daqbsp_nodeids.h" +#include +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_impl.cpp index 194f3c4..7f0be61 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_impl.cpp @@ -1,8 +1,8 @@ #include #include -#include "opcuatms_client/objects/tms_client_function_factory.h" -#include "opcuatms/converters/variant_converter.h" -#include "opcuatms/converters/list_conversion_utils.h" +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS using namespace opcua; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp index 5f4f9e4..72399bc 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp @@ -1,7 +1,7 @@ -#include "open62541/daqbsp_nodeids.h" -#include "opcuatms/converters/variant_converter.h" -#include "opcuatms_client/objects/tms_client_input_port_impl.h" -#include "opcuatms/errors.h" +#include +#include +#include +#include #include #include diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp index fc15dd9..9c74d1e 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_io_folder_impl.cpp @@ -1,8 +1,8 @@ -#include "opcuatms_client/objects/tms_client_io_folder_impl.h" -#include "opcuatms_client/objects/tms_client_channel_factory.h" -#include "opcuatms_client/objects/tms_client_io_folder_factory.h" -#include "open62541/daqdevice_nodeids.h" -#include "opendaq/folder_config_ptr.h" +#include +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_object_impl.cpp index 0430f9e..6177801 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_object_impl.cpp @@ -1,6 +1,6 @@ -#include "opcuatms_client/objects/tms_client_object_impl.h" -#include "opcuaclient/browse_request.h" -#include "opcuaclient/browser/opcuabrowser.h" +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_procedure_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_procedure_impl.cpp index b60fb75..b3b4d2d 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_procedure_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_procedure_impl.cpp @@ -1,7 +1,7 @@ -#include "coretypes/validation.h" -#include "opcuatms_client/objects/tms_client_procedure_factory.h" -#include "opcuatms/converters/variant_converter.h" -#include "opcuatms/converters/list_conversion_utils.h" +#include +#include +#include +#include #include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp index 2d7f3e1..e3af167 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp @@ -1,12 +1,12 @@ -#include "opcuatms_client/objects/tms_client_property_impl.h" +#include #include -#include "coreobjects/coercer_factory.h" -#include "coreobjects/eval_value_factory.h" -#include "coreobjects/validator_factory.h" -#include "opcuatms/converters/variant_converter.h" -#include "opcuatms/converters/selection_converter.h" -#include "open62541/daqbt_nodeids.h" -#include "opendaq/custom_log.h" +#include +#include +#include +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_server_capability_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_server_capability_impl.cpp index 87e28e9..35b7753 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_server_capability_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_server_capability_impl.cpp @@ -1,4 +1,4 @@ -#include "opcuatms_client/objects/tms_client_server_capability_impl.h" +#include #include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp index 4be3a6c..9c9abec 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp @@ -1,9 +1,9 @@ #include -#include "open62541/daqbsp_nodeids.h" -#include "opcuashared/opcuacommon.h" -#include "opcuatms/exceptions.h" -#include "opcuatms_client/objects/tms_client_signal_impl.h" -#include "opcuatms/converters/variant_converter.h" +#include +#include +#include +#include +#include #include #include diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_tags_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_tags_impl.cpp index 295a89c..8e01482 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_tags_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_tags_impl.cpp @@ -1,7 +1,7 @@ -#include "opcuatms_client/objects/tms_client_tags_impl.h" -#include "opendaq/tags_factory.h" -#include "opendaq/custom_log.h" -#include "opcuatms/errors.h" +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_channel.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_channel.h index 242a2fa..64f2aee 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_channel.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_channel.h @@ -17,7 +17,7 @@ #pragma once #include #include -#include "opcuatms_server/objects/tms_server_function_block.h" +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h index 95aba9d..4a0f372 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h @@ -19,10 +19,10 @@ #include #include #include -#include "opcuatms_server/objects/tms_server_property_object.h" -#include "opcuatms/converters/variant_converter.h" -#include "opcuatms_server/tms_server_context.h" -#include "open62541/daqdevice_nodeids.h" +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -123,31 +123,33 @@ bool TmsServerComponent::createOptionalNode(const OpcUaNodeId& nodeId) template void TmsServerComponent::bindCallbacks() { - this->addReadCallback("Tags",[this]() - { - const TagsPtr tags = this->object.getTags(); - if (tags.assigned()) - return VariantConverter::ToArrayVariant(tags.getList()); - return VariantConverter::ToArrayVariant(List()); - }); - - this->addReadCallback("Active", [this]() { return VariantConverter::ToVariant( this->object.getActive()); }); + this->addReadCallback("Tags",[this] + { + const TagsPtr tags = this->object.getTags(); + if (tags.assigned()) + return VariantConverter::ToArrayVariant(tags.getList()); + return VariantConverter::ToArrayVariant(List()); + }); + + this->addReadCallback("Active", [this] { return VariantConverter::ToVariant( this->object.getActive()); }); if (!this->object.template supportsInterface() || !this->object.isFrozen()) { - this->addWriteCallback("Active", [this](const OpcUaVariant& variant){ - this->object.setActive(VariantConverter::ToDaqObject(variant)); - return UA_STATUSCODE_GOOD; - }); + this->addWriteCallback("Active", [this] (const OpcUaVariant& variant) + { + this->object.setActive(VariantConverter::ToDaqObject(variant)); + return UA_STATUSCODE_GOOD; + }); } - this->addReadCallback("Visible", [this]() { return VariantConverter::ToVariant( this->object.getVisible()); }); + this->addReadCallback("Visible", [this] { return VariantConverter::ToVariant( this->object.getVisible()); }); if (!this->object.template supportsInterface() || !this->object.isFrozen()) { - this->addWriteCallback("Visible", [this](const OpcUaVariant& variant){ - this->object.setVisible(VariantConverter::ToDaqObject(variant)); - return UA_STATUSCODE_GOOD; - }); + this->addWriteCallback("Visible", [this] (const OpcUaVariant& variant) + { + this->object.setVisible(VariantConverter::ToDaqObject(variant)); + return UA_STATUSCODE_GOOD; + }); } DisplayNameChangedCallback nameChangedCallback = diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h index aa907f4..c2a1adc 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h @@ -16,13 +16,13 @@ #pragma once #include -#include "opcuatms_server/objects/tms_server_function_block.h" -#include "opcuatms_server/objects/tms_server_channel.h" -#include "opcuatms_server/objects/tms_server_folder.h" -#include "opcuatms_server/objects/tms_server_component.h" -#include "opcuatms_server/objects/tms_server_property_object.h" -#include "opcuatms_server/objects/tms_server_function_block_type.h" -#include "opcuatms_server/objects/tms_server_sync_component.h" +#include +#include +#include +#include +#include +#include +#include #include diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_eval_value.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_eval_value.h index c011277..3668a95 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_eval_value.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_eval_value.h @@ -15,8 +15,8 @@ */ #pragma once -#include "coreobjects/eval_value_factory.h" -#include "opcuatms_server/objects/tms_server_variable.h" +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_folder.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_folder.h index 5e123f9..a4aac03 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_folder.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_folder.h @@ -16,7 +16,7 @@ #pragma once #include -#include "opcuatms_server/objects/tms_server_channel.h" +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block.h index 1cafdd0..9bc9d13 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block.h @@ -16,9 +16,9 @@ #pragma once #include -#include "opcuatms_server/objects/tms_server_property_object.h" -#include "opcuatms_server/objects/tms_server_signal.h" -#include "opcuatms_server/objects/tms_server_input_port.h" +#include +#include +#include #include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h index 097d9b9..904b99b 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h @@ -16,7 +16,7 @@ #pragma once #include -#include "opcuatms_server/objects/tms_server_component.h" +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h index 6c1daa6..9d8e4e5 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h @@ -18,9 +18,9 @@ #include #include #include -#include "opcuaserver/node_event_manager.h" -#include "opcuaserver/opcuaserver.h" -#include "opcuatms/opcuatms.h" +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h index 77e73e9..2cc8965 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h @@ -15,11 +15,11 @@ */ #pragma once -#include "property_internal_ptr.h" -#include "coreobjects/property_ptr.h" -#include "coretypes/listobject.h" -#include "opcuatms_server/objects/tms_server_eval_value.h" -#include "opcuatms_server/objects/tms_server_object.h" +#include +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -34,19 +34,23 @@ class TmsServerProperty : public TmsServerVariable TmsServerProperty(const PropertyPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, - const TmsServerContextPtr& tmsContext); + const TmsServerContextPtr& tmsContext, + const std::string& browseName = ""); TmsServerProperty(const PropertyPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext, - const std::unordered_map& propOrder); + const std::unordered_map& propOrder, + const std::string& browseName = ""); TmsServerProperty(const PropertyPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext, const PropertyObjectPtr& parent, - const std::unordered_map& propOrder); + const std::unordered_map& propOrder, + const std::string& browseName = ""); + std::string getPropertyName(); std::string getBrowseName() override; void bindCallbacks() override; @@ -84,6 +88,7 @@ class TmsServerProperty : public TmsServerVariable std::unordered_set HiddenNodes = {"FieldCoercionExpression", "FieldValidationExpression", ""}; std::unordered_map childProperties; std::unordered_map propOrder; + std::string browseName; }; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h index b6cefe4..d996cd3 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h @@ -15,9 +15,9 @@ */ #pragma once -#include "coreobjects/property_object_ptr.h" -#include "opcuatms_server/objects/tms_server_object.h" -#include "opcuatms_server/objects/tms_server_property.h" +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -52,14 +52,16 @@ class TmsServerPropertyObject : public TmsServerObjectBaseImpl ignoredProps; + std::unordered_map propBrowseName; // property name -> browse name (if not set use browse name as property name) protected: void configureNodeAttributes(opcua::OpcUaObject& attr) override; void triggerEvent(PropertyObjectPtr& sender, PropertyValueEventArgsPtr& args); opcua::OpcUaNodeId getTmsTypeId() override; void addPropertyNode(const std::string& name, const opcua::OpcUaNodeId& parentId); - void bindPropertyCallbacks(const std::string& name); + void bindPropertyCallbacks(const std::string& browseName, const std::string& propName); std::unordered_map childProperties; std::unordered_map childObjects; @@ -75,6 +77,7 @@ class TmsServerPropertyObject : public TmsServerObjectBaseImpl -#include "opcuatms_server/objects/tms_server_component.h" +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h index 7f6b046..20fa0d9 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h @@ -15,7 +15,7 @@ */ #pragma once -#include "opcuatms_server/objects/tms_server_object.h" +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h index 40c3ea3..ada9af5 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h @@ -18,7 +18,7 @@ #include #include #include -#include "opcuaserver/opcuaserver.h" +#include #include #include diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_channel.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_channel.cpp index 04978d5..50e73f5 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_channel.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_channel.cpp @@ -1,7 +1,7 @@ -#include "opcuatms_server/objects/tms_server_function_block.h" -#include "opcuatms_server/objects/tms_server_channel.h" -#include "opcuatms/converters/variant_converter.h" -#include "open62541/daqdevice_nodeids.h" +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index d5aa1a5..2fb69c5 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -2,11 +2,11 @@ #include #include #include -#include "opcuatms_server/objects/tms_server_device.h" -#include "opcuatms/core_types_utils.h" -#include "opcuatms/type_mappings.h" +#include +#include +#include #include -#include "opcuatms/converters/struct_converter.h" +#include #include #include #include @@ -33,7 +33,7 @@ namespace detail static std::unordered_map> componentFieldToVariant = { {"AssetId", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getAssetId().getCharPtr()}; }}, - {"ComponentName", [](const DeviceInfoPtr& info){ return createLocalizedTextVariant(info.getName().getCharPtr()); }}, + {"ComponentName", [](const DeviceInfoPtr& info) { return createLocalizedTextVariant(info.getName().getCharPtr()); }}, {"DeviceClass", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getDeviceClass().getCharPtr()}; }}, {"DeviceManual", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getDeviceManual().getCharPtr()}; }}, {"DeviceRevision", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getDeviceRevision().getCharPtr()}; }}, @@ -89,7 +89,7 @@ bool TmsServerDevice::createOptionalNode(const OpcUaNodeId& nodeId) void TmsServerDevice::bindCallbacks() { - this->addReadCallback("Domain",[this]() + this->addReadCallback("Domain", [this] { const auto deviceDomain = object.getDomain(); @@ -480,6 +480,9 @@ void TmsServerDevice::addChildNodes() syncComponentNode->registerToExistingOpcUaNode(syncComponentNodeId); syncComponents.push_back(std::move(syncComponentNode)); + tmsPropertyObject->propBrowseName.emplace("userName", "UserName"); + tmsPropertyObject->propBrowseName.emplace("location", "Location"); + // TODO add "Srv" as a default node numberInList = 0; diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_eval_value.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_eval_value.cpp index 5d1ffe2..c8fbbef 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_eval_value.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_eval_value.cpp @@ -1,7 +1,7 @@ -#include "opcuatms_server/objects/tms_server_eval_value.h" -#include "opcuatms/converters/variant_converter.h" -#include "opcuatms/converters/selection_converter.h" -#include "open62541/daqbt_nodeids.h" +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp index 7eab585..435b791 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp @@ -1,9 +1,9 @@ -#include "opcuatms_server/objects/tms_server_channel.h" -#include "opcuatms_server/objects/tms_server_folder.h" -#include "opcuatms/converters/variant_converter.h" -#include "open62541/daqdevice_nodeids.h" -#include "opendaq/io_folder_config.h" -#include "opendaq/search_filter_factory.h" +#include +#include +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp index 10d72ba..2e90250 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block.cpp @@ -1,10 +1,10 @@ #include -#include "opcuatms_server/objects/tms_server_function_block.h" -#include "opcuatms/converters/variant_converter.h" -#include "open62541/statuscodes.h" -#include "open62541/daqbsp_nodeids.h" -#include "open62541/di_nodeids.h" -#include "opendaq/search_filter_factory.h" +#include +#include +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp index cb778ef..d7bf122 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp @@ -1,10 +1,10 @@ #include -#include "opcuatms_server/objects/tms_server_input_port.h" -#include "opcuatms/converters/variant_converter.h" -#include "open62541/statuscodes.h" -#include "open62541/daqbsp_nodeids.h" -#include "open62541/di_nodeids.h" -#include "open62541/daqbsp_nodeids.h" +#include +#include +#include +#include +#include +#include #include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp index 187a8a2..9ba753e 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp @@ -2,9 +2,9 @@ #include #include #include -#include "opcuatms/converters/variant_converter.h" -#include "open62541/server.h" -#include "open62541/daqbsp_nodeids.h" +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp index 970122a..8a0231b 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp @@ -1,12 +1,12 @@ -#include "opcuatms_server/objects/tms_server_property.h" +#include #include #include #include #include #include #include -#include "opcuatms/converters/variant_converter.h" -#include "open62541/daqbsp_nodeids.h" +#include +#include #include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -16,10 +16,13 @@ using namespace opcua; TmsServerProperty::TmsServerProperty(const PropertyPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, - const TmsServerContextPtr& tmsContext) + const TmsServerContextPtr& tmsContext, + const std::string& browseName) : Super(object, server, context, tmsContext) + , browseName(browseName) { objectInternal = object.asPtr(false); + if (isReferenceType()) hideReferenceTypeChildren(); if (isNumericType()) @@ -36,8 +39,9 @@ TmsServerProperty::TmsServerProperty(const PropertyPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext, - const std::unordered_map& propOrder) - : TmsServerProperty(object, server, context, tmsContext) + const std::unordered_map& propOrder, + const std::string& browseName) + : TmsServerProperty(object, server, context, tmsContext, browseName) { this->propOrder = propOrder; this->numberInList = propOrder.at(object.getName()); @@ -48,27 +52,33 @@ TmsServerProperty::TmsServerProperty(const PropertyPtr& object, const ContextPtr& context, const TmsServerContextPtr& tmsContext, const PropertyObjectPtr& parent, - const std::unordered_map& propOrder) - : TmsServerProperty(object, server, context, tmsContext, propOrder) + const std::unordered_map& propOrder, + const std::string& browseName) + : TmsServerProperty(object, server, context, tmsContext, propOrder, browseName) { this->parent = parent; } -std::string TmsServerProperty::getBrowseName() +std::string TmsServerProperty::getPropertyName() { return this->object.getName(); } +std::string TmsServerProperty::getBrowseName() +{ + return this->browseName.empty() ? this->object.getName().toStdString() : this->browseName; +} + void TmsServerProperty::bindCallbacks() { if (!HiddenNodes.count("CoercionExpression")) { - addReadCallback("CoercionExpression", [this]() { return VariantConverter::ToVariant(object.getCoercer().getEval()); }); + addReadCallback("CoercionExpression", [this] { return VariantConverter::ToVariant(object.getCoercer().getEval()); }); } if (!HiddenNodes.count("ValidationExpression")) { - addReadCallback("ValidationExpression", [this]() { return VariantConverter::ToVariant(object.getValidator().getEval()); }); + addReadCallback("ValidationExpression", [this] { return VariantConverter::ToVariant(object.getValidator().getEval()); }); } for (auto childProp : childProperties) @@ -77,26 +87,29 @@ void TmsServerProperty::bindCallbacks() auto parentObj = this->parent.getRef(); if (!parentObj.getProperty(name).asPtr().getReferencedPropertyUnresolved().assigned()) { - addReadCallback(name, [this, name]() { - const auto value = this->parent.getRef().getPropertyValue(name); - return VariantConverter::ToVariant(value, nullptr, daqContext); - }); + addReadCallback(name, [this, name] + { + const auto value = this->parent.getRef().getPropertyValue(name); + return VariantConverter::ToVariant(value, nullptr, daqContext); + }); if (!parentObj.supportsInterface() || !parentObj.isFrozen()) { - addWriteCallback(name, [this, name](const OpcUaVariant& variant) { - const auto value = VariantConverter::ToDaqObject(variant, daqContext); - this->parent.getRef().setPropertyValue(name, value); - return UA_STATUSCODE_GOOD; - }); + addWriteCallback(name, [this, name](const OpcUaVariant& variant) + { + const auto value = VariantConverter::ToDaqObject(variant, daqContext); + this->parent.getRef().setPropertyValue(name, value); + return UA_STATUSCODE_GOOD; + }); } } else { - addReadCallback(name, [this, name]() { - const auto refProp = this->parent.getRef().getProperty(name).asPtr().getReferencedPropertyUnresolved(); - return VariantConverter::ToVariant(refProp.getEval(), nullptr, daqContext); - }); + addReadCallback(name, [this, name] + { + const auto refProp = this->parent.getRef().getProperty(name).asPtr().getReferencedPropertyUnresolved(); + return VariantConverter::ToVariant(refProp.getEval(), nullptr, daqContext); + }); } } @@ -320,7 +333,7 @@ void TmsServerProperty::addReferenceTypeChildNodes() auto prop = parent.getRef().getProperty(propName); if (prop.getValueType() != ctObject) { - auto serverInfo = registerTmsObjectOrAddReference(nodeId, prop, std::numeric_limits::max(), parent.getRef(),propOrder); + auto serverInfo = registerTmsObjectOrAddReference(nodeId, prop, std::numeric_limits::max(), parent.getRef(), propOrder); auto childNodeId = serverInfo->getNodeId(); childProperties.insert({childNodeId, serverInfo}); } @@ -330,28 +343,28 @@ void TmsServerProperty::addReferenceTypeChildNodes() void TmsServerProperty::addNumericTypeChildNodes() { if (!HiddenNodes.count("MinValue")) - registerEvalValueNode("MinValue", [this]() { return this->objectInternal.getMinValueUnresolved(); }); + registerEvalValueNode("MinValue", [this] { return this->objectInternal.getMinValueUnresolved(); }); if (!HiddenNodes.count("MaxValue")) - registerEvalValueNode("MaxValue", [this]() { return this->objectInternal.getMaxValueUnresolved(); }); + registerEvalValueNode("MaxValue", [this] { return this->objectInternal.getMaxValueUnresolved(); }); if (!HiddenNodes.count("SuggestedValues")) - registerEvalValueNode("SuggestedValues", [this]() { return this->objectInternal.getSuggestedValuesUnresolved(); }); + registerEvalValueNode("SuggestedValues", [this] { return this->objectInternal.getSuggestedValuesUnresolved(); }); } void TmsServerProperty::addSelectionTypeChildNodes() { - registerEvalValueNode("SelectionValues", [this]() { return this->objectInternal.getSelectionValuesUnresolved(); }, true); + registerEvalValueNode("SelectionValues", [this] { return this->objectInternal.getSelectionValuesUnresolved(); }, true); } void TmsServerProperty::addIntrospectionTypeChildNodes() { if (!HiddenNodes.count("IsReadOnly")) - registerEvalValueNode("IsReadOnly", [this]() { return this->objectInternal.getReadOnlyUnresolved(); }); + registerEvalValueNode("IsReadOnly", [this] { return this->objectInternal.getReadOnlyUnresolved(); }); if (!HiddenNodes.count("IsVisible")) - registerEvalValueNode("IsVisible", [this]() { return this->objectInternal.getVisibleUnresolved(); }); + registerEvalValueNode("IsVisible", [this] { return this->objectInternal.getVisibleUnresolved(); }); if (!HiddenNodes.count("DefaultValue")) - registerEvalValueNode("DefaultValue", [this]() { return this->objectInternal.getDefaultValueUnresolved(); }); + registerEvalValueNode("DefaultValue", [this] { return this->objectInternal.getDefaultValueUnresolved(); }); if (!HiddenNodes.count("Unit")) - registerEvalValueNode("Unit", [this]() { return this->objectInternal.getUnitUnresolved(); }); + registerEvalValueNode("Unit", [this] { return this->objectInternal.getUnitUnresolved(); }); } END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp index e35d005..e9b4b5b 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp @@ -1,17 +1,17 @@ -#include "opcuatms_server/objects/tms_server_property_object.h" +#include #include #include -#include "coreobjects/argument_info_factory.h" -#include "coreobjects/property_object_internal_ptr.h" -#include "opcuatms/converters/variant_converter.h" -#include "opcuatms_server/objects/tms_server_property.h" +#include +#include +#include +#include #include -#include "coreobjects/property_object_protected_ptr.h" -#include "open62541/nodeids.h" -#include "open62541/statuscodes.h" -#include "open62541/daqbsp_nodeids.h" -#include "open62541/daqbt_nodeids.h" -#include "open62541/types_generated.h" +#include +#include +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -73,25 +73,24 @@ void TmsServerPropertyObject::addChildNodes() if (objProp.assigned()) { if (objProp.getVisibleUnresolved().assigned()) - registerEvalValueNode("IsVisible", [this]() { return objProp.getVisibleUnresolved(); }); + registerEvalValueNode("IsVisible", [this] { return objProp.getVisibleUnresolved(); }); if (objProp.getReadOnlyUnresolved().assigned()) - registerEvalValueNode("IsReadOnly", [this]() { return objProp.getReadOnlyUnresolved(); }); + registerEvalValueNode("IsReadOnly", [this] { return objProp.getReadOnlyUnresolved(); }); } - uint32_t propNumber = 0; std::unordered_map propOrder; for (const auto& prop : object.getAllProperties()) { if (ignoredProps.count(prop.getName())) continue; - propOrder.insert(std::pair(prop.getName(), propNumber)); - propNumber++; + propOrder.insert(std::pair(prop.getName(), numberInList++)); } for (const auto& prop : object.getAllProperties()) { - if (ignoredProps.count(prop.getName())) + const auto propName = prop.getName(); + if (ignoredProps.count(propName)) continue; // NOTE: ctObject types cannot be placed below ReferenceVariableType properties @@ -101,7 +100,7 @@ void TmsServerPropertyObject::addChildNodes() continue; if (prop.getValueType() == ctFunc || prop.getValueType() == ctProc) { - addMethodPropertyNode(prop, propOrder[prop.getName()]); + addMethodPropertyNode(prop, propOrder[propName]); continue; } @@ -129,18 +128,21 @@ void TmsServerPropertyObject::addChildNodes() } } + std::string browseName = propName; + if (auto it = propBrowseName.find(propName); it != propBrowseName.end()) + browseName = it->second; + OpcUaNodeId childNodeId; std::shared_ptr serverInfo; - const auto propName = prop.getName(); - if (hasChildNode(propName)) + if (hasChildNode(browseName)) { - const auto tempId = getChildNodeId(propName); - serverInfo = std::make_shared(prop, server, daqContext, tmsContext, object, propOrder); + const auto tempId = getChildNodeId(browseName); + serverInfo = std::make_shared(prop, server, daqContext, tmsContext, object, propOrder, browseName); childNodeId = serverInfo->registerToExistingOpcUaNode(tempId); } else { - serverInfo = registerTmsObjectOrAddReference(nodeId, prop, std::numeric_limits::max(), object, propOrder); + serverInfo = registerTmsObjectOrAddReference(nodeId, prop, std::numeric_limits::max(), object, propOrder, browseName); childNodeId = serverInfo->getNodeId(); } @@ -148,7 +150,6 @@ void TmsServerPropertyObject::addChildNodes() } else { - const auto propName = prop.getName(); PropertyObjectPtr obj = object.getPropertyValue(propName); if (hasChildNode(propName)) { @@ -175,7 +176,7 @@ void TmsServerPropertyObject::bindCallbacks() for (const auto& [id, prop] : childProperties) { //this->object.getOnPropertyValueWrite(prop->getBrowseName()) += event(this, &TmsServerPropertyObject::triggerEvent); - bindPropertyCallbacks(prop->getBrowseName()); + bindPropertyCallbacks(prop->getBrowseName(), prop->getPropertyName()); } bindMethodCallbacks(); @@ -194,29 +195,38 @@ bool TmsServerPropertyObject::createOptionalNode(const opcua::OpcUaNodeId& nodeI return true; } -void TmsServerPropertyObject::bindPropertyCallbacks(const std::string& name) +void TmsServerPropertyObject::addProperty(const TmsServerPropertyPtr& childProperty) { - if (!this->object.getProperty(name).asPtr().getReferencedPropertyUnresolved().assigned()) + childProperties.insert({childProperty->getNodeId(), childProperty}); + childProperty->setNumberInList(numberInList++); +} + +void TmsServerPropertyObject::bindPropertyCallbacks(const std::string& browseName, const std::string& propName) +{ + if (!this->object.getProperty(propName).asPtr().getReferencedPropertyUnresolved().assigned()) { - addReadCallback(name, [this, name]() { - const auto value = this->object.getPropertyValue(name); + addReadCallback(browseName, [this, propName] + { + const auto value = this->object.getPropertyValue(propName); return VariantConverter::ToVariant(value, nullptr, daqContext); }); const auto freezable = this->object.asPtrOrNull(); if (!freezable.assigned() || !this->object.isFrozen()) { - addWriteCallback(name, [this, name](const OpcUaVariant& variant) { + addWriteCallback(browseName, [this, propName](const OpcUaVariant& variant) + { const auto value = VariantConverter::ToDaqObject(variant, daqContext); - this->object.asPtr().setProtectedPropertyValue(name, value); + this->object.asPtr().setProtectedPropertyValue(propName, value); return UA_STATUSCODE_GOOD; }); } } else { - addReadCallback(name, [this, name]() { - const auto refProp = this->object.getProperty(name).asPtr().getReferencedPropertyUnresolved(); + addReadCallback(browseName, [this, propName] + { + const auto refProp = this->object.getProperty(propName).asPtr().getReferencedPropertyUnresolved(); return VariantConverter::ToVariant(refProp.getEval(), nullptr, daqContext); }); } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp index 5a4feac..094ed05 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp @@ -1,7 +1,7 @@ -#include "opcuatms_server/objects/tms_server_signal.h" -#include "opcuatms/converters/variant_converter.h" -#include "open62541/daqbsp_nodeids.h" -#include "open62541/statuscodes.h" +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp index 53b2bb9..f50cf90 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp @@ -1,7 +1,7 @@ -#include "opcuatms_server/objects/tms_server_variable.h" -#include "coreobjects/eval_value_ptr.h" -#include "open62541/server.h" -#include "opendaq/function_block_type_ptr.h" +#include +#include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h b/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h index 602fd9d..6b1b413 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h @@ -21,10 +21,10 @@ #include #include #include -#include "opendaq/mock/mock_device_module.h" -#include "opendaq/mock/mock_fb_module.h" -#include "opendaq/mock/mock_physical_device.h" -#include "open62541/daqbsp_nodeids.h" +#include +#include +#include +#include #include namespace test_helpers diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_channel.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_channel.cpp index 2ac6bf9..47e819f 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_channel.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_channel.cpp @@ -2,13 +2,13 @@ #include #include #include -#include "coreobjects/property_object_factory.h" -#include "gtest/gtest.h" -#include "opendaq/mock/mock_channel_factory.h" -#include "opcuaclient/opcuaclient.h" -#include "opcuatms_server/objects/tms_server_channel.h" +#include +#include +#include +#include +#include #include "tms_server_test.h" -#include "open62541/daqbsp_nodeids.h" +#include using namespace daq; using namespace opcua::tms; diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_device.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_device.cpp index 9ce589f..8d65798 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_device.cpp @@ -5,9 +5,9 @@ #include #include #include -#include "gtest/gtest.h" -#include "opcuaclient/opcuaclient.h" -#include "opcuatms_server/objects/tms_server_device.h" +#include +#include +#include #include "test_helpers.h" #include "tms_server_test.h" diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp index 6ac3077..ddaf552 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_function_block.cpp @@ -2,12 +2,12 @@ #include #include #include -#include "gtest/gtest.h" +#include #include -#include "opcuaclient/opcuaclient.h" -#include "opcuatms_server/objects/tms_server_function_block.h" +#include +#include #include "tms_server_test.h" -#include "open62541/daqbsp_nodeids.h" +#include #include using namespace daq; diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp index 7232882..d778f54 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_input_port.cpp @@ -1,10 +1,10 @@ #include #include #include -#include "gtest/gtest.h" -#include "opcuaclient/opcuaclient.h" -#include "opcuatms_server/objects/tms_server_input_port.h" -#include "opcuatms_server/objects/tms_server_signal.h" +#include +#include +#include +#include #include "tms_server_test.h" #include #include @@ -12,7 +12,7 @@ #include #include #include -#include +#include "test_input_port_notifications.h" #include using namespace daq; diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_property_object.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_property_object.cpp index 13147ec..35ab66b 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_property_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_property_object.cpp @@ -1,15 +1,15 @@ -#include "coreobjects/property_object_factory.h" -#include "gtest/gtest.h" -#include "opcuaclient/opcuaclient.h" +#include +#include +#include #include #include #include -#include "coreobjects/property_object_class_ptr.h" -#include "opcuatms_server/objects/tms_server_property_object.h" +#include +#include #include "tms_server_test.h" #include #include -#include "opendaq/context_factory.h" +#include using namespace daq; using namespace opcua::tms; diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_signal.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_signal.cpp index b795f30..26fae39 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_signal.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_signal.cpp @@ -4,10 +4,10 @@ #include #include #include -#include "gtest/gtest.h" -#include "opcuaclient/opcuaclient.h" -#include "opcuatms_server/objects/tms_server_input_port.h" -#include "opcuatms_server/objects/tms_server_signal.h" +#include +#include +#include +#include #include "tms_server_test.h" using namespace daq; diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.h b/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.h index 03097d7..aaf4982 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.h +++ b/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.h @@ -15,9 +15,9 @@ */ #pragma once -#include "tms_object_test.h" +#include #include -#include "opcuatms_server/tms_server_context.h" +#include class TmsServerObjectTest : public TmsObjectTest { diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp index 366dd92..0bc51b8 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_property_object_advanced.cpp @@ -1,23 +1,23 @@ #include -#include "coreobjects/property_object_factory.h" -#include "gtest/gtest.h" -#include "opcuaclient/opcuaclient.h" -#include "opcuatms_client/objects/tms_client_property_object_factory.h" -#include "opcuatms_client/objects/tms_client_property_object_impl.h" -#include "opcuatms_server/objects/tms_server_property_object.h" +#include +#include +#include +#include +#include +#include #include "tms_object_integration_test.h" -#include "coreobjects/argument_info_factory.h" -#include "coreobjects/callable_info_factory.h" -#include "coreobjects/coercer_factory.h" -#include "coreobjects/validator_factory.h" -#include "opendaq/instance_factory.h" -#include "coreobjects/unit_factory.h" -#include "coretypes/struct_factory.h" -#include "coretypes/type_manager_factory.h" +#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include "opendaq/device_type_factory.h" -#include "opendaq/server_type_factory.h" +#include +#include using namespace daq; using namespace opcua::tms; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp index 015aff9..f9a5588 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp @@ -8,8 +8,8 @@ #include #include #include -#include "websocket_streaming/websocket_streaming_server.h" -#include "stream/WebsocketClientStream.hpp" +#include +#include #include #include #include diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp index 20828e9..e233f3b 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_amplifier.cpp @@ -1,15 +1,15 @@ #include -#include "coreobjects/callable_info_factory.h" -#include "coreobjects/property_object_factory.h" -#include "coreobjects/unit_factory.h" -#include "coretypes/type_manager_factory.h" -#include "gtest/gtest.h" -#include "opcuaclient/opcuaclient.h" -#include "opcuatms_client/objects/tms_client_property_object_factory.h" -#include "opcuatms_client/objects/tms_client_property_object_impl.h" -#include "opcuatms_server/objects/tms_server_property_object.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "tms_object_integration_test.h" -#include "opendaq/instance_factory.h" +#include using namespace daq; using namespace opcua::tms; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_channel.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_channel.cpp index 675a844..d03e1d9 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_channel.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_channel.cpp @@ -2,16 +2,16 @@ #include #include #include -#include "gtest/gtest.h" -#include "opcuaclient/opcuaclient.h" -#include "opcuatms/exceptions.h" -#include "opcuatms_server/objects/tms_server_channel.h" +#include +#include +#include +#include #include -#include "opcuatms_client/objects/tms_client_input_port_factory.h" -#include "opcuatms_client/objects/tms_client_signal_factory.h" -#include "open62541/daqbsp_nodeids.h" +#include +#include +#include #include "tms_object_integration_test.h" -#include "opendaq/mock/mock_channel_factory.h" +#include using namespace daq; using namespace opcua::tms; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_component.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_component.cpp index d2dc8c3..238e5bd 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_component.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_component.cpp @@ -1,9 +1,9 @@ -#include "opendaq/component_factory.h" -#include "opcuatms_client/objects/tms_client_component_factory.h" -#include "opcuatms_server/objects/tms_server_component.h" +#include +#include +#include #include "tms_object_integration_test.h" -#include "coreobjects/property_object_factory.h" -#include "opendaq/context_factory.h" +#include +#include using namespace daq; using namespace opcua::tms; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp index 02847ef..5c955a5 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp @@ -7,12 +7,12 @@ #include #include #include -#include "opcuatms/exceptions.h" +#include #include #include #include #include "tms_object_integration_test.h" -#include "opendaq/device_info_internal_ptr.h" +#include using namespace daq; using namespace opcua::tms; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp index 7b58e48..d20920e 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_folder.cpp @@ -1,11 +1,11 @@ -#include "coreobjects/property_object_factory.h" -#include "opcuatms_client/objects/tms_client_folder_factory.h" -#include "opcuatms_server/objects/tms_server_folder.h" -#include "opendaq/context_factory.h" +#include +#include +#include +#include #include "tms_object_integration_test.h" -#include "opcuatms_client/objects/tms_client_io_folder_factory.h" -#include "opendaq/io_folder_factory.h" -#include "opendaq/mock/mock_channel_factory.h" +#include +#include +#include using namespace daq; using namespace opcua::tms; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp index a69f403..97ad4d0 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block.cpp @@ -6,19 +6,19 @@ #include #include #include -#include "gtest/gtest.h" -#include "opcuaclient/opcuaclient.h" -#include "opcuatms/exceptions.h" -#include "opcuatms_server/objects/tms_server_function_block.h" +#include +#include +#include +#include #include -#include "opcuatms_client/objects/tms_client_input_port_factory.h" -#include "opcuatms_client/objects/tms_client_signal_factory.h" -#include "open62541/daqbsp_nodeids.h" +#include +#include +#include #include "tms_object_integration_test.h" -#include "opendaq/folder_config_ptr.h" +#include -#include "opendaq/mock/mock_fb_factory.h" -#include "opendaq/mock/default_mocks_factory.h" +#include +#include using namespace daq; using namespace opcua::tms; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block_type.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block_type.cpp index b6280c6..0c69209 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block_type.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_block_type.cpp @@ -1,4 +1,4 @@ -#include "gtest/gtest.h" +#include #include "tms_object_integration_test.h" #include #include diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_property.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_property.cpp index 6133093..fee0d76 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_property.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_function_property.cpp @@ -1,13 +1,13 @@ #include -#include "coreobjects/callable_info_factory.h" -#include "coreobjects/property_object_factory.h" -#include "gtest/gtest.h" -#include "opcuatms_client/objects/tms_client_property_object_factory.h" -#include "opcuatms_client/objects/tms_client_property_object_impl.h" -#include "opcuatms_server/objects/tms_server_property_object.h" +#include +#include +#include +#include +#include +#include #include "tms_object_integration_test.h" -#include "coreobjects/argument_info_factory.h" -#include "opendaq/context_factory.h" +#include +#include using namespace daq; using namespace opcua::tms; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp index 3289ca0..8cd975c 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp @@ -1,17 +1,17 @@ #include #include -#include "coreobjects/callable_info_factory.h" -#include "coreobjects/property_object_factory.h" -#include "coreobjects/unit_factory.h" -#include "coretypes/type_manager_factory.h" -#include "gtest/gtest.h" -#include "opcuaclient/opcuaclient.h" -#include "opcuatms_client/objects/tms_client_property_object_factory.h" -#include "opcuatms_client/objects/tms_client_property_object_impl.h" -#include "opcuatms_client/objects/tms_client_signal_factory.h" -#include "opcuatms_server/objects/tms_server_property_object.h" -#include "opcuatms_server/objects/tms_server_signal.h" -#include "opendaq/instance_factory.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "tms_object_integration_test.h" using namespace daq; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp index 8b9cce3..83c2e01 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_input_port.cpp @@ -2,20 +2,20 @@ #include #include #include -#include "gtest/gtest.h" -#include "opcuaclient/opcuaclient.h" -#include "opcuatms/exceptions.h" -#include "opcuatms_client/objects/tms_client_input_port_factory.h" -#include "opcuatms_client/objects/tms_client_signal_factory.h" -#include "opcuatms_server/objects/tms_server_input_port.h" -#include "opcuatms_server/objects/tms_server_signal.h" +#include +#include +#include +#include +#include +#include +#include #include "tms_object_integration_test.h" #include #include #include #include #include -#include +#include "test_input_port_notifications.h" using namespace daq; using namespace opcua::tms; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property.cpp index 908ca91..39abcc2 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property.cpp @@ -1,9 +1,9 @@ -#include "gtest/gtest.h" +#include #include "tms_object_integration_test.h" -#include "coreobjects/property_factory.h" -#include "coreobjects/property_object_class_ptr.h" -#include "opcuatms_server/objects/tms_server_property.h" -#include "opcuatms_client/objects/tms_client_property_factory.h" +#include +#include +#include +#include #include #include diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp index c4d0033..84e29c5 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp @@ -1,14 +1,14 @@ -#include "coreobjects/property_object_factory.h" -#include "gtest/gtest.h" -#include "opcuaclient/opcuaclient.h" -#include "opcuatms_client/objects/tms_client_property_object_impl.h" +#include +#include +#include +#include #include #include #include -#include "coreobjects/property_object_class_ptr.h" -#include "opcuatms_server/objects/tms_server_property_object.h" +#include +#include #include "tms_object_integration_test.h" -#include "opcuatms_client/objects/tms_client_property_object_factory.h" +#include #include #include diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp index 45e084f..a9bf16e 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp @@ -7,12 +7,12 @@ #include #include #include -#include "gtest/gtest.h" -#include "opcuaclient/opcuaclient.h" -#include "opcuatms/exceptions.h" -#include "opcuatms_client/objects/tms_client_signal_factory.h" -#include "opcuatms_server/objects/tms_server_signal.h" -#include "open62541/daqbsp_nodeids.h" +#include +#include +#include +#include +#include +#include #include "tms_object_integration_test.h" using namespace daq; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h index 6b6f401..13abd9c 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h @@ -15,9 +15,9 @@ */ #pragma once -#include "tms_object_test.h" +#include #include -#include "opcuatms_server/tms_server_context.h" +#include #include #include diff --git a/shared/libraries/opcuatms/tests/test_utils/tms_object_test.cpp b/shared/libraries/opcuatms/tests/test_utils/tms_object_test.cpp index 82993aa..b339166 100644 --- a/shared/libraries/opcuatms/tests/test_utils/tms_object_test.cpp +++ b/shared/libraries/opcuatms/tests/test_utils/tms_object_test.cpp @@ -1,5 +1,5 @@ -#include "tms_object_test.h" -#include "opcuaclient/opcuaclient.h" +#include +#include #include #include #include diff --git a/shared/libraries/opcuatms/tests/test_utils/tms_object_test.h b/shared/libraries/opcuatms/tests/test_utils/tms_object_test.h index cf14d94..2d0d9d5 100644 --- a/shared/libraries/opcuatms/tests/test_utils/tms_object_test.h +++ b/shared/libraries/opcuatms/tests/test_utils/tms_object_test.h @@ -16,8 +16,8 @@ #pragma once #include -#include "opcuaclient/opcuaclient.h" -#include "opcuaserver/opcuaserver.h" +#include +#include class TmsObjectTest : public testing::Test { From 6d5fdd8bdb7efecb0f28190a8b2fed19d5f6c402 Mon Sep 17 00:00:00 2001 From: Nikolai Shipilov Date: Tue, 8 Oct 2024 16:24:49 +0200 Subject: [PATCH 171/217] Complete the missing changes for event packet triggering on setting a nullptr descriptor: * LT-streaming: - Fix event packet generation on the client side when signal descriptors are unassigned - Add "subscribed" attribute to input signals to track explicit subscriptions - Introduce an input placeholder signal for uninitialized and incomplete signals - Manage signal descriptor transitions between unsupported and supported types * Disallow explicit setting of Null sample type descruptor for signal * Add tests for setting nullptr descriptor within core signal implementation * Fix handling of event packets with null-descriptors in native transport and packet streaming * Correct the creation of initial event packets in reader implementations when retrieving descriptors from input ports * Check for Null sample type in OPC UA converters * Rework streaming integration tests to cover setting nullptr descriptors across different streaming and configuration protocol combinations --- shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp | 4 ++++ .../opcuatms/opcuatms/tests/test_core_types_utils.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp b/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp index 4d7bc05..a0ea61b 100644 --- a/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp @@ -146,6 +146,10 @@ UA_SampleTypeEnumeration SampleTypeToTmsEnum(SampleType daqEnum) return UA_SAMPLETYPEENUMERATION_RANGEINT64; case SampleType::Struct: return UA_SAMPLETYPEENUMERATION_INVALID; + case SampleType::Null: + throw ConversionFailedException( + "SampleType \"Null\" is not convertible and reserved for \"DATA_DESCRIPTOR_CHANGED\" event packet." + ); default: throw ConversionFailedException(); } diff --git a/shared/libraries/opcuatms/opcuatms/tests/test_core_types_utils.cpp b/shared/libraries/opcuatms/opcuatms/tests/test_core_types_utils.cpp index 6e6ead7..78cdb9b 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/test_core_types_utils.cpp +++ b/shared/libraries/opcuatms/opcuatms/tests/test_core_types_utils.cpp @@ -1,6 +1,7 @@ #include #include #include +#include using CoreTypesUtilsTest = testing::Test; @@ -59,4 +60,7 @@ TEST_F(CoreTypesUtilsTest, SampleTypeConverter) ASSERT_EQ(SampleTypeFromTmsEnum(SampleTypeToTmsEnum(SampleType::Int32)), SampleType::Int32); ASSERT_EQ(SampleTypeFromTmsEnum(SampleTypeToTmsEnum(SampleType::Int64)), SampleType::Int64); ASSERT_EQ(SampleTypeFromTmsEnum(SampleTypeToTmsEnum(SampleType::UInt64)), SampleType::UInt64); + ASSERT_THROW_MSG(SampleTypeToTmsEnum(SampleType::Null), + ConversionFailedException, + "SampleType \"Null\" is not convertible and reserved for \"DATA_DESCRIPTOR_CHANGED\" event packet."); } From 15ff9db04a34a7dd8e7c3e5c8287e0cd2a4bfb14 Mon Sep 17 00:00:00 2001 From: Daniel Barros <113608885+dduraesdebarros@users.noreply.github.com> Date: Wed, 23 Oct 2024 15:53:37 +0100 Subject: [PATCH 172/217] [openDAQ] OPC UA - Add missing namepaceUri field in EUInformationWithQuantity struct converter and extend unit tests (openDAQ/openDAQ#559) --- .../opcuatms/src/converters/unit_converter.cpp | 1 + .../opcuatms_integration/test_tms_fusion_device.cpp | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/unit_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/unit_converter.cpp index 323ae5c..410ec32 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/unit_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/unit_converter.cpp @@ -32,6 +32,7 @@ OpcUaObject StructConverter tmsUnit; + tmsUnit->namespaceUri = UA_STRING_ALLOC("http://www.opcfoundation.org/UA/units/un/cefact"); tmsUnit->unitId = object.getId(); tmsUnit->description = UA_LOCALIZEDTEXT_ALLOC("en-US", object.getName().getCharPtr()); tmsUnit->displayName = UA_LOCALIZEDTEXT_ALLOC("en-US", object.getSymbol().getCharPtr()); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp index 8cd975c..5329492 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_fusion_device.cpp @@ -75,6 +75,7 @@ class TmsFusionDevice : public TmsObjectIntegrationTest {"MaximumElectrical", 5.0}, {"UsedWires", 6}}), objManager))) + .addProperty(StructProperty("EUInformationWithQuantity", Unit("m/s", 1, "meter per second", "50"))) .build(); objManager.addType(fusionAmpClass); } @@ -166,6 +167,18 @@ TEST_F(TmsFusionDevice, FullBridge) ASSERT_EQ(serverFullBridge, newFullBridge); } +TEST_F(TmsFusionDevice, EUInformationWithQuantity) +{ + const auto obj = PropertyObject(objManager, "FusionAmp"); + auto [serverObj, fusionAmp] = registerPropertyObject(obj); + + // Test unit property + const auto EUInformationStruct = Unit("s", 1, "seconds", "50"); + fusionAmp.setPropertyValue("EUInformationWithQuantity", EUInformationStruct); + + ASSERT_EQ(fusionAmp.getPropertyValue("EUInformationWithQuantity"), EUInformationStruct); +} + TEST_F(TmsFusionDevice, EnumTest) { // This test should be moved to coreobjects From a17ea8deb6fe95e4b2ab676d71e5ed93090c0091 Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Thu, 24 Oct 2024 14:08:07 +0200 Subject: [PATCH 173/217] Implement LogFileInfo interface (openDAQ/openDAQ#544) - implement logFileInfo interface - implement realization for reference device --- .../opcuatms_client/objects/tms_client_device_impl.h | 2 ++ .../src/objects/tms_client_device_impl.cpp | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h index 0493197..7fffa07 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h @@ -51,6 +51,8 @@ class TmsClientDeviceImpl : public TmsClientComponentBaseImpl onGetAvailableFunctionBlockTypes() override; FunctionBlockPtr onAddFunctionBlock(const StringPtr& typeId, const PropertyObjectPtr& config) override; void onRemoveFunctionBlock(const FunctionBlockPtr& functionBlock) override; + ListPtr ongetLogFileInfos() override; + StringPtr onGetLog(const StringPtr& id, Int size, Int offset) override; void findAndCreateServerCapabilities(const DeviceInfoPtr& deviceInfo); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 06d1b8c..2539088 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -639,4 +639,14 @@ void TmsClientDeviceImpl::onRemoveFunctionBlock(const FunctionBlockPtr& function removeNestedFunctionBlock(functionBlock); } +ListPtr TmsClientDeviceImpl::ongetLogFileInfos() +{ + throw OpcUaClientCallNotAvailableException("getLogFileInfos is not available for OpcUA client device"); +} + +StringPtr TmsClientDeviceImpl::onGetLog(const StringPtr& id, Int size, Int offset) +{ + throw OpcUaClientCallNotAvailableException("GetLog is not available for OpcUA client device"); +} + END_NAMESPACE_OPENDAQ_OPCUA_TMS From 1ebe9e1e97213ea66b1ebaf8311c03c8a76e621e Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Tue, 29 Oct 2024 13:19:26 +0100 Subject: [PATCH 174/217] [TBBAS-1850]: Implement communication protocol version info (openDAQ/openDAQ#556) - Implement protocol version info - Broadcasting protocol version via mDNS - Add transferring the connection string path from server --- .../opcua_client_module/src/opcua_client_module_impl.cpp | 1 + modules/opcua_server_module/src/opcua_server_impl.cpp | 2 ++ .../opcuatms_server/include/opcuatms_server/tms_server.h | 2 ++ .../libraries/opcuatms/opcuatms_server/src/tms_server.cpp | 6 ++++++ 4 files changed, 11 insertions(+) diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index d05bd15..73b2897 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -69,6 +69,7 @@ OpcUaClientModule::OpcUaClientModule(ContextPtr context) } cap.setConnectionType("TCP/IP"); cap.setPrefix(DaqOpcUaDevicePrefix); + cap.setProtocolVersion(discoveredDevice.getPropertyOrDefault("protocolVersion", "")); if (discoveredDevice.servicePort > 0) cap.setPort(discoveredDevice.servicePort); return cap; diff --git a/modules/opcua_server_module/src/opcua_server_impl.cpp b/modules/opcua_server_module/src/opcua_server_impl.cpp index f5e7227..d85e14b 100644 --- a/modules/opcua_server_module/src/opcua_server_impl.cpp +++ b/modules/opcua_server_module/src/opcua_server_impl.cpp @@ -20,6 +20,7 @@ OpcUaServerImpl::OpcUaServerImpl(const DevicePtr& rootDevice, const uint16_t port = config.getPropertyValue("Port"); server.setOpcUaPort(port); + server.setOpcUaPath(config.getPropertyValue("Path")); server.start(); } @@ -83,6 +84,7 @@ PropertyObjectPtr OpcUaServerImpl::getDiscoveryConfig() discoveryConfig.addProperty(StringProperty("ServiceCap", "OPENDAQ")); discoveryConfig.addProperty(StringProperty("Path", config.getPropertyValue("Path"))); discoveryConfig.addProperty(IntProperty("Port", config.getPropertyValue("Port"))); + discoveryConfig.addProperty(StringProperty("ProtocolVersion", "")); return discoveryConfig; } diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h index ada9af5..8d3b596 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h @@ -32,6 +32,7 @@ class TmsServer ~TmsServer(); void setOpcUaPort(uint16_t port); + void setOpcUaPath(const std::string& path); void start(); void stop(); @@ -42,6 +43,7 @@ class TmsServer std::shared_ptr tmsContext; daq::opcua::OpcUaServerPtr server; uint16_t opcUaPort = 4840; + std::string opcUaPath = "/"; }; diff --git a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp index 0c03a48..16f4d5d 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp @@ -34,6 +34,11 @@ void TmsServer::setOpcUaPort(uint16_t port) this->opcUaPort = port; } +void TmsServer::setOpcUaPath(const std::string& path) +{ + this->opcUaPath = path; +} + void TmsServer::start() { if (!device.assigned()) @@ -53,6 +58,7 @@ void TmsServer::start() serverCapability.setPrefix("daq.opcua"); serverCapability.setConnectionType("TCP/IP"); serverCapability.setPort(opcUaPort); + serverCapability.addProperty(StringProperty("Path", opcUaPath == "/" ? "" : opcUaPath)); device.getInfo().asPtr().addServerCapability(serverCapability); tmsDevice = std::make_unique(device, server, context, tmsContext); From d6cf26a7a3efb9ff739ac04b0f95668a6440dd39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE=20Fran=C4=8Di=C4=8D?= Date: Tue, 26 Nov 2024 11:17:31 +0100 Subject: [PATCH 175/217] Add Module Info (openDAQ/openDAQ#609) * Delete the fields `id`, `name`, and `versionInfo` from the `IModule` interface and add them to the new `IModuleInfo` interface, which is a new field in the `IModule` interface * `IModuleInfo` field is also added to `IComponentType` interface * Works over Native * Component Type is moved from `coreobjects` to `opendaq` --- .../tests/test_opcua_client_module.cpp | 38 +++++++++++++++++-- .../tests/test_opcua_server_module.cpp | 38 +++++++++++++++++-- 2 files changed, 70 insertions(+), 6 deletions(-) diff --git a/modules/opcua_client_module/tests/test_opcua_client_module.cpp b/modules/opcua_client_module/tests/test_opcua_client_module.cpp index e7371fe..eecd8ec 100644 --- a/modules/opcua_client_module/tests/test_opcua_client_module.cpp +++ b/modules/opcua_client_module/tests/test_opcua_client_module.cpp @@ -34,19 +34,19 @@ TEST_F(OpcUaClientModuleTest, CreateModule) TEST_F(OpcUaClientModuleTest, ModuleName) { auto module = CreateModule(); - ASSERT_EQ(module.getName(), "OpenDAQOPCUAClientModule"); + ASSERT_EQ(module.getModuleInfo().getName(), "OpenDAQOPCUAClientModule"); } TEST_F(OpcUaClientModuleTest, VersionAvailable) { auto module = CreateModule(); - ASSERT_TRUE(module.getVersionInfo().assigned()); + ASSERT_TRUE(module.getModuleInfo().getVersionInfo().assigned()); } TEST_F(OpcUaClientModuleTest, VersionCorrect) { auto module = CreateModule(); - auto version = module.getVersionInfo(); + auto version = module.getModuleInfo().getVersionInfo(); ASSERT_EQ(version.getMajor(), OPCUA_CLIENT_MODULE_MAJOR_VERSION); ASSERT_EQ(version.getMinor(), OPCUA_CLIENT_MODULE_MINOR_VERSION); @@ -130,6 +130,38 @@ TEST_F(OpcUaClientModuleTest, GetAvailableComponentTypes) DictPtr serverTypes; ASSERT_NO_THROW(serverTypes = module.getAvailableServerTypes()); ASSERT_EQ(serverTypes.getCount(), 0u); + + // Check module info for module + ModuleInfoPtr moduleInfo; + ASSERT_NO_THROW(moduleInfo = module.getModuleInfo()); + ASSERT_NE(moduleInfo, nullptr); + ASSERT_EQ(moduleInfo.getName(), "OpenDAQOPCUAClientModule"); + ASSERT_EQ(moduleInfo.getId(), "OpenDAQOPCUAClientModule"); + + // Check version info for module + VersionInfoPtr versionInfoModule; + ASSERT_NO_THROW(versionInfoModule = moduleInfo.getVersionInfo()); + ASSERT_NE(versionInfoModule, nullptr); + ASSERT_EQ(versionInfoModule.getMajor(), OPCUA_CLIENT_MODULE_MAJOR_VERSION); + ASSERT_EQ(versionInfoModule.getMinor(), OPCUA_CLIENT_MODULE_MINOR_VERSION); + ASSERT_EQ(versionInfoModule.getPatch(), OPCUA_CLIENT_MODULE_PATCH_VERSION); + + // Check module and version info for device types + for (const auto& deviceType : deviceTypes) + { + ModuleInfoPtr moduleInfoDeviceType; + ASSERT_NO_THROW(moduleInfoDeviceType = deviceType.second.getModuleInfo()); + ASSERT_NE(moduleInfoDeviceType, nullptr); + ASSERT_EQ(moduleInfoDeviceType.getName(), "OpenDAQOPCUAClientModule"); + ASSERT_EQ(moduleInfoDeviceType.getId(), "OpenDAQOPCUAClientModule"); + + VersionInfoPtr versionInfoDeviceType; + ASSERT_NO_THROW(versionInfoDeviceType = moduleInfoDeviceType.getVersionInfo()); + ASSERT_NE(versionInfoDeviceType, nullptr); + ASSERT_EQ(versionInfoDeviceType.getMajor(), OPCUA_CLIENT_MODULE_MAJOR_VERSION); + ASSERT_EQ(versionInfoDeviceType.getMinor(), OPCUA_CLIENT_MODULE_MINOR_VERSION); + ASSERT_EQ(versionInfoDeviceType.getPatch(), OPCUA_CLIENT_MODULE_PATCH_VERSION); + } } TEST_F(OpcUaClientModuleTest, DefaultDeviceConfig) diff --git a/modules/opcua_server_module/tests/test_opcua_server_module.cpp b/modules/opcua_server_module/tests/test_opcua_server_module.cpp index 3c6fe81..f8ce236 100644 --- a/modules/opcua_server_module/tests/test_opcua_server_module.cpp +++ b/modules/opcua_server_module/tests/test_opcua_server_module.cpp @@ -77,19 +77,19 @@ TEST_F(OpcUaServerModuleTest, CreateModule) TEST_F(OpcUaServerModuleTest, ModuleName) { auto module = CreateModule(); - ASSERT_EQ(module.getName(), "OpenDAQOPCUAServerModule"); + ASSERT_EQ(module.getModuleInfo().getName(), "OpenDAQOPCUAServerModule"); } TEST_F(OpcUaServerModuleTest, VersionAvailable) { auto module = CreateModule(); - ASSERT_TRUE(module.getVersionInfo().assigned()); + ASSERT_TRUE(module.getModuleInfo().getVersionInfo().assigned()); } TEST_F(OpcUaServerModuleTest, VersionCorrect) { auto module = CreateModule(); - auto version = module.getVersionInfo(); + auto version = module.getModuleInfo().getVersionInfo(); ASSERT_EQ(version.getMajor(), OPCUA_SERVER_MODULE_MAJOR_VERSION); ASSERT_EQ(version.getMinor(), OPCUA_SERVER_MODULE_MINOR_VERSION); @@ -113,6 +113,38 @@ TEST_F(OpcUaServerModuleTest, GetAvailableComponentTypes) ASSERT_EQ(serverTypes.getCount(), 1u); ASSERT_TRUE(serverTypes.hasKey("OpenDAQOPCUA")); ASSERT_EQ(serverTypes.get("OpenDAQOPCUA").getId(), "OpenDAQOPCUA"); + + // Check module info for module + ModuleInfoPtr moduleInfo; + ASSERT_NO_THROW(moduleInfo = module.getModuleInfo()); + ASSERT_NE(moduleInfo, nullptr); + ASSERT_EQ(moduleInfo.getName(), "OpenDAQOPCUAServerModule"); + ASSERT_EQ(moduleInfo.getId(), "OpenDAQOPCUAServerModule"); + + // Check version info for module + VersionInfoPtr versionInfoModule; + ASSERT_NO_THROW(versionInfoModule = moduleInfo.getVersionInfo()); + ASSERT_NE(versionInfoModule, nullptr); + ASSERT_EQ(versionInfoModule.getMajor(), OPCUA_SERVER_MODULE_MAJOR_VERSION); + ASSERT_EQ(versionInfoModule.getMinor(), OPCUA_SERVER_MODULE_MINOR_VERSION); + ASSERT_EQ(versionInfoModule.getPatch(), OPCUA_SERVER_MODULE_PATCH_VERSION); + + // Check module and version info for server types + for (const auto& serverType : serverTypes) + { + ModuleInfoPtr moduleInfoServerType; + ASSERT_NO_THROW(moduleInfoServerType = serverType.second.getModuleInfo()); + ASSERT_NE(moduleInfoServerType, nullptr); + ASSERT_EQ(moduleInfoServerType.getName(), "OpenDAQOPCUAServerModule"); + ASSERT_EQ(moduleInfoServerType.getId(), "OpenDAQOPCUAServerModule"); + + VersionInfoPtr versionInfoServerType; + ASSERT_NO_THROW(versionInfoServerType = moduleInfoServerType.getVersionInfo()); + ASSERT_NE(versionInfoServerType, nullptr); + ASSERT_EQ(versionInfoServerType.getMajor(), OPCUA_SERVER_MODULE_MAJOR_VERSION); + ASSERT_EQ(versionInfoServerType.getMinor(), OPCUA_SERVER_MODULE_MINOR_VERSION); + ASSERT_EQ(versionInfoServerType.getPatch(), OPCUA_SERVER_MODULE_PATCH_VERSION); + } } TEST_F(OpcUaServerModuleTest, ServerConfig) From d1594dc9bb58c4caaa070d7a0ac41eba7daaad3d Mon Sep 17 00:00:00 2001 From: Jaka Mohorko <96818661+JakaMohorkoDS@users.noreply.github.com> Date: Thu, 5 Dec 2024 08:04:12 +0100 Subject: [PATCH 176/217] Add "onAny" property value read and write events (openDAQ/openDAQ#631) --- .../objects/tms_client_property_object_impl.h | 2 ++ .../objects/tms_client_property_object_impl.cpp | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h index b3ba28e..90db578 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h @@ -115,6 +115,8 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl ErrCode INTERFACE_FUNC removeProperty(IString* propertyName) override; ErrCode INTERFACE_FUNC getOnPropertyValueWrite(IString* propertyName, IEvent** event) override; ErrCode INTERFACE_FUNC getOnPropertyValueRead(IString* propertyName, IEvent** event) override; + ErrCode INTERFACE_FUNC getOnAnyPropertyValueWrite(IEvent** event) override; + ErrCode INTERFACE_FUNC getOnAnyPropertyValueRead(IEvent** event) override; ErrCode INTERFACE_FUNC getVisibleProperties(IList** properties) override; ErrCode INTERFACE_FUNC hasProperty(IString* propertyName, Bool* hasProperty) override; ErrCode INTERFACE_FUNC getAllProperties(IList** properties) override; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index aa09b19..9c0079f 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -189,13 +189,25 @@ ErrCode TmsClientPropertyObjectBaseImpl::removeProperty(IString* propertyN } template -ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::getOnPropertyValueWrite(IString* propertyName, IEvent** event) +ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::getOnPropertyValueWrite(IString* /*propertyName*/, IEvent** /*event*/) { return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; } template -ErrCode TmsClientPropertyObjectBaseImpl::getOnPropertyValueRead(IString* propertyName, IEvent** event) +ErrCode TmsClientPropertyObjectBaseImpl::getOnPropertyValueRead(IString* /*propertyName*/, IEvent** /*event*/) +{ + return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; +} + +template +ErrCode TmsClientPropertyObjectBaseImpl::getOnAnyPropertyValueWrite(IEvent** /*event*/) +{ + return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; +} + +template +ErrCode TmsClientPropertyObjectBaseImpl::getOnAnyPropertyValueRead(IEvent** /*event*/) { return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; } From 6601b9c8a016f0e42e8b7d41673bfa5e7c68476c Mon Sep 17 00:00:00 2001 From: Jaka Mohorko <96818661+JakaMohorkoDS@users.noreply.github.com> Date: Thu, 5 Dec 2024 14:21:30 +0100 Subject: [PATCH 177/217] Fix onGetLogFileInfos case (openDAQ/openDAQ#630) --- .../include/opcuatms_client/objects/tms_client_device_impl.h | 2 +- .../opcuatms_client/src/objects/tms_client_device_impl.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h index 7fffa07..144728c 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h @@ -51,7 +51,7 @@ class TmsClientDeviceImpl : public TmsClientComponentBaseImpl onGetAvailableFunctionBlockTypes() override; FunctionBlockPtr onAddFunctionBlock(const StringPtr& typeId, const PropertyObjectPtr& config) override; void onRemoveFunctionBlock(const FunctionBlockPtr& functionBlock) override; - ListPtr ongetLogFileInfos() override; + ListPtr onGetLogFileInfos() override; StringPtr onGetLog(const StringPtr& id, Int size, Int offset) override; void findAndCreateServerCapabilities(const DeviceInfoPtr& deviceInfo); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 2539088..f6dd777 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -639,9 +639,9 @@ void TmsClientDeviceImpl::onRemoveFunctionBlock(const FunctionBlockPtr& function removeNestedFunctionBlock(functionBlock); } -ListPtr TmsClientDeviceImpl::ongetLogFileInfos() +ListPtr TmsClientDeviceImpl::onGetLogFileInfos() { - throw OpcUaClientCallNotAvailableException("getLogFileInfos is not available for OpcUA client device"); + throw OpcUaClientCallNotAvailableException("getLogFileInfo is not available for OpcUA client device"); } StringPtr TmsClientDeviceImpl::onGetLog(const StringPtr& id, Int size, Int offset) From d3494fef19a1a592a3a9792825be9ad934d3435d Mon Sep 17 00:00:00 2001 From: Jaka Mohorko <96818661+JakaMohorkoDS@users.noreply.github.com> Date: Mon, 30 Dec 2024 13:06:15 +0100 Subject: [PATCH 178/217] Other/merge 3.10 main (openDAQ/openDAQ#652) --- .../tests/opcuatms_integration/test_tms_device.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp index 5c955a5..ed9567d 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp @@ -148,12 +148,12 @@ TEST_F(TmsDeviceTest, DISABLED_Property) auto serverVisibleProps = serverDevice.getVisibleProperties(); auto visibleProperties = clientDevice.getVisibleProperties(); - ASSERT_EQ(visibleProperties.getCount(), 3u); - ASSERT_EQ(visibleProperties[2].getName(), "SampleRate"); + ASSERT_EQ(visibleProperties.getCount(), 5u); + ASSERT_EQ(visibleProperties[4].getName(), "SampleRate"); auto properties = clientDevice.getAllProperties(); - ASSERT_EQ(properties.getCount(), 3u); - ASSERT_EQ(properties[2].getName(), "SampleRate"); + ASSERT_EQ(properties.getCount(), 5u); + ASSERT_EQ(properties[4].getName(), "SampleRate"); ASSERT_TRUE(clientDevice.hasProperty("SampleRate")); ASSERT_EQ(clientDevice.getPropertyValue("SampleRate"), 100.0); From 9eaa933fed3890ca7acbe6616149bfc1fa28ac43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alja=C5=BE=20Fran=C4=8Di=C4=8D?= Date: Mon, 6 Jan 2025 08:35:08 +0100 Subject: [PATCH 179/217] Bump year in license, etc. to 2025 (openDAQ/openDAQ#656) * Bump year in license, etc. to 2025 * Update additional files --- .../opcua_client_module/include/opcua_client_module/common.h | 2 +- .../include/opcua_client_module/module_dll.h | 2 +- .../include/opcua_client_module/opcua_client_module_impl.h | 2 +- .../opcua_server_module/include/opcua_server_module/common.h | 2 +- .../include/opcua_server_module/module_dll.h | 2 +- .../include/opcua_server_module/opcua_server_impl.h | 2 +- .../include/opcua_server_module/opcua_server_module_impl.h | 2 +- .../opcua/opcuaclient/include/opcuaclient/attribute_reader.h | 2 +- .../opcua/opcuaclient/include/opcuaclient/browse_request.h | 2 +- .../opcuaclient/include/opcuaclient/browser/opcuabrowser.h | 2 +- .../include/opcuaclient/browser/opcuanodefactorybrowser.h | 2 +- .../opcuaclient/include/opcuaclient/browser/opcuanodevisitor.h | 2 +- .../include/opcuaclient/browser/opcuatransactionbrowser.h | 2 +- .../opcuaclient/include/opcuaclient/cached_reference_browser.h | 2 +- .../include/opcuaclient/chdatagather/_alignsyncchdatagather.h | 2 +- .../include/opcuaclient/chdatagather/_chdatagather.h | 2 +- .../opcua/opcuaclient/include/opcuaclient/event_filter.h | 2 +- .../include/opcuaclient/monitored_item_create_request.h | 2 +- .../opcuaclient/include/opcuaclient/opcuaasyncexecthread.h | 2 +- .../opcuaclient/include/opcuaclient/opcuacallmethodrequest.h | 2 +- .../opcua/opcuaclient/include/opcuaclient/opcuaclient.h | 2 +- .../opcua/opcuaclient/include/opcuaclient/opcuanodefactory.h | 2 +- .../opcua/opcuaclient/include/opcuaclient/opcuareadvalueid.h | 2 +- .../include/opcuaclient/opcuatimertaskcontextcollection.h | 2 +- .../opcuaclient/include/opcuaclient/opcuatimertaskhelper.h | 2 +- .../opcua/opcuaclient/include/opcuaclient/request_handler.h | 2 +- .../opcua/opcuaclient/include/opcuaclient/subscriptions.h | 2 +- .../include/opcuaclient/taskprocessor/opcuataskprocessor.h | 2 +- .../opcua/opcuaclient/tests/include/opcuaservertesthelper.h | 2 +- shared/libraries/opcua/opcuaserver/include/opcuaserver/common.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/event_attributes.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/node_event_manager.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/opcuaserver.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/opcuaserverlock.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/opcuaservernode.h | 2 +- .../opcuaserver/include/opcuaserver/opcuaservernodefactory.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/opcuasession.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/opcuataskqueue.h | 2 +- .../opcua/opcuaserver/include/opcuaserver/opcuatmstypes.h | 2 +- .../opcuaserver/include/opcuaserver/server_event_manager.h | 2 +- .../libraries/opcua/opcuaserver/tests/common_test_functions.h | 2 +- shared/libraries/opcua/opcuashared/include/opcuashared/bcrypt.h | 2 +- .../opcua/opcuashared/include/opcuashared/node/opcuadatatype.h | 2 +- .../opcua/opcuashared/include/opcuashared/node/opcuanode.h | 2 +- .../opcuashared/include/opcuashared/node/opcuanodemethod.h | 2 +- .../opcuashared/include/opcuashared/node/opcuanodeobject.h | 2 +- .../opcuashared/include/opcuashared/node/opcuanodevariable.h | 2 +- .../opcuashared/include/opcuashared/node/opcuaobjecttype.h | 2 +- .../opcua/opcuashared/include/opcuashared/node/opcuatype.h | 2 +- .../opcuashared/include/opcuashared/node/opcuavariabletype.h | 2 +- shared/libraries/opcua/opcuashared/include/opcuashared/opcua.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcua_attribute.h | 2 +- .../opcuashared/include/opcuashared/opcuacallmethodresult.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuacollection.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuacommon.h | 2 +- .../opcuashared/include/opcuashared/opcuadatatypearraylist.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuadatavalue.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuaendpoint.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuaexception.h | 2 +- .../libraries/opcua/opcuashared/include/opcuashared/opcualog.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuanodecollection.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuanodeid.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuaobject.h | 2 +- .../opcuashared/include/opcuashared/opcuasecurity_config.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuasecuritycommon.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuavariant.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuavector.h | 2 +- .../opcua/opcuashared/include/opcuashared/opcuaversion.h | 2 +- .../opcuatms/opcuatms/include/opcuatms/converter_maps.h | 2 +- .../include/opcuatms/converters/list_conversion_utils.h | 2 +- .../opcuatms/converters/property_object_conversion_utils.h | 2 +- .../opcuatms/include/opcuatms/converters/selection_converter.h | 2 +- .../opcuatms/include/opcuatms/converters/struct_converter.h | 2 +- .../opcuatms/include/opcuatms/converters/variant_converter.h | 2 +- .../opcuatms/opcuatms/include/opcuatms/core_types_utils.h | 2 +- shared/libraries/opcuatms/opcuatms/include/opcuatms/errors.h | 2 +- .../libraries/opcuatms/opcuatms/include/opcuatms/exceptions.h | 2 +- .../opcuatms/opcuatms/include/opcuatms/extension_object.h | 2 +- shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h | 2 +- .../opcuatms/opcuatms/include/opcuatms/type_mappings.h | 2 +- .../opcuatms_client/objects/tms_client_channel_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_channel_impl.h | 2 +- .../include/opcuatms_client/objects/tms_client_component.h | 2 +- .../opcuatms_client/objects/tms_client_component_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_component_impl.h | 2 +- .../include/opcuatms_client/objects/tms_client_context.h | 2 +- .../include/opcuatms_client/objects/tms_client_device_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_device_impl.h | 2 +- .../include/opcuatms_client/objects/tms_client_folder_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_folder_impl.h | 2 +- .../opcuatms_client/objects/tms_client_function_block_factory.h | 2 +- .../opcuatms_client/objects/tms_client_function_block_impl.h | 2 +- .../objects/tms_client_function_block_type_factory.h | 2 +- .../objects/tms_client_function_block_type_impl.h | 2 +- .../opcuatms_client/objects/tms_client_function_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_function_impl.h | 2 +- .../opcuatms_client/objects/tms_client_input_port_factory.h | 2 +- .../opcuatms_client/objects/tms_client_input_port_impl.h | 2 +- .../opcuatms_client/objects/tms_client_io_folder_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_io_folder_impl.h | 2 +- .../include/opcuatms_client/objects/tms_client_object_impl.h | 2 +- .../opcuatms_client/objects/tms_client_procedure_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_procedure_impl.h | 2 +- .../opcuatms_client/objects/tms_client_property_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_property_impl.h | 2 +- .../objects/tms_client_property_object_factory.h | 2 +- .../opcuatms_client/objects/tms_client_property_object_impl.h | 2 +- .../objects/tms_client_server_capability_factory.h | 2 +- .../opcuatms_client/objects/tms_client_server_capability_impl.h | 2 +- .../include/opcuatms_client/objects/tms_client_signal_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_signal_impl.h | 2 +- .../opcuatms_client/objects/tms_client_sync_component_factory.h | 2 +- .../opcuatms_client/objects/tms_client_sync_component_impl.h | 2 +- .../include/opcuatms_client/objects/tms_client_tags_factory.h | 2 +- .../include/opcuatms_client/objects/tms_client_tags_impl.h | 2 +- .../include/opcuatms_client/tms_attribute_collector.h | 2 +- .../opcuatms_client/include/opcuatms_client/tms_client.h | 2 +- .../include/opcuatms_server/objects/tms_server_channel.h | 2 +- .../include/opcuatms_server/objects/tms_server_component.h | 2 +- .../include/opcuatms_server/objects/tms_server_device.h | 2 +- .../include/opcuatms_server/objects/tms_server_eval_value.h | 2 +- .../include/opcuatms_server/objects/tms_server_folder.h | 2 +- .../include/opcuatms_server/objects/tms_server_function_block.h | 2 +- .../opcuatms_server/objects/tms_server_function_block_type.h | 2 +- .../include/opcuatms_server/objects/tms_server_input_port.h | 2 +- .../include/opcuatms_server/objects/tms_server_object.h | 2 +- .../include/opcuatms_server/objects/tms_server_property.h | 2 +- .../opcuatms_server/objects/tms_server_property_object.h | 2 +- .../include/opcuatms_server/objects/tms_server_signal.h | 2 +- .../include/opcuatms_server/objects/tms_server_sync_component.h | 2 +- .../include/opcuatms_server/objects/tms_server_sync_interface.h | 2 +- .../include/opcuatms_server/objects/tms_server_variable.h | 2 +- .../opcuatms_server/include/opcuatms_server/tms_server.h | 2 +- .../include/opcuatms_server/tms_server_context.h | 2 +- shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h | 2 +- .../libraries/opcuatms/opcuatms_server/tests/tms_server_test.h | 2 +- .../tests/opcuatms_integration/tms_object_integration_test.h | 2 +- .../opcuatms/tests/test_utils/test_input_port_notifications.h | 2 +- shared/libraries/opcuatms/tests/test_utils/tms_object_test.h | 2 +- 140 files changed, 140 insertions(+), 140 deletions(-) diff --git a/modules/opcua_client_module/include/opcua_client_module/common.h b/modules/opcua_client_module/include/opcua_client_module/common.h index cfb43ff..1a02ecf 100644 --- a/modules/opcua_client_module/include/opcua_client_module/common.h +++ b/modules/opcua_client_module/include/opcua_client_module/common.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/modules/opcua_client_module/include/opcua_client_module/module_dll.h b/modules/opcua_client_module/include/opcua_client_module/module_dll.h index 239f7bf..a2cc14e 100644 --- a/modules/opcua_client_module/include/opcua_client_module/module_dll.h +++ b/modules/opcua_client_module/include/opcua_client_module/module_dll.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h index 8d06915..e95e526 100644 --- a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h +++ b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/modules/opcua_server_module/include/opcua_server_module/common.h b/modules/opcua_server_module/include/opcua_server_module/common.h index 55425f3..1fb8458 100644 --- a/modules/opcua_server_module/include/opcua_server_module/common.h +++ b/modules/opcua_server_module/include/opcua_server_module/common.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/modules/opcua_server_module/include/opcua_server_module/module_dll.h b/modules/opcua_server_module/include/opcua_server_module/module_dll.h index 539477b..a3fdaa2 100644 --- a/modules/opcua_server_module/include/opcua_server_module/module_dll.h +++ b/modules/opcua_server_module/include/opcua_server_module/module_dll.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h b/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h index 7fb3d86..9f9cd4f 100644 --- a/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h +++ b/modules/opcua_server_module/include/opcua_server_module/opcua_server_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/modules/opcua_server_module/include/opcua_server_module/opcua_server_module_impl.h b/modules/opcua_server_module/include/opcua_server_module/opcua_server_module_impl.h index 3c066bd..34c3926 100644 --- a/modules/opcua_server_module/include/opcua_server_module/opcua_server_module_impl.h +++ b/modules/opcua_server_module/include/opcua_server_module/opcua_server_module_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/attribute_reader.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/attribute_reader.h index bece48d..f489834 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/attribute_reader.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/attribute_reader.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browse_request.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browse_request.h index 96d39a2..56a811b 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browse_request.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browse_request.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuabrowser.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuabrowser.h index f27f52a..69068d1 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuabrowser.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuabrowser.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodefactorybrowser.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodefactorybrowser.h index 4b1b35f..db74681 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodefactorybrowser.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodefactorybrowser.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodevisitor.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodevisitor.h index 1c559f1..ac980c7 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodevisitor.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuanodevisitor.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuatransactionbrowser.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuatransactionbrowser.h index e546401..9251d03 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuatransactionbrowser.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/browser/opcuatransactionbrowser.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h index da8887f..a7dea81 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/cached_reference_browser.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_alignsyncchdatagather.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_alignsyncchdatagather.h index 56b2521..cbbf949 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_alignsyncchdatagather.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_alignsyncchdatagather.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_chdatagather.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_chdatagather.h index 9222435..5d47370 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_chdatagather.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/chdatagather/_chdatagather.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/event_filter.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/event_filter.h index 812a6e4..eaa91d9 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/event_filter.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/event_filter.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/monitored_item_create_request.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/monitored_item_create_request.h index 071ca5d..fe53e00 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/monitored_item_create_request.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/monitored_item_create_request.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaasyncexecthread.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaasyncexecthread.h index 70b1d01..a11351f 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaasyncexecthread.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaasyncexecthread.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuacallmethodrequest.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuacallmethodrequest.h index c4e891d..563b5b6 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuacallmethodrequest.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuacallmethodrequest.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h index 3a8ac14..d689e39 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuanodefactory.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuanodefactory.h index d2e53a8..8472b7a 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuanodefactory.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuanodefactory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuareadvalueid.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuareadvalueid.h index 98af9a7..0593203 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuareadvalueid.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuareadvalueid.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskcontextcollection.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskcontextcollection.h index acc21db..7440c93 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskcontextcollection.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskcontextcollection.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskhelper.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskhelper.h index d3f2a0a..bee05d7 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskhelper.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuatimertaskhelper.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/request_handler.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/request_handler.h index e34170d..bc6d77b 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/request_handler.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/request_handler.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/subscriptions.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/subscriptions.h index 3781cb8..0aa48fb 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/subscriptions.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/subscriptions.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/taskprocessor/opcuataskprocessor.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/taskprocessor/opcuataskprocessor.h index 4730de7..3132a52 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/taskprocessor/opcuataskprocessor.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/taskprocessor/opcuataskprocessor.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h b/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h index 077e560..de9997e 100644 --- a/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h +++ b/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/common.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/common.h index 51c2ad6..3cea232 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/common.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/common.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/event_attributes.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/event_attributes.h index 306847d..fb6280a 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/event_attributes.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/event_attributes.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/node_event_manager.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/node_event_manager.h index bc0ba5f..fb2c395 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/node_event_manager.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/node_event_manager.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h index b8b5dfa..27b8236 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaaddnodeparams.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h index 8e89500..0c451ac 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserverlock.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserverlock.h index cdc29c3..ff5f1ab 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserverlock.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserverlock.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernode.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernode.h index 3129082..55e1ca6 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernode.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernode.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernodefactory.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernodefactory.h index e77b628..319063e 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernodefactory.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaservernodefactory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuasession.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuasession.h index 93c63db..e5b066b 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuasession.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuasession.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuataskqueue.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuataskqueue.h index d361ed7..36dea76 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuataskqueue.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuataskqueue.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuatmstypes.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuatmstypes.h index ae91ee3..57601d5 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuatmstypes.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuatmstypes.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/server_event_manager.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/server_event_manager.h index cd03ea6..adcff98 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/server_event_manager.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/server_event_manager.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuaserver/tests/common_test_functions.h b/shared/libraries/opcua/opcuaserver/tests/common_test_functions.h index f996eaf..ec32e07 100644 --- a/shared/libraries/opcua/opcuaserver/tests/common_test_functions.h +++ b/shared/libraries/opcua/opcuaserver/tests/common_test_functions.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/bcrypt.h b/shared/libraries/opcua/opcuashared/include/opcuashared/bcrypt.h index 81539b0..04c721f 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/bcrypt.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/bcrypt.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuadatatype.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuadatatype.h index edf5f0c..4d90d85 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuadatatype.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuadatatype.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanode.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanode.h index e749e14..b5ac36b 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanode.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanode.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodemethod.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodemethod.h index 13172f3..0fefe18 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodemethod.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodemethod.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodeobject.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodeobject.h index 60b4fab..6f07406 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodeobject.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodeobject.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodevariable.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodevariable.h index b43c634..8231bf1 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodevariable.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuanodevariable.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuaobjecttype.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuaobjecttype.h index 11d8d4d..282006c 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuaobjecttype.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuaobjecttype.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuatype.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuatype.h index bf052e9..7aadbbc 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuatype.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuatype.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuavariabletype.h b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuavariabletype.h index 5c63285..2747ded 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuavariabletype.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/node/opcuavariabletype.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcua.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcua.h index 168eb7e..ba6923b 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcua.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcua.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcua_attribute.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcua_attribute.h index 435e9e0..cf7eb0a 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcua_attribute.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcua_attribute.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacallmethodresult.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacallmethodresult.h index 52cb75d..a0194b7 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacallmethodresult.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacallmethodresult.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacollection.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacollection.h index 3ff7d15..aabe253 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacollection.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacollection.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacommon.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacommon.h index e2f3012..303f5a1 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacommon.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacommon.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatatypearraylist.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatatypearraylist.h index ffecd1b..643f30d 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatatypearraylist.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatatypearraylist.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatavalue.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatavalue.h index e14ad59..ba0950f 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatavalue.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuadatavalue.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaendpoint.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaendpoint.h index 753b89b..71fc7e3 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaendpoint.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaendpoint.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaexception.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaexception.h index 856bf19..0b37afe 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaexception.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaexception.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcualog.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcualog.h index 74d48c2..a3331c6 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcualog.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcualog.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodecollection.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodecollection.h index 1bc3a27..a26ab6b 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodecollection.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodecollection.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodeid.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodeid.h index bdf8f77..d360cd2 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodeid.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuanodeid.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaobject.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaobject.h index 0cc4699..95dd8ac 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaobject.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaobject.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecurity_config.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecurity_config.h index 890d4a7..4517c18 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecurity_config.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecurity_config.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecuritycommon.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecuritycommon.h index 696808d..67a03a6 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecuritycommon.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuasecuritycommon.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h index 43d9e0b..64832e9 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavector.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavector.h index b81a99e..025b3ee 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavector.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavector.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaversion.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaversion.h index f5f8be0..9c42d4e 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaversion.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuaversion.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h index cfe34ce..9b997c4 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converter_maps.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/list_conversion_utils.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/list_conversion_utils.h index 33df436..ca3fe54 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/list_conversion_utils.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/list_conversion_utils.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/property_object_conversion_utils.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/property_object_conversion_utils.h index cdfdccb..448e986 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/property_object_conversion_utils.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/property_object_conversion_utils.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/selection_converter.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/selection_converter.h index 7ec2ea4..bc13c5a 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/selection_converter.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/selection_converter.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/struct_converter.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/struct_converter.h index 38d5f09..76a8009 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/struct_converter.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/struct_converter.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/variant_converter.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/variant_converter.h index 4274eb2..7f3c35c 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/variant_converter.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/variant_converter.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h index 00a452f..19565d7 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/core_types_utils.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/errors.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/errors.h index 9bf2c32..6c9e840 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/errors.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/errors.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/exceptions.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/exceptions.h index 423fe8e..0dd4192 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/exceptions.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/exceptions.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/extension_object.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/extension_object.h index 4db7d8f..b49869c 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/extension_object.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/extension_object.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h index 2d56ea1..25ec288 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/opcuatms.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h index 10e913f..ed3c4ad 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/type_mappings.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_factory.h index e750f97..e79d7a7 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_impl.h index d958670..0bb9820 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_channel_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component.h index 1bfa61e..4de1231 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_factory.h index e1617fb..c122440 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h index deb4ec9..f872d20 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h index 549e9d0..fb6fe6e 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_context.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_factory.h index 8998b47..2c125f1 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h index 144728c..9dea076 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_factory.h index f689282..ebb3966 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h index c9cf3a4..50157d1 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_folder_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_factory.h index f1bde5b..ec4f7c0 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h index 2b82c4c..2437ea5 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_factory.h index 578d3bd..6aa163a 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_impl.h index de543e8..41187a2 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_block_type_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_factory.h index b0c6817..1d4cfdb 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_impl.h index 39748ac..fb31f72 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_function_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_factory.h index 5c151e5..f788c4c 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h index a710d8d..d3ed577 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_factory.h index 118ad09..11344f4 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h index 5cd1cac..2f8a0f2 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_io_folder_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h index 84bb4e6..592f782 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_object_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_factory.h index 8befce3..e315f75 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_impl.h index e9b8e13..26d099b 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_procedure_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_factory.h index f441f56..9cd2737 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h index 462fade..203af6d 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_factory.h index cd8d7d2..a839c34 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h index 90db578..d2fa0c6 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_factory.h index ff23f14..73f9409 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_impl.h index f7461a4..8655ff4 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_server_capability_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_factory.h index e401e3f..02f646e 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h index 04d63dd..3ad423a 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_sync_component_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_sync_component_factory.h index 852d251..61e3599 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_sync_component_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_sync_component_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_sync_component_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_sync_component_impl.h index 80634f4..17317d4 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_sync_component_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_sync_component_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_factory.h index e1da477..61b176d 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_factory.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h index 34f6725..f1dd9ad 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_tags_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_attribute_collector.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_attribute_collector.h index 5c41ab5..b99effb 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_attribute_collector.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_attribute_collector.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h index 9c76dfd..6a3257d 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/tms_client.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_channel.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_channel.h index 64f2aee..da88f5e 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_channel.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_channel.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h index 4a0f372..63870db 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h index c2a1adc..5409eef 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_eval_value.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_eval_value.h index 3668a95..c1520a9 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_eval_value.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_eval_value.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_folder.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_folder.h index a4aac03..0a795af 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_folder.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_folder.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block.h index 9bc9d13..2c976d4 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block_type.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block_type.h index b5fda41..963ca46 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block_type.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_function_block_type.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h index 904b99b..ac1a9e3 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_input_port.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h index 9d8e4e5..e415d52 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h index 2cc8965..77bf617 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h index d996cd3..16e8df6 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h index 79501dc..30c07a5 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_sync_component.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_sync_component.h index 7e7644f..0b3b038 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_sync_component.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_sync_component.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_sync_interface.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_sync_interface.h index 79b6f0c..c002757 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_sync_interface.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_sync_interface.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h index 20fa0d9..baa8968 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_variable.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h index 8d3b596..4d00912 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server_context.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server_context.h index 60ce1dc..2275682 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server_context.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server_context.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h b/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h index 6b1b413..ef37ac0 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_helpers.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.h b/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.h index aaf4982..fe4d66e 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.h +++ b/shared/libraries/opcuatms/opcuatms_server/tests/tms_server_test.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h index 13abd9c..a85d8c9 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/tests/test_utils/test_input_port_notifications.h b/shared/libraries/opcuatms/tests/test_utils/test_input_port_notifications.h index 2faf6b3..7b551fd 100644 --- a/shared/libraries/opcuatms/tests/test_utils/test_input_port_notifications.h +++ b/shared/libraries/opcuatms/tests/test_utils/test_input_port_notifications.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/shared/libraries/opcuatms/tests/test_utils/tms_object_test.h b/shared/libraries/opcuatms/tests/test_utils/tms_object_test.h index 2d0d9d5..1790706 100644 --- a/shared/libraries/opcuatms/tests/test_utils/tms_object_test.h +++ b/shared/libraries/opcuatms/tests/test_utils/tms_object_test.h @@ -1,5 +1,5 @@ /* - * Copyright 2022-2024 openDAQ d.o.o. + * Copyright 2022-2025 openDAQ d.o.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From a69b69d403eb6eba957a12f20ba2975bd9faaeb4 Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Mon, 27 Jan 2025 11:27:07 +0100 Subject: [PATCH 180/217] Implement configurable device info fields on core (openDAQ/openDAQ#607) --- .../src/opcua_client_module_impl.cpp | 6 +- .../include/opcuaserver/opcuaserver.h | 2 + .../opcua/opcuaserver/src/opcuaserver.cpp | 6 + .../objects/tms_client_component_impl.h | 5 +- .../objects/tms_client_device_impl.h | 3 +- .../objects/tms_client_property_factory.h | 30 +-- .../objects/tms_client_property_impl.h | 2 +- .../objects/tms_client_property_object_impl.h | 25 ++- .../src/objects/tms_client_device_impl.cpp | 211 +++++++++++++----- .../src/objects/tms_client_property_impl.cpp | 6 +- .../tms_client_property_object_impl.cpp | 23 +- .../opcuatms_client/src/tms_client.cpp | 16 +- .../objects/tms_server_device.h | 1 + .../objects/tms_server_property_object.h | 4 +- .../src/objects/tms_server_device.cpp | 201 ++++++++++------- .../tms_server_function_block_type.cpp | 3 +- .../src/objects/tms_server_property.cpp | 28 +-- .../objects/tms_server_property_object.cpp | 15 +- .../opcuatms_integration/test_tms_device.cpp | 69 ++++++ 19 files changed, 442 insertions(+), 214 deletions(-) diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 73b2897..43a37cd 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -137,7 +137,9 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, completeServerCapabilities(device, host); // Set the connection info for the device - ServerCapabilityConfigPtr connectionInfo = device.getInfo().getConfigurationConnectionInfo(); + DeviceInfoConfigPtr deviceInfo = device.getInfo(); + deviceInfo.setConnectionString(connectionString); + ServerCapabilityConfigPtr connectionInfo = deviceInfo.getConfigurationConnectionInfo(); const auto addressInfo = AddressInfoBuilder().setAddress(host) .setReachabilityStatus(AddressReachabilityStatus::Reachable) @@ -167,7 +169,7 @@ void OpcUaClientModule::completeServerCapabilities(const DevicePtr& device, cons for (const auto& capability : deviceInfo.getServerCapabilities()) { if (capability.getConnectionType() == "TCP/IP") - capability.asPtr().addAddress(deviceAddress); + capability.asPtr(true).addAddress(deviceAddress); } } } diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h index 0c451ac..3da1306 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h @@ -91,6 +91,8 @@ class OpcUaServer final : public daq::utils::ThreadEx void setDescription(const OpcUaNodeId& nodeId, const OpcUaObject& localizedText); void setDescription(const OpcUaNodeId& nodeId, const std::string& text); + void setAccessLevel(const OpcUaNodeId& nodeId, UA_Byte accessLevel); + void writeValue(const OpcUaNodeId& nodeId, const OpcUaVariant& var); OpcUaVariant readValue(const OpcUaNodeId& nodeId); OpcUaNodeId readDataType(const OpcUaNodeId& typeNodeId); diff --git a/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp b/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp index a13e10d..9624250 100644 --- a/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp +++ b/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp @@ -452,6 +452,12 @@ void OpcUaServer::setDescription(const OpcUaNodeId& nodeId, const std::string& t setDescription(nodeId, localizedText); } +void OpcUaServer::setAccessLevel(const OpcUaNodeId& nodeId, UA_Byte accessLevel) +{ + const auto status = UA_Server_writeAccessLevel(server, *nodeId, accessLevel); + CheckStatusCodeException(status); +} + void OpcUaServer::writeValue(const OpcUaNodeId& nodeId, const OpcUaVariant& value) { CheckStatusCodeException(UA_Server_writeValue(server, *nodeId, *value)); diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h index f872d20..6d769af 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h @@ -36,8 +36,9 @@ class TmsClientComponentBaseImpl : public TmsClientPropertyObjectBaseImpl const ComponentPtr& parent, const StringPtr& localId, const TmsClientContextPtr& clientContext, - const opcua::OpcUaNodeId& nodeId) - : TmsClientPropertyObjectBaseImpl(ctx, parent, localId, clientContext, nodeId) + const opcua::OpcUaNodeId& nodeId, + const std::map& propBrowseName = {}) + : TmsClientPropertyObjectBaseImpl(ctx, parent, localId, clientContext, nodeId, propBrowseName) { initComponent(); clientContext->readObjectAttributes(nodeId); diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h index 9dea076..2663776 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h @@ -24,6 +24,7 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS class TmsClientDeviceImpl : public TmsClientComponentBaseImpl> { public: + using Impl = MirroredDeviceBase; using Super = TmsClientComponentBaseImpl>; explicit TmsClientDeviceImpl(const ContextPtr& ctx, const ComponentPtr& parent, @@ -47,7 +48,6 @@ class TmsClientDeviceImpl : public TmsClientComponentBaseImpl onGetAvailableFunctionBlockTypes() override; FunctionBlockPtr onAddFunctionBlock(const StringPtr& typeId, const PropertyObjectPtr& config) override; void onRemoveFunctionBlock(const FunctionBlockPtr& functionBlock) override; @@ -65,6 +65,7 @@ class TmsClientDeviceImpl : public TmsClientComponentBaseImpl deviceInfoChangeableFields; }; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_factory.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_factory.h index 9cd2737..5c3d64a 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_factory.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_factory.h @@ -20,28 +20,22 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS OPENDAQ_DECLARE_CLASS_FACTORY_WITH_INTERFACE(INLINE_FACTORY, - TmsClientProperty, - IProperty, - const daq::ContextPtr&, - daqContext, - const daq::opcua::tms::TmsClientContextPtr&, - ctx, - const opcua::OpcUaNodeId&, - nodeId) + TmsClientProperty, IProperty, + const daq::ContextPtr&, daqContext, + const daq::opcua::tms::TmsClientContextPtr&, ctx, + const opcua::OpcUaNodeId&, nodeId, + const daq::StringPtr&, propertyName) OPENDAQ_DEFINE_CLASS_FACTORY_WITH_INTERFACE(INLINE_FACTORY, - TmsClientProperty, - IProperty, - const daq::ContextPtr&, - daqContext, - const daq::opcua::tms::TmsClientContextPtr&, - client, - const opcua::OpcUaNodeId&, - nodeId) + TmsClientProperty, IProperty, + const daq::ContextPtr&, daqContext, + const daq::opcua::tms::TmsClientContextPtr&, client, + const opcua::OpcUaNodeId&, nodeId, + const daq::StringPtr&, propertyName) -inline PropertyPtr TmsClientProperty(const ContextPtr& daqContext, const TmsClientContextPtr& ctx, const OpcUaNodeId& nodeId) +inline PropertyPtr TmsClientProperty(const ContextPtr& daqContext, const TmsClientContextPtr& ctx, const OpcUaNodeId& nodeId, const StringPtr& propertyName = nullptr) { - PropertyPtr obj(TmsClientProperty_Create(daqContext, ctx, nodeId)); + PropertyPtr obj(TmsClientProperty_Create(daqContext, ctx, nodeId, propertyName)); return obj; } diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h index 203af6d..9d1bd9b 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_impl.h @@ -24,7 +24,7 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS class TmsClientPropertyImpl : public TmsClientObjectImpl, public PropertyImpl { public: - explicit TmsClientPropertyImpl(const ContextPtr& daqContext, const TmsClientContextPtr& ctx, const opcua::OpcUaNodeId& nodeId); + explicit TmsClientPropertyImpl(const ContextPtr& daqContext, const TmsClientContextPtr& ctx, const opcua::OpcUaNodeId& nodeId, const StringPtr& propertyName = nullptr); protected: LoggerComponentPtr loggerComponent; diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h index d2fa0c6..6cf352d 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h @@ -46,9 +46,13 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl public: template = 0> - TmsClientPropertyObjectBaseImpl(const ContextPtr& daqContext, const TmsClientContextPtr& clientContext, const opcua::OpcUaNodeId& nodeId) + TmsClientPropertyObjectBaseImpl(const ContextPtr& daqContext, + const TmsClientContextPtr& clientContext, + const opcua::OpcUaNodeId& nodeId, + const std::map& propBrowseName = {}) : TmsClientObjectImpl(daqContext, clientContext, nodeId) , Impl() + , propBrowseName(propBrowseName) { init(); } @@ -58,9 +62,11 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl const StringPtr& protocolName, const StringPtr& protocolId, const TmsClientContextPtr& clientContext, - const opcua::OpcUaNodeId& nodeId) + const opcua::OpcUaNodeId& nodeId, + const std::map& propBrowseName = {}) : TmsClientObjectImpl(daqContext, clientContext, nodeId) , Impl(protocolId, protocolName, ProtocolType::Streaming) + , propBrowseName(propBrowseName) { init(); } @@ -70,9 +76,11 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl const ComponentPtr& parent, const StringPtr& localId, const TmsClientContextPtr& clientContext, - const opcua::OpcUaNodeId& nodeId) + const opcua::OpcUaNodeId& nodeId, + const std::map& propBrowseName = {}) : TmsClientObjectImpl(ctx, clientContext, nodeId) , Impl(ctx, parent, localId) + , propBrowseName(propBrowseName) { init(); } @@ -82,9 +90,11 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl const ComponentPtr& parent, const StringPtr& localId, const TmsClientContextPtr& clientContext, - const opcua::OpcUaNodeId& nodeId) + const opcua::OpcUaNodeId& nodeId, + const std::map& propBrowseName = {}) : TmsClientObjectImpl(ctx, clientContext, nodeId) , Impl(ctx, parent, localId, nullptr) + , propBrowseName(propBrowseName) { init(); } @@ -95,9 +105,11 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl const StringPtr& localId, const TmsClientContextPtr& clientContext, const opcua::OpcUaNodeId& nodeId, - const FunctionBlockTypePtr& type) + const FunctionBlockTypePtr& type, + const std::map& propBrowseName = {}) : TmsClientObjectImpl(ctx, clientContext, nodeId) , Impl(type, ctx, parent, localId, nullptr) + , propBrowseName(propBrowseName) { init(); } @@ -128,6 +140,7 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl std::unordered_map introspectionVariableIdMap; std::unordered_map referenceVariableIdMap; std::unordered_map objectTypeIdMap; + std::map propBrowseName; opcua::OpcUaNodeId methodParentNodeId; LoggerComponentPtr loggerComponent; @@ -141,7 +154,7 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl PropertyPtr addVariableBlockProperty(const StringPtr& propName, const OpcUaNodeId& propNodeId); void browseRawProperties(); bool isIgnoredMethodPeoperty(const std::string& browseName); - ErrCode INTERFACE_FUNC setPropertyValueInternal(IString* propertyName, IBaseObject* value, bool protectedWrite); + virtual ErrCode INTERFACE_FUNC setPropertyValueInternal(IString* propertyName, IBaseObject* value, bool protectedWrite); }; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index f6dd777..f37e0bd 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -36,7 +36,35 @@ namespace detail { static std::unordered_set defaultComponents = {"Sig", "FB", "IO", "ServerCapabilities", "Synchronization"}; - static std::unordered_map> deviceInfoSetterMap = { + static std::unordered_map deviceInfoFieldMap = + { + {"AssetId", "assetId"}, + {"ComponentName", "name"}, + {"DeviceClass", "deviceClass"}, + {"DeviceManual", "deviceManual"}, + {"DeviceRevision", "deviceRevision"}, + {"HardwareRevision", "hardwareRevision"}, + {"Manufacturer", "manufacturer"}, + {"ManufacturerUri", "manufacturerUri"}, + {"Model", "model"}, + {"ProductCode", "productCode"}, + {"ProductInstanceUri", "productInstanceUri"}, + {"RevisionCounter", "revisionCounter"}, + {"SerialNumber", "serialNumber"}, + {"SoftwareRevision", "softwareRevision"}, + {"MacAddress", "macAddress"}, + {"ParentMacAddress", "parentMacAddress"}, + {"Platform", "platform"}, + {"Position", "position"}, + {"SystemType", "systemType"}, + {"SystemUUID", "systemUuid"}, + {"OpenDaqPackageVersion", "sdkVersion"}, + {"Location", "location"}, + {"UserName", "userName"}, + }; + + static std::unordered_map> deviceInfoSetterMap = + { {"AssetId", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setAssetId(v.toString()); }}, {"ComponentName", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setName(v.toString()); }}, {"DeviceClass", [](const DeviceInfoConfigPtr& info, const OpcUaVariant& v) { info.setDeviceClass(v.toString()); }}, @@ -69,7 +97,12 @@ TmsClientDeviceImpl::TmsClientDeviceImpl(const ContextPtr& ctx, const TmsClientContextPtr& clientContext, const opcua::OpcUaNodeId& nodeId, bool isRootDevice) - : TmsClientComponentBaseImpl(ctx, parent, localId, clientContext, nodeId) + : TmsClientComponentBaseImpl(ctx, + parent, + localId, + clientContext, + nodeId, + {{"UserName", "userName"}, {"Location", "location"}}) , logger(ctx.getLogger()) , loggerComponent( this->logger.assigned() ? this->logger.getOrAddComponent("TmsClientDevice") @@ -86,7 +119,6 @@ TmsClientDeviceImpl::TmsClientDeviceImpl(const ContextPtr& ctx, findAndCreateInputsOutputs(); findAndCreateCustomComponents(); findAndCreateSyncComponent(); - findAndCreateProporties(); } ErrCode TmsClientDeviceImpl::getDomain(IDeviceDomain** deviceDomain) @@ -114,7 +146,7 @@ void TmsClientDeviceImpl::findAndCreateSubdevices() auto numberInList = this->tryReadChildNumberInList(subdeviceNodeId); if (numberInList != std::numeric_limits::max() && !orderedDevices.count(numberInList)) - orderedDevices.insert(std::pair(numberInList, clientSubdevice)); + orderedDevices.emplace(numberInList, clientSubdevice); else unorderedDevices.emplace_back(clientSubdevice); } @@ -140,60 +172,122 @@ void TmsClientDeviceImpl::onRemoveDevice(const DevicePtr& /*device*/) throw OpcUaClientCallNotAvailableException(); } -DeviceInfoPtr TmsClientDeviceImpl::onGetInfo() +static bool IsVersionHigher(const std::string &version, int major, int minor) { - auto deviceInfo = DeviceInfo("", this->client->readDisplayName(this->nodeId)); + int majorVersion = 0, minorVersion = 0; + std::stringstream ss(version); + ss >> majorVersion; + ss.ignore(); + ss >> minorVersion; + return majorVersion > major || (majorVersion == major && minorVersion >= minor); +} +DeviceInfoPtr TmsClientDeviceImpl::onGetInfo() +{ auto browseFilter = BrowseFilter(); browseFilter.nodeClass = UA_NODECLASS_VARIABLE; + browseFilter.typeDefinition = OpcUaNodeId(UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE)); const auto& references = clientContext->getReferenceBrowser()->browseFiltered(nodeId, browseFilter); auto reader = AttributeReader(client, clientContext->getMaxNodesPerRead()); for (const auto& [browseName, ref] : references.byBrowseName) + { reader.addAttribute({ref->nodeId.nodeId, UA_ATTRIBUTEID_VALUE}); - + reader.addAttribute({ref->nodeId.nodeId, UA_ATTRIBUTEID_ACCESSLEVEL}); + } reader.read(); + bool serverSupportsEditableProperties = true; + if (references.byBrowseName.contains("OpenDaqPackageVersion")) + { + const auto refNodeId = OpcUaNodeId(references.byBrowseName.at("OpenDaqPackageVersion")->nodeId.nodeId); + const auto sdkVersion = reader.getValue(refNodeId, UA_ATTRIBUTEID_VALUE).toString(); + serverSupportsEditableProperties = sdkVersion.empty() || IsVersionHigher(sdkVersion, 3, 11); + } + + std::set ignoreProps = {"NumberInList", "Active", "Visible", "Tags"}; + auto changeableProperties = List(); + if (serverSupportsEditableProperties) + { + for (const auto& [browseName, ref] : references.byBrowseName) + { + const auto refNodeId = OpcUaNodeId(ref->nodeId.nodeId); + const auto value = reader.getValue(refNodeId, UA_ATTRIBUTEID_VALUE); + const auto accessLevel = reader.getValue(refNodeId, UA_ATTRIBUTEID_ACCESSLEVEL).toInteger(); + + if (!value.isScalar()) + continue; + if ((accessLevel & UA_ACCESSLEVELMASK_WRITE) == 0) + continue; + if (ignoreProps.count(browseName)) + continue; + + std::string propertyName = browseName; + if (detail::deviceInfoFieldMap.count(propertyName)) + propertyName = detail::deviceInfoFieldMap[propertyName]; + + deviceInfoChangeableFields.emplace(propertyName, refNodeId); + } + for (const auto& [name, _] : deviceInfoChangeableFields) + changeableProperties.pushBack(String(name)); + } + + if (this->objPtr.hasProperty("userName")) + changeableProperties.pushBack("userName"); + if (this->objPtr.hasProperty("location")) + changeableProperties.pushBack("location"); + + auto deviceInfo = DeviceInfoWithChanegableFields(changeableProperties); + deviceInfo.setName(this->client->readDisplayName(this->nodeId)); + for (const auto& [browseName, ref] : references.byBrowseName) { const auto refNodeId = OpcUaNodeId(ref->nodeId.nodeId); const auto value = reader.getValue(refNodeId, UA_ATTRIBUTEID_VALUE); - if (detail::deviceInfoSetterMap.count(browseName)) - { - detail::deviceInfoSetterMap[browseName](deviceInfo, value); + if (!value.isScalar()) continue; - } - - if (browseName == "NumberInList") + if (ignoreProps.count(browseName)) continue; - + try { - if (value.isScalar()) + std::string propertyName = browseName; + if (auto it = detail::deviceInfoFieldMap.find(propertyName); it != detail::deviceInfoFieldMap.end()) + propertyName = it->second; + + if (deviceInfo.hasProperty(propertyName)) { - if (deviceInfo.hasProperty(browseName)) - { - if (value.isString()) - deviceInfo.asPtr(true).setProtectedPropertyValue(browseName, value.toString()); - else if (value.isBool()) - deviceInfo.asPtr(true).setProtectedPropertyValue(browseName, value.toBool()); - else if (value.isDouble()) - deviceInfo.asPtr(true).setProtectedPropertyValue(browseName, value.toDouble()); - else if (value.isInteger()) - deviceInfo.asPtr(true).setProtectedPropertyValue(browseName, value.toInteger()); - } - else + BaseObjectPtr daqValue; + if (value.isString()) + daqValue = String(value.toString()); + else if (value.isBool()) + daqValue = Bool(value.toBool()); + else if (value.isDouble()) + daqValue = Float(value.toDouble()); + else if (value.isInteger()) + daqValue = Int(value.toInteger()); + + if (daqValue.assigned()) + deviceInfo.asPtr(true).setProtectedPropertyValue(propertyName, daqValue); + } + else + { + PropertyBuilderPtr propertyBuilder; + if (value.isString()) + propertyBuilder = StringPropertyBuilder(propertyName, value.toString()); + else if (value.isBool()) + propertyBuilder = BoolPropertyBuilder(propertyName, value.toBool()); + else if (value.isDouble()) + propertyBuilder = FloatPropertyBuilder(propertyName, value.toDouble()); + else if (value.isInteger()) + propertyBuilder = IntPropertyBuilder(propertyName, value.toInteger()); + + if (propertyBuilder.assigned()) { - if (value.isString()) - deviceInfo.addProperty(StringProperty(browseName, value.toString())); - else if (value.isBool()) - deviceInfo.addProperty(BoolProperty(browseName, value.toBool())); - else if (value.isDouble()) - deviceInfo.addProperty(FloatProperty(browseName, value.toDouble())); - else if (value.isInteger()) - deviceInfo.addProperty(IntProperty(browseName, value.toInteger())); + const bool isReadOnly = deviceInfoChangeableFields.count(propertyName) == 0; + deviceInfo.addProperty(propertyBuilder.setReadOnly(isReadOnly).build()); } } } @@ -202,18 +296,34 @@ DeviceInfoPtr TmsClientDeviceImpl::onGetInfo() LOG_W("Failed to read device info attribute on OpcUa client device \"{}\": {}", this->globalId, e.what()); } } - - findAndCreateServerCapabilities(deviceInfo); - for (const auto & cap : deviceInfo.getServerCapabilities()) + for (const auto & entry : deviceInfoChangeableFields) { - if (cap.getProtocolId() == "OpenDAQOPCUAConfiguration") + const auto& propName = entry.first; + const auto& nodeId = entry.second; + + try + { + deviceInfo.getOnPropertyValueWrite(propName) += [this, &nodeId](PropertyObjectPtr&, PropertyValueEventArgsPtr& args) + { + const auto variant = VariantConverter::ToVariant(args.getValue(), nullptr, daqContext); + client->writeValue(nodeId, variant); + }; + + deviceInfo.getOnPropertyValueRead(propName) += [this, &nodeId](PropertyObjectPtr&, PropertyValueEventArgsPtr& args) + { + const auto variant = client->readValue(nodeId); + const auto daqValue = VariantConverter::ToDaqObject(variant, daqContext); + args.setValue(daqValue); + }; + } + catch (...) { - deviceInfo.setConnectionString(cap.getConnectionString()); + } } - deviceInfo.freeze(); + findAndCreateServerCapabilities(deviceInfo); return deviceInfo; } @@ -260,19 +370,6 @@ void TmsClientDeviceImpl::findAndCreateSyncComponent() syncComponentNodeId)); } -void TmsClientDeviceImpl::findAndCreateProporties() -{ - if (auto it = this->introspectionVariableIdMap.find("UserName"); it != this->introspectionVariableIdMap.end()) - { - introspectionVariableIdMap.emplace("userName", it->second); - } - - if (auto it = this->introspectionVariableIdMap.find("Location"); it != this->introspectionVariableIdMap.end()) - { - introspectionVariableIdMap.emplace("location", it->second); - } -} - void TmsClientDeviceImpl::fetchTicksSinceOrigin() { auto timeDomainNodeId = getNodeId("Domain"); @@ -316,7 +413,7 @@ void TmsClientDeviceImpl::findAndCreateFunctionBlocks() auto clientFunctionBlock = TmsClientFunctionBlock(context, this->functionBlocks, browseName, clientContext, functionBlockNodeId); const auto numberInList = this->tryReadChildNumberInList(functionBlockNodeId); if (numberInList != std::numeric_limits::max() && !orderedFunctionBlocks.count(numberInList)) - orderedFunctionBlocks.insert(std::pair(numberInList, clientFunctionBlock)); + orderedFunctionBlocks.emplace(numberInList, clientFunctionBlock); else unorderedFunctionBlocks.emplace_back(clientFunctionBlock); } @@ -347,7 +444,7 @@ void TmsClientDeviceImpl::findAndCreateSignals() auto clientSignal = FindOrCreateTmsClientSignal(context, signals, clientContext, signalNodeId); const auto numberInList = this->tryReadChildNumberInList(signalNodeId); if (numberInList != std::numeric_limits::max() && !orderedSignals.count(numberInList)) - orderedSignals.insert(std::pair(numberInList, clientSignal)); + orderedSignals.emplace(numberInList, clientSignal); else unorderedSignals.emplace_back(clientSignal); } @@ -443,7 +540,7 @@ void TmsClientDeviceImpl::findAndCreateServerCapabilities(const DeviceInfoPtr& d capabilityCopy.addProperty(prop.asPtr().clone()); // AddressInfo is a special case, add it as a child object property of type IAddressInfo - if (name == "AddressInfo") + if (name == "AddressInfo") { const auto addrInfoId = clientContext->getReferenceBrowser()->getChildNodeId(optionNodeId, "AddressInfo"); const auto& addrInfoRefs = getChildReferencesOfType(addrInfoId, OpcUaNodeId(NAMESPACE_DAQBT, UA_DAQBTID_VARIABLEBLOCKTYPE)); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp index e3af167..11ce84a 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp @@ -42,13 +42,14 @@ namespace details }; } -TmsClientPropertyImpl::TmsClientPropertyImpl(const ContextPtr& daqContext, const TmsClientContextPtr& ctx, const opcua::OpcUaNodeId& nodeId) +TmsClientPropertyImpl::TmsClientPropertyImpl(const ContextPtr& daqContext, const TmsClientContextPtr& ctx, const opcua::OpcUaNodeId& nodeId, const StringPtr& propertyName) : TmsClientObjectImpl(daqContext, ctx, nodeId) { if (!this->daqContext.getLogger().assigned()) throw ArgumentNullException("Logger must not be null"); this->loggerComponent = this->daqContext.getLogger().getOrAddComponent("TmsClientPropertyImpl"); + this->name = propertyName; clientContext->readObjectAttributes(nodeId); @@ -59,7 +60,8 @@ TmsClientPropertyImpl::TmsClientPropertyImpl(const ContextPtr& daqContext, const void TmsClientPropertyImpl::readBasicInfo() { auto reader = clientContext->getAttributeReader(); - this->name = String(reader->getValue(nodeId, UA_ATTRIBUTEID_DISPLAYNAME).toString()); + if (!this->name.assigned()) + this->name = String(reader->getValue(nodeId, UA_ATTRIBUTEID_DISPLAYNAME).toString()); this->description = String(reader->getValue(nodeId, UA_ATTRIBUTEID_DESCRIPTION).toString()); const auto dataType = reader->getValue(nodeId, UA_ATTRIBUTEID_DATATYPE).toNodeId(); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index 9c0079f..14b2dc9 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -123,7 +123,8 @@ ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::getPropertyValue(I auto propertyNamePtr = StringPtr::Borrow(propertyName); StringPtr lastProccessDescription = ""; - ErrCode errCode = daqTry([&]() { + ErrCode errCode = daqTry([&] + { if (const auto& introIt = introspectionVariableIdMap.find(propertyNamePtr); introIt != introspectionVariableIdMap.cend()) { const auto variant = client->readValue(introIt->second); @@ -145,7 +146,7 @@ ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::getPropertyValue(I }); if (OPENDAQ_FAILED(errCode)) { - LOG_W("Failed to set value for property \"{}\" on OpcUA client property object", propertyNamePtr); + LOG_W("Failed to get value for property \"{}\" on OpcUA client property object", propertyNamePtr); } return OPENDAQ_SUCCESS; } @@ -282,7 +283,9 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par for (auto& [childNodeId, ref] : references.byNodeId) { const auto typeId = OpcUaNodeId(ref->typeDefinition.nodeId); - const auto propName = String(utils::ToStdString(ref->browseName.name)); + auto propName = String(utils::ToStdString(ref->browseName.name)); + if (propBrowseName.count(propName)) + propName = propBrowseName[propName]; if (detail::ignoredPropertyNames.count(propName)) continue; @@ -299,7 +302,7 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par prop = ReferenceProperty(propName, EvalValue(refPropEval)); } - referenceVariableIdMap.insert(std::pair(propName, childNodeId)); + referenceVariableIdMap.emplace(propName, childNodeId); addProperties(childNodeId, orderedProperties, unorderedProperties); } catch(const std::exception& e) @@ -314,9 +317,9 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par try { if (!hasProp) - prop = TmsClientProperty(daqContext, clientContext, ref->nodeId.nodeId); + prop = TmsClientProperty(daqContext, clientContext, ref->nodeId.nodeId, propName); - introspectionVariableIdMap.insert(std::pair(propName, childNodeId)); + introspectionVariableIdMap.emplace(propName, childNodeId); } catch(const std::exception& e) { @@ -331,7 +334,7 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par if (!hasProp) prop = addVariableBlockProperty(propName, childNodeId); - objectTypeIdMap.insert(std::pair(propName, childNodeId)); + objectTypeIdMap.emplace(propName, childNodeId); } catch (const std::exception& e) { @@ -344,7 +347,7 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par { auto numberInList = tryReadChildNumberInList(childNodeId); if (numberInList != std::numeric_limits::max() && !orderedProperties.count(numberInList)) - orderedProperties.insert(std::pair(numberInList, prop)); + orderedProperties.emplace(numberInList, prop); else unorderedProperties.push_back(prop); } @@ -423,9 +426,9 @@ void TmsClientPropertyObjectBaseImpl::addMethodProperties(const OpcUaNodeI func = TmsClientProcedure(clientContext, daqContext, parentNodeId, childNodeId); } - functionPropValues.insert(std::pair(propName, func)); + functionPropValues.emplace(propName, func); if (numberInList != std::numeric_limits::max() && !orderedProperties.count(numberInList)) - orderedProperties.insert(std::pair(numberInList, prop)); + orderedProperties.emplace(numberInList, prop); else unorderedProperties.push_back(prop); } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp index f5626d7..bd47ede 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp @@ -66,16 +66,14 @@ daq::DevicePtr TmsClient::connect() auto device = TmsClientRootDevice(context, parent, rootDeviceBrowseName, tmsClientContext, rootDeviceNodeId); const auto deviceInfo = device.getInfo(); - if (deviceInfo.hasProperty("OpenDaqPackageVersion")) - { - const std::string packageVersion = deviceInfo.getPropertyValue("OpenDaqPackageVersion"); + deviceInfo.asPtr(true).setConnectionString(endpoint.getUrl()); - if (packageVersion != OPENDAQ_PACKAGE_VERSION) - { - LOG_D("Connected to openDAQ OPC UA server with different version. Client version: {}, server version: {}", - OPENDAQ_PACKAGE_VERSION, - packageVersion); - } + const std::string packageVersion = deviceInfo.getSdkVersion(); + if (!packageVersion.empty() && packageVersion != OPENDAQ_PACKAGE_VERSION) + { + LOG_D("Connected to openDAQ OPC UA server with different version. Client version: {}, server version: {}", + OPENDAQ_PACKAGE_VERSION, + packageVersion); } const auto endTime = std::chrono::steady_clock::now(); diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h index 5409eef..715ed61 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_device.h @@ -70,6 +70,7 @@ class TmsServerDevice : public TmsServerComponent std::list serverCapabilities; std::list functionBlockTypes; std::list syncComponents; + std::list deviceInfoProperties; }; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h index 16e8df6..a0d6039 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_property_object.h @@ -54,14 +54,14 @@ class TmsServerPropertyObject : public TmsServerObjectBaseImpl ignoredProps; - std::unordered_map propBrowseName; // property name -> browse name (if not set use browse name as property name) + std::unordered_map propBrowseName; // property name -> browse name (if not use browse name as property name) protected: void configureNodeAttributes(opcua::OpcUaObject& attr) override; void triggerEvent(PropertyObjectPtr& sender, PropertyValueEventArgsPtr& args); opcua::OpcUaNodeId getTmsTypeId() override; void addPropertyNode(const std::string& name, const opcua::OpcUaNodeId& parentId); - void bindPropertyCallbacks(const std::string& browseName, const std::string& propName); + void bindPropertyCallbacks(const opcua::OpcUaNodeId& nodeId, const std::string& propName); std::unordered_map childProperties; std::unordered_map childObjects; diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index 2fb69c5..79feb21 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -1,7 +1,9 @@ #include #include +#include #include #include +#include #include #include #include @@ -16,6 +18,7 @@ #include #include #include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -31,27 +34,36 @@ namespace detail return v; } + static std::unordered_map componentFieldToDeviceInfo = { + {"AssetId", "assetId"}, + {"ComponentName", "name"}, + {"DeviceClass", "deviceClass"}, + {"DeviceManual", "deviceManual"}, + {"DeviceRevision", "deviceRevision"}, + {"HardwareRevision", "hardwareRevision"}, + {"Manufacturer", "manufacturer"}, + {"ManufacturerUri", "manufacturerUri"}, + {"Model", "model"}, + {"ProductCode", "productCode"}, + {"ProductInstanceUri", "productInstanceUri"}, + {"RevisionCounter", "revisionCounter"}, + {"SerialNumber", "serialNumber"}, + {"SoftwareRevision", "softwareRevision"}, + {"MacAddress", "macAddress"}, + {"ParentMacAddress", "parentMacAddress"}, + {"Platform", "platform"}, + {"Position", "position"}, + {"SystemType", "systemType"}, + {"SystemUUID", "systemUuid"}, + {"OpenDaqPackageVersion", "sdkVersion"}, + }; + static std::unordered_map> componentFieldToVariant = { - {"AssetId", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getAssetId().getCharPtr()}; }}, {"ComponentName", [](const DeviceInfoPtr& info) { return createLocalizedTextVariant(info.getName().getCharPtr()); }}, - {"DeviceClass", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getDeviceClass().getCharPtr()}; }}, - {"DeviceManual", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getDeviceManual().getCharPtr()}; }}, - {"DeviceRevision", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getDeviceRevision().getCharPtr()}; }}, - {"HardwareRevision", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getHardwareRevision().getCharPtr()}; }}, {"Manufacturer", [](const DeviceInfoPtr& info) { return createLocalizedTextVariant(info.getManufacturer().getCharPtr()); }}, - {"ManufacturerUri", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getManufacturerUri().getCharPtr()}; }}, {"Model", [](const DeviceInfoPtr& info) { return createLocalizedTextVariant(info.getModel().getCharPtr()); }}, - {"ProductCode", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getProductCode().getCharPtr()}; }}, - {"ProductInstanceUri", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getProductInstanceUri().getCharPtr()}; }}, {"RevisionCounter", [](const DeviceInfoPtr& info) { return OpcUaVariant{static_cast(info.getRevisionCounter())}; }}, - {"SerialNumber", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getSerialNumber().getCharPtr()}; }}, - {"SoftwareRevision", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getSoftwareRevision().getCharPtr()}; }}, - {"MacAddress", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getMacAddress().getCharPtr()}; }}, - {"ParentMacAddress", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getParentMacAddress().getCharPtr()}; }}, - {"Platform", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getPlatform().getCharPtr()}; }}, {"Position", [](const DeviceInfoPtr& info) { return OpcUaVariant{static_cast(info.getPosition())}; }}, - {"SystemType", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getSystemType().getCharPtr()}; }}, - {"SystemUUID", [](const DeviceInfoPtr& info) { return OpcUaVariant{info.getSystemUuid().getCharPtr()}; }}, }; } @@ -90,38 +102,38 @@ bool TmsServerDevice::createOptionalNode(const OpcUaNodeId& nodeId) void TmsServerDevice::bindCallbacks() { this->addReadCallback("Domain", [this] - { + { + const auto deviceDomain = object.getDomain(); + if (!deviceDomain.assigned()) + return OpcUaVariant{}; - const auto deviceDomain = object.getDomain(); - if (!deviceDomain.assigned()) - return OpcUaVariant{}; + const auto functionBlockNodeId = getChildNodeId("Domain"); + try + { + OpcUaObject uaDeviceDomain; + uaDeviceDomain->resolution.numerator = deviceDomain.getTickResolution().getNumerator(); + uaDeviceDomain->resolution.denominator = deviceDomain.getTickResolution().getDenominator(); + uaDeviceDomain->origin = ConvertToOpcUaString(deviceDomain.getOrigin()).getDetachedValue(); + uaDeviceDomain->ticksSinceOrigin = object.getTicksSinceOrigin(); + auto unit = StructConverter::ToTmsType(deviceDomain.getUnit()); + uaDeviceDomain->unit = unit.getDetachedValue(); - const auto functionBlockNodeId = getChildNodeId("Domain"); - try - { - OpcUaObject uaDeviceDomain; - uaDeviceDomain->resolution.numerator = deviceDomain.getTickResolution().getNumerator(); - uaDeviceDomain->resolution.denominator = deviceDomain.getTickResolution().getDenominator(); - uaDeviceDomain->origin = ConvertToOpcUaString(deviceDomain.getOrigin()).getDetachedValue(); - uaDeviceDomain->ticksSinceOrigin = object.getTicksSinceOrigin(); - auto unit = StructConverter::ToTmsType(deviceDomain.getUnit()); - uaDeviceDomain->unit = unit.getDetachedValue(); - - OpcUaVariant v; - v.setScalar(*uaDeviceDomain); - return v; - } - catch (...) - { - return OpcUaVariant{}; - } - }); + OpcUaVariant v; + v.setScalar(*uaDeviceDomain); + return v; + } + catch (...) + { + return OpcUaVariant{}; + } + }); Super::bindCallbacks(); } void TmsServerDevice::populateDeviceInfo() { + auto deviceInfo = object.getInfo(); auto createNode = [this](std::string name, CoreType type) { @@ -150,18 +162,15 @@ void TmsServerDevice::populateDeviceInfo() server->addVariableNode(params); }; - auto deviceInfo = object.getInfo(); - createNode("OpenDaqPackageVersion", ctString); - const auto customInfoNames = deviceInfo.getCustomInfoPropertyNames(); std::unordered_set customInfoNamesSet; - - for (auto propName : customInfoNames) + for (auto propName : deviceInfo.getCustomInfoPropertyNames()) { try { - createNode(propName, deviceInfo.getProperty(propName).getValueType()); + auto prop = deviceInfo.getProperty(propName); + createNode(propName, prop.getValueType()); customInfoNamesSet.insert(propName); } catch(...) @@ -179,45 +188,81 @@ void TmsServerDevice::populateDeviceInfo() const auto& reference = result->references[i]; std::string browseName = opcua::utils::ToStdString(reference.browseName.name); - if (detail::componentFieldToVariant.count(browseName)) - { - auto v = detail::componentFieldToVariant[browseName](deviceInfo); - server->writeValue(reference.nodeId.nodeId, *v); - } - else if (browseName == "OpenDaqPackageVersion") - { - auto v = OpcUaVariant{deviceInfo.getSdkVersion().getCharPtr()}; - server->writeValue(reference.nodeId.nodeId, *v); - } + std::string propName; + if (const auto it = detail::componentFieldToDeviceInfo.find(browseName); it != detail::componentFieldToDeviceInfo.end()) + propName = it->second; else if (customInfoNamesSet.count(browseName)) + propName = browseName; + else + continue; + + const auto & nodeId = reference.nodeId.nodeId; + const auto prop = deviceInfo.getProperty(propName); + + if (prop.getReadOnly()) { - const auto valueType = deviceInfo.getProperty(browseName).getValueType(); - OpcUaVariant v; - if (valueType == ctBool) - { - bool val = deviceInfo.getPropertyValue(browseName); - v = OpcUaVariant(val); - } - else if (valueType == ctInt) + server->setAccessLevel(nodeId, UA_ACCESSLEVELMASK_READ); + OpcUaVariant value; + if (const auto it = detail::componentFieldToVariant.find(browseName); it != detail::componentFieldToVariant.end()) { - int64_t val = deviceInfo.getPropertyValue(browseName); - v = OpcUaVariant(val); + value = it->second(deviceInfo); } - else if (valueType == ctFloat) + else { - double val = deviceInfo.getPropertyValue(browseName); - v = OpcUaVariant(val); + const auto daqValue = deviceInfo.getPropertyValue(propName); + value = VariantConverter::ToVariant(daqValue, nullptr, daqContext); } - else if (valueType == ctString) + server->writeValue(nodeId, *value); + continue; + } + + server->setAccessLevel(nodeId, UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE); + + if (const auto it = detail::componentFieldToVariant.find(browseName); it != detail::componentFieldToVariant.end()) + this->addReadCallback(nodeId, std::bind(it->second, deviceInfo)); + else + this->addReadCallback(nodeId, [this, name = propName] { - v = OpcUaVariant(deviceInfo.getPropertyValue(browseName).asPtr().getCharPtr()); - } - else + const auto value = object.getInfo().getPropertyValue(name); + return VariantConverter::ToVariant(value, nullptr, daqContext); + }); + + this->addWriteCallback(nodeId, [this, name = propName](const OpcUaVariant& variant) + { + const auto value = VariantConverter::ToDaqObject(variant, daqContext); + this->object.getInfo().setPropertyValue(name, value); + return UA_STATUSCODE_GOOD; + }); + } + + std::map theBestProportiesEver = + { + {"userName", "UserName"}, + {"location", "Location"} + }; + + for (const auto& [propName, browseName] : theBestProportiesEver) + { + const auto& prop = deviceInfo.getProperty(propName); + const auto nodeId = getChildNodeId(browseName); + auto tmsProperty = std::make_shared(prop, server, daqContext, tmsContext, browseName); + tmsProperty->registerToExistingOpcUaNode(nodeId); + deviceInfoProperties.push_back(tmsProperty); + + this->addReadCallback(nodeId, [this, name = propName] + { + const auto value = object.getInfo().getPropertyValue(name); + return VariantConverter::ToVariant(value, nullptr, daqContext); + }); + + if (!prop.getReadOnly()) + { + this->addWriteCallback(nodeId, [this, name = propName](const OpcUaVariant& variant) { - continue; - } - - server->writeValue(reference.nodeId.nodeId, *v); + const auto value = VariantConverter::ToDaqObject(variant, daqContext); + this->object.getInfo().setPropertyValue(name, value); + return UA_STATUSCODE_GOOD; + }); } } } @@ -480,8 +525,8 @@ void TmsServerDevice::addChildNodes() syncComponentNode->registerToExistingOpcUaNode(syncComponentNodeId); syncComponents.push_back(std::move(syncComponentNode)); - tmsPropertyObject->propBrowseName.emplace("userName", "UserName"); - tmsPropertyObject->propBrowseName.emplace("location", "Location"); + tmsPropertyObject->ignoredProps.emplace("userName"); + tmsPropertyObject->ignoredProps.emplace("location"); // TODO add "Srv" as a default node diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block_type.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block_type.cpp index fb93763..b78f13b 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block_type.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_function_block_type.cpp @@ -60,8 +60,7 @@ void TmsServerFunctionBlockType::addDefaultConfigNode() if (!defaultConfig.assigned()) return; - if (!defaultConfig.isFrozen()) - defaultConfig.freeze(); + defaultConfig.freeze(); tmsDefaultConfig = std::make_shared(defaultConfig, server, daqContext, tmsContext, "DefaultConfig"); tmsDefaultConfig->registerOpcUaNode(nodeId); diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp index 8a0231b..d4b1024 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property.cpp @@ -88,28 +88,28 @@ void TmsServerProperty::bindCallbacks() if (!parentObj.getProperty(name).asPtr().getReferencedPropertyUnresolved().assigned()) { addReadCallback(name, [this, name] - { - const auto value = this->parent.getRef().getPropertyValue(name); - return VariantConverter::ToVariant(value, nullptr, daqContext); - }); + { + const auto value = this->parent.getRef().getPropertyValue(name); + return VariantConverter::ToVariant(value, nullptr, daqContext); + }); if (!parentObj.supportsInterface() || !parentObj.isFrozen()) { addWriteCallback(name, [this, name](const OpcUaVariant& variant) - { - const auto value = VariantConverter::ToDaqObject(variant, daqContext); - this->parent.getRef().setPropertyValue(name, value); - return UA_STATUSCODE_GOOD; - }); + { + const auto value = VariantConverter::ToDaqObject(variant, daqContext); + this->parent.getRef().setPropertyValue(name, value); + return UA_STATUSCODE_GOOD; + }); } } else { - addReadCallback(name, [this, name] - { - const auto refProp = this->parent.getRef().getProperty(name).asPtr().getReferencedPropertyUnresolved(); - return VariantConverter::ToVariant(refProp.getEval(), nullptr, daqContext); - }); + addReadCallback(name, [this, name] + { + const auto refProp = this->parent.getRef().getProperty(name).asPtr().getReferencedPropertyUnresolved(); + return VariantConverter::ToVariant(refProp.getEval(), nullptr, daqContext); + }); } } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp index e9b4b5b..421f0be 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp @@ -50,8 +50,6 @@ TmsServerPropertyObject::TmsServerPropertyObject(const PropertyObjectPtr& object TmsServerPropertyObject::~TmsServerPropertyObject() { - //for (auto prop : this->object.getAllProperties()) - // this->object.getOnPropertyValueWrite(prop.getName()) -= event(this, &TmsServerPropertyObject::triggerEvent); } std::string TmsServerPropertyObject::getBrowseName() @@ -174,10 +172,7 @@ void TmsServerPropertyObject::addChildNodes() void TmsServerPropertyObject::bindCallbacks() { for (const auto& [id, prop] : childProperties) - { - //this->object.getOnPropertyValueWrite(prop->getBrowseName()) += event(this, &TmsServerPropertyObject::triggerEvent); - bindPropertyCallbacks(prop->getBrowseName(), prop->getPropertyName()); - } + bindPropertyCallbacks(id, prop->getPropertyName()); bindMethodCallbacks(); } @@ -201,11 +196,11 @@ void TmsServerPropertyObject::addProperty(const TmsServerPropertyPtr& childPrope childProperty->setNumberInList(numberInList++); } -void TmsServerPropertyObject::bindPropertyCallbacks(const std::string& browseName, const std::string& propName) +void TmsServerPropertyObject::bindPropertyCallbacks(const opcua::OpcUaNodeId& nodeId, const std::string& propName) { if (!this->object.getProperty(propName).asPtr().getReferencedPropertyUnresolved().assigned()) { - addReadCallback(browseName, [this, propName] + addReadCallback(nodeId, [this, propName] { const auto value = this->object.getPropertyValue(propName); return VariantConverter::ToVariant(value, nullptr, daqContext); @@ -214,7 +209,7 @@ void TmsServerPropertyObject::bindPropertyCallbacks(const std::string& browseNam const auto freezable = this->object.asPtrOrNull(); if (!freezable.assigned() || !this->object.isFrozen()) { - addWriteCallback(browseName, [this, propName](const OpcUaVariant& variant) + addWriteCallback(nodeId, [this, propName](const OpcUaVariant& variant) { const auto value = VariantConverter::ToDaqObject(variant, daqContext); this->object.asPtr().setProtectedPropertyValue(propName, value); @@ -224,7 +219,7 @@ void TmsServerPropertyObject::bindPropertyCallbacks(const std::string& browseNam } else { - addReadCallback(browseName, [this, propName] + addReadCallback(nodeId, [this, propName] { const auto refProp = this->object.getProperty(propName).asPtr().getReferencedPropertyUnresolved(); return VariantConverter::ToVariant(refProp.getEval(), nullptr, daqContext); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp index ed9567d..33a5308 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp @@ -531,3 +531,72 @@ TEST_F(TmsDeviceTest, DeviceInfoChanges) ASSERT_EQ(serverDeviceInfo.getName(), clientDeviceInfo.getName()); ASSERT_EQ(serverDeviceInfo.getLocation(), clientDeviceInfo.getLocation()); } + +TEST_F(TmsDeviceTest, DeviceInfoChangeableField) +{ + const auto ctx = NullContext(); + const DevicePtr serverDevice = createDevice(); + + auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); + const auto nodeId = serverTmsDevice.registerOpcUaNode(); + const auto serverDeviceInfo = serverDevice.getDevices()[1].getInfo(); + + const auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId); + const auto clientSubDevice = clientDevice.getDevices()[1]; + const auto clientDeviceInfo = clientSubDevice.getInfo(); + + ASSERT_EQ(serverDeviceInfo.getPropertyValue("TestChangeableField"), clientDeviceInfo.getPropertyValue("TestChangeableField")); + + serverDeviceInfo.setPropertyValue("TestChangeableField", "new_value"); + ASSERT_EQ("new_value", serverDeviceInfo.getPropertyValue("TestChangeableField")); + ASSERT_EQ("new_value", clientDeviceInfo.getPropertyValue("TestChangeableField")); + + clientDeviceInfo.setPropertyValue("TestChangeableField", "new_value_2"); + ASSERT_EQ("new_value_2", serverDeviceInfo.getPropertyValue("TestChangeableField")); + ASSERT_EQ("new_value_2", clientDeviceInfo.getPropertyValue("TestChangeableField")); +} + +TEST_F(TmsDeviceTest, DeviceInfoNotChangeableField) +{ + const auto ctx = NullContext(); + const DevicePtr serverDevice = createDevice(); + + auto serverTmsDevice = TmsServerDevice(serverDevice, this->getServer(), ctx, serverContext); + const auto nodeId = serverTmsDevice.registerOpcUaNode(); + const auto serverDeviceInfo = serverDevice.getDevices()[1].getInfo(); + + const auto clientDevice = TmsClientRootDevice(ctx, nullptr, "dev", clientContext, nodeId); + const auto clientSubDevice = clientDevice.getDevices()[1]; + const auto clientDeviceInfo = clientSubDevice.getInfo(); + + ASSERT_EQ("manufacturer", serverDeviceInfo.getManufacturer()); + ASSERT_EQ("manufacturer", clientDeviceInfo.getManufacturer()); + + { + ASSERT_ANY_THROW(serverDeviceInfo.setPropertyValue("manufacturer", "server_manufacturer")); + ASSERT_EQ("manufacturer", serverDeviceInfo.getManufacturer()); + ASSERT_EQ("manufacturer", clientDeviceInfo.getManufacturer()); + + serverDeviceInfo.asPtr(true).setProtectedPropertyValue("manufacturer", "server_manufacturer_2"); + ASSERT_EQ("server_manufacturer_2", serverDeviceInfo.getManufacturer()); + ASSERT_EQ("manufacturer", clientDeviceInfo.getManufacturer()); + + serverDeviceInfo.asPtr(true).setManufacturer("server_manufacturer_3"); + ASSERT_EQ("server_manufacturer_3", serverDeviceInfo.getManufacturer()); + ASSERT_EQ("manufacturer", clientDeviceInfo.getManufacturer()); + } + + { + ASSERT_ANY_THROW(clientDeviceInfo.setPropertyValue("manufacturer", "client_manufacturer")); + ASSERT_EQ("server_manufacturer_3", serverDeviceInfo.getManufacturer()); + ASSERT_EQ("manufacturer", clientDeviceInfo.getManufacturer()); + + clientDeviceInfo.asPtr(true).setProtectedPropertyValue("manufacturer", "client_manufacturer_2"); + ASSERT_EQ("server_manufacturer_3", serverDeviceInfo.getManufacturer()); + ASSERT_EQ("client_manufacturer_2", clientDeviceInfo.getManufacturer()); + + clientDeviceInfo.asPtr(true).setManufacturer("client_manufacturer_3"); + ASSERT_EQ("server_manufacturer_3", serverDeviceInfo.getManufacturer()); + ASSERT_EQ("client_manufacturer_3", clientDeviceInfo.getManufacturer()); + } +} \ No newline at end of file From d50852d21d85d46c987b873af68af9af55f40e12 Mon Sep 17 00:00:00 2001 From: NikolaiShipilov <127689162+NikolaiShipilov@users.noreply.github.com> Date: Tue, 28 Jan 2025 02:56:10 -0800 Subject: [PATCH 181/217] Resolve CMake dependency issues (openDAQ/openDAQ#680) * Avoid forcing module build when test or example app requires it; instead, validate module existence before adding dependent build target. * Add markdown document with complete list of CMake build options * Remove unused CMake option OPENDAQ_ENABLE_APPLICATION and obsolete example app/test_app/ * Correct module dependencies for webpage examples being build with SDK --- shared/libraries/opcuatms/tests/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/shared/libraries/opcuatms/tests/CMakeLists.txt b/shared/libraries/opcuatms/tests/CMakeLists.txt index de099d6..949577c 100644 --- a/shared/libraries/opcuatms/tests/CMakeLists.txt +++ b/shared/libraries/opcuatms/tests/CMakeLists.txt @@ -4,6 +4,8 @@ project(opcuatms_integration_tests CXX) add_subdirectory(test_utils) -if (OPENDAQ_ENABLE_INTEGRATION_TESTS) +option(OPENDAQ_ENABLE_OPCUA_INTEGRATION_TESTS "Enable OpcUa integration testing" OFF) + +if (OPENDAQ_ENABLE_OPCUA_INTEGRATION_TESTS) add_subdirectory(opcuatms_integration) endif() From 85b913c17a2a06cacc521a31fb530e3a6f1ffb7e Mon Sep 17 00:00:00 2001 From: NikolaiShipilov <127689162+NikolaiShipilov@users.noreply.github.com> Date: Thu, 30 Jan 2025 04:33:33 -0800 Subject: [PATCH 182/217] IP modification mechanism (openDAQ/openDAQ#642) * shared libraries: - & extend MDNS discovery server and client to enable transmitting the custom non-discovery packages - Automatically advertise the ip-modification service within mdns discovery server if IP-modification is enabled within instance * core: - enable passing the root device reference to mdns servers * external dependencies: - Add patch for header-only mdns library to support custom non-discovery queries - Rename and extend parameters of mdns query callbacks * Discovery refactoring: - replace dependency on opendaq to dependency on coreobjects lib - replace modules callbacks with direct instantiation of DeviceInfo object using discovered device data - Rename services to servers for discovery - Move duplicating discovery and ip modification code into common library * Simulator: - Enable changing and retrieving IP config on simulator over netplan - Fix getting RefDevice SerialNumber from module options - Update vagrant installation for standalone build-packages ci job - Replace Avahi with internal mDNS server for OPC UA discovery - Remove Avahi from simulator and clean-up it's dependencies - Reduce simulator boot time when network is offline * Add cpp and python examples for IP modification * Fix unused variable warning in reader bindings --- .../opcua_client_module_impl.h | 1 + .../src/opcua_client_module_impl.cpp | 108 +++++++++--------- 2 files changed, 58 insertions(+), 51 deletions(-) diff --git a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h index e95e526..bff5d38 100644 --- a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h +++ b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h @@ -41,6 +41,7 @@ class OpcUaClientModule final : public Module static PropertyObjectPtr createDefaultConfig(); static void completeServerCapabilities(const DevicePtr& device, const StringPtr& deviceAddress); static PropertyObjectPtr populateDefaultConfig(const PropertyObjectPtr& config); + static DeviceInfoPtr populateDiscoveredDevice(const discovery::MdnsDiscoveredDevice& discoveredDevice); discovery::DiscoveryClient discoveryClient; std::mutex sync; diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 43a37cd..8ba1cda 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -13,6 +13,7 @@ #include #include #include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_CLIENT_MODULE @@ -29,52 +30,6 @@ OpcUaClientModule::OpcUaClientModule(ContextPtr context) std::move(context), "OpenDAQOPCUAClientModule") , discoveryClient( - { - [context = this->context](MdnsDiscoveredDevice discoveredDevice) - { - auto cap = ServerCapability(DaqOpcUaDeviceTypeId, "OpenDAQOPCUA", ProtocolType::Configuration); - if (!discoveredDevice.ipv4Address.empty()) - { - auto connectionStringIpv4 = fmt::format("{}://{}:{}{}", - DaqOpcUaDevicePrefix, - discoveredDevice.ipv4Address, - discoveredDevice.servicePort, - discoveredDevice.getPropertyOrDefault("path", "/")); - cap.addConnectionString(connectionStringIpv4); - cap.addAddress(discoveredDevice.ipv4Address); - - const auto addressInfo = AddressInfoBuilder().setAddress(discoveredDevice.ipv4Address) - .setReachabilityStatus(AddressReachabilityStatus::Unknown) - .setType("IPv4") - .setConnectionString(connectionStringIpv4) - .build(); - cap.addAddressInfo(addressInfo); - } - if(!discoveredDevice.ipv6Address.empty()) - { - auto connectionStringIpv6 = fmt::format("{}://{}:{}{}", - DaqOpcUaDevicePrefix, - discoveredDevice.ipv6Address, - discoveredDevice.servicePort, - discoveredDevice.getPropertyOrDefault("path", "/")); - cap.addConnectionString(connectionStringIpv6); - cap.addAddress(discoveredDevice.ipv6Address); - - const auto addressInfo = AddressInfoBuilder().setAddress(discoveredDevice.ipv6Address) - .setReachabilityStatus(AddressReachabilityStatus::Unknown) - .setType("IPv6") - .setConnectionString(connectionStringIpv6) - .build(); - cap.addAddressInfo(addressInfo); - } - cap.setConnectionType("TCP/IP"); - cap.setPrefix(DaqOpcUaDevicePrefix); - cap.setProtocolVersion(discoveredDevice.getPropertyOrDefault("protocolVersion", "")); - if (discoveredDevice.servicePort > 0) - cap.setPort(discoveredDevice.servicePort); - return cap; - } - }, {"OPENDAQ"} ) { @@ -84,11 +39,9 @@ OpcUaClientModule::OpcUaClientModule(ContextPtr context) ListPtr OpcUaClientModule::onGetAvailableDevices() { - auto availableDevices = discoveryClient.discoverDevices(); - for (auto device : availableDevices) - { - device.asPtr().setDeviceType(createDeviceType()); - } + auto availableDevices = List(); + for (const auto& device : discoveryClient.discoverMdnsDevices()) + availableDevices.pushBack(populateDiscoveredDevice(device)); return availableDevices; } @@ -187,6 +140,59 @@ PropertyObjectPtr OpcUaClientModule::populateDefaultConfig(const PropertyObjectP return defConfig; } +DeviceInfoPtr OpcUaClientModule::populateDiscoveredDevice(const MdnsDiscoveredDevice& discoveredDevice) +{ + PropertyObjectPtr deviceInfo = DeviceInfo(""); + DiscoveryClient::populateDiscoveredInfoProperties(deviceInfo, discoveredDevice); + + auto cap = ServerCapability(DaqOpcUaDeviceTypeId, "OpenDAQOPCUA", ProtocolType::Configuration); + if (!discoveredDevice.ipv4Address.empty()) + { + auto connectionStringIpv4 = fmt::format("{}://{}:{}{}", + DaqOpcUaDevicePrefix, + discoveredDevice.ipv4Address, + discoveredDevice.servicePort, + discoveredDevice.getPropertyOrDefault("path", "/")); + cap.addConnectionString(connectionStringIpv4); + cap.addAddress(discoveredDevice.ipv4Address); + + const auto addressInfo = AddressInfoBuilder().setAddress(discoveredDevice.ipv4Address) + .setReachabilityStatus(AddressReachabilityStatus::Unknown) + .setType("IPv4") + .setConnectionString(connectionStringIpv4) + .build(); + cap.addAddressInfo(addressInfo); + } + if(!discoveredDevice.ipv6Address.empty()) + { + auto connectionStringIpv6 = fmt::format("{}://{}:{}{}", + DaqOpcUaDevicePrefix, + discoveredDevice.ipv6Address, + discoveredDevice.servicePort, + discoveredDevice.getPropertyOrDefault("path", "/")); + cap.addConnectionString(connectionStringIpv6); + cap.addAddress(discoveredDevice.ipv6Address); + + const auto addressInfo = AddressInfoBuilder().setAddress(discoveredDevice.ipv6Address) + .setReachabilityStatus(AddressReachabilityStatus::Unknown) + .setType("IPv6") + .setConnectionString(connectionStringIpv6) + .build(); + cap.addAddressInfo(addressInfo); + } + cap.setConnectionType("TCP/IP"); + cap.setPrefix(DaqOpcUaDevicePrefix); + cap.setProtocolVersion(discoveredDevice.getPropertyOrDefault("protocolVersion", "")); + if (discoveredDevice.servicePort > 0) + cap.setPort(discoveredDevice.servicePort); + + deviceInfo.asPtr().addServerCapability(cap); + deviceInfo.asPtr().setConnectionString(cap.getConnectionString()); + deviceInfo.asPtr().setDeviceType(createDeviceType()); + + return deviceInfo; +} + StringPtr OpcUaClientModule::formConnectionString(const StringPtr& connectionString, const PropertyObjectPtr& config, std::string& host, int& port, std::string& hostType) { std::string urlString = connectionString.toStdString(); From 33f8488c8d0717becde2a5aa100de58f52fa4672 Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Thu, 30 Jan 2025 15:35:09 +0100 Subject: [PATCH 183/217] fix CI tests (openDAQ/openDAQ#683) * fix ServerCoreEvents segfault * mac os fix deadlock --- shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp b/shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp index 84e5da3..5bcf93e 100644 --- a/shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp +++ b/shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp @@ -61,9 +61,7 @@ OpcUaClient::OpcUaClient(const std::string& url) OpcUaClient::~OpcUaClient() { - stopIterate(); disconnect(); - clear(); } void OpcUaClient::initialize() @@ -217,12 +215,12 @@ void OpcUaClient::connect() void OpcUaClient::disconnect(bool doClear) { + stopIterate(); std::lock_guard guard(getLock()); + if (!uaclient) return; - stopIterate(); - UA_Client_disconnect(uaclient); if (doClear) @@ -328,8 +326,8 @@ void OpcUaClient::executeIterateCallback() UA_StatusCode OpcUaClient::iterate(std::chrono::milliseconds timeout) { - assert(timeout.count() >= 0); UA_Int32 timeoutMs = timeout.count(); + assert(timeoutMs >= 0); return UA_Client_run_iterate_timer_tasks(getLockedUaClient(), timeoutMs, true); } From 29c3ae5ad3e52f6db40d29d29d5d9417d782a38e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20R=C3=BChmer?= <108338550+Daniel-BB@users.noreply.github.com> Date: Thu, 13 Feb 2025 16:11:26 +0100 Subject: [PATCH 184/217] Fixed unknown std::chrono namespace issue introduced in VS2022 17.13.0 (openDAQ/openDAQ#698) --- .../opcua/opcuaclient/include/opcuaclient/opcuaclient.h | 1 + .../opcua/opcuaclient/tests/include/opcuaservertesthelper.h | 1 + 2 files changed, 2 insertions(+) diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h index d689e39..eb6ed23 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include diff --git a/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h b/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h index de9997e..b343a96 100644 --- a/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h +++ b/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h @@ -22,6 +22,7 @@ #include "opcuashared/opcua.h" #include "opcuashared/opcuacommon.h" #include +#include #include BEGIN_NAMESPACE_OPENDAQ_OPCUA From 1253be8ea8e5206e7e61c382c69ed152596b3f30 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko <96818661+JakaMohorkoDS@users.noreply.github.com> Date: Tue, 18 Feb 2025 11:42:39 +0100 Subject: [PATCH 185/217] Device info `setName` changed device name + setting owner prevents writing of read-only values (openDAQ/openDAQ#700) --- .../opcua_client_module/src/opcua_client_module_impl.cpp | 7 ++++--- .../libraries/opcuatms/opcuatms_client/src/tms_client.cpp | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 8ba1cda..bc7e612 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include BEGIN_NAMESPACE_OPENDAQ_OPCUA_CLIENT_MODULE @@ -90,8 +91,8 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, completeServerCapabilities(device, host); // Set the connection info for the device - DeviceInfoConfigPtr deviceInfo = device.getInfo(); - deviceInfo.setConnectionString(connectionString); + DeviceInfoPtr deviceInfo = device.getInfo(); + deviceInfo.asPtr().setProtectedPropertyValue("connectionString", connectionString); ServerCapabilityConfigPtr connectionInfo = deviceInfo.getConfigurationConnectionInfo(); const auto addressInfo = AddressInfoBuilder().setAddress(host) @@ -187,7 +188,7 @@ DeviceInfoPtr OpcUaClientModule::populateDiscoveredDevice(const MdnsDiscoveredDe cap.setPort(discoveredDevice.servicePort); deviceInfo.asPtr().addServerCapability(cap); - deviceInfo.asPtr().setConnectionString(cap.getConnectionString()); + deviceInfo.asPtr().setProtectedPropertyValue("connectionString", cap.getConnectionString()); deviceInfo.asPtr().setDeviceType(createDeviceType()); return deviceInfo; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp index bd47ede..89bf09d 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp @@ -66,7 +66,7 @@ daq::DevicePtr TmsClient::connect() auto device = TmsClientRootDevice(context, parent, rootDeviceBrowseName, tmsClientContext, rootDeviceNodeId); const auto deviceInfo = device.getInfo(); - deviceInfo.asPtr(true).setConnectionString(endpoint.getUrl()); + deviceInfo.asPtr().setProtectedPropertyValue("connectionString", endpoint.getUrl()); const std::string packageVersion = deviceInfo.getSdkVersion(); if (!packageVersion.empty() && packageVersion != OPENDAQ_PACKAGE_VERSION) From e62b038371532cf2b6b68951e8fa659bf09468ab Mon Sep 17 00:00:00 2001 From: Jaka Mohorko <96818661+JakaMohorkoDS@users.noreply.github.com> Date: Tue, 4 Mar 2025 13:22:54 +0100 Subject: [PATCH 186/217] Fix selection value dot access (openDAQ/openDAQ#719) --- .../opcua/opcuaclient/tests/src/test_opcuaasyncexecthread.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/shared/libraries/opcua/opcuaclient/tests/src/test_opcuaasyncexecthread.cpp b/shared/libraries/opcua/opcuaclient/tests/src/test_opcuaasyncexecthread.cpp index 05a34ba..6e7faee 100644 --- a/shared/libraries/opcua/opcuaclient/tests/src/test_opcuaasyncexecthread.cpp +++ b/shared/libraries/opcua/opcuaclient/tests/src/test_opcuaasyncexecthread.cpp @@ -1,6 +1,7 @@ #include "gtest/gtest.h" #include "opcuaclient/opcuaasyncexecthread.h" +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA From eb59a6782c2cf142ad56e91b90b19d32ca4702ea Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Fri, 7 Mar 2025 19:41:05 +0100 Subject: [PATCH 187/217] Device operation modes (openDAQ/openDAQ#704) --- .../tests/src/test_opcuaasyncexecthread.cpp | 2 +- .../objects/tms_client_device_impl.h | 4 ++ .../src/objects/tms_client_device_impl.cpp | 53 +++++++++++++++++++ .../tms_client_property_object_impl.cpp | 2 +- .../src/objects/tms_server_device.cpp | 34 +++++++++++- 5 files changed, 92 insertions(+), 3 deletions(-) diff --git a/shared/libraries/opcua/opcuaclient/tests/src/test_opcuaasyncexecthread.cpp b/shared/libraries/opcua/opcuaclient/tests/src/test_opcuaasyncexecthread.cpp index 6e7faee..e947ddc 100644 --- a/shared/libraries/opcua/opcuaclient/tests/src/test_opcuaasyncexecthread.cpp +++ b/shared/libraries/opcua/opcuaclient/tests/src/test_opcuaasyncexecthread.cpp @@ -1,5 +1,5 @@ #include "gtest/gtest.h" - +#include #include "opcuaclient/opcuaasyncexecthread.h" #include diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h index 2663776..85ab391 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h @@ -34,6 +34,10 @@ class TmsClientDeviceImpl : public TmsClientComponentBaseImplhasReference("OperationModeOptions")) + return this->makeErrorInfo(OPENDAQ_ERR_NOT_SUPPORTED, "OperationModes are not supported by the server"); + + const auto nodeId = getNodeId("OperationModeOptions"); + auto opModesNodeStrList = VariantConverter::ToDaqList(client->readValue(nodeId)); + *availableOpModes = opModesNodeStrList.detach(); + + return OPENDAQ_SUCCESS; + +} + +ErrCode TmsClientDeviceImpl::setOperationMode(IString* modeType) +{ + OPENDAQ_PARAM_NOT_NULL(modeType); + + if (!this->hasReference("OperationMode")) + return this->makeErrorInfo(OPENDAQ_ERR_NOT_SUPPORTED, "OperationModes are not supported by the server"); + + const auto nodeId = getNodeId("OperationMode"); + const auto modeTypeStr = StringPtr::Borrow(modeType).toStdString(); + + const auto variant = VariantConverter::ToVariant(String(modeTypeStr), nullptr, daqContext); + client->writeValue(nodeId, variant); + + return OPENDAQ_SUCCESS; +} + +ErrCode TmsClientDeviceImpl::setOperationModeRecursive(IString* modeType) +{ + OPENDAQ_PARAM_NOT_NULL(modeType); + const auto modeTypeStr = "Recursive" + StringPtr::Borrow(modeType).toStdString(); + return this->setOperationMode(String(modeTypeStr)); +} + +ErrCode TmsClientDeviceImpl::getOperationMode(IString** modeType) +{ + OPENDAQ_PARAM_NOT_NULL(modeType); + + if (!this->hasReference("OperationMode")) + return this->makeErrorInfo(OPENDAQ_ERR_NOT_SUPPORTED, "OperationModes are not supported by the server"); + + const auto nodeId = getNodeId("OperationMode"); + const auto variant = client->readValue(nodeId); + + *modeType = VariantConverter::ToDaqObject(variant, daqContext).detach(); + + return OPENDAQ_SUCCESS; +} + void TmsClientDeviceImpl::findAndCreateSubdevices() { std::map orderedDevices; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index 14b2dc9..ab71db1 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -23,7 +23,7 @@ using namespace opcua; namespace detail { - std::unordered_set ignoredPropertyNames{"ServerCapabilities"}; + std::unordered_set ignoredPropertyNames{"ServerCapabilities", "OperationMode", "OperationModeOptions"}; } template diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index 79feb21..6889227 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -107,7 +107,6 @@ void TmsServerDevice::bindCallbacks() if (!deviceDomain.assigned()) return OpcUaVariant{}; - const auto functionBlockNodeId = getChildNodeId("Domain"); try { OpcUaObject uaDeviceDomain; @@ -265,6 +264,39 @@ void TmsServerDevice::populateDeviceInfo() }); } } + + { + const auto opModeOptions = ListProperty("OperationModeOptions", List(), false); + const auto tmsOpModeOptions = std::make_shared(opModeOptions, server, daqContext, tmsContext, "OperationModeOptions"); + tmsOpModeOptions->registerOpcUaNode(this->nodeId); + deviceInfoProperties.push_back(tmsOpModeOptions); + this->addReadCallback(tmsOpModeOptions->getNodeId(), [this] + { + const auto opMode = object.getAvailableOperationModes(); + return VariantConverter::ToArrayVariant(opMode, nullptr, daqContext); + }); + + const auto opMode = StringProperty("OperationMode", "", false); + const auto tmsOpMode = std::make_shared(opMode, server, daqContext, tmsContext, "OperationMode"); + tmsOpMode->registerOpcUaNode(this->nodeId); + deviceInfoProperties.push_back(tmsOpMode); + + this->addReadCallback(tmsOpMode->getNodeId(), [this] + { + const auto opMode = object.getOperationMode(); + return VariantConverter::ToVariant(opMode, nullptr, daqContext); + }); + + this->addWriteCallback(tmsOpMode->getNodeId(), [this](const OpcUaVariant& variant) + { + const auto strValue = VariantConverter::ToDaqObject(variant).asPtr().toStdString(); + if (strValue.find("Recursive") == 0) + this->object.setOperationModeRecursive(strValue.substr(9)); + else + this->object.setOperationMode(strValue); + return UA_STATUSCODE_GOOD; + }); + } } void TmsServerDevice::populateServerCapabilities() From a08a3a762b3742044078ea448da4a96557c7e0d1 Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Fri, 14 Mar 2025 09:22:02 +0100 Subject: [PATCH 188/217] Logging improvement (openDAQ/openDAQ#721) --- .../src/opcua_client_module_impl.cpp | 10 ++++----- .../src/opcua_server_module_impl.cpp | 2 +- .../converters/list_conversion_utils.h | 6 ++--- .../src/converters/argument_converter.cpp | 6 ++--- .../src/converters/base_object_converter.cpp | 6 ++--- .../converters/complex_number_converter.cpp | 8 +++---- .../src/converters/core_types_converter.cpp | 22 +++++++++---------- .../converters/data_descriptor_converter.cpp | 8 +++---- .../src/converters/data_rule_converter.cpp | 18 +++++++-------- .../src/converters/dict_converter.cpp | 14 ++++++------ .../src/converters/dimension_converter.cpp | 6 ++--- .../converters/dimension_rule_converter.cpp | 20 ++++++++--------- .../function_block_type_converter.cpp | 6 ++--- .../generic_enumeration_converter.cpp | 8 +++---- .../converters/generic_struct_converter.cpp | 14 ++++++------ .../src/converters/number_converter.cpp | 8 +++---- .../src/converters/range_converter.cpp | 6 ++--- .../src/converters/ratio_converter.cpp | 8 +++---- .../src/converters/scaling_converter.cpp | 10 ++++----- .../src/converters/selection_converter.cpp | 10 ++++----- .../src/converters/unit_converter.cpp | 8 +++---- .../opcuatms/src/core_types_utils.cpp | 16 +++++++------- .../src/objects/tms_client_device_impl.cpp | 8 +++---- .../objects/tms_client_input_port_impl.cpp | 14 +++++++----- .../src/objects/tms_client_property_impl.cpp | 10 ++++----- .../tms_client_property_object_impl.cpp | 2 +- .../opcuatms_client/src/tms_client.cpp | 6 ++--- .../src/objects/tms_server_folder.cpp | 2 +- .../opcuatms_server/src/tms_server.cpp | 4 ++-- .../test_streaming_integration.cpp | 4 ++-- .../tms_object_integration_test.cpp | 4 ++-- 31 files changed, 139 insertions(+), 135 deletions(-) diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index bc7e612..a7b2b5f 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -60,7 +60,7 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, const PropertyObjectPtr& config) { if (!connectionString.assigned()) - throw ArgumentNullException(); + DAQ_THROW_EXCEPTION(ArgumentNullException); PropertyObjectPtr configPtr = config; if (!configPtr.assigned()) @@ -69,10 +69,10 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, configPtr = populateDefaultConfig(configPtr); if (!acceptsConnectionParameters(connectionString, configPtr)) - throw InvalidParameterException(); + DAQ_THROW_EXCEPTION(InvalidParameterException); if (!context.assigned()) - throw InvalidParameterException{"Context is not available."}; + DAQ_THROW_EXCEPTION(InvalidParameterException, "Context is not available."); std::string host; std::string hostType; @@ -236,10 +236,10 @@ StringPtr OpcUaClientModule::formConnectionString(const StringPtr& connectionStr path = match[4]; } else - throw InvalidParameterException("Host name not found in url: {}", connectionString); + DAQ_THROW_EXCEPTION(InvalidParameterException, "Host name not found in url: {}", connectionString); if (prefix != std::string(DaqOpcUaDevicePrefix) + "://") - throw InvalidParameterException("OpcUa does not support connection string with prefix {}", prefix); + DAQ_THROW_EXCEPTION(InvalidParameterException, "OpcUa does not support connection string with prefix {}", prefix); return std::string(OpcUaScheme) + "://" + host + ":" + std::to_string(port) + path; } diff --git a/modules/opcua_server_module/src/opcua_server_module_impl.cpp b/modules/opcua_server_module/src/opcua_server_module_impl.cpp index 75e82a7..ef50d40 100644 --- a/modules/opcua_server_module/src/opcua_server_module_impl.cpp +++ b/modules/opcua_server_module/src/opcua_server_module_impl.cpp @@ -29,7 +29,7 @@ ServerPtr OpcUaServerModule::onCreateServer(const StringPtr& serverType, const DevicePtr& rootDevice) { if (!context.assigned()) - throw InvalidParameterException{"Context parameter cannot be null."}; + DAQ_THROW_EXCEPTION(InvalidParameterException, "Context parameter cannot be null."); PropertyObjectPtr config = serverConfig; if (!config.assigned()) diff --git a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/list_conversion_utils.h b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/list_conversion_utils.h index ca3fe54..7a16cbf 100644 --- a/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/list_conversion_utils.h +++ b/shared/libraries/opcuatms/opcuatms/include/opcuatms/converters/list_conversion_utils.h @@ -64,7 +64,7 @@ inline OpcUaVariant ListConversionUtils::ToVariantTypeArrayVariant(const ListPtr inline ListPtr ListConversionUtils::VariantTypeArrayToList(const OpcUaVariant& variant, const ContextPtr& context) { if (!variant.isType()) - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); auto list = List(); const auto data = static_cast(variant->data); @@ -107,7 +107,7 @@ template ListPtr ListConversionUtils::VariantToList(const OpcUaVariant& variant, const ContextPtr& context) { if (!variant.isType()) - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); auto data = static_cast(variant->data); auto list = List(); @@ -151,7 +151,7 @@ template ListPtr ListConversionUtils::ExtensionObjectVariantToList(const OpcUaVariant& variant, const ContextPtr& context) { if (!variant.isType()) - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); const auto data = static_cast(variant->data); auto list = List(); diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/argument_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/argument_converter.cpp index b5a18a6..30b45fe 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/argument_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/argument_converter.cpp @@ -47,7 +47,7 @@ ArgumentInfoPtr VariantConverter::ToDaqObject(const OpcUaVariant& const auto decodedVariant = DecodeIfExtensionObject(variant); if (!decodedVariant.isType()) - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); return StructConverter::ToDaqObject(*static_cast(decodedVariant->data)); } @@ -62,7 +62,7 @@ OpcUaVariant VariantConverter::ToVariant(const ArgumentInfoPtr& o if (targetType == nullptr || targetType == &UA_TYPES[UA_TYPES_ARGUMENT]) variant.setScalar(*StructConverter::ToTmsType(object)); else - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); return variant; } @@ -82,7 +82,7 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr(list); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp index 7811cf8..180bdab 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/base_object_converter.cpp @@ -52,7 +52,7 @@ ListPtr VariantConverter::ToDaqList(const OpcUaVariant if (typeKind == UA_DATATYPEKIND_STRUCTURE || typeKind == UA_DATATYPEKIND_OPTSTRUCT) return VariantConverter::ToDaqList(variant, context); - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -100,7 +100,7 @@ BaseObjectPtr VariantConverter::ToDaqObject(const OpcUaVariant& var return VariantConverter::ToDaqObject(unwrapped, context); - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -172,7 +172,7 @@ OpcUaVariant VariantConverter::ToVariant(const BaseObjectPtr& objec } } - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); } END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/complex_number_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/complex_number_converter.cpp index dbb8970..ec59d5c 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/complex_number_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/complex_number_converter.cpp @@ -63,7 +63,7 @@ ComplexNumberPtr VariantConverter::ToDaqObject(const OpcUaVarian return StructConverter::ToDaqObject( *static_cast(decodedVariant->data)); - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -78,7 +78,7 @@ OpcUaVariant VariantConverter::ToVariant(const ComplexNumberPtr& else if (targetType == &UA_TYPES[UA_TYPES_COMPLEXNUMBERTYPE]) variant.setScalar(*StructConverter::ToTmsType(object)); else - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); return variant; } @@ -90,7 +90,7 @@ ListPtr VariantConverter::ToDaqList(const OpcUaV if (variant.isType()) return ListConversionUtils::VariantToList(variant); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -103,7 +103,7 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr(list); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/core_types_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/core_types_converter.cpp index 75856ff..a49d059 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/core_types_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/core_types_converter.cpp @@ -32,7 +32,7 @@ OpcUaVariant VariantConverter::ToVariant(const BoolPtr& object, const if (targetType == nullptr || targetType == &UA_TYPES[UA_TYPES_BOOLEAN]) return OpcUaVariant(static_cast(object)); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -49,7 +49,7 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& if (targetType == nullptr || targetType == &UA_TYPES[UA_TYPES_BOOLEAN]) return ListConversionUtils::ToArrayVariant(list); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } // Int @@ -181,7 +181,7 @@ OpcUaVariant VariantConverter::ToVariant(const IntegerPtr& object, con else if (targetType == &UA_TYPES[UA_TYPES_SBYTE]) variant.setScalar(*StructConverter::ToTmsType(object)); else - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); return variant; } @@ -206,7 +206,7 @@ ListPtr VariantConverter::ToDaqList(const OpcUaVariant& vari if (variant.isType()) return ListConversionUtils::VariantToList(variant); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -231,7 +231,7 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& if (targetType == &UA_TYPES[UA_TYPES_SBYTE]) return ListConversionUtils::ToArrayVariant(list); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } // Float @@ -279,7 +279,7 @@ OpcUaVariant VariantConverter::ToVariant(const FloatPtr& object, const U else if (targetType == &UA_TYPES[UA_TYPES_FLOAT]) variant.setScalar(*StructConverter::ToTmsType(object)); else - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); return variant; } @@ -292,7 +292,7 @@ ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, if (variant.isType()) return ListConversionUtils::VariantToList(variant); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -305,7 +305,7 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& lis if (targetType == &UA_TYPES[UA_TYPES_FLOAT]) return ListConversionUtils::ToArrayVariant(list); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } // String @@ -366,7 +366,7 @@ OpcUaVariant VariantConverter::ToVariant(const StringPtr& object, const else if (targetType == &UA_TYPES[UA_TYPES_QUALIFIEDNAME]) variant.setScalar(*StructConverter::ToTmsType(object)); else - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); return variant; } @@ -381,7 +381,7 @@ ListPtr VariantConverter::ToDaqList(const OpcUaVariant& varian if (variant.isType()) return ListConversionUtils::VariantToList(variant); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -394,7 +394,7 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& l if (targetType == &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]) return ListConversionUtils::ToArrayVariant(list); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/data_descriptor_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/data_descriptor_converter.cpp index 523926a..099d0fa 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/data_descriptor_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/data_descriptor_converter.cpp @@ -261,7 +261,7 @@ DataDescriptorPtr VariantConverter::ToDaqObject(const OpcUaVari return StructConverter::ToDaqObject(*tmsStruct); } - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -283,7 +283,7 @@ OpcUaVariant VariantConverter::ToVariant(const DataDescriptorPt else if (targetType ==&UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_STRUCTDESCRIPTORSTRUCTURE]) variant.setScalar(*StructConverter::ToTmsType(object)); else - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); return variant; } @@ -298,7 +298,7 @@ ListPtr VariantConverter::ToDaqList(const OpcU if (variant.isType()) return ListConversionUtils::VariantToList(variant); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -313,7 +313,7 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr(list); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/data_rule_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/data_rule_converter.cpp index f7991c0..2de529e 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/data_rule_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/data_rule_converter.cpp @@ -18,7 +18,7 @@ DataRulePtr StructConverter::ToDaq const ContextPtr& /*context*/) { if (tmsStruct.type != "linear") - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); const NumberPtr delta = VariantConverter::ToDaqObject(OpcUaVariant(tmsStruct.delta)); const NumberPtr start = VariantConverter::ToDaqObject(OpcUaVariant(tmsStruct.start)); @@ -49,7 +49,7 @@ DataRulePtr StructConverter::ToD const UA_ConstantRuleDescriptionStructure& tmsStruct, const ContextPtr& /*context*/) { if (tmsStruct.type != "constant") - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); const NumberPtr value = VariantConverter::ToDaqObject(tmsStruct.value); return ConstantDataRule(); @@ -75,7 +75,7 @@ DataRulePtr StructConverter::ToDaqOb const ContextPtr& /*context*/) { if (tmsStruct.type != "explicit") - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); return ExplicitDataRule(); } @@ -97,7 +97,7 @@ DataRulePtr StructConverter::ToDaqObject(OpcUaVariant(tmsStruct.minExpectedDelta)); const NumberPtr maxExpectedDelta = VariantConverter::ToDaqObject(OpcUaVariant(tmsStruct.maxExpectedDelta)); @@ -129,7 +129,7 @@ DataRulePtr StructConverter::ToDaq const ContextPtr& context) { if (tmsStruct.type != "custom") - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); auto params = Dict(); for (size_t i = 0; i < tmsStruct.parametersSize; i++) @@ -214,7 +214,7 @@ DataRulePtr VariantConverter::ToDaqObject(const OpcUaVariant& variant return StructConverter::ToDaqObject(*tmsStruct); } - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -262,7 +262,7 @@ OpcUaVariant VariantConverter::ToVariant(const DataRulePtr& object, c else if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_EXPLICITDOMAINRULEDESCRIPTIONSTRUCTURE]) variant.setScalar(*StructConverter::ToTmsType(object)); else - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); return variant; } @@ -283,7 +283,7 @@ ListPtr VariantConverter::ToDaqList(const OpcUaVariant& va if (variant.isType()) return ListConversionUtils::VariantToList(variant); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -303,7 +303,7 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr(list); if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_CUSTOMRULEDESCRIPTIONSTRUCTURE]) return ListConversionUtils::ToArrayVariant(list); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/dict_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/dict_converter.cpp index 866df74..4092778 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/dict_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/dict_converter.cpp @@ -29,10 +29,10 @@ namespace dict_converter if (extensionObject.isDecoded()) decodedVariant = extensionObject.getAsVariant(); else - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); if (!decodedVariant.isType()) - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); const auto decodedData = static_cast(decodedVariant->data); @@ -76,13 +76,13 @@ template <> DictPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& context) { if (variant.isScalar()) - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); if (variant.isType()) return dict_converter::ExtensionObjectToDict(variant, context); if (variant.isType()) return dict_converter::DaqKeyValuePairToDict(variant, context); - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -91,7 +91,7 @@ OpcUaVariant VariantConverter::ToVariant(const DictPtr::ToVariant(const DictPtr ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, const ContextPtr& /*context*/) { - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -123,7 +123,7 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& /*lis const UA_DataType* /*targetType*/, const ContextPtr& /*context*/) { - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/dimension_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/dimension_converter.cpp index 2cf693f..5ba5cba 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/dimension_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/dimension_converter.cpp @@ -62,7 +62,7 @@ DimensionPtr VariantConverter::ToDaqObject(const OpcUaVariant& varia const auto decodedVariant = DecodeIfExtensionObject(variant); if (!decodedVariant.isType()) - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); const auto tmsStruct = static_cast(decodedVariant->data); return StructConverter::ToDaqObject(*tmsStruct); @@ -77,7 +77,7 @@ OpcUaVariant VariantConverter::ToVariant(const DimensionPtr& object, if (targetType == nullptr || targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_DIMENSIONDESCRIPTORSTRUCTURE]) variant.setScalar(*StructConverter::ToTmsType(object)); else - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); return variant; } @@ -99,7 +99,7 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr(list); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/dimension_rule_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/dimension_rule_converter.cpp index d2d5ee2..9338fa7 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/dimension_rule_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/dimension_rule_converter.cpp @@ -21,10 +21,10 @@ DimensionRulePtr StructConverter::ToDaqObject(tmsStruct.delta); @@ -58,7 +58,7 @@ DimensionRulePtr StructConverter const UA_LogRuleDescriptionStructure& tmsStruct, const ContextPtr& /*context*/) { if (tmsStruct.type != "log") - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); const NumberPtr delta = VariantConverter::ToDaqObject(tmsStruct.delta); const NumberPtr start = VariantConverter::ToDaqObject(tmsStruct.start); @@ -92,11 +92,11 @@ DimensionRulePtr StructConverter list = List(); for (SizeT i = 0; i < elementsSize; i++) @@ -130,7 +130,7 @@ DimensionRulePtr StructConverter(); for (size_t i = 0; i < tmsStruct.parametersSize; i++) @@ -209,7 +209,7 @@ DimensionRulePtr VariantConverter::ToDaqObject(const OpcUaVarian return StructConverter::ToDaqObject(*tmsRuleDescription); } - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -254,7 +254,7 @@ OpcUaVariant VariantConverter::ToVariant(const DimensionRulePtr& else if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_CUSTOMRULEDESCRIPTIONSTRUCTURE]) variant.setScalar(*StructConverter::ToTmsType(object)); else - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); return variant; } @@ -273,7 +273,7 @@ ListPtr VariantConverter::ToDaqList(const OpcUaV if (variant.isType()) return ListConversionUtils::VariantToList(variant); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -292,7 +292,7 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr(list); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/function_block_type_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/function_block_type_converter.cpp index b1ba942..612d821 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/function_block_type_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/function_block_type_converter.cpp @@ -46,7 +46,7 @@ FunctionBlockTypePtr VariantConverter::ToDaqObject(const Opc const auto decodedVariant = DecodeIfExtensionObject(variant); if (!decodedVariant.isType()) - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); const auto tmsStruct = static_cast(decodedVariant->data); return StructConverter::ToDaqObject(*tmsStruct); @@ -62,7 +62,7 @@ OpcUaVariant VariantConverter::ToVariant(const FunctionBlock if (targetType == nullptr || targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_FUNCTIONBLOCKINFOSTRUCTURE]) variant.setScalar(*StructConverter::ToTmsType(object)); else - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); return variant; } @@ -84,7 +84,7 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr< if (targetType == nullptr || targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_FUNCTIONBLOCKINFOSTRUCTURE]) return ListConversionUtils::ToArrayVariant(list); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/generic_enumeration_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/generic_enumeration_converter.cpp index 649c182..44a9105 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/generic_enumeration_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/generic_enumeration_converter.cpp @@ -16,7 +16,7 @@ EnumerationPtr VariantConverter::ToDaqObject(const OpcUaVariant& v return nullptr; if (!context.assigned() || !context.getTypeManager().assigned()) - throw ConversionFailedException{"Generic numeration conversion requires the TypeManager."}; + DAQ_THROW_EXCEPTION(ConversionFailedException, "Generic numeration conversion requires the TypeManager."); const auto typeManager = context.getTypeManager(); @@ -28,7 +28,7 @@ EnumerationPtr VariantConverter::ToDaqObject(const OpcUaVariant& v if (typeManager.hasType(DataType->typeName)) Type = typeManager.getType(DataType->typeName); else - throw ConversionFailedException{"EnumerationType is not present in Type Manager."}; + DAQ_THROW_EXCEPTION(ConversionFailedException, "EnumerationType is not present in Type Manager."); DictPtr dictEnumValues = Type.getAsDictionary(); @@ -64,7 +64,7 @@ OpcUaVariant VariantConverter::ToVariant(const EnumerationPtr& obj template <> ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, const ContextPtr& context) { - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -72,7 +72,7 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr::ToDaqObject(const OpcUaVariant& variant, co return nullptr; if (!context.assigned() || !context.getTypeManager().assigned()) - throw ConversionFailedException{"Generic struct conversion requires the TypeManager."}; + DAQ_THROW_EXCEPTION(ConversionFailedException, "Generic struct conversion requires the TypeManager."); const auto typeManager = context.getTypeManager(); @@ -143,7 +143,7 @@ OpcUaVariant VariantConverter::ToVariant(const StructPtr& object, const { const auto type = GetUAStructureDataTypeByName(object.getStructType().getName()); if (type == nullptr) - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); const UA_DataTypeMember* members = type->members; const UA_UInt32 membersSize = type->membersSize; @@ -152,7 +152,7 @@ OpcUaVariant VariantConverter::ToVariant(const StructPtr& object, const const auto daqMembers = object.getAsDictionary(); if (membersSize != daqMembers.getCount()) - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); auto dst = reinterpret_cast(data); for (SizeT i = 0; i < membersSize; ++i) @@ -161,7 +161,7 @@ OpcUaVariant VariantConverter::ToVariant(const StructPtr& object, const const UA_DataType* memberType = member->memberType; if (!daqMembers.hasKey(member->memberName)) - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); auto daqMember = daqMembers.get(member->memberName); dst += member->padding; @@ -176,12 +176,12 @@ OpcUaVariant VariantConverter::ToVariant(const StructPtr& object, const continue; } - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } OpcUaVariant variant = VariantConverter::ToVariant(daqMember, memberType, context); if (variant->type != memberType && !(variant->data == UA_EMPTY_ARRAY_SENTINEL && variant->arrayLength == 0)) - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); void* src = variant->data; @@ -263,7 +263,7 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& l { auto convertedStruct = ToVariant(list[i], nullptr, context); if (convertedStruct->type != type) - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); UA_copy(convertedStruct->data, reinterpret_cast(dst), convertedStruct->type); dst += convertedStruct->type->memSize; diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/number_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/number_converter.cpp index 45bcdd7..05a5f94 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/number_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/number_converter.cpp @@ -22,7 +22,7 @@ NumberPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, co if (decodedVariant.isDouble()) return VariantConverter::ToDaqObject(decodedVariant); - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -36,13 +36,13 @@ OpcUaVariant VariantConverter::ToVariant(const NumberPtr& object, const if (object.getCoreType() == ctFloat) return VariantConverter::ToVariant(object.getFloatValue()); - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); } //TODO: Add if statements for target types of int and float - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -61,7 +61,7 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& l //TODO: Add if statements for target types of int and float - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); } END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/range_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/range_converter.cpp index 6b3b1bd..b50b09d 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/range_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/range_converter.cpp @@ -37,7 +37,7 @@ RangePtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, cons const auto decodedVariant = DecodeIfExtensionObject(variant); if (!decodedVariant.isType()) - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); return StructConverter::ToDaqObject(*static_cast(decodedVariant->data)); } @@ -50,7 +50,7 @@ OpcUaVariant VariantConverter::ToVariant(const RangePtr& object, const U if (targetType == nullptr || targetType == &UA_TYPES[UA_TYPES_RANGE]) variant.setScalar(*StructConverter::ToTmsType(object)); else - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); return variant; } @@ -69,7 +69,7 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& lis if (targetType == nullptr || targetType == &UA_TYPES[UA_TYPES_RANGE]) return ListConversionUtils::ToArrayVariant(list); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/ratio_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/ratio_converter.cpp index 4629a4c..2d150dd 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/ratio_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/ratio_converter.cpp @@ -69,7 +69,7 @@ RatioPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, cons return StructConverter::ToDaqObject(*tmsStruct); } - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -82,7 +82,7 @@ OpcUaVariant VariantConverter::ToVariant(const RatioPtr& object, const U else if (targetType == &UA_TYPES[UA_TYPES_RATIONALNUMBER]) variant.setScalar(*StructConverter::ToTmsType(object)); else - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); return variant; } @@ -97,7 +97,7 @@ ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, if (variant.isType()) return ListConversionUtils::VariantToList(variant); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -110,7 +110,7 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& lis if (targetType == &UA_TYPES[UA_TYPES_RATIONALNUMBER]) return ListConversionUtils::ToArrayVariant(list); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/scaling_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/scaling_converter.cpp index 4526f56..f82d362 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/scaling_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/scaling_converter.cpp @@ -47,7 +47,7 @@ OpcUaObject StructConverter scaling; scaling->type = UA_STRING_ALLOC("linear"); @@ -123,7 +123,7 @@ ScalingPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, return StructConverter::ToDaqObject(*tmsStruct); } - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -136,7 +136,7 @@ OpcUaVariant VariantConverter::ToVariant(const ScalingPtr& object, con else if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_LINEARSCALINGDESCRIPTIONSTRUCTURE]) variant.setScalar(*StructConverter::ToTmsType(object)); else - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); return variant; } @@ -151,7 +151,7 @@ ListPtr VariantConverter::ToDaqList(const OpcUaVariant& vari if (variant.isType()) return ListConversionUtils::VariantToList(variant); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -164,7 +164,7 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& if (targetType == &UA_TYPES_DAQBSP[UA_TYPES_DAQBSP_LINEARSCALINGDESCRIPTIONSTRUCTURE]) return ListConversionUtils::ToArrayVariant(list); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/selection_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/selection_converter.cpp index 16d8337..e1e24db 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/selection_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/selection_converter.cpp @@ -8,7 +8,7 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS BaseObjectPtr SelectionVariantConverter::ToDaqObject(const OpcUaVariant& variant, const ContextPtr& context) { if (!variant.isType()) - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); auto data = static_cast(variant->data); auto dict = Dict(); @@ -23,10 +23,10 @@ BaseObjectPtr SelectionVariantConverter::ToDaqObject(const OpcUaVariant& variant if (extensionObject.isDecoded()) decodedVariant = extensionObject.getAsVariant(); else - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); if (!decodedVariant.isType()) - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); const auto decodedData = static_cast(decodedVariant->data); @@ -46,7 +46,7 @@ BaseObjectPtr SelectionVariantConverter::ToDaqObject(const OpcUaVariant& variant OpcUaVariant SelectionVariantConverter::ToVariant(const BaseObjectPtr& selectionValues, const ContextPtr& context) { if (!selectionValues.assigned()) - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); const auto list = selectionValues.asPtrOrNull(); if (list.assigned()) @@ -56,7 +56,7 @@ OpcUaVariant SelectionVariantConverter::ToVariant(const BaseObjectPtr& selection if (dict.assigned()) return DictToVariant(dict, context); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } OpcUaObject SelectionVariantConverter::ToKeyValuePair(const IntegerPtr& key, diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/unit_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/unit_converter.cpp index 410ec32..265229c 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/unit_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/unit_converter.cpp @@ -77,7 +77,7 @@ UnitPtr VariantConverter::ToDaqObject(const OpcUaVariant& variant, const if (decodedVariant.isType()) return StructConverter::ToDaqObject(*static_cast(decodedVariant->data)); - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -90,7 +90,7 @@ OpcUaVariant VariantConverter::ToVariant(const UnitPtr& object, const UA_ else if (targetType == &UA_TYPES[UA_TYPES_EUINFORMATION]) variant.setScalar(*StructConverter::ToTmsType(object)); else - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); return variant; } @@ -105,7 +105,7 @@ ListPtr VariantConverter::ToDaqList(const OpcUaVariant& variant, c if (variant.isType()) return ListConversionUtils::VariantToList(variant); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } template <> @@ -118,7 +118,7 @@ OpcUaVariant VariantConverter::ToArrayVariant(const ListPtr& list, if (targetType == &UA_TYPES[UA_TYPES_EUINFORMATION]) return ListConversionUtils::ToArrayVariant(list); - throw ConversionFailedException{}; + DAQ_THROW_EXCEPTION(ConversionFailedException); } END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp b/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp index a0ea61b..5237909 100644 --- a/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/core_types_utils.cpp @@ -104,7 +104,7 @@ SampleType SampleTypeFromTmsEnum(UA_SampleTypeEnumeration tmsEnum) case UA_SAMPLETYPEENUMERATION_RANGEINT64: return SampleType::RangeInt64; default: - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); } } @@ -147,11 +147,11 @@ UA_SampleTypeEnumeration SampleTypeToTmsEnum(SampleType daqEnum) case SampleType::Struct: return UA_SAMPLETYPEENUMERATION_INVALID; case SampleType::Null: - throw ConversionFailedException( + DAQ_THROW_EXCEPTION(ConversionFailedException, "SampleType \"Null\" is not convertible and reserved for \"DATA_DESCRIPTOR_CHANGED\" event packet." ); default: - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); } } @@ -164,7 +164,7 @@ ScaledSampleType ScaledSampleTypeFromTmsEnum(UA_SampleTypeEnumeration tmsEnum) case UA_SAMPLETYPEENUMERATION_FLOAT64: return ScaledSampleType::Float64; default: - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); } } @@ -177,7 +177,7 @@ UA_SampleTypeEnumeration ScaledSampleTypeToTmsEnum(ScaledSampleType daqEnum) case ScaledSampleType::Float64: return UA_SAMPLETYPEENUMERATION_FLOAT64; default: - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); } } @@ -204,7 +204,7 @@ OpcUaNodeId CoreTypeToUANodeID(CoreType type) case ctComplexNumber: case ctUndefined: default: - throw ConversionFailedException{"Mapping between core type and node id is not available"}; + DAQ_THROW_EXCEPTION(ConversionFailedException, "Mapping between core type and node id is not available"); } } @@ -212,7 +212,7 @@ CoreType UANodeIdToCoreType(OpcUaNodeId nodeId) { if (const auto it = details::nodeIdToCoreTypeMap.find(nodeId); it != details::nodeIdToCoreTypeMap.cend()) return it->second; - throw ConversionFailedException{"Mapping between node id and core type is not available."}; + DAQ_THROW_EXCEPTION(ConversionFailedException, "Mapping between node id and core type is not available."); } OpcUaVariant DecodeIfExtensionObject(const OpcUaVariant& variant) @@ -224,7 +224,7 @@ OpcUaVariant DecodeIfExtensionObject(const OpcUaVariant& variant) if (extensionObject.isDecoded()) return extensionObject.getAsVariant(); - throw ConversionFailedException(); + DAQ_THROW_EXCEPTION(ConversionFailedException); } return variant; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index fc6824c..ca974d2 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -135,7 +135,7 @@ ErrCode TmsClientDeviceImpl::getAvailableOperationModes(IList** availableOpModes OPENDAQ_PARAM_NOT_NULL(availableOpModes); if (!this->hasReference("OperationModeOptions")) - return this->makeErrorInfo(OPENDAQ_ERR_NOT_SUPPORTED, "OperationModes are not supported by the server"); + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_NOT_SUPPORTED, "OperationModes are not supported by the server"); const auto nodeId = getNodeId("OperationModeOptions"); auto opModesNodeStrList = VariantConverter::ToDaqList(client->readValue(nodeId)); @@ -150,7 +150,7 @@ ErrCode TmsClientDeviceImpl::setOperationMode(IString* modeType) OPENDAQ_PARAM_NOT_NULL(modeType); if (!this->hasReference("OperationMode")) - return this->makeErrorInfo(OPENDAQ_ERR_NOT_SUPPORTED, "OperationModes are not supported by the server"); + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_NOT_SUPPORTED, "OperationModes are not supported by the server"); const auto nodeId = getNodeId("OperationMode"); const auto modeTypeStr = StringPtr::Borrow(modeType).toStdString(); @@ -164,7 +164,7 @@ ErrCode TmsClientDeviceImpl::setOperationMode(IString* modeType) ErrCode TmsClientDeviceImpl::setOperationModeRecursive(IString* modeType) { OPENDAQ_PARAM_NOT_NULL(modeType); - const auto modeTypeStr = "Recursive" + StringPtr::Borrow(modeType).toStdString(); + const auto modeTypeStr = "Recursive" + StringPtr::Borrow(modeType).toStdString(); return this->setOperationMode(String(modeTypeStr)); } @@ -173,7 +173,7 @@ ErrCode TmsClientDeviceImpl::getOperationMode(IString** modeType) OPENDAQ_PARAM_NOT_NULL(modeType); if (!this->hasReference("OperationMode")) - return this->makeErrorInfo(OPENDAQ_ERR_NOT_SUPPORTED, "OperationModes are not supported by the server"); + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_NOT_SUPPORTED, "OperationModes are not supported by the server"); const auto nodeId = getNodeId("OperationMode"); const auto variant = client->readValue(nodeId); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp index 72399bc..e75eff2 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp @@ -39,7 +39,8 @@ ErrCode TmsClientInputPortImpl::acceptsSignal(ISignal* signal, Bool* accepts) { return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; - //return daqTry([&]() { + //return daqTry([&]() + //{ // OpcUaNodeId methodId(NAMESPACE_DAQBSP, UA_DAQBSPID_INPUTPORTTYPE_ACCEPTSSIGNAL); // auto signalNodeId = clientContext->getNodeId(signal); @@ -60,9 +61,10 @@ ErrCode TmsClientInputPortImpl::acceptsSignal(ISignal* signal, Bool* accepts) ErrCode TmsClientInputPortImpl::connect(ISignal* signal) { - return daqTry([&]() { + return daqTry([&]() + { if (!isChildComponent(signal)) - throw NotFoundException(); + DAQ_THROW_EXCEPTION(NotFoundException); const SignalPtr signalPtr = signal; const auto methodNodeId = getNodeId("Connect"); @@ -87,7 +89,8 @@ ErrCode TmsClientInputPortImpl::connect(ISignal* signal) ErrCode TmsClientInputPortImpl::disconnect() { - return daqTry([&]() { + return daqTry([&]() + { const auto methodNodeId = getNodeId("Disconnect"); auto request = OpcUaCallMethodRequest(); @@ -134,7 +137,8 @@ SignalPtr TmsClientInputPortImpl::onGetSignal() ErrCode TmsClientInputPortImpl::getConnection(IConnection** connection) { - return daqTry([&]() { + return daqTry([&]() + { // TODO: Implement. Awaits support to implement return OPENDAQ_ERR_NOTIMPLEMENTED; }); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp index 11ce84a..bb69199 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_impl.cpp @@ -46,7 +46,7 @@ TmsClientPropertyImpl::TmsClientPropertyImpl(const ContextPtr& daqContext, const : TmsClientObjectImpl(daqContext, ctx, nodeId) { if (!this->daqContext.getLogger().assigned()) - throw ArgumentNullException("Logger must not be null"); + DAQ_THROW_EXCEPTION(ArgumentNullException, "Logger must not be null"); this->loggerComponent = this->daqContext.getLogger().getOrAddComponent("TmsClientPropertyImpl"); this->name = propertyName; @@ -190,7 +190,7 @@ void TmsClientPropertyImpl::configurePropertyFields() if (clientContext->getReferenceBrowser()->isSubtypeOf(dataType, enumerationTypeId)) { if (value->type != &UA_TYPES[UA_TYPES_INT32]) - throw ConversionFailedException{"Enumeration node data type is not uint32_t"}; + DAQ_THROW_EXCEPTION(ConversionFailedException, "Enumeration node data type is not uint32_t"); const auto enumBrowseName = client->readBrowseName(dataType); const auto enumType = GetUAEnumerationDataTypeByName(enumBrowseName); @@ -201,7 +201,7 @@ void TmsClientPropertyImpl::configurePropertyFields() else this->defaultValue = VariantConverter::ToDaqObject(value, daqContext); - if (this->defaultValue.assigned() && this->defaultValue.supportsInterface()) + if (this->defaultValue.supportsInterface()) this->defaultValue.freeze(); break; @@ -225,7 +225,7 @@ void TmsClientPropertyImpl::configurePropertyFields() { this->suggestedValues = VariantConverter::ToDaqList(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE), daqContext); - if (this->suggestedValues.assigned() && this->suggestedValues.supportsInterface()) + if (this->suggestedValues.supportsInterface()) this->suggestedValues.freeze(); break; } @@ -233,7 +233,7 @@ void TmsClientPropertyImpl::configurePropertyFields() { this->selectionValues = SelectionVariantConverter::ToDaqObject(reader->getValue(childNodeId, UA_ATTRIBUTEID_VALUE)); - if (this->selectionValues.assigned() && this->selectionValues.supportsInterface()) + if (this->selectionValues.supportsInterface()) this->selectionValues.freeze(); break; } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index ab71db1..4dda7a9 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -93,7 +93,7 @@ template void TmsClientPropertyObjectBaseImpl::init() { if (!this->daqContext.getLogger().assigned()) - throw ArgumentNullException("Logger must not be null"); + DAQ_THROW_EXCEPTION(ArgumentNullException, "Logger must not be null"); this->loggerComponent = this->daqContext.getLogger().getOrAddComponent("TmsClientPropertyObject"); clientContext->readObjectAttributes(nodeId); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp index 89bf09d..4e672bd 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp @@ -93,7 +93,7 @@ void TmsClient::getRootDeviceNodeAttributes(OpcUaNodeId& nodeIdOut, std::string& const auto& references = tmsClientContext->getReferenceBrowser()->browseFiltered(rootNodeId, filter); if (references.byNodeId.empty()) - throw NotFoundException(); + DAQ_THROW_EXCEPTION(NotFoundException); nodeIdOut = OpcUaNodeId(references.byBrowseName.begin().value()->nodeId.nodeId); browseNameOut = references.byBrowseName.begin().key(); @@ -112,9 +112,9 @@ void TmsClient::createAndConectClient() { case UA_STATUSCODE_BADUSERACCESSDENIED: case UA_STATUSCODE_BADIDENTITYTOKENINVALID: - throw AuthenticationFailedException(e.what()); + DAQ_THROW_EXCEPTION(AuthenticationFailedException, e.what()); default: - throw NotFoundException(e.what()); + DAQ_THROW_EXCEPTION(NotFoundException, e.what()); } } } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp index 435b791..45f3388 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_folder.cpp @@ -40,7 +40,7 @@ void TmsServerFolder::addChildNodes() } else { - throw daq::NotImplementedException("Unhandled item: " + item.getGlobalId()); + DAQ_THROW_EXCEPTION(daq::NotImplementedException, "Unhandled item: " + item.getGlobalId()); } } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp index 16f4d5d..42ef62b 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp @@ -42,9 +42,9 @@ void TmsServer::setOpcUaPath(const std::string& path) void TmsServer::start() { if (!device.assigned()) - throw InvalidStateException("Device is not set."); + DAQ_THROW_EXCEPTION(InvalidStateException, "Device is not set."); if (!context.assigned()) - throw InvalidStateException("Context is not set."); + DAQ_THROW_EXCEPTION(InvalidStateException, "Context is not set."); server = std::make_shared(); server->setPort(opcUaPort); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp index f9a5588..61da5a0 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp @@ -83,7 +83,7 @@ class StreamingIntegrationTest : public testing::Test } } - throw NotFoundException(); + DAQ_THROW_EXCEPTION(NotFoundException); } PacketReaderPtr createReader(const DevicePtr& device, const std::string& signalName) @@ -97,7 +97,7 @@ class StreamingIntegrationTest : public testing::Test return PacketReader(signal); } - throw NotFoundException(); + DAQ_THROW_EXCEPTION(NotFoundException); } ListPtr tryReadPackets(const PacketReaderPtr& reader, diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp index e4d3708..d147f7b 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/tms_object_integration_test.cpp @@ -30,10 +30,10 @@ void TmsObjectIntegrationTest::SetUp() LastMessageLoggerSinkPrivatePtr TmsObjectIntegrationTest::getPrivateSink() { if(!debugSink.assigned()) - throw ArgumentNullException("Sink must not be null"); + DAQ_THROW_EXCEPTION(ArgumentNullException, "Sink must not be null"); auto sinkPtr = debugSink.asPtrOrNull(); if (sinkPtr == nullptr) - throw InvalidTypeException("Wrong sink. GetLastMessage supports only by LastMessageLoggerSink"); + DAQ_THROW_EXCEPTION(InvalidTypeException, "Wrong sink. GetLastMessage supports only by LastMessageLoggerSink"); return sinkPtr; } From b0f15be7a252a2ea91c3248a490a3be48f06c02d Mon Sep 17 00:00:00 2001 From: Jaka Mohorko <96818661+JakaMohorkoDS@users.noreply.github.com> Date: Mon, 17 Mar 2025 16:27:54 +0100 Subject: [PATCH 189/217] Nested property object cleanup (openDAQ/openDAQ#731) --- .../objects/tms_client_property_object_impl.h | 11 +- .../objects/tms_client_sync_component_impl.h | 4 - .../tms_client_property_object_impl.cpp | 87 ++++- .../opcuatms_integration/test_tms_device.cpp | 18 +- .../test_tms_integration.cpp | 30 ++ .../test_tms_property_object.cpp | 341 ++++++++++++++++++ 6 files changed, 465 insertions(+), 26 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h index 6cf352d..da51fd2 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_property_object_impl.h @@ -143,7 +143,8 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl std::map propBrowseName; opcua::OpcUaNodeId methodParentNodeId; LoggerComponentPtr loggerComponent; - + + ErrCode setOPCUAPropertyValueInternal(IString* propertyName, IBaseObject* value, bool protectedWrite); void addProperties(const OpcUaNodeId& parentId, std::map& orderedProperties, std::vector& unorderedProperties); @@ -153,8 +154,12 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl std::unordered_map& functionPropValues); PropertyPtr addVariableBlockProperty(const StringPtr& propName, const OpcUaNodeId& propNodeId); void browseRawProperties(); - bool isIgnoredMethodPeoperty(const std::string& browseName); - virtual ErrCode INTERFACE_FUNC setPropertyValueInternal(IString* propertyName, IBaseObject* value, bool protectedWrite); + bool isIgnoredMethodProperty(const std::string& browseName); + PropertyObjectPtr cloneChildPropertyObject(const PropertyPtr& prop) override; + +private: + bool isBasePropertyObject(const PropertyObjectPtr& propObj); }; + END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_sync_component_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_sync_component_impl.h index 17317d4..ffc78c3 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_sync_component_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_sync_component_impl.h @@ -34,10 +34,6 @@ class TmsClientSyncComponentImpl : public TmsClientComponentBaseImpl -ErrCode TmsClientPropertyObjectBaseImpl::setPropertyValueInternal(IString* propertyName, IBaseObject* value, bool protectedWrite) +ErrCode TmsClientPropertyObjectBaseImpl::setOPCUAPropertyValueInternal(IString* propertyName, IBaseObject* value, bool protectedWrite) { if (propertyName == nullptr) { @@ -36,6 +36,22 @@ ErrCode TmsClientPropertyObjectBaseImpl::setPropertyValueInternal(IString* } auto propertyNamePtr = StringPtr::Borrow(propertyName); + StringPtr childName; + StringPtr subName; + if (this->isChildProperty(propertyNamePtr, childName, subName)) + { + PropertyPtr prop; + ErrCode err = getProperty(propertyNamePtr, &prop); + if (OPENDAQ_FAILED(err)) + return err; + + if (!prop.assigned()) + throw NotFoundException(R"(Child property "{}" not found)", propertyNamePtr); + if (protectedWrite) + return prop.asPtr()->setValueProtected(value); + return prop->setValue(value); + } + StringPtr lastProcessDescription = ""; ErrCode errCode = daqTry( [&]() @@ -103,13 +119,13 @@ void TmsClientPropertyObjectBaseImpl::init() template ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::setPropertyValue(IString* propertyName, IBaseObject* value) { - return setPropertyValueInternal(propertyName, value, false); + return setOPCUAPropertyValueInternal(propertyName, value, false); } template ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::setProtectedPropertyValue(IString* propertyName, IBaseObject* value) { - return setPropertyValueInternal(propertyName, value, true); + return setOPCUAPropertyValueInternal(propertyName, value, true); } template @@ -122,6 +138,21 @@ ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::getPropertyValue(I } auto propertyNamePtr = StringPtr::Borrow(propertyName); + StringPtr childName; + StringPtr subName; + if (this->isChildProperty(propertyNamePtr, childName, subName)) + { + PropertyPtr prop; + ErrCode err = getProperty(propertyNamePtr, &prop); + if (OPENDAQ_FAILED(err)) + return err; + + if (!prop.assigned()) + throw NotFoundException(R"(Child property "{}" not found)", propertyNamePtr); + + return prop->getValue(value); + } + StringPtr lastProccessDescription = ""; ErrCode errCode = daqTry([&] { @@ -136,11 +167,6 @@ ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::getPropertyValue(I const auto refProp = this->objPtr.getProperty(propertyName).getReferencedProperty(); return getPropertyValue(refProp.getName(), value); } - else if (const auto& objIt = objectTypeIdMap.find(propertyNamePtr); objIt != objectTypeIdMap.cend()) - { - *value = TmsClientPropertyObject(daqContext, clientContext, objIt->second).detach(); - return OPENDAQ_SUCCESS; - } return Impl::getPropertyValue(propertyName, value); }); @@ -332,7 +358,14 @@ void TmsClientPropertyObjectBaseImpl::addProperties(const OpcUaNodeId& par try { if (!hasProp) + { prop = addVariableBlockProperty(propName, childNodeId); + } + else if (this->objPtr.template supportsInterface()) + { + Impl::removeProperty(propName); + prop = addVariableBlockProperty(propName, childNodeId); + } objectTypeIdMap.emplace(propName, childNodeId); } @@ -371,7 +404,7 @@ void TmsClientPropertyObjectBaseImpl::addMethodProperties(const OpcUaNodeI const auto typeId = OpcUaNodeId(ref->typeDefinition.nodeId); const auto propName = String(utils::ToStdString(ref->browseName.name)); - if (isIgnoredMethodPeoperty(propName)) + if (isIgnoredMethodProperty(propName)) continue; Bool hasProp; @@ -510,11 +543,45 @@ void TmsClientPropertyObjectBaseImpl::browseRawProperties() } template -bool TmsClientPropertyObjectBaseImpl::isIgnoredMethodPeoperty(const std::string& browseName) +bool TmsClientPropertyObjectBaseImpl::isIgnoredMethodProperty(const std::string& browseName) { return browseName == "BeginUpdate" || browseName == "EndUpdate" || browseName == "GetErrorInformation"; } +template +PropertyObjectPtr TmsClientPropertyObjectBaseImpl::cloneChildPropertyObject(const PropertyPtr& prop) +{ + const auto propPtrInternal = prop.asPtr(); + if (propPtrInternal.assigned() && propPtrInternal.getValueTypeUnresolved() == ctObject && prop.getDefaultValue().assigned()) + { + const auto propName = prop.getName(); + const auto defaultValueObj = prop.getDefaultValue().asPtrOrNull(); + if (!defaultValueObj.assigned()) + return nullptr; + + if (!isBasePropertyObject(defaultValueObj)) + { + return defaultValueObj.asPtr(true).clone(); + } + + if (const auto& objIt = objectTypeIdMap.find(propName); objIt != objectTypeIdMap.cend()) + { + return TmsClientPropertyObject(daqContext, clientContext, objIt->second); + } + + throw NotFoundException{"Object property with name {} not found", propName}; + } + + return nullptr; +} + +template +bool TmsClientPropertyObjectBaseImpl::isBasePropertyObject(const PropertyObjectPtr& propObj) +{ + return !propObj.supportsInterface() + && !propObj.supportsInterface(); +} + template class TmsClientPropertyObjectBaseImpl; template class TmsClientPropertyObjectBaseImpl>; template class TmsClientPropertyObjectBaseImpl>; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp index 33a5308..71a3fc9 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_device.cpp @@ -581,22 +581,22 @@ TEST_F(TmsDeviceTest, DeviceInfoNotChangeableField) ASSERT_EQ("server_manufacturer_2", serverDeviceInfo.getManufacturer()); ASSERT_EQ("manufacturer", clientDeviceInfo.getManufacturer()); - serverDeviceInfo.asPtr(true).setManufacturer("server_manufacturer_3"); - ASSERT_EQ("server_manufacturer_3", serverDeviceInfo.getManufacturer()); + ASSERT_ANY_THROW(serverDeviceInfo.asPtr(true).setManufacturer("server_manufacturer_3")); + ASSERT_EQ("server_manufacturer_2", serverDeviceInfo.getManufacturer()); ASSERT_EQ("manufacturer", clientDeviceInfo.getManufacturer()); } { ASSERT_ANY_THROW(clientDeviceInfo.setPropertyValue("manufacturer", "client_manufacturer")); - ASSERT_EQ("server_manufacturer_3", serverDeviceInfo.getManufacturer()); + ASSERT_EQ("server_manufacturer_2", serverDeviceInfo.getManufacturer()); ASSERT_EQ("manufacturer", clientDeviceInfo.getManufacturer()); - clientDeviceInfo.asPtr(true).setProtectedPropertyValue("manufacturer", "client_manufacturer_2"); - ASSERT_EQ("server_manufacturer_3", serverDeviceInfo.getManufacturer()); - ASSERT_EQ("client_manufacturer_2", clientDeviceInfo.getManufacturer()); + clientDeviceInfo.asPtr(true).setProtectedPropertyValue("manufacturer", "client_manufacturer_3"); + ASSERT_EQ("server_manufacturer_2", serverDeviceInfo.getManufacturer()); + ASSERT_EQ("client_manufacturer_3", clientDeviceInfo.getManufacturer()); - clientDeviceInfo.asPtr(true).setManufacturer("client_manufacturer_3"); - ASSERT_EQ("server_manufacturer_3", serverDeviceInfo.getManufacturer()); + ASSERT_ANY_THROW(clientDeviceInfo.asPtr(true).setManufacturer("client_manufacturer_3")); + ASSERT_EQ("server_manufacturer_2", serverDeviceInfo.getManufacturer()); ASSERT_EQ("client_manufacturer_3", clientDeviceInfo.getManufacturer()); } -} \ No newline at end of file +} diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index 87f2dcd..ecf2663 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -409,6 +409,36 @@ TEST_F(TmsIntegrationTest, BeginEndUpdateDevice) ASSERT_NO_THROW(clientDevice.endUpdate()); } + +TEST_F(TmsIntegrationTest, SyncComponentNoSubdevices) +{ + auto inst = Instance(); + auto serverTypeManager = inst.getContext().getTypeManager(); + auto serverSync = inst.getSyncComponent(); + SyncComponentPrivatePtr syncComponentPrivate = serverSync.asPtr(true); + + syncComponentPrivate.addInterface(PropertyObject(serverTypeManager, "PtpSyncInterface")); + syncComponentPrivate.addInterface(PropertyObject(serverTypeManager, "InterfaceClockSync")); + + serverSync.setSelectedSource(1); + + TmsServer tmsServer(inst); + tmsServer.start(); + + TmsClient tmsClient(inst.getContext(), nullptr, OPC_URL); + DevicePtr clientDevice = tmsClient.connect(); + auto clientSync = clientDevice.getSyncComponent(); + + ASSERT_EQ(serverSync.getSelectedSource(), clientSync.getSelectedSource()); + ASSERT_EQ(serverSync.getSyncLocked(), clientSync.getSyncLocked()); + + auto serverInterfaces = serverSync.getInterfaces(); + auto clientInterfaces = clientSync.getInterfaces(); + + ASSERT_EQ(serverInterfaces.getCount(), clientInterfaces.getCount()); + ASSERT_EQ(serverInterfaces.getKeyList(), clientInterfaces.getKeyList()); +} + TEST_F(TmsIntegrationTest, SyncComponent) { InstancePtr device = createDevice(); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp index 84e29c5..051b4cd 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp @@ -10,6 +10,7 @@ #include "tms_object_integration_test.h" #include #include +#include #include #include @@ -262,3 +263,343 @@ TEST_F(TmsPropertyObjectTest, TestReadOnlyWriteFail) ASSERT_EQ(clientObj.getPropertyValue("ReadOnly"), 0); ASSERT_THROW(clientObj.setPropertyValue("ReadOnly", 100), AccessDeniedException); } + +TEST_F(TmsPropertyObjectTest, DotAccessClient) +{ + PropertyObjectPtr obj = PropertyObject(); + PropertyObjectPtr child1 = PropertyObject(); + PropertyObjectPtr child2 = PropertyObject(); + + child2.addProperty(StringProperty("foo", "bar")); + child1.addProperty(ObjectProperty("child", child2)); + obj.addProperty(ObjectProperty("child", child1)); + + auto [serverObj, clientObj] = registerPropertyObject(obj); + + auto prop = clientObj.getProperty("child.child.foo"); + + ASSERT_EQ(clientObj.getPropertyValue("child.child.foo"), "bar"); + ASSERT_EQ(prop.getValue(), "bar"); + + ASSERT_NO_THROW(clientObj.setPropertyValue("child.child.foo", "test")); + ASSERT_EQ(obj.getPropertyValue("child.child.foo"), "test"); + ASSERT_EQ(prop.getValue(), "test"); + ASSERT_EQ(clientObj.getPropertyValue("child.child.foo"), "test"); + + ASSERT_NO_THROW(prop.setValue("bar")); + ASSERT_EQ(obj.getPropertyValue("child.child.foo"), "bar"); + ASSERT_EQ(prop.getValue(), "bar"); + ASSERT_EQ(clientObj.getPropertyValue("child.child.foo"), "bar"); +} + +TEST_F(TmsPropertyObjectTest, DotAccessClientSelection) +{ + PropertyObjectPtr obj = PropertyObject(); + PropertyObjectPtr child1 = PropertyObject(); + PropertyObjectPtr child2 = PropertyObject(); + + child2.addProperty(SelectionProperty("fruit", List("apple", "orange", "banana"), 0)); + child1.addProperty(ObjectProperty("child", child2)); + obj.addProperty(ObjectProperty("child", child1)); + + auto [serverObj, clientObj] = registerPropertyObject(obj); + + auto prop = clientObj.getProperty("child.child.fruit"); + + ASSERT_EQ(clientObj.getPropertyValue("child.child.fruit"), 0); + ASSERT_EQ(prop.getValue(), 0); + ASSERT_EQ(clientObj.getPropertySelectionValue("child.child.fruit"), "apple"); + ASSERT_EQ(obj.getPropertySelectionValue("child.child.fruit"), "apple"); + + ASSERT_NO_THROW(clientObj.setPropertyValue("child.child.fruit", 1)); + ASSERT_EQ(clientObj.getPropertyValue("child.child.fruit"), 1); + ASSERT_EQ(prop.getValue(), 1); + ASSERT_EQ(clientObj.getPropertySelectionValue("child.child.fruit"), "orange"); + ASSERT_EQ(obj.getPropertySelectionValue("child.child.fruit"), "orange"); + + ASSERT_NO_THROW(prop.setValue(2)); + ASSERT_EQ(clientObj.getPropertyValue("child.child.fruit"), 2); + ASSERT_EQ(prop.getValue(), 2); + ASSERT_EQ(clientObj.getPropertySelectionValue("child.child.fruit"), "banana"); + ASSERT_EQ(obj.getPropertySelectionValue("child.child.fruit"), "banana"); +} + +TEST_F(TmsPropertyObjectTest, DotAccessClientServerChange) +{ + PropertyObjectPtr obj = PropertyObject(); + PropertyObjectPtr child1 = PropertyObject(); + PropertyObjectPtr child2 = PropertyObject(); + + child2.addProperty(StringProperty("foo", "bar")); + child1.addProperty(ObjectProperty("child", child2)); + obj.addProperty(ObjectProperty("child", child1)); + + auto [serverObj, clientObj] = registerPropertyObject(obj); + + auto prop = clientObj.getProperty("child.child.foo"); + auto serverProp = obj.getProperty("child.child.foo"); + + ASSERT_EQ(clientObj.getPropertyValue("child.child.foo"), "bar"); + ASSERT_EQ(prop.getValue(), "bar"); + + ASSERT_NO_THROW(obj.setPropertyValue("child.child.foo", "test")); + ASSERT_EQ(clientObj.getPropertyValue("child.child.foo"), "test"); + ASSERT_EQ(prop.getValue(), "test"); + + ASSERT_NO_THROW(serverProp.setValue("bar")); + ASSERT_EQ(clientObj.getPropertyValue("child.child.foo"), "bar"); + ASSERT_EQ(prop.getValue(), "bar"); +} + +class TmsNestedPropertyObjectTest : public TmsObjectIntegrationTest +{ +public: + + void SetUp() override + { + TmsObjectIntegrationTest::SetUp(); + serverObj = test_utils::createMockNestedPropertyObject(); + auto registeredObj = registerPropertyObject(serverObj); + serverTMSObj = registeredObj.serverProp; + clientObj = registeredObj.clientProp; + } + + void TearDown() override + { + TmsObjectIntegrationTest::TearDown(); + } + + RegisteredPropertyObject registerPropertyObject(const PropertyObjectPtr& prop) + { + auto serverProp = std::make_shared(prop, server, ctx, serverContext); + auto nodeId = serverProp->registerOpcUaNode(); + auto clientProp = TmsClientPropertyObject(NullContext(logger), clientContext, nodeId); + return {serverProp, clientProp}; + } + + PropertyObjectPtr serverObj; + TmsServerPropertyObjectPtr serverTMSObj; + PropertyObjectPtr clientObj; +}; + +TEST_F(TmsNestedPropertyObjectTest, TestNestedObjectClientGet) +{ + const PropertyObjectPtr child1 = clientObj.getPropertyValue("child1"); + const PropertyObjectPtr child2 = clientObj.getPropertyValue("child2"); + const PropertyObjectPtr child1_1 = child1.getPropertyValue("child1_1"); + const PropertyObjectPtr child1_2 = child1.getPropertyValue("child1_2"); + const PropertyObjectPtr child1_2_1 = child1_2.getPropertyValue("child1_2_1"); + const PropertyObjectPtr child2_1 = child2.getPropertyValue("child2_1"); + + ASSERT_EQ(child1_2_1.getPropertyValue("String"), "String"); + ASSERT_DOUBLE_EQ(child1_1.getPropertyValue("Float"), 1.1); + ASSERT_EQ(child1_2.getPropertyValue("Int"), 1); + ASSERT_EQ(child2_1.getPropertyValue("Ratio"), Ratio(1,2)); +} + + +TEST_F(TmsNestedPropertyObjectTest, TestNestedObjectClientGetDotAccess) +{ + ASSERT_EQ(clientObj.getPropertyValue("child1.child1_2.child1_2_1.String"), "String"); + ASSERT_DOUBLE_EQ(clientObj.getPropertyValue("child1.child1_1.Float"), 1.1); + ASSERT_EQ(clientObj.getPropertyValue("child1.child1_2.Int"), 1); + ASSERT_EQ(clientObj.getPropertyValue("child2.child2_1.Ratio"), Ratio(1, 2)); +} + +TEST_F(TmsNestedPropertyObjectTest, TestNestedObjectClientGetSelectionValueDotAccess) +{ + ASSERT_EQ(clientObj.getPropertyValue("child1.child1_2.child1_2_1.Selection"), 0); + ASSERT_EQ(clientObj.getPropertySelectionValue("child1.child1_2.child1_2_1.Selection"), "a"); + clientObj.setPropertyValue("child1.child1_2.child1_2_1.Selection", 1); + ASSERT_EQ(clientObj.getPropertyValue("child1.child1_2.child1_2_1.Selection"), 1); + ASSERT_EQ(clientObj.getPropertySelectionValue("child1.child1_2.child1_2_1.Selection"), "b"); +} + +TEST_F(TmsNestedPropertyObjectTest, TestNestedObjectClientSet) +{ + const PropertyObjectPtr child1 = clientObj.getPropertyValue("child1"); + const PropertyObjectPtr child2 = clientObj.getPropertyValue("child2"); + const PropertyObjectPtr child1_1 = child1.getPropertyValue("child1_1"); + const PropertyObjectPtr child1_2 = child1.getPropertyValue("child1_2"); + const PropertyObjectPtr child1_2_1 = child1_2.getPropertyValue("child1_2_1"); + const PropertyObjectPtr child2_1 = child2.getPropertyValue("child2_1"); + + child1_2_1.setPropertyValue("String", "new_string"); + child1_1.setPropertyValue("Float", 2.1); + child1_2.setPropertyValue("Int", 2); + child2_1.setPropertyValue("Ratio", Ratio(1, 5)); + + ASSERT_EQ(serverObj.getPropertyValue("child1.child1_2.child1_2_1.String"), "new_string"); + ASSERT_DOUBLE_EQ(serverObj.getPropertyValue("child1.child1_1.Float"), 2.1); + ASSERT_EQ(serverObj.getPropertyValue("child1.child1_2.Int"), 2); + ASSERT_EQ(serverObj.getPropertyValue("child2.child2_1.Ratio"), Ratio(1, 5)); + + ASSERT_EQ(child1_2_1.getPropertyValue("String"), "new_string"); + ASSERT_DOUBLE_EQ(child1_1.getPropertyValue("Float"), 2.1); + ASSERT_EQ(child1_2.getPropertyValue("Int"), 2); + ASSERT_EQ(child2_1.getPropertyValue("Ratio"), Ratio(1, 5)); +} + +TEST_F(TmsNestedPropertyObjectTest, TestNestedObjectClientSetDotAccess) +{ + clientObj.setPropertyValue("child1.child1_2.child1_2_1.String", "new_string"); + clientObj.setPropertyValue("child1.child1_1.Float", 2.1); + clientObj.setPropertyValue("child1.child1_2.Int", 2); + clientObj.setPropertyValue("child2.child2_1.Ratio", Ratio(1, 5)); + + ASSERT_EQ(serverObj.getPropertyValue("child1.child1_2.child1_2_1.String"), "new_string"); + ASSERT_DOUBLE_EQ(serverObj.getPropertyValue("child1.child1_1.Float"), 2.1); + ASSERT_EQ(serverObj.getPropertyValue("child1.child1_2.Int"), 2); + ASSERT_EQ(serverObj.getPropertyValue("child2.child2_1.Ratio"), Ratio(1, 5)); + + ASSERT_EQ(clientObj.getPropertyValue("child1.child1_2.child1_2_1.String"), "new_string"); + ASSERT_DOUBLE_EQ(clientObj.getPropertyValue("child1.child1_1.Float"), 2.1); + ASSERT_EQ(clientObj.getPropertyValue("child1.child1_2.Int"), 2); + ASSERT_EQ(clientObj.getPropertyValue("child2.child2_1.Ratio"), Ratio(1, 5)); +} + +TEST_F(TmsNestedPropertyObjectTest, TestNestedObjectClientProtectedSet) +{ + ASSERT_THROW(clientObj.setPropertyValue("child1.child1_2.child1_2_1.ReadOnlyString", "new_string"), AccessDeniedException); + ASSERT_EQ(serverObj.getPropertyValue("child1.child1_2.child1_2_1.ReadOnlyString"), "String"); + ASSERT_EQ(clientObj.getPropertyValue("child1.child1_2.child1_2_1.ReadOnlyString"), "String"); + + ASSERT_NO_THROW(clientObj.asPtr().setProtectedPropertyValue("child1.child1_2.child1_2_1.ReadOnlyString", "new_string")); + ASSERT_EQ(serverObj.getPropertyValue("child1.child1_2.child1_2_1.ReadOnlyString"), "new_string"); + ASSERT_EQ(clientObj.getPropertyValue("child1.child1_2.child1_2_1.ReadOnlyString"), "new_string"); +} + +// TODO: Enable once clearing property values is supported via OPC UA +TEST_F(TmsNestedPropertyObjectTest, DISABLED_TestNestedObjectClientClear) +{ + clientObj.setPropertyValue("child1.child1_2.child1_2_1.String", "new_string"); + clientObj.setPropertyValue("child1.child1_1.Float", 2.1); + clientObj.setPropertyValue("child1.child1_2.Int", 2); + clientObj.setPropertyValue("child2.child2_1.Ratio", Ratio(1, 5)); + + clientObj.clearPropertyValue("ObjectProperty"); + + ASSERT_EQ(serverObj.getPropertyValue("child1.child1_2.child1_2_1.String"), "String"); + ASSERT_DOUBLE_EQ(serverObj.getPropertyValue("child1.child1_1.Float"), 1.1); + ASSERT_EQ(serverObj.getPropertyValue("child1.child1_2.Int"), 1); + ASSERT_EQ(serverObj.getPropertyValue("child2.child2_1.Ratio"), Ratio(1, 2)); + + ASSERT_EQ(clientObj.getPropertyValue("child1.child1_2.child1_2_1.String"), "String"); + ASSERT_DOUBLE_EQ(clientObj.getPropertyValue("child1.child1_1.Float"), 1.1); + ASSERT_EQ(clientObj.getPropertyValue("child1.child1_2.Int"), 1); + ASSERT_EQ(clientObj.getPropertyValue("child2.child2_1.Ratio"), Ratio(1, 2)); + + clientObj.setPropertyValue("child1.child1_2.child1_2_1.String", "new_string"); + clientObj.setPropertyValue("child1.child1_1.Float", 2.1); + clientObj.setPropertyValue("child1.child1_2.Int", 2); + clientObj.setPropertyValue("child2.child2_1.Ratio", Ratio(1, 5)); + + clientObj.clearPropertyValue("child1"); + + ASSERT_EQ(serverObj.getPropertyValue("child1.child1_2.child1_2_1.String"), "String"); + ASSERT_DOUBLE_EQ(serverObj.getPropertyValue("child1.child1_1.Float"), 1.1); + ASSERT_EQ(serverObj.getPropertyValue("child1.child1_2.Int"), 1); + ASSERT_EQ(serverObj.getPropertyValue("child2.child2_1.Ratio"), Ratio(1, 5)); + + ASSERT_EQ(clientObj.getPropertyValue("child1.child1_2.child1_2_1.String"), "String"); + ASSERT_DOUBLE_EQ(clientObj.getPropertyValue("child1.child1_1.Float"), 1.1); + ASSERT_EQ(clientObj.getPropertyValue("child1.child1_2.Int"), 1); + ASSERT_EQ(clientObj.getPropertyValue("child2.child2_1.Ratio"), Ratio(1, 5)); +} + +TEST_F(TmsNestedPropertyObjectTest, TestNestedObjectServerSet) +{ + serverObj.setPropertyValue("child1.child1_2.child1_2_1.String", "new_string"); + serverObj.setPropertyValue("child1.child1_1.Float", 2.1); + serverObj.setPropertyValue("child1.child1_2.Int", 2); + serverObj.setPropertyValue("child2.child2_1.Ratio", Ratio(1, 5)); + + ASSERT_EQ(clientObj.getPropertyValue("child1.child1_2.child1_2_1.String"), "new_string"); + ASSERT_DOUBLE_EQ(clientObj.getPropertyValue("child1.child1_1.Float"), 2.1); + ASSERT_EQ(clientObj.getPropertyValue("child1.child1_2.Int"), 2); + ASSERT_EQ(clientObj.getPropertyValue("child2.child2_1.Ratio"), Ratio(1, 5)); +} + +TEST_F(TmsNestedPropertyObjectTest, TestNestedObjectServerClearIndividual) +{ + serverObj.setPropertyValue("child1.child1_2.child1_2_1.String", "new_string"); + serverObj.setPropertyValue("child1.child1_1.Float", 2.1); + serverObj.setPropertyValue("child1.child1_2.Int", 2); + serverObj.setPropertyValue("child2.child2_1.Ratio", Ratio(1, 5)); + + ASSERT_EQ(clientObj.getPropertyValue("child1.child1_2.child1_2_1.String"), "new_string"); + ASSERT_DOUBLE_EQ(clientObj.getPropertyValue("child1.child1_1.Float"), 2.1); + ASSERT_EQ(clientObj.getPropertyValue("child1.child1_2.Int"), 2); + ASSERT_EQ(clientObj.getPropertyValue("child2.child2_1.Ratio"), Ratio(1, 5)); + + serverObj.clearPropertyValue("child1.child1_2.child1_2_1.String"); + serverObj.clearPropertyValue("child1.child1_1.Float"); + serverObj.clearPropertyValue("child1.child1_2.Int"); + serverObj.clearPropertyValue("child2.child2_1.Ratio"); + + ASSERT_EQ(clientObj.getPropertyValue("child1.child1_2.child1_2_1.String"), "String"); + ASSERT_DOUBLE_EQ(clientObj.getPropertyValue("child1.child1_1.Float"), 1.1); + ASSERT_EQ(clientObj.getPropertyValue("child1.child1_2.Int"), 1); + ASSERT_EQ(clientObj.getPropertyValue("child2.child2_1.Ratio"), Ratio(1, 2)); +} + +TEST_F(TmsNestedPropertyObjectTest, TestNestedObjectServerClearObject) +{ + serverObj.setPropertyValue("child1.child1_2.child1_2_1.String", "new_string"); + serverObj.setPropertyValue("child1.child1_1.Float", 2.1); + serverObj.setPropertyValue("child1.child1_2.Int", 2); + serverObj.setPropertyValue("child2.child2_1.Ratio", Ratio(1, 5)); + + ASSERT_EQ(clientObj.getPropertyValue("child1.child1_2.child1_2_1.String"), "new_string"); + ASSERT_DOUBLE_EQ(clientObj.getPropertyValue("child1.child1_1.Float"), 2.1); + ASSERT_EQ(clientObj.getPropertyValue("child1.child1_2.Int"), 2); + ASSERT_EQ(clientObj.getPropertyValue("child2.child2_1.Ratio"), Ratio(1, 5)); + + for (const auto& prop : serverObj.getAllProperties()) + serverObj.asPtr().clearProtectedPropertyValue(prop.getName()); + + ASSERT_EQ(serverObj.getPropertyValue("child1.child1_2.child1_2_1.String"), "String"); + ASSERT_DOUBLE_EQ(serverObj.getPropertyValue("child1.child1_1.Float"), 1.1); + ASSERT_EQ(serverObj.getPropertyValue("child1.child1_2.Int"), 1); + ASSERT_EQ(serverObj.getPropertyValue("child2.child2_1.Ratio"), Ratio(1, 2)); + ASSERT_EQ(clientObj.getPropertyValue("child1.child1_2.child1_2_1.String"), "String"); + + ASSERT_DOUBLE_EQ(clientObj.getPropertyValue("child1.child1_1.Float"), 1.1); + ASSERT_EQ(clientObj.getPropertyValue("child1.child1_2.Int"), 1); + ASSERT_EQ(clientObj.getPropertyValue("child2.child2_1.Ratio"), Ratio(1, 2)); + + serverObj.setPropertyValue("child1.child1_2.child1_2_1.String", "new_string"); + serverObj.setPropertyValue("child1.child1_1.Float", 2.1); + serverObj.setPropertyValue("child1.child1_2.Int", 2); + serverObj.setPropertyValue("child2.child2_1.Ratio", Ratio(1, 5)); + + serverObj.asPtr().clearProtectedPropertyValue("child1"); + + ASSERT_EQ(clientObj.getPropertyValue("child1.child1_2.child1_2_1.String"), "String"); + ASSERT_DOUBLE_EQ(clientObj.getPropertyValue("child1.child1_1.Float"), 1.1); + ASSERT_EQ(clientObj.getPropertyValue("child1.child1_2.Int"), 1); + ASSERT_EQ(clientObj.getPropertyValue("child2.child2_1.Ratio"), Ratio(1, 5)); +} + +TEST_F(TmsNestedPropertyObjectTest, TestNestedObjectClientFunctionCall) +{ + const PropertyObjectPtr child = clientObj.getPropertyValue("child1.child1_2.child1_2_1"); + FunctionPtr func1 = clientObj.getPropertyValue("child1.child1_2.child1_2_1.Function"); + FunctionPtr func2 = child.getPropertyValue("Function"); + + ASSERT_EQ(func1(1), 1); + ASSERT_EQ(func2(5), 5); +} + +// NOTE: OPC UA does not propagate error codes. +TEST_F(TmsNestedPropertyObjectTest, TestNestedObjectClientProcedureCall) +{ + const PropertyObjectPtr child = clientObj.getPropertyValue("child1.child1_2.child1_2_1"); + ProcedurePtr proc1 = clientObj.getPropertyValue("child1.child1_2.child1_2_1.Procedure"); + ProcedurePtr proc2 = child.getPropertyValue("Procedure"); + + ASSERT_NO_THROW(proc1(5)); + ASSERT_NO_THROW(proc1(0)); // Outputs warning + ASSERT_NO_THROW(proc2(5)); + ASSERT_NO_THROW(proc2(0)); // Outputs warning +} From 2437c566bfc4e4653524d0e26e4b1ebdfb94a699 Mon Sep 17 00:00:00 2001 From: Dejan Crnila Date: Fri, 21 Mar 2025 07:36:24 +0100 Subject: [PATCH 190/217] Add function to name threads (openDAQ/openDAQ#737) --- shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp b/shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp index 5bcf93e..ebb9ccb 100644 --- a/shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp +++ b/shared/libraries/opcua/opcuaclient/src/opcuaclient.cpp @@ -49,6 +49,7 @@ ClientLockGuard::operator UA_Client*() OpcUaClient::OpcUaClient(const OpcUaEndpoint& endpoint) : endpoint(endpoint) , timerTasks() + , iterateThread("OpcUaClient") { iterateThread.setCallback(std::bind(&OpcUaClient::executeIterateCallback, this)); initialize(); From ce0afb9d8f5b2dfef3e804e32377845eea08f39a Mon Sep 17 00:00:00 2001 From: Dejan Crnila Date: Tue, 25 Mar 2025 12:55:02 +0100 Subject: [PATCH 191/217] Name additional threads (openDAQ/openDAQ#742) --- .../opcua/opcuaclient/include/opcuaclient/opcuaclient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h index eb6ed23..13c67d4 100644 --- a/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h +++ b/shared/libraries/opcua/opcuaclient/include/opcuaclient/opcuaclient.h @@ -168,7 +168,7 @@ class OpcUaClient std::chrono::milliseconds iterateTimeout; - daq::utils::TimerThread iterateThread; + daq::utils::NamedTimerThread iterateThread; }; END_NAMESPACE_OPENDAQ_OPCUA From 550e16b2c863c1f0426e1215bdbfe36a88718195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20R=C3=BChmer?= <108338550+Daniel-BB@users.noreply.github.com> Date: Fri, 4 Apr 2025 16:53:11 +0200 Subject: [PATCH 192/217] Replaced WORKING_DIRECTORY by full path for all tests (openDAQ/openDAQ#756) --- modules/opcua_client_module/tests/CMakeLists.txt | 2 +- modules/opcua_server_module/tests/CMakeLists.txt | 2 +- shared/libraries/opcua/opcuaclient/tests/CMakeLists.txt | 2 +- shared/libraries/opcua/opcuaserver/tests/CMakeLists.txt | 2 +- shared/libraries/opcua/opcuashared/tests/CMakeLists.txt | 2 +- shared/libraries/opcua/tests/testopcua/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms/tests/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms_client/tests/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt | 2 +- .../opcuatms/tests/opcuatms_integration/CMakeLists.txt | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/opcua_client_module/tests/CMakeLists.txt b/modules/opcua_client_module/tests/CMakeLists.txt index 365da57..326d216 100644 --- a/modules/opcua_client_module/tests/CMakeLists.txt +++ b/modules/opcua_client_module/tests/CMakeLists.txt @@ -14,7 +14,7 @@ target_link_libraries(${TEST_APP} PRIVATE daq::test_utils add_test(NAME ${TEST_APP} COMMAND $ - WORKING_DIRECTORY bin + WORKING_DIRECTORY $ ) if (OPENDAQ_ENABLE_COVERAGE) diff --git a/modules/opcua_server_module/tests/CMakeLists.txt b/modules/opcua_server_module/tests/CMakeLists.txt index 7228e63..d262445 100644 --- a/modules/opcua_server_module/tests/CMakeLists.txt +++ b/modules/opcua_server_module/tests/CMakeLists.txt @@ -17,7 +17,7 @@ target_link_libraries(${TEST_APP} PRIVATE daq::test_utils add_test(NAME ${TEST_APP} COMMAND $ - WORKING_DIRECTORY bin + WORKING_DIRECTORY $ ) if (MSVC) # Ignoring warning for the Taskflow diff --git a/shared/libraries/opcua/opcuaclient/tests/CMakeLists.txt b/shared/libraries/opcua/opcuaclient/tests/CMakeLists.txt index 1b4a4c3..f230794 100644 --- a/shared/libraries/opcua/opcuaclient/tests/CMakeLists.txt +++ b/shared/libraries/opcua/opcuaclient/tests/CMakeLists.txt @@ -32,7 +32,7 @@ target_include_directories(${TEST_APP} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/incl add_test(NAME ${TEST_APP} COMMAND $ - WORKING_DIRECTORY bin + WORKING_DIRECTORY $ ) if (MSVC) diff --git a/shared/libraries/opcua/opcuaserver/tests/CMakeLists.txt b/shared/libraries/opcua/opcuaserver/tests/CMakeLists.txt index 022758e..2c4d336 100644 --- a/shared/libraries/opcua/opcuaserver/tests/CMakeLists.txt +++ b/shared/libraries/opcua/opcuaserver/tests/CMakeLists.txt @@ -21,7 +21,7 @@ target_link_libraries(${TEST_APP} PRIVATE ${SDK_TARGET_NAMESPACE}::${MODULE_NAME add_test(NAME ${TEST_APP} COMMAND $ - WORKING_DIRECTORY bin + WORKING_DIRECTORY $ ) if(OPENDAQ_ENABLE_COVERAGE) diff --git a/shared/libraries/opcua/opcuashared/tests/CMakeLists.txt b/shared/libraries/opcua/opcuashared/tests/CMakeLists.txt index 5e467ef..4980b7d 100644 --- a/shared/libraries/opcua/opcuashared/tests/CMakeLists.txt +++ b/shared/libraries/opcua/opcuashared/tests/CMakeLists.txt @@ -29,7 +29,7 @@ endif() add_test(NAME ${TEST_APP} COMMAND $ - WORKING_DIRECTORY bin + WORKING_DIRECTORY $ ) if (OPENDAQ_ENABLE_COVERAGE) diff --git a/shared/libraries/opcua/tests/testopcua/CMakeLists.txt b/shared/libraries/opcua/tests/testopcua/CMakeLists.txt index 11579fb..e573e21 100644 --- a/shared/libraries/opcua/tests/testopcua/CMakeLists.txt +++ b/shared/libraries/opcua/tests/testopcua/CMakeLists.txt @@ -21,7 +21,7 @@ endif() add_test(NAME ${TEST_APP} COMMAND $ - WORKING_DIRECTORY bin + WORKING_DIRECTORY $ ) if (OPENDAQ_ENABLE_COVERAGE) diff --git a/shared/libraries/opcuatms/opcuatms/tests/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms/tests/CMakeLists.txt index 72f3084..6acdfbb 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms/tests/CMakeLists.txt @@ -22,7 +22,7 @@ target_link_libraries(${TEST_APP} PRIVATE ${SDK_TARGET_NAMESPACE}::${MODULE_NAME add_test(NAME ${TEST_APP} COMMAND $ - WORKING_DIRECTORY bin + WORKING_DIRECTORY $ ) if (OPENDAQ_ENABLE_COVERAGE) diff --git a/shared/libraries/opcuatms/opcuatms_client/tests/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_client/tests/CMakeLists.txt index b5b9541..09d2ff2 100644 --- a/shared/libraries/opcuatms/opcuatms_client/tests/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_client/tests/CMakeLists.txt @@ -21,7 +21,7 @@ target_link_libraries(${TEST_APP} PRIVATE ${SDK_TARGET_NAMESPACE}::${MODULE_NAME add_test(NAME ${TEST_APP} COMMAND $ - WORKING_DIRECTORY bin + WORKING_DIRECTORY $ ) if (OPENDAQ_ENABLE_COVERAGE) diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt index d1af844..c882bb6 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_server/tests/CMakeLists.txt @@ -31,7 +31,7 @@ target_link_libraries(${TEST_APP} PRIVATE ${SDK_TARGET_NAMESPACE}::${MODULE_NAME add_test(NAME ${TEST_APP} COMMAND $ - WORKING_DIRECTORY bin + WORKING_DIRECTORY $ ) if (OPENDAQ_ENABLE_COVERAGE) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt b/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt index 9512c84..de9c48f 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt @@ -62,7 +62,7 @@ endif() add_test(NAME ${TEST_APP} COMMAND $ - WORKING_DIRECTORY bin + WORKING_DIRECTORY $ ) if (MSVC) From a46adbfa1c32ac1e96380c35a672d9c5fdbf8954 Mon Sep 17 00:00:00 2001 From: David Norris Date: Mon, 7 Apr 2025 07:35:08 +0200 Subject: [PATCH 193/217] OPC-UA client: warn and ignore duplicate properties (openDAQ/openDAQ#754) * OPC-UA client: warn and ignore duplicate properties * Update changelog and logger message --------- Co-authored-by: Jaka Mohorko --- .../src/objects/tms_client_property_object_impl.cpp | 13 +++++++++++-- .../src/objects/tms_server_device.cpp | 4 ++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index 05e86f0..a628e7a 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -533,10 +533,19 @@ void TmsClientPropertyObjectBaseImpl::browseRawProperties() addMethodProperties(nodeId, orderedProperties, unorderedProperties, functionPropValues); } + auto addPropertyIgnoreDuplicates = [this](const daq::PropertyPtr& prop) + { + auto ec = Impl::addProperty(prop); + if (ec != OPENDAQ_ERR_ALREADYEXISTS) + return ec; + LOG_W("OPC UA exposes two properties with the same name \"{}\". The duplicate property will be ignored.", prop.getName()) + return OPENDAQ_SUCCESS; + }; + for (const auto& val : orderedProperties) - daq::checkErrorInfo(Impl::addProperty(val.second)); + daq::checkErrorInfo(addPropertyIgnoreDuplicates(val.second)); for (const auto& val : unorderedProperties) - daq::checkErrorInfo(Impl::addProperty(val)); + daq::checkErrorInfo(addPropertyIgnoreDuplicates(val)); for (const auto& val : functionPropValues) daq::checkErrorInfo(Impl::setProtectedPropertyValue(String(val.first), val.second)); diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index 6889227..15be0f1 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -234,13 +234,13 @@ void TmsServerDevice::populateDeviceInfo() }); } - std::map theBestProportiesEver = + std::map deviceInfoFieldsMap = { {"userName", "UserName"}, {"location", "Location"} }; - for (const auto& [propName, browseName] : theBestProportiesEver) + for (const auto& [propName, browseName] : deviceInfoFieldsMap) { const auto& prop = deviceInfo.getProperty(propName); const auto nodeId = getChildNodeId(browseName); From af95c002c35fe148278180544672a2ab32641bdc Mon Sep 17 00:00:00 2001 From: NikolaiShipilov <127689162+NikolaiShipilov@users.noreply.github.com> Date: Mon, 7 Apr 2025 00:36:22 -0700 Subject: [PATCH 194/217] Fix IPv6 addresses discovering on windows (openDAQ/openDAQ#751) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix parsing IPv6 addresses * modify regex parsing according to https://datatracker.ietf.org/doc/html/rfc3986#section-2.3 Co-authored-by: Aljaž Frančič * Fix linklocal suffix for discovered IPv6 addresses on Windows * Make connection string parsing regex static * Update changelog * Fix LT pseudo-device IPv6 connection info * add tests for device connection info using IPv6 connection --------- Co-authored-by: Aljaž Frančič --- .../src/opcua_client_module_impl.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index a7b2b5f..811fa1d 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -22,6 +22,9 @@ static const char* DaqOpcUaDeviceTypeId = "OpenDAQOPCUAConfiguration"; static const char* DaqOpcUaDevicePrefix = "daq.opcua"; static const char* OpcUaScheme = "opc.tcp"; +static const std::regex RegexIpv6Hostname(R"(^(.*://)?(\[[a-fA-F0-9:]+(?:\%[a-zA-Z0-9_\.-~]+)?\])(?::(\d+))?(/.*)?$)"); +static const std::regex RegexIpv4Hostname(R"(^(.*://)?([^:/\s]+)(?::(\d+))?(/.*)?$)"); + using namespace discovery; using namespace daq::opcua; @@ -197,9 +200,6 @@ DeviceInfoPtr OpcUaClientModule::populateDiscoveredDevice(const MdnsDiscoveredDe StringPtr OpcUaClientModule::formConnectionString(const StringPtr& connectionString, const PropertyObjectPtr& config, std::string& host, int& port, std::string& hostType) { std::string urlString = connectionString.toStdString(); - - auto regexIpv6Hostname = std::regex(R"(^(.*://)?(\[[a-fA-F0-9:]+(?:\%[a-zA-Z0-9]+)?\])(?::(\d+))?(/.*)?$)"); - auto regexIpv4Hostname = std::regex(R"(^(.*://)?([^:/\s]+)(?::(\d+))?(/.*)?$)"); std::smatch match; std::string prefix = ""; @@ -215,12 +215,12 @@ StringPtr OpcUaClientModule::formConnectionString(const StringPtr& connectionStr } bool parsed = false; - parsed = std::regex_search(urlString, match, regexIpv6Hostname); + parsed = std::regex_search(urlString, match, RegexIpv6Hostname); hostType = "IPv6"; if (!parsed) { - parsed = std::regex_search(urlString, match, regexIpv4Hostname); + parsed = std::regex_search(urlString, match, RegexIpv4Hostname); hostType = "IPv4"; } From 4220cd100a6d5208c00b815dfa7c9a838caf89bc Mon Sep 17 00:00:00 2001 From: NikolaiShipilov <127689162+NikolaiShipilov@users.noreply.github.com> Date: Thu, 10 Apr 2025 00:26:43 -0700 Subject: [PATCH 195/217] Provide list of connected clients via DeviceInfo (openDAQ/openDAQ#730) * Provide host name for native client * Fix redundant dropping of streaming connections when exclusive control client connected * Fix property add and remove core events for DeviceInfo via config protocol * Provide backward compatibility for older native config clients * Switch to libNativeStreaming tag v1.0.18 * Make property removing thread-safe * Add module helper method to populate discovered device info properties --- .../src/opcua_client_module_impl.cpp | 13 +----- .../src/opcua_server_impl.cpp | 7 --- .../include/opcuaserver/opcuaserver.h | 7 +++ .../opcua/opcuaserver/src/opcuaserver.cpp | 17 +++++++ .../opcuaserver/tests/test_opcuaserver.cpp | 37 ++++++++++++++++ .../include/opcuashared/opcuacommon.h | 20 +++++++++ .../opcua/opcuashared/src/opcuanodeid.cpp | 2 + .../tms_client_property_object_impl.cpp | 5 ++- .../include/opcuatms_server/tms_server.h | 2 +- .../opcuatms_server/src/tms_server.cpp | 44 +++++++++++++++++++ 10 files changed, 132 insertions(+), 22 deletions(-) diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 811fa1d..c0c31bb 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -9,12 +9,8 @@ #include #include #include -#include -#include #include #include -#include -#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_CLIENT_MODULE @@ -146,9 +142,6 @@ PropertyObjectPtr OpcUaClientModule::populateDefaultConfig(const PropertyObjectP DeviceInfoPtr OpcUaClientModule::populateDiscoveredDevice(const MdnsDiscoveredDevice& discoveredDevice) { - PropertyObjectPtr deviceInfo = DeviceInfo(""); - DiscoveryClient::populateDiscoveredInfoProperties(deviceInfo, discoveredDevice); - auto cap = ServerCapability(DaqOpcUaDeviceTypeId, "OpenDAQOPCUA", ProtocolType::Configuration); if (!discoveredDevice.ipv4Address.empty()) { @@ -190,11 +183,7 @@ DeviceInfoPtr OpcUaClientModule::populateDiscoveredDevice(const MdnsDiscoveredDe if (discoveredDevice.servicePort > 0) cap.setPort(discoveredDevice.servicePort); - deviceInfo.asPtr().addServerCapability(cap); - deviceInfo.asPtr().setProtectedPropertyValue("connectionString", cap.getConnectionString()); - deviceInfo.asPtr().setDeviceType(createDeviceType()); - - return deviceInfo; + return populateDiscoveredDeviceInfo(DiscoveryClient::populateDiscoveredInfoProperties, discoveredDevice, cap, createDeviceType()); } StringPtr OpcUaClientModule::formConnectionString(const StringPtr& connectionString, const PropertyObjectPtr& config, std::string& host, int& port, std::string& hostType) diff --git a/modules/opcua_server_module/src/opcua_server_impl.cpp b/modules/opcua_server_module/src/opcua_server_impl.cpp index d85e14b..70ddbc4 100644 --- a/modules/opcua_server_module/src/opcua_server_impl.cpp +++ b/modules/opcua_server_module/src/opcua_server_impl.cpp @@ -99,13 +99,6 @@ ServerTypePtr OpcUaServerImpl::createType(const ContextPtr& context) void OpcUaServerImpl::onStopServer() { server.stop(); - if (const DevicePtr rootDevice = this->rootDeviceRef.assigned() ? this->rootDeviceRef.getRef() : nullptr; rootDevice.assigned()) - { - const auto info = rootDevice.getInfo(); - const auto infoInternal = info.asPtr(); - if (info.hasServerCapability("OpenDAQOPCUAConfiguration")) - infoInternal.removeServerCapability("OpenDAQOPCUAConfiguration"); - } } OPENDAQ_DEFINE_CLASS_FACTORY_WITH_INTERFACE( diff --git a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h index 3da1306..589e9c0 100644 --- a/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h +++ b/shared/libraries/opcua/opcuaserver/include/opcuaserver/opcuaserver.h @@ -36,6 +36,9 @@ BEGIN_NAMESPACE_OPENDAQ_OPCUA class OpcUaServer final : public daq::utils::ThreadEx { public: + using OnClientConnectedCallback = std::function; + using OnClientDisconnectedCallback = std::function; + OpcUaServer(); ~OpcUaServer(); @@ -44,6 +47,8 @@ class OpcUaServer final : public daq::utils::ThreadEx uint16_t& getPort(); void setPort(uint16_t port); void setAuthenticationProvider(const AuthenticationProviderPtr& authenticationProvider); + void setClientConnectedHandler(const OnClientConnectedCallback& callback); + void setClientDisconnectedHandler(const OnClientDisconnectedCallback& callback); void setSecurityConfig(OpcUaServerSecurityConfig* config); const OpcUaServerSecurityConfig* getSecurityConfig() const; @@ -160,6 +165,8 @@ class OpcUaServer final : public daq::utils::ThreadEx std::unordered_set sessionContext; ServerEventManagerPtr eventManager; AuthenticationProviderPtr authenticationProvider; + OnClientConnectedCallback clientConnectedHandler; + OnClientDisconnectedCallback clientDisconnectedHandler; }; END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp b/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp index 9624250..14e42b9 100644 --- a/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp +++ b/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp @@ -54,6 +54,16 @@ void OpcUaServer::setAuthenticationProvider(const AuthenticationProviderPtr& aut this->authenticationProvider = authenticationProvider; } +void OpcUaServer::setClientConnectedHandler(const OnClientConnectedCallback& callback) +{ + this->clientConnectedHandler = callback; +} + +void OpcUaServer::setClientDisconnectedHandler(const OnClientDisconnectedCallback& callback) +{ + this->clientDisconnectedHandler = callback; +} + void OpcUaServer::setSecurityConfig(OpcUaServerSecurityConfig* config) { throw std::runtime_error("method setSecurityConfig() is deprecated"); @@ -566,7 +576,11 @@ UA_StatusCode OpcUaServer::activateSession(UA_Server* server, } if (status == UA_STATUSCODE_GOOD) + { serverInstance->createSession(*sessionId, sessionContext); + if (serverInstance->clientConnectedHandler) + serverInstance->clientConnectedHandler(OpcUaNodeId::getIdentifier(*sessionId)); + } return status; } @@ -583,6 +597,9 @@ void OpcUaServer::closeSession(UA_Server* server, UA_AccessControl* ac, const UA if (serverInstance->deleteSessionContextCallback) serverInstance->deleteSessionContextCallback(sessionContext); + + if (serverInstance->clientDisconnectedHandler) + serverInstance->clientDisconnectedHandler(OpcUaNodeId::getIdentifier(*sessionId)); } diff --git a/shared/libraries/opcua/opcuaserver/tests/test_opcuaserver.cpp b/shared/libraries/opcua/opcuaserver/tests/test_opcuaserver.cpp index 0e13ee8..6f557ce 100644 --- a/shared/libraries/opcua/opcuaserver/tests/test_opcuaserver.cpp +++ b/shared/libraries/opcua/opcuaserver/tests/test_opcuaserver.cpp @@ -143,6 +143,43 @@ TEST_F_OPTIONAL(OpcUaServerTest, ClientConnectTestSessionContextStopBeforeClient UA_Client_delete(client); } +TEST_F(OpcUaServerTest, ClientConnectDisconnectCallbacks) +{ + auto server = OpcUaServer(); + server.setPort(4840); + + std::string clientId; + bool clientConnected{false}; + bool clientDisconnected{false}; + server.setClientConnectedHandler( + [&clientId, &clientConnected](const std::string& id) + { + clientConnected = true; + clientId = id; + } + ); + server.setClientDisconnectedHandler( + [&clientId, &clientConnected, &clientDisconnected](const std::string& id) + { + if (clientConnected && id == clientId) + clientDisconnected = true; + } + ); + + server.start(); + + UA_Client* client = CreateClient(); + ASSERT_EQ_STATUS(UA_Client_connect(client, SERVER_URL), UA_STATUSCODE_GOOD); + + ASSERT_TRUE(clientConnected); + ASSERT_NE(clientId, ""); + + UA_Client_delete(client); + ASSERT_TRUE(clientDisconnected); + + server.stop(); +} + TEST_F(OpcUaServerTest, ReadBrowseName) { OpcUaServer server = createServer(); diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacommon.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacommon.h index 303f5a1..39d55cc 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacommon.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuacommon.h @@ -24,6 +24,7 @@ #include #include #include +#include #include "open62541/util.h" @@ -36,6 +37,25 @@ namespace utils return std::string((const char*) value.data, value.length); } + inline std::string GuidToString(const UA_Guid& guid) + { + std::ostringstream oss; + oss << std::hex << std::setfill('0') + << std::setw(8) << guid.data1 << "-" + << std::setw(4) << guid.data2 << "-" + << std::setw(4) << guid.data3 << "-" + << std::setw(2) << static_cast(guid.data4[0]) + << std::setw(2) << static_cast(guid.data4[1]) << "-" + << std::setw(2) << static_cast(guid.data4[2]) + << std::setw(2) << static_cast(guid.data4[3]) + << std::setw(2) << static_cast(guid.data4[4]) + << std::setw(2) << static_cast(guid.data4[5]) + << std::setw(2) << static_cast(guid.data4[6]) + << std::setw(2) << static_cast(guid.data4[7]); + + return oss.str(); + } + double ToSeconds(const UA_DateTime& time); UA_StatusCode ToUaVariant(double value, const UA_NodeId& dataTypeNodeId, UA_Variant* var); void ToUaVariant(const std::string& value, const UA_NodeId& dataTypeNodeId, UA_Variant* var); diff --git a/shared/libraries/opcua/opcuashared/src/opcuanodeid.cpp b/shared/libraries/opcua/opcuashared/src/opcuanodeid.cpp index 15352c0..4fb9ccb 100644 --- a/shared/libraries/opcua/opcuashared/src/opcuanodeid.cpp +++ b/shared/libraries/opcua/opcuashared/src/opcuanodeid.cpp @@ -101,6 +101,8 @@ OpcUaIdentifierUniversal OpcUaNodeId::getIdentifier(const UA_NodeId& uaNodeId) return std::to_string(uaNodeId.identifier.numeric); case OpcUaIdentifierType::String: return utils::ToStdString(uaNodeId.identifier.string); + case OpcUaIdentifierType::Guid: + return utils::GuidToString(uaNodeId.identifier.guid); default: throw std::runtime_error("C Exception: unsupported identifier type!"); }; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index a628e7a..be74e11 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -587,8 +587,9 @@ PropertyObjectPtr TmsClientPropertyObjectBaseImpl::cloneChildPropertyObjec template bool TmsClientPropertyObjectBaseImpl::isBasePropertyObject(const PropertyObjectPtr& propObj) { - return !propObj.supportsInterface() - && !propObj.supportsInterface(); + return !propObj.supportsInterface() + && !propObj.supportsInterface() + && !propObj.supportsInterface(); } template class TmsClientPropertyObjectBaseImpl; diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h index 4d00912..9435921 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/tms_server.h @@ -44,7 +44,7 @@ class TmsServer daq::opcua::OpcUaServerPtr server; uint16_t opcUaPort = 4840; std::string opcUaPath = "/"; - + std::unordered_map registeredClientIds; }; END_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp index 42ef62b..30932c3 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp @@ -49,6 +49,36 @@ void TmsServer::start() server = std::make_shared(); server->setPort(opcUaPort); server->setAuthenticationProvider(context.getAuthenticationProvider()); + server->setClientConnectedHandler( + [this](const std::string& clientId) + { + const auto loggerComponent = context.getLogger().getOrAddComponent("TmsServer"); + LOG_I("New client connected, ID: {}", clientId); + SizeT clientNumber = 0; + if (device.assigned() && !device.isRemoved()) + { + device.getInfo().asPtr(true).addConnectedClient( + &clientNumber, + ConnectedClientInfo("", ProtocolType::Configuration, "OpenDAQOPCUA", "", "")); + } + registeredClientIds.insert({clientId, clientNumber}); + } + ); + server->setClientDisconnectedHandler( + [this](const std::string& clientId) + { + if (auto it = registeredClientIds.find(clientId); it != registeredClientIds.end()) + { + const auto loggerComponent = context.getLogger().getOrAddComponent("TmsServer"); + LOG_I("Client disconnected, ID: {}", clientId); + if (device.assigned() && !device.isRemoved() && it->second != 0) + { + device.getInfo().asPtr(true).removeConnectedClient(it->second); + } + registeredClientIds.erase(it); + } + } + ); server->prepare(); tmsContext = std::make_shared(context, device); @@ -70,6 +100,20 @@ void TmsServer::start() void TmsServer::stop() { + if (device.assigned() && !device.isRemoved()) + { + const auto info = device.getInfo(); + const auto infoInternal = info.asPtr(); + if (info.hasServerCapability("OpenDAQOPCUAConfiguration")) + infoInternal.removeServerCapability("OpenDAQOPCUAConfiguration"); + for (const auto& [_, clientNumber] : registeredClientIds) + { + if (clientNumber != 0) + infoInternal.removeConnectedClient(clientNumber); + } + } + registeredClientIds.clear(); + if (server) server->stop(); From d93774dacdcbf47154d6bba1c1e9ec388987494c Mon Sep 17 00:00:00 2001 From: Jaka Mohorko <96818661+JakaMohorkoDS@users.noreply.github.com> Date: Fri, 11 Apr 2025 08:44:47 +0200 Subject: [PATCH 196/217] Merge discovery info and device info based on SN and manufacturer (openDAQ/openDAQ#757) --- .../opcua_client_module_impl.h | 1 - .../src/opcua_client_module_impl.cpp | 41 +++++++------------ .../opcuatms_server/src/tms_server.cpp | 7 +++- 3 files changed, 20 insertions(+), 29 deletions(-) diff --git a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h index bff5d38..aca54a9 100644 --- a/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h +++ b/modules/opcua_client_module/include/opcua_client_module/opcua_client_module_impl.h @@ -39,7 +39,6 @@ class OpcUaClientModule final : public Module StringPtr formConnectionString(const StringPtr& connectionString, const PropertyObjectPtr& config, std::string& host, int& port, std::string& hostType); static DeviceTypePtr createDeviceType(); static PropertyObjectPtr createDefaultConfig(); - static void completeServerCapabilities(const DevicePtr& device, const StringPtr& deviceAddress); static PropertyObjectPtr populateDefaultConfig(const PropertyObjectPtr& config); static DeviceInfoPtr populateDiscoveredDevice(const discovery::MdnsDiscoveredDevice& discoveredDevice); discovery::DiscoveryClient discoveryClient; diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index c0c31bb..8f51dd5 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -18,8 +18,8 @@ static const char* DaqOpcUaDeviceTypeId = "OpenDAQOPCUAConfiguration"; static const char* DaqOpcUaDevicePrefix = "daq.opcua"; static const char* OpcUaScheme = "opc.tcp"; -static const std::regex RegexIpv6Hostname(R"(^(.*://)?(\[[a-fA-F0-9:]+(?:\%[a-zA-Z0-9_\.-~]+)?\])(?::(\d+))?(/.*)?$)"); -static const std::regex RegexIpv4Hostname(R"(^(.*://)?([^:/\s]+)(?::(\d+))?(/.*)?$)"); +static const std::regex RegexIpv6Hostname(R"(^(.+://)?(\[[a-fA-F0-9:]+(?:\%[a-zA-Z0-9_\.-~]+)?\])(?::(\d+))?(/.*)?$)"); +static const std::regex RegexIpv4Hostname(R"(^(.+://)?([^:/\s]+)(?::(\d+))?(/.*)?$)"); using namespace discovery; using namespace daq::opcua; @@ -87,7 +87,6 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, TmsClient client(context, parent, endpoint); auto device = client.connect(); - completeServerCapabilities(device, host); // Set the connection info for the device DeviceInfoPtr deviceInfo = device.getInfo(); @@ -114,19 +113,6 @@ DevicePtr OpcUaClientModule::onCreateDevice(const StringPtr& connectionString, return device; } -void OpcUaClientModule::completeServerCapabilities(const DevicePtr& device, const StringPtr& deviceAddress) -{ - auto deviceInfo = device.getInfo(); - if (deviceInfo.assigned()) - { - for (const auto& capability : deviceInfo.getServerCapabilities()) - { - if (capability.getConnectionType() == "TCP/IP") - capability.asPtr(true).addAddress(deviceAddress); - } - } -} - PropertyObjectPtr OpcUaClientModule::populateDefaultConfig(const PropertyObjectPtr& config) { const auto defConfig = createDefaultConfig(); @@ -218,7 +204,7 @@ StringPtr OpcUaClientModule::formConnectionString(const StringPtr& connectionStr prefix = match[1]; host = match[2]; - if (match[3].matched && port == 4840) + if (match[3].matched) port = std::stoi(match[3]); if (match[4].matched) @@ -237,10 +223,7 @@ bool OpcUaClientModule::acceptsConnectionParameters(const StringPtr& connectionS { std::string connStr = connectionString; auto found = connStr.find(std::string(DaqOpcUaDevicePrefix) + "://"); - if (found == 0) - return true; - else - return false; + return found == 0; } Bool OpcUaClientModule::onCompleteServerCapability(const ServerCapabilityPtr& source, const ServerCapabilityConfigPtr& target) @@ -248,9 +231,6 @@ Bool OpcUaClientModule::onCompleteServerCapability(const ServerCapabilityPtr& so if (target.getProtocolId() != "OpenDAQOPCUAConfiguration") return false; - if (target.getConnectionString().getLength() != 0) - return true; - if (source.getConnectionType() != "TCP/IP") return false; @@ -276,13 +256,22 @@ Bool OpcUaClientModule::onCompleteServerCapability(const ServerCapabilityPtr& so } const auto path = target.hasProperty("Path") ? target.getPropertyValue("Path") : ""; + const auto targetAddress = target.getAddresses(); for (const auto& addrInfo : addrInfos) { const auto address = addrInfo.getAddress(); + if (auto it = std::find(targetAddress.begin(), targetAddress.end(), address); it != targetAddress.end()) + continue; + + const auto prefix = target.getPrefix(); + StringPtr connectionString; + if (source.getPrefix() == prefix) + connectionString = addrInfo.getConnectionString(); + else + connectionString = fmt::format("{}://{}:{}{}", prefix, address, port, path); - std::string connectionString = fmt::format("{}://{}:{}/{}", DaqOpcUaDevicePrefix, address, port, path); const auto targetAddrInfo = AddressInfoBuilder() - .setAddress(addrInfo.getAddress()) + .setAddress(address) .setReachabilityStatus(addrInfo.getReachabilityStatus()) .setType(addrInfo.getType()) .setConnectionString(connectionString) diff --git a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp index 30932c3..874bc22 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp @@ -46,6 +46,10 @@ void TmsServer::start() if (!context.assigned()) DAQ_THROW_EXCEPTION(InvalidStateException, "Context is not set."); + auto info = device.getInfo(); + if (info.hasServerCapability("OpenDAQOPCUAConfiguration")) + DAQ_THROW_EXCEPTION(InvalidStateException, fmt::format("Device \"{}\" already has an OpenDAQOPCUAConfiguration server capability.", info.getName())); + server = std::make_shared(); server->setPort(opcUaPort); server->setAuthenticationProvider(context.getAuthenticationProvider()); @@ -82,14 +86,13 @@ void TmsServer::start() server->prepare(); tmsContext = std::make_shared(context, device); - auto signals = device.getSignals(); auto serverCapability = ServerCapability("OpenDAQOPCUAConfiguration", "OpenDAQOPCUA", ProtocolType::Configuration); serverCapability.setPrefix("daq.opcua"); serverCapability.setConnectionType("TCP/IP"); serverCapability.setPort(opcUaPort); serverCapability.addProperty(StringProperty("Path", opcUaPath == "/" ? "" : opcUaPath)); - device.getInfo().asPtr().addServerCapability(serverCapability); + info.asPtr(true).addServerCapability(serverCapability); tmsDevice = std::make_unique(device, server, context, tmsContext); tmsDevice->registerOpcUaNode(OpcUaNodeId(NAMESPACE_DI, UA_DIID_DEVICESET)); From 5be6b1539b669f9c2943cf773579651644126124 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko <96818661+JakaMohorkoDS@users.noreply.github.com> Date: Fri, 18 Apr 2025 15:34:47 +0200 Subject: [PATCH 197/217] `hasProperty` extension for nested property object paths (openDAQ/openDAQ#773) --- .../src/objects/tms_client_property_object_impl.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index be74e11..6c9e937 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -36,9 +36,7 @@ ErrCode TmsClientPropertyObjectBaseImpl::setOPCUAPropertyValueInternal(ISt } auto propertyNamePtr = StringPtr::Borrow(propertyName); - StringPtr childName; - StringPtr subName; - if (this->isChildProperty(propertyNamePtr, childName, subName)) + if (this->isChildProperty(propertyNamePtr)) { PropertyPtr prop; ErrCode err = getProperty(propertyNamePtr, &prop); @@ -138,9 +136,7 @@ ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::getPropertyValue(I } auto propertyNamePtr = StringPtr::Borrow(propertyName); - StringPtr childName; - StringPtr subName; - if (this->isChildProperty(propertyNamePtr, childName, subName)) + if (this->isChildProperty(propertyNamePtr)) { PropertyPtr prop; ErrCode err = getProperty(propertyNamePtr, &prop); From a6022b4d555261e2848571ba259537bb941a05fe Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Sat, 26 Apr 2025 07:02:03 +0200 Subject: [PATCH 198/217] Improving device operation mode (openDAQ/openDAQ#771) --- .../objects/tms_client_device_impl.h | 6 ++-- .../src/objects/tms_client_device_impl.cpp | 32 ++++++++++++------- .../src/objects/tms_server_device.cpp | 19 ++++++++--- 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h index 85ab391..63af97b 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h @@ -35,9 +35,9 @@ class TmsClientDeviceImpl : public TmsClientComponentBaseImpl::ToDaqList(client->readValue(nodeId)); - *availableOpModes = opModesNodeStrList.detach(); + auto convertedOpModes = List(); + for (const auto& opMode : opModesNodeStrList) + convertedOpModes.pushBack(static_cast(OperationModeTypeFromString(opMode))); - return OPENDAQ_SUCCESS; + *availableOpModes = convertedOpModes.detach(); + return OPENDAQ_SUCCESS; } -ErrCode TmsClientDeviceImpl::setOperationMode(IString* modeType) +ErrCode TmsClientDeviceImpl::setOperationMode(OperationModeType modeType) { - OPENDAQ_PARAM_NOT_NULL(modeType); - if (!this->hasReference("OperationMode")) return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_NOT_SUPPORTED, "OperationModes are not supported by the server"); const auto nodeId = getNodeId("OperationMode"); - const auto modeTypeStr = StringPtr::Borrow(modeType).toStdString(); + const auto modeTypeStr = OperationModeTypeToString(modeType); const auto variant = VariantConverter::ToVariant(String(modeTypeStr), nullptr, daqContext); client->writeValue(nodeId, variant); @@ -161,14 +162,21 @@ ErrCode TmsClientDeviceImpl::setOperationMode(IString* modeType) return OPENDAQ_SUCCESS; } -ErrCode TmsClientDeviceImpl::setOperationModeRecursive(IString* modeType) +ErrCode TmsClientDeviceImpl::setOperationModeRecursive(OperationModeType modeType) { - OPENDAQ_PARAM_NOT_NULL(modeType); - const auto modeTypeStr = "Recursive" + StringPtr::Borrow(modeType).toStdString(); - return this->setOperationMode(String(modeTypeStr)); + if (!this->hasReference("OperationMode")) + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_NOT_SUPPORTED, "OperationModes are not supported by the server"); + + const auto nodeId = getNodeId("OperationMode"); + const auto modeTypeStr = "Recursive" + OperationModeTypeToString(modeType); + + const auto variant = VariantConverter::ToVariant(String(modeTypeStr), nullptr, daqContext); + client->writeValue(nodeId, variant); + + return OPENDAQ_SUCCESS; } -ErrCode TmsClientDeviceImpl::getOperationMode(IString** modeType) +ErrCode TmsClientDeviceImpl::getOperationMode(OperationModeType* modeType) { OPENDAQ_PARAM_NOT_NULL(modeType); @@ -178,7 +186,7 @@ ErrCode TmsClientDeviceImpl::getOperationMode(IString** modeType) const auto nodeId = getNodeId("OperationMode"); const auto variant = client->readValue(nodeId); - *modeType = VariantConverter::ToDaqObject(variant, daqContext).detach(); + *modeType = OperationModeTypeFromString(VariantConverter::ToDaqObject(variant, daqContext)); return OPENDAQ_SUCCESS; } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index 15be0f1..faf476b 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -19,6 +19,7 @@ #include #include #include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -272,8 +273,10 @@ void TmsServerDevice::populateDeviceInfo() deviceInfoProperties.push_back(tmsOpModeOptions); this->addReadCallback(tmsOpModeOptions->getNodeId(), [this] { - const auto opMode = object.getAvailableOperationModes(); - return VariantConverter::ToArrayVariant(opMode, nullptr, daqContext); + auto opModes = List(); + for (const auto& opMode : object.getAvailableOperationModes()) + opModes.pushBack(OperationModeTypeToString(opMode)); + return VariantConverter::ToArrayVariant(opModes, nullptr, daqContext); }); const auto opMode = StringProperty("OperationMode", "", false); @@ -283,7 +286,7 @@ void TmsServerDevice::populateDeviceInfo() this->addReadCallback(tmsOpMode->getNodeId(), [this] { - const auto opMode = object.getOperationMode(); + const auto opMode = OperationModeTypeToString(object.getOperationMode()); return VariantConverter::ToVariant(opMode, nullptr, daqContext); }); @@ -291,9 +294,15 @@ void TmsServerDevice::populateDeviceInfo() { const auto strValue = VariantConverter::ToDaqObject(variant).asPtr().toStdString(); if (strValue.find("Recursive") == 0) - this->object.setOperationModeRecursive(strValue.substr(9)); + { + auto opMode = OperationModeTypeFromString(strValue.substr(9)); + this->object.setOperationModeRecursive(opMode); + } else - this->object.setOperationMode(strValue); + { + auto opMode = OperationModeTypeFromString(strValue); + this->object.setOperationMode(opMode); + } return UA_STATUSCODE_GOOD; }); } From 70b695da169f33b3371a0a472feaaf149bcc12df Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Tue, 29 Apr 2025 17:21:14 +0200 Subject: [PATCH 199/217] Using component config while loading configuration for the devices and function blocks (openDAQ/openDAQ#734) * Fixes [TBBAS-2132] --- .../property_object_conversion_utils.cpp | 15 ++++++- .../objects/tms_client_component_impl.h | 2 + .../objects/tms_client_device_impl.h | 1 + .../src/objects/tms_client_component_impl.cpp | 14 ++++++- .../src/objects/tms_client_device_impl.cpp | 27 +++++------- .../tms_client_function_block_impl.cpp | 1 + .../objects/tms_server_component.h | 42 ++++++++++++------- .../src/objects/tms_server_device.cpp | 9 +--- 8 files changed, 70 insertions(+), 41 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/property_object_conversion_utils.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/property_object_conversion_utils.cpp index 432198a..d765209 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/property_object_conversion_utils.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/property_object_conversion_utils.cpp @@ -1,6 +1,7 @@ #include #include #include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -31,7 +32,19 @@ void PropertyObjectConversionUtils::ToPropertyObject(const OpcUaVariant& variant const auto dict = VariantConverter::ToDaqObject(variant); for (const auto& entry : dict) - objOut.setPropertyValue(entry.first, entry.second); + { + if (!objOut.hasProperty(entry.first)) + { + auto property = PropertyBuilder(entry.first).setValueType(entry.second.getCoreType()) + .setDefaultValue(entry.second) + .build(); + objOut.addProperty(property); + } + else + { + objOut.setPropertyValue(entry.first, entry.second); + } + } } PropertyObjectPtr PropertyObjectConversionUtils::ClonePropertyObject(const PropertyObjectPtr& obj) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h index 6d769af..66bd481 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h @@ -73,6 +73,8 @@ class TmsClientComponentBaseImpl : public TmsClientPropertyObjectBaseImpl protected: bool isChildComponent(const ComponentPtr& component); + PropertyObjectPtr findAndCreateComponentConfig(); + private: LoggerComponentPtr getLoggerComponent(); void initComponent(); diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h index 63af97b..4ffd7c0 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h @@ -61,6 +61,7 @@ class TmsClientDeviceImpl : public TmsClientComponentBaseImpl #include +#include #include #include #include #include #include #include - BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS using namespace daq::opcua; @@ -207,6 +207,18 @@ bool TmsClientComponentBaseImpl::isChildComponent(const ComponentPtr& comp return false; } +template +PropertyObjectPtr TmsClientComponentBaseImpl::findAndCreateComponentConfig() +{ + PropertyObjectPtr componentConfig; + if (const auto& objIt = this->objectTypeIdMap.find("ComponentConfig"); objIt != this->objectTypeIdMap.cend()) + { + componentConfig = TmsClientPropertyObject(this->daqContext, this->clientContext, objIt->second); + this->objectTypeIdMap.erase(objIt); + } + return componentConfig; +} + template class TmsClientComponentBaseImpl>; template class TmsClientComponentBaseImpl>; template class TmsClientComponentBaseImpl>; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 31ffb9b..8a2a932 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -104,7 +103,7 @@ TmsClientDeviceImpl::TmsClientDeviceImpl(const ContextPtr& ctx, nodeId, {{"UserName", "userName"}, {"Location", "location"}}) , logger(ctx.getLogger()) - , loggerComponent( this->logger.assigned() + , loggerComponent(this->logger.assigned() ? this->logger.getOrAddComponent("TmsClientDevice") : throw ArgumentNullException("Logger must not be null")) { @@ -119,6 +118,10 @@ TmsClientDeviceImpl::TmsClientDeviceImpl(const ContextPtr& ctx, findAndCreateInputsOutputs(); findAndCreateCustomComponents(); findAndCreateSyncComponent(); + + // for the root device the client side local config object is used + if (!isRootDevice) + this->componentConfig = this->findAndCreateComponentConfig(); } ErrCode TmsClientDeviceImpl::getDomain(IDeviceDomain** deviceDomain) @@ -657,6 +660,11 @@ void TmsClientDeviceImpl::removed() Super::removed(); } +bool TmsClientDeviceImpl::isAddedToLocalComponentTree() +{ + return this->clientContext->getRootDevice() == this->thisPtr(); +} + void TmsClientDeviceImpl::findAndCreateCustomComponents() { std::map orderedComponents; @@ -757,21 +765,6 @@ FunctionBlockPtr TmsClientDeviceImpl::onAddFunctionBlock(const StringPtr& typeId auto clientFunctionBlock = TmsClientFunctionBlock(context, this->functionBlocks, localId, clientContext, fbNodeId); addNestedFunctionBlock(clientFunctionBlock); - auto fbSignals = clientFunctionBlock.getSignals(search::Recursive(search::Any())); - auto deviceStreamingSources = this->thisPtr().getStreamingSources(); - for (const auto& streaming : deviceStreamingSources) - { - streaming.addSignals(fbSignals); - } - if (deviceStreamingSources.getCount() > 0) - { - for (const auto& signal : fbSignals) - { - if (signal.getPublic()) - signal.asPtr().setActiveStreamingSource(deviceStreamingSources[0].getConnectionString()); - } - } - return clientFunctionBlock; } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp index 05fa2c3..a4f568c 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_block_impl.cpp @@ -29,6 +29,7 @@ TmsClientFunctionBlockBaseImpl::TmsClientFunctionBlockBaseImpl( findAndCreateFunctionBlocks(); findAndCreateSignals(); findAndCreateInputPorts(); + this->componentConfig = this->findAndCreateComponentConfig(); } template diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h index 63870db..df54e46 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h @@ -16,6 +16,7 @@ #pragma once #include +#include #include #include #include @@ -55,6 +56,7 @@ class TmsServerComponent : public TmsServerObjectBaseImpl void configureNodeAttributes(opcua::OpcUaObject& attr) override; std::unique_ptr tmsPropertyObject; + std::unique_ptr tmsComponentConfig; private: bool selfChange; @@ -68,6 +70,12 @@ TmsServerComponent::TmsServerComponent(const ComponentPtr& object, const Op , selfChange(false) { tmsPropertyObject = std::make_unique(this->object, this->server, this->daqContext, this->tmsContext, std::unordered_set{"Name", "Description"}); + if (auto componentPrivate = this->object.template asPtrOrNull(true); componentPrivate.assigned()) + { + auto componentConfig = componentPrivate.getComponentConfig(); + if (componentConfig.assigned()) + tmsComponentConfig = std::make_unique(componentConfig, this->server, this->daqContext, this->tmsContext, "ComponentConfig"); + } } template @@ -123,22 +131,22 @@ bool TmsServerComponent::createOptionalNode(const OpcUaNodeId& nodeId) template void TmsServerComponent::bindCallbacks() { - this->addReadCallback("Tags",[this] - { - const TagsPtr tags = this->object.getTags(); - if (tags.assigned()) - return VariantConverter::ToArrayVariant(tags.getList()); - return VariantConverter::ToArrayVariant(List()); - }); + this->addReadCallback("Tags", [this] + { + const TagsPtr tags = this->object.getTags(); + if (tags.assigned()) + return VariantConverter::ToArrayVariant(tags.getList()); + return VariantConverter::ToArrayVariant(List()); + }); this->addReadCallback("Active", [this] { return VariantConverter::ToVariant( this->object.getActive()); }); if (!this->object.template supportsInterface() || !this->object.isFrozen()) { this->addWriteCallback("Active", [this] (const OpcUaVariant& variant) - { - this->object.setActive(VariantConverter::ToDaqObject(variant)); - return UA_STATUSCODE_GOOD; - }); + { + this->object.setActive(VariantConverter::ToDaqObject(variant)); + return UA_STATUSCODE_GOOD; + }); } this->addReadCallback("Visible", [this] { return VariantConverter::ToVariant( this->object.getVisible()); }); @@ -146,10 +154,10 @@ void TmsServerComponent::bindCallbacks() if (!this->object.template supportsInterface() || !this->object.isFrozen()) { this->addWriteCallback("Visible", [this] (const OpcUaVariant& variant) - { - this->object.setVisible(VariantConverter::ToDaqObject(variant)); - return UA_STATUSCODE_GOOD; - }); + { + this->object.setVisible(VariantConverter::ToDaqObject(variant)); + return UA_STATUSCODE_GOOD; + }); } DisplayNameChangedCallback nameChangedCallback = @@ -227,7 +235,11 @@ void TmsServerComponent::addChildNodes() this->server->addVariableNode(params); + // this property will be added manually + tmsPropertyObject->ignoredProps.emplace("ComponentConfig"); tmsPropertyObject->registerToExistingOpcUaNode(this->nodeId); + if (tmsComponentConfig) + tmsComponentConfig->registerOpcUaNode(this->nodeId); } template diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index faf476b..7946e31 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -504,15 +504,10 @@ void TmsServerDevice::removeFunctionBlock(const StringPtr& localId) } } - const auto objFunctionBlocks = this->object.getFunctionBlocks(search::Any()); - + const auto objFunctionBlocks = this->object.getFunctionBlocks(search::LocalId(localId)); for (const auto& fb : objFunctionBlocks) { - if (fb.getLocalId() == localId) - { - this->object.removeFunctionBlock(fb); - break; - } + this->object.removeFunctionBlock(fb); } } From a357bfc4a535c621de871a3621447b219e5ef5e9 Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Tue, 29 Apr 2025 21:00:00 +0200 Subject: [PATCH 200/217] Support restoring device info fields (openDAQ/openDAQ#764) --- .../converters/property_object_conversion_utils.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/property_object_conversion_utils.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/property_object_conversion_utils.cpp index d765209..0fc572e 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/property_object_conversion_utils.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/property_object_conversion_utils.cpp @@ -31,18 +31,18 @@ void PropertyObjectConversionUtils::ToPropertyObject(const OpcUaVariant& variant { const auto dict = VariantConverter::ToDaqObject(variant); - for (const auto& entry : dict) + for (const auto& [name, value] : dict) { - if (!objOut.hasProperty(entry.first)) + if (!objOut.hasProperty(name)) { - auto property = PropertyBuilder(entry.first).setValueType(entry.second.getCoreType()) - .setDefaultValue(entry.second) - .build(); + auto property = PropertyBuilder(name).setValueType(value.getCoreType()) + .setDefaultValue(value) + .build(); objOut.addProperty(property); } else { - objOut.setPropertyValue(entry.first, entry.second); + objOut.setPropertyValue(name, value); } } } @@ -50,7 +50,6 @@ void PropertyObjectConversionUtils::ToPropertyObject(const OpcUaVariant& variant PropertyObjectPtr PropertyObjectConversionUtils::ClonePropertyObject(const PropertyObjectPtr& obj) { // This is a workaround until PropertyObject implemnts IClonable. - auto serializer = JsonSerializer(); auto deserializer = JsonDeserializer(); obj.serialize(serializer); From be66aa2d55d1233610757ae3a7e8d8ea32b35b90 Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Wed, 30 Apr 2025 10:24:30 +0200 Subject: [PATCH 201/217] Creating error info for error codes (openDAQ/openDAQ#768) --- .../src/objects/tms_client_device_impl.cpp | 2 +- .../src/objects/tms_client_function_impl.cpp | 12 ++- .../objects/tms_client_input_port_impl.cpp | 8 +- .../src/objects/tms_client_procedure_impl.cpp | 12 ++- .../tms_client_property_object_impl.cpp | 100 +++++++++--------- .../src/objects/tms_client_signal_impl.cpp | 13 +-- .../src/objects/tms_client_tags_impl.cpp | 6 +- 7 files changed, 81 insertions(+), 72 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 8a2a932..dbccf1b 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -127,7 +127,7 @@ TmsClientDeviceImpl::TmsClientDeviceImpl(const ContextPtr& ctx, ErrCode TmsClientDeviceImpl::getDomain(IDeviceDomain** deviceDomain) { if (this->isComponentRemoved) - return OPENDAQ_ERR_COMPONENT_REMOVED; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_COMPONENT_REMOVED); fetchTimeDomain(); return Super::getDomain(deviceDomain); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_impl.cpp index 7f0be61..a1a5eb2 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_function_impl.cpp @@ -47,16 +47,20 @@ ErrCode TmsClientFunctionImpl::call(IBaseObject* args, IBaseObject** result) lastProccessDescription = "Calling function"; OpcUaObject callResult = ctx->getClient()->callMethod(callRequest); if (OPCUA_STATUSCODE_FAILED(callResult->statusCode) || (callResult->outputArgumentsSize != 1)) - return OPENDAQ_ERR_CALLFAILED; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_CALLFAILED); lastProccessDescription = "Getting call result"; *result = VariantConverter::ToDaqObject(OpcUaVariant(callResult->outputArguments[0]), daqContext).detach(); return OPENDAQ_SUCCESS; }); - if (OPENDAQ_FAILED(errCode) && this->daqContext.getLogger().assigned()) + if (OPENDAQ_FAILED(errCode)) { - auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClientProcedure"); - LOG_W("Failed to call function on OpcUA client. Error in \"{}\"", lastProccessDescription); + daqClearErrorInfo(); + if (this->daqContext.getLogger().assigned()) + { + auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClientProcedure"); + LOG_W("Failed to call function on OpcUA client. Error in \"{}\"", lastProccessDescription); + } } return OPENDAQ_SUCCESS; } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp index e75eff2..2ed7a20 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp @@ -32,12 +32,12 @@ ErrCode TmsClientInputPortImpl::getRequiresSignal(Bool* value) ErrCode TmsClientInputPortImpl::setRequiresSignal(Bool value) { - return OPENDAQ_ERR_NOTIMPLEMENTED; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_NOTIMPLEMENTED); } ErrCode TmsClientInputPortImpl::acceptsSignal(ISignal* signal, Bool* accepts) { - return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE); //return daqTry([&]() //{ @@ -50,7 +50,7 @@ ErrCode TmsClientInputPortImpl::acceptsSignal(ISignal* signal, Bool* accepts) // OpcUaCallMethodRequest callRequest(methodId, nodeId, 1, inputArg.get()); // OpcUaObject result = client->callMethod(callRequest); // if (OPCUA_STATUSCODE_FAILED(result->statusCode) || (result->outputArgumentsSize != 1)) - // return OPENDAQ_ERR_CALLFAILED; + // return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_CALLFAILED); // *accepts = OpcUaVariant(result->outputArguments[0]).toBool(); // @@ -140,7 +140,7 @@ ErrCode TmsClientInputPortImpl::getConnection(IConnection** connection) return daqTry([&]() { // TODO: Implement. Awaits support to implement - return OPENDAQ_ERR_NOTIMPLEMENTED; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_NOTIMPLEMENTED); }); } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_procedure_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_procedure_impl.cpp index b3b4d2d..5615a46 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_procedure_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_procedure_impl.cpp @@ -48,14 +48,18 @@ ErrCode TmsClientProcedureImpl::dispatch(IBaseObject* args) lastProccessDescription = "Calling procedure"; OpcUaObject callResult = ctx->getClient()->callMethod(callRequest); if (OPCUA_STATUSCODE_FAILED(callResult->statusCode) || (callResult->outputArgumentsSize != 0)) - return OPENDAQ_ERR_CALLFAILED; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_CALLFAILED); return OPENDAQ_SUCCESS; }); - if (OPENDAQ_FAILED(errCode) && this->daqContext.getLogger().assigned()) + if (OPENDAQ_FAILED(errCode)) { - auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClientProcudure"); - LOG_W("Failed to call procedure on OpcUA client. Error: \"{}\"", lastProccessDescription); + daqClearErrorInfo(); + if (this->daqContext.getLogger().assigned()) + { + auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpcUaClientProcudure"); + LOG_W("Failed to call procedure on OpcUA client. Error: \"{}\"", lastProccessDescription); + } } return OPENDAQ_SUCCESS; } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index 6c9e937..6886d71 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -40,8 +40,7 @@ ErrCode TmsClientPropertyObjectBaseImpl::setOPCUAPropertyValueInternal(ISt { PropertyPtr prop; ErrCode err = getProperty(propertyNamePtr, &prop); - if (OPENDAQ_FAILED(err)) - return err; + OPENDAQ_RETURN_IF_FAILED(err); if (!prop.assigned()) throw NotFoundException(R"(Child property "{}" not found)", propertyNamePtr); @@ -51,54 +50,55 @@ ErrCode TmsClientPropertyObjectBaseImpl::setOPCUAPropertyValueInternal(ISt } StringPtr lastProcessDescription = ""; - ErrCode errCode = daqTry( - [&]() + ErrCode errCode = daqTry([&] + { + if (const auto& it = introspectionVariableIdMap.find(propertyNamePtr); it != introspectionVariableIdMap.cend()) { - if (const auto& it = introspectionVariableIdMap.find(propertyNamePtr); it != introspectionVariableIdMap.cend()) + PropertyPtr prop; + checkErrorInfo(getProperty(propertyName, &prop)); + if (!protectedWrite) { - PropertyPtr prop; - checkErrorInfo(getProperty(propertyName, &prop)); - if (!protectedWrite) - { - lastProcessDescription = "Checking existing property is read-only"; - if (prop.getReadOnly()) - return OPENDAQ_ERR_ACCESSDENIED; - } + lastProcessDescription = "Checking existing property is read-only"; + if (prop.getReadOnly()) + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_ACCESSDENIED); + } - BaseObjectPtr valuePtr = value; - const auto ct = prop.getValueType(); - const auto valueCt = valuePtr.getCoreType(); - if (ct != valueCt) - valuePtr = valuePtr.convertTo(ct); + BaseObjectPtr valuePtr = value; + const auto ct = prop.getValueType(); + const auto valueCt = valuePtr.getCoreType(); + if (ct != valueCt) + valuePtr = valuePtr.convertTo(ct); - lastProcessDescription = "Writing property value"; - const auto variant = VariantConverter::ToVariant(valuePtr, nullptr, daqContext); - client->writeValue(it->second, variant); - return OPENDAQ_SUCCESS; - } + lastProcessDescription = "Writing property value"; + const auto variant = VariantConverter::ToVariant(valuePtr, nullptr, daqContext); + client->writeValue(it->second, variant); + return OPENDAQ_SUCCESS; + } - if (const auto& it = referenceVariableIdMap.find(propertyNamePtr); it != referenceVariableIdMap.cend()) - { - lastProcessDescription = "Setting property value"; - const auto refProp = this->objPtr.getProperty(propertyName).getReferencedProperty(); - return setPropertyValue(refProp.getName(), value); - } + if (const auto& it = referenceVariableIdMap.find(propertyNamePtr); it != referenceVariableIdMap.cend()) + { + lastProcessDescription = "Setting property value"; + const auto refProp = this->objPtr.getProperty(propertyName).getReferencedProperty(); + return setPropertyValue(refProp.getName(), value); + } - if (const auto& it = objectTypeIdMap.find((propertyNamePtr)); it != objectTypeIdMap.cend()) - { - lastProcessDescription = "Object type properties cannot be set over OpcUA"; - return OPENDAQ_ERR_NOTIMPLEMENTED; - } + if (const auto& it = objectTypeIdMap.find((propertyNamePtr)); it != objectTypeIdMap.cend()) + { + lastProcessDescription = "Object type properties cannot be set over OpcUA"; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_NOTIMPLEMENTED); + } - lastProcessDescription = "Property not found"; - return OPENDAQ_ERR_NOTFOUND; - }); + lastProcessDescription = "Property not found"; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_NOTFOUND); + }); if (OPENDAQ_FAILED(errCode)) LOG_W("Failed to set value for property \"{}\" on OpcUA client property object: {}", propertyNamePtr, lastProcessDescription); - + if (errCode == OPENDAQ_ERR_NOTFOUND || errCode == OPENDAQ_ERR_ACCESSDENIED) - return errCode; + return DAQ_MAKE_ERROR_INFO(errCode, fmt::format("Property \"{}\" not found or access denied", propertyNamePtr)); + else if (OPENDAQ_FAILED(errCode)) + daqClearErrorInfo(); return OPENDAQ_SUCCESS; } @@ -140,8 +140,7 @@ ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::getPropertyValue(I { PropertyPtr prop; ErrCode err = getProperty(propertyNamePtr, &prop); - if (OPENDAQ_FAILED(err)) - return err; + OPENDAQ_RETURN_IF_FAILED(err); if (!prop.assigned()) throw NotFoundException(R"(Child property "{}" not found)", propertyNamePtr); @@ -168,6 +167,7 @@ ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::getPropertyValue(I }); if (OPENDAQ_FAILED(errCode)) { + daqClearErrorInfo(); LOG_W("Failed to get value for property \"{}\" on OpcUA client property object", propertyNamePtr); } return OPENDAQ_SUCCESS; @@ -184,13 +184,13 @@ ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::getPropertySelecti template ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::clearPropertyValue(IString* propertyName) { - return OPENDAQ_ERR_INVALID_OPERATION; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_INVALID_OPERATION); } template ErrCode TmsClientPropertyObjectBaseImpl::clearProtectedPropertyValue(IString* propertyName) { - return OPENDAQ_ERR_INVALID_OPERATION; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_INVALID_OPERATION); } template @@ -202,37 +202,37 @@ ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::getProperty(IStrin template ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::addProperty(IProperty* property) { - return OPENDAQ_ERR_INVALID_OPERATION; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_INVALID_OPERATION); } template ErrCode TmsClientPropertyObjectBaseImpl::removeProperty(IString* propertyName) { - return OPENDAQ_ERR_INVALID_OPERATION; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_INVALID_OPERATION); } template ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::getOnPropertyValueWrite(IString* /*propertyName*/, IEvent** /*event*/) { - return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE); } template ErrCode TmsClientPropertyObjectBaseImpl::getOnPropertyValueRead(IString* /*propertyName*/, IEvent** /*event*/) { - return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE); } template ErrCode TmsClientPropertyObjectBaseImpl::getOnAnyPropertyValueWrite(IEvent** /*event*/) { - return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE); } template ErrCode TmsClientPropertyObjectBaseImpl::getOnAnyPropertyValueRead(IEvent** /*event*/) { - return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE); } template @@ -256,7 +256,7 @@ ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::getAllProperties(I template ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::setPropertyOrder(IList* orderedPropertyNames) { - return OPENDAQ_ERR_INVALID_OPERATION; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_INVALID_OPERATION); } template diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp index 9c9abec..0fde018 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp @@ -47,7 +47,7 @@ ErrCode TmsClientSignalImpl::setPublic(Bool valPublic) ErrCode TmsClientSignalImpl::setDescriptor(IDataDescriptor* /*descriptor*/) { - return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE); } SignalPtr TmsClientSignalImpl::onGetDomainSignal() @@ -104,7 +104,7 @@ bool TmsClientSignalImpl::clearDescriptorOnUnsubscribe() ErrCode TmsClientSignalImpl::setDomainSignal(ISignal* signal) { - return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE); } ErrCode TmsClientSignalImpl::getRelatedSignals(IList** signals) @@ -114,6 +114,7 @@ ErrCode TmsClientSignalImpl::getRelatedSignals(IList** signals) *signals = signalsPtr.detach(); if (OPENDAQ_FAILED(errCode)) { + daqClearErrorInfo(); LOG_W("Failed to get related signals on OpcUA client signal \"{}\"", this->globalId); } return OPENDAQ_SUCCESS; @@ -141,22 +142,22 @@ ListPtr TmsClientSignalImpl::onGetRelatedSignals() ErrCode TmsClientSignalImpl::setRelatedSignals(IList* signals) { - return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE); } ErrCode TmsClientSignalImpl::addRelatedSignal(ISignal* signal) { - return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE); } ErrCode TmsClientSignalImpl::removeRelatedSignal(ISignal* signal) { - return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE); } ErrCode TmsClientSignalImpl::clearRelatedSignals() { - return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE); } Bool TmsClientSignalImpl::onTriggerEvent(const EventPacketPtr& eventPacket) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_tags_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_tags_impl.cpp index 8e01482..00f854a 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_tags_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_tags_impl.cpp @@ -20,17 +20,17 @@ ErrCode TmsClientTagsImpl::getList(IList** value) ErrCode TmsClientTagsImpl::add(IString* name) { - return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE); } ErrCode TmsClientTagsImpl::replace(IList* tags) { - return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE); } ErrCode TmsClientTagsImpl::remove(IString* name) { - return OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE; + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE); } ErrCode TmsClientTagsImpl::contains(IString* name, Bool* value) From 56ea1099b1f6497d22b011896ceecc240580ca46 Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Wed, 11 Jun 2025 10:02:39 +0200 Subject: [PATCH 202/217] Increase cmake min version to 3.10 (openDAQ/openDAQ#817) Co-authored-by: Jaka Mohorko --- external/opcua_daq_types/CMakeLists.txt | 2 +- modules/opcua_client_module/CMakeLists.txt | 2 +- modules/opcua_server_module/CMakeLists.txt | 2 +- shared/libraries/opcua/opcuaclient/CMakeLists.txt | 2 +- shared/libraries/opcua/opcuaserver/CMakeLists.txt | 2 +- shared/libraries/opcua/opcuashared/CMakeLists.txt | 2 +- shared/libraries/opcua/tests/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt | 2 +- shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt | 2 +- shared/libraries/opcuatms/tests/CMakeLists.txt | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/external/opcua_daq_types/CMakeLists.txt b/external/opcua_daq_types/CMakeLists.txt index 2d8315d..6b0d8de 100644 --- a/external/opcua_daq_types/CMakeLists.txt +++ b/external/opcua_daq_types/CMakeLists.txt @@ -23,7 +23,7 @@ FetchContent_Declare(daqspec FetchContent_GetProperties(daqspec) if(NOT daqspec_POPULATED) message(STATUS "Fetching daq specification ${daq_spec_REQUIREDVERSION}...") - FetchContent_Populate(daqspec) + FetchContent_MakeAvailable(daqspec) set(COMPANION_SPECIFICATIONS_DIRPREFIX "${daqspec_SOURCE_DIR}/opendaq") endif() diff --git a/modules/opcua_client_module/CMakeLists.txt b/modules/opcua_client_module/CMakeLists.txt index 0180af3..4a134c4 100644 --- a/modules/opcua_client_module/CMakeLists.txt +++ b/modules/opcua_client_module/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.10) set_cmake_folder_context(TARGET_FOLDER_NAME) project(ClientModule VERSION ${OPENDAQ_PACKAGE_VERSION} LANGUAGES C CXX) diff --git a/modules/opcua_server_module/CMakeLists.txt b/modules/opcua_server_module/CMakeLists.txt index 5e3460c..5ff8681 100644 --- a/modules/opcua_server_module/CMakeLists.txt +++ b/modules/opcua_server_module/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.10) set_cmake_folder_context(TARGET_FOLDER_NAME) project(ServerModule VERSION ${OPENDAQ_PACKAGE_VERSION} LANGUAGES CXX) diff --git a/shared/libraries/opcua/opcuaclient/CMakeLists.txt b/shared/libraries/opcua/opcuaclient/CMakeLists.txt index 5164676..94b3492 100644 --- a/shared/libraries/opcua/opcuaclient/CMakeLists.txt +++ b/shared/libraries/opcua/opcuaclient/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.10) set_cmake_folder_context(TARGET_FOLDER_NAME client) project(OpcUaClient CXX) diff --git a/shared/libraries/opcua/opcuaserver/CMakeLists.txt b/shared/libraries/opcua/opcuaserver/CMakeLists.txt index 47cc777..3a87fe1 100644 --- a/shared/libraries/opcua/opcuaserver/CMakeLists.txt +++ b/shared/libraries/opcua/opcuaserver/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.10) set_cmake_folder_context(TARGET_FOLDER_NAME server) project(OpcUaServer CXX) diff --git a/shared/libraries/opcua/opcuashared/CMakeLists.txt b/shared/libraries/opcua/opcuashared/CMakeLists.txt index 94316e4..8f97f58 100644 --- a/shared/libraries/opcua/opcuashared/CMakeLists.txt +++ b/shared/libraries/opcua/opcuashared/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.10) set_cmake_folder_context(TARGET_FOLDER_NAME shared) project(OpcUaShared CXX C) diff --git a/shared/libraries/opcua/tests/CMakeLists.txt b/shared/libraries/opcua/tests/CMakeLists.txt index 7521b7c..0ecb069 100644 --- a/shared/libraries/opcua/tests/CMakeLists.txt +++ b/shared/libraries/opcua/tests/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.10) set_cmake_folder_context(TARGET_FOLDER_NAME) project(OpcUaTests CXX) diff --git a/shared/libraries/opcuatms/opcuatms/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms/CMakeLists.txt index 35cf34b..b7bd299 100644 --- a/shared/libraries/opcuatms/opcuatms/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.10) set_cmake_folder_context(TARGET_FOLDER_NAME) project(opcuatms VERSION ${OPENDAQ_PACKAGE_VERSION} LANGUAGES CXX) diff --git a/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt index 7b0ec16..190673c 100644 --- a/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_client/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.10) set_cmake_folder_context(TARGET_FOLDER_NAME) project(opcuatms_client VERSION ${OPENDAQ_PACKAGE_VERSION} LANGUAGES CXX) diff --git a/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt index c587e6e..847fbec 100644 --- a/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_server/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.10) set_cmake_folder_context(TARGET_FOLDER_NAME) project(opcuatms_server VERSION ${OPENDAQ_PACKAGE_VERSION} LANGUAGES CXX) diff --git a/shared/libraries/opcuatms/tests/CMakeLists.txt b/shared/libraries/opcuatms/tests/CMakeLists.txt index 949577c..499d41e 100644 --- a/shared/libraries/opcuatms/tests/CMakeLists.txt +++ b/shared/libraries/opcuatms/tests/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.10) set_cmake_folder_context(TARGET_FOLDER_NAME) project(opcuatms_integration_tests CXX) From a2aaea5a86bb6fed0fd0dffa7564fa3659875c8d Mon Sep 17 00:00:00 2001 From: Jaka Mohorko <96818661+JakaMohorkoDS@users.noreply.github.com> Date: Mon, 16 Jun 2025 16:22:25 +0200 Subject: [PATCH 203/217] Allow IP connection with scheduler notification (openDAQ/openDAQ#834) --- .../opcuatms_client/objects/tms_client_input_port_impl.h | 1 + .../src/objects/tms_client_input_port_impl.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h index d3ed577..098cfb7 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_input_port_impl.h @@ -31,6 +31,7 @@ class TmsClientInputPortImpl : public TmsClientComponentBaseImpl Date: Wed, 18 Jun 2025 12:32:35 +0200 Subject: [PATCH 204/217] Remove opendaq_dev library (openDAQ/openDAQ#835) --- shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt index d8a25f5..7ab112a 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_client/src/CMakeLists.txt @@ -134,8 +134,6 @@ target_link_libraries(${LIB_NAME} PUBLIC daq::opcuatms daq::opcuaclient - PRIVATE - daq::opendaq_dev ) target_include_directories(${LIB_NAME} PUBLIC $ From 89d4331f440ff3e92658003155963a51211394c1 Mon Sep 17 00:00:00 2001 From: NikolaiShipilov <127689162+NikolaiShipilov@users.noreply.github.com> Date: Mon, 23 Jun 2025 00:58:36 -0700 Subject: [PATCH 205/217] Parallel device connection (openDAQ/openDAQ#828) * Add implementation of parallel device creation using std::async combined with existing device creation logic. * Introduce new OPENDAQ_PARTIAL_SUCCESS status code. * Add serialization support for IErrorInfo to enable error details transfer over the native configuration protocol. * Extend native configuration protocol (and bump version to 16) to support bulk device addition. --- .../opcuatms_client/objects/tms_client_device_impl.h | 3 +++ .../opcuatms_client/src/objects/tms_client_device_impl.cpp | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h index 4ffd7c0..cc00fe4 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h @@ -42,6 +42,9 @@ class TmsClientDeviceImpl : public TmsClientComponentBaseImpl onAddDevices(const DictPtr& connectionArgs, + DictPtr errCodes, + DictPtr errorInfos) override; void onRemoveDevice(const DevicePtr& device) override; DeviceInfoPtr onGetInfo() override; uint64_t onGetTicksSinceOrigin() override; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index dbccf1b..7a0b149 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -231,6 +231,13 @@ DevicePtr TmsClientDeviceImpl::onAddDevice(const StringPtr& /*connectionString*/ throw OpcUaClientCallNotAvailableException(); } +DictPtr TmsClientDeviceImpl::onAddDevices(const DictPtr& /*connectionArgs*/, + DictPtr /*errCodes*/, + DictPtr /*errorInfos*/) +{ + throw OpcUaClientCallNotAvailableException(); +} + void TmsClientDeviceImpl::onRemoveDevice(const DevicePtr& /*device*/) { throw OpcUaClientCallNotAvailableException(); From f05383281ae8bead357cb6043c5bf928a302a799 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko <96818661+JakaMohorkoDS@users.noreply.github.com> Date: Fri, 27 Jun 2025 07:04:28 +0200 Subject: [PATCH 206/217] Gracefully handle operation mode getters when not supported on server (openDAQ/openDAQ#848) --- .../src/objects/tms_client_device_impl.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 7a0b149..e266644 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -138,7 +138,10 @@ ErrCode TmsClientDeviceImpl::getAvailableOperationModes(IList** availableOpModes OPENDAQ_PARAM_NOT_NULL(availableOpModes); if (!this->hasReference("OperationModeOptions")) - return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_NOT_SUPPORTED, "OperationModes are not supported by the server"); + { + LOG_D("OperationModes are not supported by the server") + return Super::getAvailableOperationModes(availableOpModes); + } const auto nodeId = getNodeId("OperationModeOptions"); auto opModesNodeStrList = VariantConverter::ToDaqList(client->readValue(nodeId)); @@ -184,7 +187,10 @@ ErrCode TmsClientDeviceImpl::getOperationMode(OperationModeType* modeType) OPENDAQ_PARAM_NOT_NULL(modeType); if (!this->hasReference("OperationMode")) - return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_NOT_SUPPORTED, "OperationModes are not supported by the server"); + { + LOG_D("OperationModes are not supported by the server") + return Super::getOperationMode(modeType); + } const auto nodeId = getNodeId("OperationMode"); const auto variant = client->readValue(nodeId); From 52fb50b4a4d29fd7d9eaf28049c4d6159d7d1edb Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Fri, 20 Jun 2025 18:49:28 +0200 Subject: [PATCH 207/217] Exclude ComponentConfig from OPC UA Component Properties (openDAQ/openDAQ#842) --- .../src/objects/tms_client_component_impl.cpp | 14 +++++++------- .../objects/tms_client_property_object_impl.cpp | 5 ++++- .../opcuatms_server/objects/tms_server_component.h | 2 -- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp index c492cd3..b9b4069 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp @@ -210,13 +210,13 @@ bool TmsClientComponentBaseImpl::isChildComponent(const ComponentPtr& comp template PropertyObjectPtr TmsClientComponentBaseImpl::findAndCreateComponentConfig() { - PropertyObjectPtr componentConfig; - if (const auto& objIt = this->objectTypeIdMap.find("ComponentConfig"); objIt != this->objectTypeIdMap.cend()) - { - componentConfig = TmsClientPropertyObject(this->daqContext, this->clientContext, objIt->second); - this->objectTypeIdMap.erase(objIt); - } - return componentConfig; + + std::string referenceName = "ComponentConfig"; + if (!this->hasReference(referenceName)) + return nullptr; + + auto refNodeId = this->getNodeId(referenceName); + return TmsClientPropertyObject(this->daqContext, this->clientContext, refNodeId); } template class TmsClientComponentBaseImpl>; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index 6886d71..17a16a4 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -23,7 +23,10 @@ using namespace opcua; namespace detail { - std::unordered_set ignoredPropertyNames{"ServerCapabilities", "OperationMode", "OperationModeOptions"}; + std::unordered_set ignoredPropertyNames{"ServerCapabilities", + "OperationMode", + "OperationModeOptions", + "ComponentConfig"}; } template diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h index df54e46..f0c3cc5 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h @@ -235,8 +235,6 @@ void TmsServerComponent::addChildNodes() this->server->addVariableNode(params); - // this property will be added manually - tmsPropertyObject->ignoredProps.emplace("ComponentConfig"); tmsPropertyObject->registerToExistingOpcUaNode(this->nodeId); if (tmsComponentConfig) tmsComponentConfig->registerOpcUaNode(this->nodeId); From 7ebe18a0d4d77f19475fcebf1498dfea8ca4e59f Mon Sep 17 00:00:00 2001 From: Jaka Mohorko <96818661+JakaMohorkoDS@users.noreply.github.com> Date: Wed, 16 Jul 2025 10:02:02 +0200 Subject: [PATCH 208/217] Add support for list and dictionary item/key type identification in Argument Info (openDAQ/openDAQ#861) --- .../src/converters/argument_converter.cpp | 4 ++ .../objects/tms_server_component.h | 2 + .../objects/tms_server_object.h | 1 + .../src/objects/tms_server_object.cpp | 3 + .../objects/tms_server_property_object.cpp | 11 +++- .../test_tms_property_object.cpp | 61 +++++++++++++++++++ 6 files changed, 80 insertions(+), 2 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/argument_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/argument_converter.cpp index 30b45fe..db522f3 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/argument_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/argument_converter.cpp @@ -30,6 +30,10 @@ OpcUaObject StructConverter::ToTmsType( OpcUaObject uaArg; uaArg->description = UA_LOCALIZEDTEXT_ALLOC("", ""); uaArg->name = UA_STRING_ALLOC(object.getName().getCharPtr()); + + auto type = object.getType(); + if (type == ctList || type == ctDict) + throw InvalidTypeException{"The OPC UA server does not yet support list or dictionary type arguments."}; uaArg->dataType = CoreTypeToUANodeID(object.getType()).getDetachedValue(); // TODO: handle list and dict diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h index f0c3cc5..8d1b50e 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h @@ -76,6 +76,8 @@ TmsServerComponent::TmsServerComponent(const ComponentPtr& object, const Op if (componentConfig.assigned()) tmsComponentConfig = std::make_unique(componentConfig, this->server, this->daqContext, this->tmsContext, "ComponentConfig"); } + + this->loggerComponent = this->daqContext.getLogger().getOrAddComponent("OPCUAServerComponent"); } template diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h index e415d52..f3a5707 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_object.h @@ -147,6 +147,7 @@ class TmsServerObject : public std::enable_shared_from_this uint32_t numberInList; TmsServerContextPtr tmsContext; std::unordered_map> references; + LoggerComponentPtr loggerComponent; private: void bindCallbacksInternal(); diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp index 9ba753e..201084c 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_object.cpp @@ -16,6 +16,9 @@ TmsServerObject::TmsServerObject(const OpcUaServerPtr& server, const ContextPtr& , daqContext(context) , numberInList(0) , tmsContext(tmsContext) + , loggerComponent(daqContext.getLogger().assigned() + ? daqContext.getLogger().getOrAddComponent("OPCUAServerComponent") + : throw ArgumentNullException("Logger must not be null")) { } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp index 421f0be..087f3ec 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp @@ -12,6 +12,7 @@ #include #include #include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -25,6 +26,7 @@ TmsServerPropertyObject::TmsServerPropertyObject(const PropertyObjectPtr& object : Super(object, server, context, tmsContext) , ignoredProps(ignoredProps) { + loggerComponent = daqContext.getLogger().getOrAddComponent("OPCUAServerPropertyObject"); } TmsServerPropertyObject::TmsServerPropertyObject(const PropertyObjectPtr& object, @@ -242,6 +244,7 @@ void TmsServerPropertyObject::registerEvalValueNode(const std::string& nodeName, childEvalValues.insert({childNodeId, serverObject}); } +// TODO: Procedure/Function properties with list/dictionary types are not yet supported over OPC UA! void TmsServerPropertyObject::addMethodPropertyNode(const PropertyPtr& prop, uint32_t numberInList) { const auto name = prop.getName(); @@ -283,9 +286,13 @@ void TmsServerPropertyObject::addMethodPropertyNode(const PropertyPtr& prop, uin methodProps.insert({methodNodeId, {name, prop.getValueType()}}); } - catch(...) + catch(const std::exception& e) { - // TODO: Log failure to add method node + LOG_W("Failed to add method property node {}: {}", name, e.what()); + } + catch (...) + { + LOG_W("Failed to add method property node {}.", name); } } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp index 051b4cd..9d1e625 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp @@ -14,6 +14,8 @@ #include #include +#include +#include using namespace daq; using namespace opcua::tms; @@ -351,6 +353,65 @@ TEST_F(TmsPropertyObjectTest, DotAccessClientServerChange) ASSERT_EQ(prop.getValue(), "bar"); } +TEST_F(TmsPropertyObjectTest, ProcedurePropWithListArg) +{ + PropertyObjectPtr obj = PropertyObject(); + auto argInfo = ListArgumentInfo("Int", ctInt); + + auto prop = FunctionProperty("ProcedureProp", ProcedureInfo(List(argInfo))); + obj.addProperty(prop); + auto proc = Procedure( + [](const ListPtr& list) + { + for (const auto& val : list) + ASSERT_EQ(val.getCoreType(), ctInt); + }); + + obj.setPropertyValue("ProcedureProp", proc); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + ASSERT_FALSE(clientObj.hasProperty("ProcedureProp")); + + // TODO: Procedure/Function properties with list/dictionary types are not yet supported over OPC UA! + //proc = clientObj.getPropertyValue("ProcedureProp"); + + //ASSERT_EQ(clientObj.getProperty("ProcedureProp").getCallableInfo().getArguments()[0], argInfo); + + //auto listArg = List(Integer(1), Integer(2)); + //proc(listArg); +} +TEST_F(TmsPropertyObjectTest, ProcedurePropWithDictArg) +{ + PropertyObjectPtr obj = PropertyObject(); + auto argInfo = DictArgumentInfo("Int", ctInt, ctString); + + auto prop = FunctionProperty("ProcedureProp", ProcedureInfo(List(argInfo))); + obj.addProperty(prop); + auto proc = Procedure( + [](const DictPtr& dict) + { + for (const auto& [key, val] : dict) + { + ASSERT_EQ(key.getCoreType(), ctInt); + ASSERT_EQ(val.getCoreType(), ctString); + } + }); + + obj.setPropertyValue("ProcedureProp", proc); + + auto [serverObj, clientObj] = registerPropertyObject(obj); + + ASSERT_FALSE(clientObj.hasProperty("ProcedureProp")); + + // TODO: Procedure/Function properties with list/dictionary types are not yet supported over OPC UA! + //proc = clientObj.getPropertyValue("ProcedureProp"); + + //ASSERT_EQ(clientObj.getProperty("ProcedureProp").getCallableInfo().getArguments()[0], argInfo); + + //auto dictArg = Dict({{0, "foo"}, {1, "bar"}}); + //proc(dictArg); +} + class TmsNestedPropertyObjectTest : public TmsObjectIntegrationTest { public: From 26fce2872cdb5fc85b3f5324347648e8b6c9464b Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Sat, 2 Aug 2025 08:26:24 +0200 Subject: [PATCH 209/217] Improving error logging and implementing an error guard (openDAQ/openDAQ#849) --- .../opcua_client_module/tests/test_app.cpp | 2 +- .../opcuaclient/src/attribute_reader.cpp | 3 -- .../src/cached_reference_browser.cpp | 1 - .../opcua/opcuaserver/src/opcuaserver.cpp | 1 + .../opcua/opcuashared/src/opcuavariant.cpp | 1 - .../converters/generic_struct_converter.cpp | 3 +- .../objects/tms_client_input_port_impl.cpp | 21 +++++---- .../tms_client_property_object_impl.cpp | 46 ++++++++++--------- .../src/objects/tms_client_signal_impl.cpp | 4 +- .../opcuatms_client/src/tms_client.cpp | 3 +- .../src/objects/tms_server_device.cpp | 3 -- .../src/objects/tms_server_input_port.cpp | 1 - .../opcuatms_server/src/tms_server.cpp | 1 - 13 files changed, 42 insertions(+), 48 deletions(-) diff --git a/modules/opcua_client_module/tests/test_app.cpp b/modules/opcua_client_module/tests/test_app.cpp index 546baf7..a7ce761 100644 --- a/modules/opcua_client_module/tests/test_app.cpp +++ b/modules/opcua_client_module/tests/test_app.cpp @@ -17,5 +17,5 @@ int main(int argc, char** args) auto res = RUN_ALL_TESTS(); - return res; + return res; } diff --git a/shared/libraries/opcua/opcuaclient/src/attribute_reader.cpp b/shared/libraries/opcua/opcuaclient/src/attribute_reader.cpp index 544d5eb..10e9e57 100644 --- a/shared/libraries/opcua/opcuaclient/src/attribute_reader.cpp +++ b/shared/libraries/opcua/opcuaclient/src/attribute_reader.cpp @@ -1,7 +1,4 @@ #include -#include -#include -#include BEGIN_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp b/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp index b5501e6..5b72b0e 100644 --- a/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp +++ b/shared/libraries/opcua/opcuaclient/src/cached_reference_browser.cpp @@ -1,5 +1,4 @@ #include -#include BEGIN_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp b/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp index 14e42b9..94b21c3 100644 --- a/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp +++ b/shared/libraries/opcua/opcuaserver/src/opcuaserver.cpp @@ -206,6 +206,7 @@ bool OpcUaServer::isUsernameIdentityTokenValid(const UA_UserNameIdentityToken* t try { + auto errorGuard = DAQ_ERROR_GUARD(); authenticationProvider.authenticate(username, password); } catch (const DaqException&) diff --git a/shared/libraries/opcua/opcuashared/src/opcuavariant.cpp b/shared/libraries/opcua/opcuashared/src/opcuavariant.cpp index 0ac1bc2..de70be7 100644 --- a/shared/libraries/opcua/opcuashared/src/opcuavariant.cpp +++ b/shared/libraries/opcua/opcuashared/src/opcuavariant.cpp @@ -3,7 +3,6 @@ #include #include #include -#include BEGIN_NAMESPACE_OPENDAQ_OPCUA diff --git a/shared/libraries/opcuatms/opcuatms/src/converters/generic_struct_converter.cpp b/shared/libraries/opcuatms/opcuatms/src/converters/generic_struct_converter.cpp index 98ab26d..9404f95 100644 --- a/shared/libraries/opcuatms/opcuatms/src/converters/generic_struct_converter.cpp +++ b/shared/libraries/opcuatms/opcuatms/src/converters/generic_struct_converter.cpp @@ -2,11 +2,10 @@ #include #include #include +#include #include #include #include -#include -#include #include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp index 7a63230..cd62fc8 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp @@ -39,7 +39,7 @@ ErrCode TmsClientInputPortImpl::acceptsSignal(ISignal* signal, Bool* accepts) { return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_OPCUA_CLIENT_CALL_NOT_AVAILABLE); - //return daqTry([&]() + //const ErrCode errCode = daqTry([&]() //{ // OpcUaNodeId methodId(NAMESPACE_DAQBSP, UA_DAQBSPID_INPUTPORTTYPE_ACCEPTSSIGNAL); @@ -57,11 +57,13 @@ ErrCode TmsClientInputPortImpl::acceptsSignal(ISignal* signal, Bool* accepts) // return OPENDAQ_SUCCESS; // //}); + //OPENDAQ_RETURN_IF_FAILED(errCode); + //return errCode; } ErrCode TmsClientInputPortImpl::connect(ISignal* signal) { - return daqTry([&]() + const ErrCode errCode = daqTry([&]() { if (!isChildComponent(signal)) DAQ_THROW_EXCEPTION(NotFoundException); @@ -85,6 +87,8 @@ ErrCode TmsClientInputPortImpl::connect(ISignal* signal) if (response->statusCode != UA_STATUSCODE_GOOD) throw OpcUaGeneralException(); }); + OPENDAQ_RETURN_IF_FAILED(errCode); + return errCode; } ErrCode TmsClientInputPortImpl::connectSignalSchedulerNotification(ISignal* signal) @@ -94,7 +98,7 @@ ErrCode TmsClientInputPortImpl::connectSignalSchedulerNotification(ISignal* sign ErrCode TmsClientInputPortImpl::disconnect() { - return daqTry([&]() + const ErrCode errCode = daqTry([&]() { const auto methodNodeId = getNodeId("Disconnect"); @@ -108,12 +112,15 @@ ErrCode TmsClientInputPortImpl::disconnect() if (response->statusCode != UA_STATUSCODE_GOOD) throw OpcUaGeneralException(); }); + OPENDAQ_RETURN_IF_FAILED(errCode); + return errCode; } ErrCode TmsClientInputPortImpl::getSignal(ISignal** signal) { SignalPtr signalPtr; - ErrCode errCode = wrapHandlerReturn(this, &TmsClientInputPortImpl::onGetSignal, signalPtr); + const ErrCode errCode = wrapHandlerReturn(this, &TmsClientInputPortImpl::onGetSignal, signalPtr); + OPENDAQ_RETURN_IF_FAILED(errCode); *signal = signalPtr.detach(); return errCode; @@ -142,11 +149,7 @@ SignalPtr TmsClientInputPortImpl::onGetSignal() ErrCode TmsClientInputPortImpl::getConnection(IConnection** connection) { - return daqTry([&]() - { - // TODO: Implement. Awaits support to implement - return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_NOTIMPLEMENTED); - }); + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_NOTIMPLEMENTED); } END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index 17a16a4..94c07d9 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -36,34 +36,35 @@ ErrCode TmsClientPropertyObjectBaseImpl::setOPCUAPropertyValueInternal(ISt { LOG_W("Failed to set value for property with nullptr name on OpcUA client property object"); return OPENDAQ_SUCCESS; - } + } auto propertyNamePtr = StringPtr::Borrow(propertyName); if (this->isChildProperty(propertyNamePtr)) { PropertyPtr prop; - ErrCode err = getProperty(propertyNamePtr, &prop); - OPENDAQ_RETURN_IF_FAILED(err); + const ErrCode errCode = getProperty(propertyNamePtr, &prop); + OPENDAQ_RETURN_IF_FAILED(errCode); if (!prop.assigned()) - throw NotFoundException(R"(Child property "{}" not found)", propertyNamePtr); + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_NOTFOUND, fmt::format(R"(Child property "{}" not found)", propertyNamePtr)); if (protectedWrite) - return prop.asPtr()->setValueProtected(value); + return prop.asPtr(true)->setValueProtected(value); return prop->setValue(value); } - StringPtr lastProcessDescription = ""; + std::string lastProcessDescription = ""; ErrCode errCode = daqTry([&] { if (const auto& it = introspectionVariableIdMap.find(propertyNamePtr); it != introspectionVariableIdMap.cend()) { PropertyPtr prop; - checkErrorInfo(getProperty(propertyName, &prop)); - if (!protectedWrite) + const ErrCode errCode = getProperty(propertyName, &prop); + OPENDAQ_RETURN_IF_FAILED(errCode); + + if (!protectedWrite && prop.getReadOnly()) { lastProcessDescription = "Checking existing property is read-only"; - if (prop.getReadOnly()) - return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_ACCESSDENIED); + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_ACCESSDENIED, fmt::format("Property \"{}\" is read-only", propertyNamePtr)); } BaseObjectPtr valuePtr = value; @@ -82,27 +83,28 @@ ErrCode TmsClientPropertyObjectBaseImpl::setOPCUAPropertyValueInternal(ISt { lastProcessDescription = "Setting property value"; const auto refProp = this->objPtr.getProperty(propertyName).getReferencedProperty(); - return setPropertyValue(refProp.getName(), value); + const ErrCode errCode = setPropertyValue(refProp.getName(), value); + OPENDAQ_RETURN_IF_FAILED(errCode, fmt::format("Failed to set value for referenced property \"{}\"", propertyNamePtr)); + return errCode; } if (const auto& it = objectTypeIdMap.find((propertyNamePtr)); it != objectTypeIdMap.cend()) { lastProcessDescription = "Object type properties cannot be set over OpcUA"; - return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_NOTIMPLEMENTED); + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_NOTIMPLEMENTED, "Object type properties cannot be set over OpcUA"); } lastProcessDescription = "Property not found"; - return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_NOTFOUND); + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_NOTFOUND, fmt::format("Property \"{}\" not found", propertyNamePtr)); }); if (OPENDAQ_FAILED(errCode)) LOG_W("Failed to set value for property \"{}\" on OpcUA client property object: {}", propertyNamePtr, lastProcessDescription); if (errCode == OPENDAQ_ERR_NOTFOUND || errCode == OPENDAQ_ERR_ACCESSDENIED) - return DAQ_MAKE_ERROR_INFO(errCode, fmt::format("Property \"{}\" not found or access denied", propertyNamePtr)); + return DAQ_EXTEND_ERROR_INFO(errCode, fmt::format("Failed to set value for property \"{}\" on OpcUA client property object", propertyNamePtr)); else if (OPENDAQ_FAILED(errCode)) daqClearErrorInfo(); - return OPENDAQ_SUCCESS; } @@ -146,26 +148,26 @@ ErrCode INTERFACE_FUNC TmsClientPropertyObjectBaseImpl::getPropertyValue(I OPENDAQ_RETURN_IF_FAILED(err); if (!prop.assigned()) - throw NotFoundException(R"(Child property "{}" not found)", propertyNamePtr); - + return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_NOTFOUND, fmt::format(R"(Child property "{}" not found)", propertyNamePtr)); return prop->getValue(value); } - StringPtr lastProccessDescription = ""; ErrCode errCode = daqTry([&] { if (const auto& introIt = introspectionVariableIdMap.find(propertyNamePtr); introIt != introspectionVariableIdMap.cend()) { const auto variant = client->readValue(introIt->second); const auto object = VariantConverter::ToDaqObject(variant, daqContext); - Impl::setProtectedPropertyValue(propertyName, object); + const ErrCode errCode = Impl::setProtectedPropertyValue(propertyName, object); + OPENDAQ_RETURN_IF_FAILED(errCode, fmt::format("Failed to get value for introspection property \"{}\"", propertyNamePtr)); } else if (referenceVariableIdMap.count(propertyNamePtr)) { const auto refProp = this->objPtr.getProperty(propertyName).getReferencedProperty(); - return getPropertyValue(refProp.getName(), value); + const ErrCode errCode = getPropertyValue(refProp.getName(), value); + OPENDAQ_RETURN_IF_FAILED(errCode, fmt::format("Failed to get value for referenced property \"{}\"", propertyNamePtr)); + return errCode; } - return Impl::getPropertyValue(propertyName, value); }); if (OPENDAQ_FAILED(errCode)) @@ -577,7 +579,7 @@ PropertyObjectPtr TmsClientPropertyObjectBaseImpl::cloneChildPropertyObjec return TmsClientPropertyObject(daqContext, clientContext, objIt->second); } - throw NotFoundException{"Object property with name {} not found", propName}; + DAQ_THROW_EXCEPTION(NotFoundException, "Object property with name {} not found", propName); } return nullptr; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp index 0fde018..ff8bc1a 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp @@ -110,13 +110,13 @@ ErrCode TmsClientSignalImpl::setDomainSignal(ISignal* signal) ErrCode TmsClientSignalImpl::getRelatedSignals(IList** signals) { ListPtr signalsPtr; - ErrCode errCode = wrapHandlerReturn(this, &TmsClientSignalImpl::onGetRelatedSignals, signalsPtr); - *signals = signalsPtr.detach(); + const ErrCode errCode = wrapHandlerReturn(this, &TmsClientSignalImpl::onGetRelatedSignals, signalsPtr); if (OPENDAQ_FAILED(errCode)) { daqClearErrorInfo(); LOG_W("Failed to get related signals on OpcUA client signal \"{}\"", this->globalId); } + *signals = signalsPtr.detach(); return OPENDAQ_SUCCESS; } diff --git a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp index 4e672bd..9df603b 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/tms_client.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -10,7 +9,7 @@ #include #include -#include +#include #include #include diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp index 7946e31..e7ad30a 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_device.cpp @@ -1,7 +1,4 @@ -#include #include -#include -#include #include #include #include diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp index d7bf122..5eb6342 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_input_port.cpp @@ -1,4 +1,3 @@ -#include #include #include #include diff --git a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp index 874bc22..64f99f8 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/tms_server.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include From 902c729f27965c026a77d7cddbaede0a7fad908b Mon Sep 17 00:00:00 2001 From: Jaka Mohorko <96818661+JakaMohorkoDS@users.noreply.github.com> Date: Mon, 18 Aug 2025 07:28:13 +0200 Subject: [PATCH 210/217] onRead events over native + Suggested/Selection values onRead (openDAQ/openDAQ#865) --- .../src/objects/tms_client_device_impl.cpp | 6 +++++- .../test_tms_property_object.cpp | 13 +++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index e266644..8f4a2a3 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -374,6 +374,11 @@ DeviceInfoPtr TmsClientDeviceImpl::onGetInfo() } } + deviceInfo.getOnPropertyValueRead("name") += [this](PropertyObjectPtr&, PropertyValueEventArgsPtr& args) + { + args.setValue(this->client->readDisplayName(this->nodeId)); + }; + for (const auto & entry : deviceInfoChangeableFields) { const auto& propName = entry.first; @@ -396,7 +401,6 @@ DeviceInfoPtr TmsClientDeviceImpl::onGetInfo() } catch (...) { - } } diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp index 9d1e625..f316843 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_property_object.cpp @@ -412,6 +412,19 @@ TEST_F(TmsPropertyObjectTest, ProcedurePropWithDictArg) //proc(dictArg); } +TEST_F(TmsPropertyObjectTest, StringSuggestedValues) +{ + PropertyObjectPtr obj = PropertyObject(); + obj.addProperty(StringPropertyBuilder("StringSuggestedValues", "Orange").setSuggestedValues(List("Apple", "Orange", "Mango")).build()); + auto [serverObj, clientObj] = registerPropertyObject(obj); + + // TODO: String suggested values are not yet supported over OPC UA! + //ASSERT_EQ(clientObj.getProperty("StringSuggestedValues").getSuggestedValues(), List("Apple", "Orange", "Mango")); + ASSERT_EQ(clientObj.getProperty("StringSuggestedValues").getSuggestedValues(), nullptr); + + ASSERT_NO_THROW(clientObj.setPropertyValue("StringSuggestedValues", "Tomato")); +} + class TmsNestedPropertyObjectTest : public TmsObjectIntegrationTest { public: From 848b16f6611993ba3e367e3ad65585243a87fb26 Mon Sep 17 00:00:00 2001 From: viacheslauK Date: Wed, 20 Aug 2025 13:01:57 +0200 Subject: [PATCH 211/217] Opcua warnings (openDAQ/openDAQ#880) Description: - Adding default values for node attributes; - Additional check of method args (if list/dict) before adding a method property node; Changelog: * fix: check if method args contain a list/dict before adding a method-property-node (list/dictionary types are not yet supported over OPC UA) * [TBBAS-1960] fix: default value for variable node attributes; it fixes a warning "Writing the value of Node failed with the following reason: DataType of the value is incompatible" * [TBBAS-1960] fix: default value for hbk variable node attributes; it fixes a warning "Writing the value of Node failed with the following reason: DataType of the value is incompatible" --- ...-default-values-for-double-variables.patch | 144 ++++++++++++++++++ external/opcua_daq_types/hbk/CMakeLists.txt | 22 +-- .../objects/tms_server_property_object.cpp | 14 +- .../src/objects/tms_server_variable.cpp | 12 +- 4 files changed, 179 insertions(+), 13 deletions(-) create mode 100644 external/opcua_daq_types/hbk/001-add-default-values-for-double-variables.patch diff --git a/external/opcua_daq_types/hbk/001-add-default-values-for-double-variables.patch b/external/opcua_daq_types/hbk/001-add-default-values-for-double-variables.patch new file mode 100644 index 0000000..59898c4 --- /dev/null +++ b/external/opcua_daq_types/hbk/001-add-default-values-for-double-variables.patch @@ -0,0 +1,144 @@ +diff --git a/opendaq/hbk/Opc.Ua.Daq.Vendor.Hbk.NodeSet2.xml b/opendaq/hbk/Opc.Ua.Daq.Vendor.Hbk.NodeSet2.xml +index fec43da..61474e8 100644 +--- a/opendaq/hbk/Opc.Ua.Daq.Vendor.Hbk.NodeSet2.xml ++++ b/opendaq/hbk/Opc.Ua.Daq.Vendor.Hbk.NodeSet2.xml +@@ -3596,6 +3596,9 @@ + i=78 + ns=1;i=5127 + ++ ++ 0 ++ + + + EngineeringUnits +@@ -3687,6 +3690,9 @@ + ns=1;i=7162 + ns=1;i=5127 + ++ ++ 0 ++ + + + DefaultValue +@@ -5103,6 +5109,9 @@ + ns=2;i=2004 + ns=1;i=5013 + ++ ++ 0 ++ + + + DefaultValue +@@ -5203,6 +5212,9 @@ + ns=2;i=2004 + ns=1;i=5013 + ++ ++ 0 ++ + + + DefaultValue +@@ -6186,6 +6198,9 @@ + i=78 + ns=1;i=5134 + ++ ++ 0 ++ + + + EngineeringUnits +@@ -6277,6 +6292,9 @@ + ns=1;i=7202 + ns=1;i=5134 + ++ ++ 0 ++ + + + DefaultValue +@@ -7926,6 +7944,9 @@ + i=80 + ns=1;i=1003 + ++ ++ 0 ++ + + + DefaultValue +@@ -9496,6 +9517,9 @@ + i=80 + ns=1;i=6072 + ++ ++ 0 ++ + + + DefaultValue +@@ -9729,6 +9753,9 @@ + ns=1;i=6912 + ns=1;i=1005 + ++ ++ 0 ++ + + + DefaultValue +@@ -9821,6 +9848,9 @@ + ns=1;i=6913 + ns=1;i=1005 + ++ ++ 0 ++ + + + DefaultValue +@@ -9868,6 +9898,9 @@ + i=78 + ns=1;i=1048 + ++ ++ 0 ++ + + + EngineeringUnits +@@ -10193,6 +10226,9 @@ + ns=2;i=2004 + ns=1;i=1048 + ++ ++ 0 ++ + + + DefaultValue +@@ -16552,6 +16588,9 @@ + ns=1;i=7455 + ns=1;i=5098 + ++ ++ 0 ++ + + + EngineeringUnits +@@ -16643,6 +16682,9 @@ + ns=2;i=2004 + ns=1;i=5098 + ++ ++ 0 ++ + + + DefaultValue diff --git a/external/opcua_daq_types/hbk/CMakeLists.txt b/external/opcua_daq_types/hbk/CMakeLists.txt index b84ba76..28441bd 100644 --- a/external/opcua_daq_types/hbk/CMakeLists.txt +++ b/external/opcua_daq_types/hbk/CMakeLists.txt @@ -1,17 +1,17 @@ set(daq_hbk_REQUIREDVERSION "3.0.12") -get_custom_fetch_content_params(daqhbkspec FC_PARAMS) -FetchContent_Declare(daqhbkspec - GIT_REPOSITORY "https://github.com/hbkworld/opc-ua-specs.git" - GIT_TAG v${daq_hbk_REQUIREDVERSION} - ${FC_PARAMS} +message(STATUS "Fetching hbk daq specification ${daq_hbk_REQUIREDVERSION}...") + +opendaq_dependency( + NAME daqhbkspec + REQUIRED_VERSION ${daq_hbk_REQUIREDVERSION} + GIT_REPOSITORY https://github.com/hbkworld/opc-ua-specs.git + GIT_REF v${daq_hbk_REQUIREDVERSION} + PATCH_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/hbk/001-add-default-values-for-double-variables.patch ) -FetchContent_GetProperties(daqhbkspec) -if(NOT daqhbkspec_POPULATED) - message(STATUS "Fetching hbk daq specification ${daq_hbk_REQUIREDVERSION}...") - FetchContent_Populate(daqhbkspec) - list(APPEND VENDOR_COMPANION_SPECIFICATION_DIRPREFIX "${daqhbkspec_SOURCE_DIR}/opendaq/hbk") -endif() + +list(APPEND VENDOR_COMPANION_SPECIFICATION_DIRPREFIX "${daqhbkspec_SOURCE_DIR}/opendaq/hbk") message(STATUS "Generating DAQ Hbk nodeset...") diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp index 087f3ec..4f4f9af 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_property_object.cpp @@ -100,7 +100,19 @@ void TmsServerPropertyObject::addChildNodes() continue; if (prop.getValueType() == ctFunc || prop.getValueType() == ctProc) { - addMethodPropertyNode(prop, propOrder[propName]); + const auto args = prop.getCallableInfo().getArguments(); + bool isCompatibleArg = true; + for (SizeT i = 0; (args.assigned() && i < args.getCount()); i++) + { + const auto type = args.getItemAt(i).getType(); + // The OPC UA server does not yet support list or dictionary type arguments + isCompatibleArg = (type != ctList && type != ctDict); + if (!isCompatibleArg) + break; + } + + if (isCompatibleArg) + addMethodPropertyNode(prop, propOrder[propName]); continue; } diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp index f50cf90..c1bb5ad 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp @@ -44,7 +44,17 @@ void TmsServerVariable::configureVariableNodeAttributes(opcua::OpcUaOb const auto dataType = this->getDataTypeId(); if (!dataType.isNull()) { - attr->dataType = dataType.getValue(); + attr->dataType = dataType.getValue(); + if (attr->dataType.identifier.numeric == UA_NS0ID_INT64) + { + UA_Int64 var = 0; + UA_Variant_setScalarCopy(&attr->value, &var, &UA_TYPES[UA_TYPES_INT64]); + } + else if (attr->dataType.identifier.numeric == UA_NS0ID_DOUBLE) + { + UA_Double var = 0; + UA_Variant_setScalarCopy(&attr->value, &var, &UA_TYPES[UA_TYPES_DOUBLE]); + } } else { From 7a3dcc3e4499a0f4f2366af8ff14dacb7c05cbee Mon Sep 17 00:00:00 2001 From: NikolaiShipilov <127689162+NikolaiShipilov@users.noreply.github.com> Date: Sun, 31 Aug 2025 23:42:42 -0700 Subject: [PATCH 212/217] Generalized client-to-device streaming (openDAQ/openDAQ#867) --- .../opcuatms_client/objects/tms_client_component_impl.h | 4 +++- .../opcuatms_client/objects/tms_client_device_impl.h | 1 + .../opcuatms_client/objects/tms_client_input_port_impl.h | 6 ++++-- .../objects/tms_client_property_object_impl.h | 6 +++--- .../opcuatms_client/objects/tms_client_signal_impl.h | 1 - .../src/objects/tms_client_component_impl.cpp | 5 +++-- .../opcuatms_client/src/objects/tms_client_device_impl.cpp | 5 +++++ .../src/objects/tms_client_input_port_impl.cpp | 5 +++++ .../src/objects/tms_client_property_object_impl.cpp | 4 ++-- .../opcuatms_client/src/objects/tms_client_signal_impl.cpp | 4 +--- 10 files changed, 27 insertions(+), 14 deletions(-) diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h index 66bd481..b6e1575 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_component_impl.h @@ -39,6 +39,7 @@ class TmsClientComponentBaseImpl : public TmsClientPropertyObjectBaseImpl const opcua::OpcUaNodeId& nodeId, const std::map& propBrowseName = {}) : TmsClientPropertyObjectBaseImpl(ctx, parent, localId, clientContext, nodeId, propBrowseName) + , remoteComponentId(nodeId.getIdentifier()) { initComponent(); clientContext->readObjectAttributes(nodeId); @@ -72,9 +73,10 @@ class TmsClientComponentBaseImpl : public TmsClientPropertyObjectBaseImpl protected: bool isChildComponent(const ComponentPtr& component); - PropertyObjectPtr findAndCreateComponentConfig(); + std::string remoteComponentId; + private: LoggerComponentPtr getLoggerComponent(); void initComponent(); diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h index cc00fe4..8af26ab 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_device_impl.h @@ -65,6 +65,7 @@ class TmsClientDeviceImpl : public TmsClientComponentBaseImpl -#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS -class TmsClientInputPortImpl : public TmsClientComponentBaseImpl> +class TmsClientInputPortImpl : public TmsClientComponentBaseImpl> { public: explicit TmsClientInputPortImpl(const ContextPtr& ctx, @@ -38,6 +38,8 @@ class TmsClientInputPortImpl : public TmsClientComponentBaseImpl #include #include -#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -71,7 +71,7 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl init(); } - template > = 0> + template > = 0> TmsClientPropertyObjectBaseImpl(const ContextPtr& ctx, const ComponentPtr& parent, const StringPtr& localId, @@ -85,7 +85,7 @@ class TmsClientPropertyObjectBaseImpl : public TmsClientObjectImpl, public Impl init(); } - template, ChannelImpl, PropertyObjectImpl, ServerCapabilityConfigImpl, GenericInputPortImpl> = 0> + template, ChannelImpl, PropertyObjectImpl, ServerCapabilityConfigImpl, MirroredInputPortBase> = 0> TmsClientPropertyObjectBaseImpl(const ContextPtr& ctx, const ComponentPtr& parent, const StringPtr& localId, diff --git a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h index 3ad423a..0a2f396 100644 --- a/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h +++ b/shared/libraries/opcuatms/opcuatms_client/include/opcuatms_client/objects/tms_client_signal_impl.h @@ -56,7 +56,6 @@ class TmsClientSignalImpl final : public TmsClientComponentBaseImpl isPublic = true; - std::string deviceSignalId; private: std::unique_ptr descriptorNodeId; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp index b9b4069..eb4882c 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_component_impl.cpp @@ -5,8 +5,9 @@ #include #include #include -#include +#include #include + BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS using namespace daq::opcua; @@ -226,7 +227,7 @@ template class TmsClientComponentBaseImpl>; template class TmsClientComponentBaseImpl>; template class TmsClientComponentBaseImpl>; -template class TmsClientComponentBaseImpl>; +template class TmsClientComponentBaseImpl>; template class TmsClientComponentBaseImpl>; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp index 8f4a2a3..941de19 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_device_impl.cpp @@ -682,6 +682,11 @@ bool TmsClientDeviceImpl::isAddedToLocalComponentTree() return this->clientContext->getRootDevice() == this->thisPtr(); } +StringPtr TmsClientDeviceImpl::onGetRemoteId() const +{ + return String(remoteComponentId).detach(); +} + void TmsClientDeviceImpl::findAndCreateCustomComponents() { std::map orderedComponents; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp index cd62fc8..4c7c006 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_input_port_impl.cpp @@ -147,6 +147,11 @@ SignalPtr TmsClientInputPortImpl::onGetSignal() return nullptr; } +StringPtr TmsClientInputPortImpl::onGetRemoteId() const +{ + return String(remoteComponentId).detach(); +} + ErrCode TmsClientInputPortImpl::getConnection(IConnection** connection) { return DAQ_MAKE_ERROR_INFO(OPENDAQ_ERR_NOTIMPLEMENTED); diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp index 94c07d9..6994eb6 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_property_object_impl.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include @@ -601,7 +601,7 @@ template class TmsClientPropertyObjectBaseImpl>; template class TmsClientPropertyObjectBaseImpl>; template class TmsClientPropertyObjectBaseImpl>; -template class TmsClientPropertyObjectBaseImpl>; +template class TmsClientPropertyObjectBaseImpl>; template class TmsClientPropertyObjectBaseImpl; template class TmsClientPropertyObjectBaseImpl>; diff --git a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp index ff8bc1a..a6a49bf 100644 --- a/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/src/objects/tms_client_signal_impl.cpp @@ -21,8 +21,6 @@ TmsClientSignalImpl::TmsClientSignalImpl( ) : TmsClientComponentBaseImpl(ctx, parent, localId, clientContext, nodeId) { - deviceSignalId = nodeId.getIdentifier(); - if (hasReference("Value")) { const auto valueNodeId = clientContext->getReferenceBrowser()->getChildNodeId(nodeId, "Value"); @@ -168,7 +166,7 @@ Bool TmsClientSignalImpl::onTriggerEvent(const EventPacketPtr& eventPacket) StringPtr TmsClientSignalImpl::onGetRemoteId() const { - return String(deviceSignalId); + return String(remoteComponentId).detach(); } ErrCode TmsClientSignalImpl::getLastValue(IBaseObject** value) From 97d26bcae03d3f2ee72ebe0976ed36b1f90cd4e0 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko <96818661+JakaMohorkoDS@users.noreply.github.com> Date: Tue, 23 Sep 2025 08:59:31 +0200 Subject: [PATCH 213/217] Other/merge 3.30 rc (openDAQ/openDAQ#928) --- .../opcuaclient/tests/include/opcuaservertesthelper.h | 2 +- .../opcuaclient/tests/src/opcuaservertesthelper.cpp | 2 +- .../opcuaclient/tests/src/test_attribute_reader.cpp | 3 ++- .../tests/src/test_cached_reference_browser.cpp | 2 +- .../opcuashared/include/opcuashared/opcua_attribute.h | 2 +- .../opcuatms_integration/test_tms_integration.cpp | 11 +++++++---- 6 files changed, 13 insertions(+), 9 deletions(-) diff --git a/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h b/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h index b343a96..29a536b 100644 --- a/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h +++ b/shared/libraries/opcua/opcuaclient/tests/include/opcuaservertesthelper.h @@ -50,7 +50,7 @@ class OpcUaServerTestHelper final const UA_DataType* type, UA_NodeId* parentNodeId, const char* locale = "en_US", - int nodeIndex = 1, + uint16_t nodeIndex = 1, size_t dimension = 1); private: diff --git a/shared/libraries/opcua/opcuaclient/tests/src/opcuaservertesthelper.cpp b/shared/libraries/opcua/opcuaclient/tests/src/opcuaservertesthelper.cpp index 4a0e59d..4cd2445 100644 --- a/shared/libraries/opcua/opcuaclient/tests/src/opcuaservertesthelper.cpp +++ b/shared/libraries/opcua/opcuaclient/tests/src/opcuaservertesthelper.cpp @@ -178,7 +178,7 @@ void OpcUaServerTestHelper::publishVariable(std::string identifier, const UA_DataType* type, UA_NodeId* parentNodeId, const char* locale, - int nodeIndex, + uint16_t nodeIndex, size_t dimension) { OpcUaObject attr = UA_VariableAttributes_default; diff --git a/shared/libraries/opcua/opcuaclient/tests/src/test_attribute_reader.cpp b/shared/libraries/opcua/opcuaclient/tests/src/test_attribute_reader.cpp index bf62196..07c52b4 100644 --- a/shared/libraries/opcua/opcuaclient/tests/src/test_attribute_reader.cpp +++ b/shared/libraries/opcua/opcuaclient/tests/src/test_attribute_reader.cpp @@ -125,7 +125,8 @@ TEST_F(AttributeReaderTest, MaxNodesPerRead) auto client = std::make_shared(getServerUrl()); client->connect(); - const size_t maxBatchSize = client->readValue(OpcUaNodeId(UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERREAD)).toInteger(); + const size_t maxBatchSize = + static_cast(client->readValue(OpcUaNodeId(UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERREAD)).toInteger()); ASSERT_EQ(maxBatchSize, maxNodesPerRead); const auto idI64 = OpcUaNodeId(1, ".i64"); diff --git a/shared/libraries/opcua/opcuaclient/tests/src/test_cached_reference_browser.cpp b/shared/libraries/opcua/opcuaclient/tests/src/test_cached_reference_browser.cpp index b352e19..985a331 100644 --- a/shared/libraries/opcua/opcuaclient/tests/src/test_cached_reference_browser.cpp +++ b/shared/libraries/opcua/opcuaclient/tests/src/test_cached_reference_browser.cpp @@ -164,7 +164,7 @@ TEST_F(CachedReferenceBrowserTest, MaxNodesPerBrowse) const auto maxNodesPerBrowse = client->readValue(maxNodesPerBrowseId).toInteger(); ASSERT_GT(maxNodesPerBrowse, 0); - auto browser = CachedReferenceBrowser(client, maxNodesPerBrowse); + auto browser = CachedReferenceBrowser(client, static_cast(maxNodesPerBrowse)); const auto& references = browser.browse(nodeId); ASSERT_FALSE(references.byNodeId.empty()); diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcua_attribute.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcua_attribute.h index cf7eb0a..231ca94 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcua_attribute.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcua_attribute.h @@ -47,7 +47,7 @@ namespace std { size_t operator()(const daq::opcua::OpcUaAttribute& attr) const noexcept { - size_t hash = UA_NodeId_hash(attr.nodeId.get()); + UA_UInt32 hash = UA_NodeId_hash(attr.nodeId.get()); return UA_ByteString_hash(hash, (const UA_Byte*) &attr.attributeId, sizeof(UA_AttributeId)); } }; diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp index ecf2663..5e6c901 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_integration.cpp @@ -378,10 +378,13 @@ TEST_F(TmsIntegrationTest, InputPortMultipleServers) auto clientDevice1 = instance.addDevice("daq.opcua://127.0.0.1:4001"); auto clientDevice2 = instance.addDevice("daq.opcua://127.0.0.1:4002"); - auto inputPort1 = clientDevice1.getChannelsRecursive().getItemAt(0).getInputPorts().getItemAt(0); - auto inputPort2 = clientDevice2.getChannelsRecursive().getItemAt(0).getInputPorts().getItemAt(0); - auto signal1 = clientDevice1.getSignalsRecursive().getItemAt(0); - auto signal2 = clientDevice2.getSignalsRecursive().getItemAt(0); + InputPortPtr inputPort1, inputPort2; + SignalPtr signal1, signal2; + ASSERT_NO_THROW(inputPort1 = clientDevice1.getChannelsRecursive().getItemAt(0).getInputPorts().getItemAt(0)); + ASSERT_NO_THROW(inputPort2 = clientDevice2.getChannelsRecursive().getItemAt(0).getInputPorts().getItemAt(0)); + ASSERT_NO_THROW(signal1 = clientDevice1.getSignalsRecursive().getItemAt(0)); + ASSERT_NO_THROW(signal2 = clientDevice2.getSignalsRecursive().getItemAt(0)); + SignalPtr portSignal; ASSERT_NO_THROW(inputPort1.connect(signal1)); From 28cca725378c7aed766b5138be981723d1bb7815 Mon Sep 17 00:00:00 2001 From: Jaka Mohorko <96818661+JakaMohorkoDS@users.noreply.github.com> Date: Thu, 9 Oct 2025 15:47:14 +0200 Subject: [PATCH 214/217] Other/merge rc (openDAQ/openDAQ#947) --- .../src/opcua_client_module_impl.cpp | 19 +- .../tests/opcuatms_integration/CMakeLists.txt | 11 - .../test_streaming_integration.cpp | 470 ------------------ 3 files changed, 11 insertions(+), 489 deletions(-) delete mode 100644 shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp diff --git a/modules/opcua_client_module/src/opcua_client_module_impl.cpp b/modules/opcua_client_module/src/opcua_client_module_impl.cpp index 8f51dd5..de589c3 100644 --- a/modules/opcua_client_module/src/opcua_client_module_impl.cpp +++ b/modules/opcua_client_module/src/opcua_client_module_impl.cpp @@ -129,40 +129,43 @@ PropertyObjectPtr OpcUaClientModule::populateDefaultConfig(const PropertyObjectP DeviceInfoPtr OpcUaClientModule::populateDiscoveredDevice(const MdnsDiscoveredDevice& discoveredDevice) { auto cap = ServerCapability(DaqOpcUaDeviceTypeId, "OpenDAQOPCUA", ProtocolType::Configuration); - if (!discoveredDevice.ipv4Address.empty()) + + for (const auto& ipAddress : discoveredDevice.ipv4Addresses) { auto connectionStringIpv4 = fmt::format("{}://{}:{}{}", DaqOpcUaDevicePrefix, - discoveredDevice.ipv4Address, + ipAddress, discoveredDevice.servicePort, discoveredDevice.getPropertyOrDefault("path", "/")); cap.addConnectionString(connectionStringIpv4); - cap.addAddress(discoveredDevice.ipv4Address); + cap.addAddress(ipAddress); - const auto addressInfo = AddressInfoBuilder().setAddress(discoveredDevice.ipv4Address) + const auto addressInfo = AddressInfoBuilder().setAddress(ipAddress) .setReachabilityStatus(AddressReachabilityStatus::Unknown) .setType("IPv4") .setConnectionString(connectionStringIpv4) .build(); cap.addAddressInfo(addressInfo); } - if(!discoveredDevice.ipv6Address.empty()) + + for (const auto& ipAddress : discoveredDevice.ipv6Addresses) { auto connectionStringIpv6 = fmt::format("{}://{}:{}{}", DaqOpcUaDevicePrefix, - discoveredDevice.ipv6Address, + ipAddress, discoveredDevice.servicePort, discoveredDevice.getPropertyOrDefault("path", "/")); cap.addConnectionString(connectionStringIpv6); - cap.addAddress(discoveredDevice.ipv6Address); + cap.addAddress(ipAddress); - const auto addressInfo = AddressInfoBuilder().setAddress(discoveredDevice.ipv6Address) + const auto addressInfo = AddressInfoBuilder().setAddress(ipAddress) .setReachabilityStatus(AddressReachabilityStatus::Unknown) .setType("IPv6") .setConnectionString(connectionStringIpv6) .build(); cap.addAddressInfo(addressInfo); } + cap.setConnectionType("TCP/IP"); cap.setPrefix(DaqOpcUaDevicePrefix); cap.setProtocolVersion(discoveredDevice.getPropertyOrDefault("protocolVersion", "")); diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt b/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt index de9c48f..0f69768 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/CMakeLists.txt @@ -21,10 +21,6 @@ set(TEST_SOURCES main.cpp test_tms_function_block_type.cpp ) -if (OPENDAQ_ENABLE_WEBSOCKET_STREAMING) - list(APPEND TEST_SOURCES test_streaming_integration.cpp) -endif() - set(SUPPORTS_ASAN 0) if(CXX_COMPILER_ID EQUAL Clang OR CXX_COMPILER_ID EQUAL AppleClang OR CXX_COMPILER_ID EQUAL GNU) @@ -40,19 +36,12 @@ if (WIN32) set(BCRYPT_LIB bcrypt.dll) endif() -set(StreamingLibraries ) - -if (OPENDAQ_ENABLE_WEBSOCKET_STREAMING) - list(APPEND StreamingLibraries PRIVATE daq::websocket_streaming) -endif() - target_link_libraries(${TEST_APP} PRIVATE daq::opcuatms_test_utils daq::opcuatms_server daq::opcuatms_client daq::opendaq_mocks ${BCRYPT_LIB} Taskflow::Taskflow - ${StreamingLibraries} ) if(SUPPORTS_ASAN) diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp deleted file mode 100644 index 61da5a0..0000000 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_streaming_integration.cpp +++ /dev/null @@ -1,470 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace daq; -using namespace daq::opcua; -using namespace std::chrono_literals; -using namespace daq::stream; -using namespace daq::websocket_streaming; -using namespace daq::streaming_protocol; - -class StreamingIntegrationTest : public testing::Test -{ -public: - const uint16_t STREAMING_PORT = 7414; - const uint16_t STREAMING_CONTROL_PORT = 7438; - const std::string OPCUA_URL = "opc.tcp://127.0.0.1/"; - const std::string STREAMING_URL = "daq.lt://127.0.0.1/"; - - using ReadCallback = std::function& readPackets)>; - - void SetUp() override - { - logger = Logger(); - loggerComponent = logger.getOrAddComponent("StreamingIntegrationTest"); - auto clientLogger = Logger(); - clientContext = Context(Scheduler(clientLogger, 1), clientLogger, TypeManager(), nullptr, nullptr); - instance = createDevice(); - } - - void TearDown() override - { - std::this_thread::sleep_for(10ms); - } - - InstancePtr getInstance() - { - return instance; - } - - void generatePackets(size_t packetCount) - { - auto devices = instance.getDevices(); - - for (const auto& device : devices) - { - auto name = device.getInfo().getName(); - if (name == "MockPhysicalDevice") - device.setPropertyValue("GeneratePackets", packetCount); - } - } - - SignalPtr getSignal(const DevicePtr& device, const std::string& signalName) - { - auto signals = device.getSignalsRecursive(); - - for (const auto& signal : signals) - { - const auto descriptor = signal.getDescriptor(); - if (descriptor.assigned() && descriptor.getName() == signalName) - { - return signal; - } - } - - DAQ_THROW_EXCEPTION(NotFoundException); - } - - PacketReaderPtr createReader(const DevicePtr& device, const std::string& signalName) - { - auto signals = device.getSignals(search::Recursive(search::Visible())); - - for (const auto& signal : signals) - { - const auto descriptor = signal.getDescriptor(); - if (descriptor.assigned() && descriptor.getName() == signalName) - return PacketReader(signal); - } - - DAQ_THROW_EXCEPTION(NotFoundException); - } - - ListPtr tryReadPackets(const PacketReaderPtr& reader, - size_t packetCount, - std::chrono::seconds timeout = std::chrono::seconds(60)) - { - auto allPackets = List(); - auto startPoint = std::chrono::system_clock::now(); - - while (allPackets.getCount() < packetCount) - { - if (reader.getAvailableCount() == 0) - { - auto now = std::chrono::system_clock::now(); - auto timeElapsed = now - startPoint; - if (timeElapsed > timeout) - { - LOG_E("Timeout expired: packets count expected {}, packets count ready {}", - packetCount, allPackets.getCount()); - break; - } - - std::this_thread::sleep_for(std::chrono::milliseconds(20)); - continue; - } - - auto packets = reader.readAll(); - - for (const auto& packet : packets) - allPackets.pushBack(packet); - } - - return allPackets; - } - - bool packetsEqual(const ListPtr& listA, const ListPtr& listB, bool compareDescriptors = true) - { - bool result = true; - if (listA.getCount() != listB.getCount()) - { - LOG_E("Compared packets count differs: A {}, B {}", listA.getCount(), listB.getCount()); - result = false; - } - - auto count = std::min(listA.getCount(), listB.getCount()); - - for (SizeT i = 0; i < count; i++) - { - if (!compareDescriptors && - listA.getItemAt(i).getType() == PacketType::Event && - listB.getItemAt(i).getType() == PacketType::Event) - continue; - if (!BaseObjectPtr::Equals(listA.getItemAt(i), listB.getItemAt(i))) - { - LOG_E("Packets at index {} differs: A - \"{}\", B - \"{}\"", - i, listA.getItemAt(i).toString(), listB.getItemAt(i).toString()); - result = false; - } - } - - return result; - } - -protected: - InstancePtr createDevice() - { - - const auto moduleManager = ModuleManager("[[none]]"); - auto context = Context(Scheduler(logger, 1), logger, TypeManager(), moduleManager, AuthenticationProvider()); - - const ModulePtr deviceModule(MockDeviceModule_Create(context)); - moduleManager.addModule(deviceModule); - - - auto instance = InstanceCustom(context, "localInstance"); - - instance.addDevice("daqmock://phys_device"); - - return instance; - } - - StreamingPtr createStreaming() - { - return WebsocketStreaming(STREAMING_URL, clientContext); - } - - void setStreamingSource(const DevicePtr& device) - { - streaming = createStreaming(); - streaming.setActive(true); - - auto mirroredDeviceConfig = device.template asPtr(); - mirroredDeviceConfig.addStreamingSource(streaming); - auto signals = device.getSignals(search::Recursive(search::Visible())); - streaming.addSignals(signals); - for (const auto& signal : signals) - { - auto mirroredSignalConfigPtr = signal.template asPtr(); - mirroredSignalConfigPtr.setActiveStreamingSource(streaming.getConnectionString()); - } - } - - LoggerPtr logger; - LoggerComponentPtr loggerComponent; - ContextPtr clientContext; - InstancePtr instance; - StreamingPtr streaming; -}; - -TEST_F(StreamingIntegrationTest, Connect) -{ - std::string host = "127.0.0.1"; - std::string target = "/"; - uint16_t port = 2000; - - // start server - - boost::asio::io_context serverContext; - auto acceptFunc = [this](StreamPtr stream) {}; - auto server = std::make_shared(serverContext, acceptFunc, port); - - auto serverThread = std::thread([&server, &serverContext]() { - server->start(); - serverContext.run(); - }); - - // start client - - auto signalMetaCallback = [this](const SubscribedSignal& subscribedSignal, const std::string& method, const nlohmann::json& params) {}; - auto protocolMetaCallback = [this](ProtocolHandler& protocolHandler, const std::string& method, const nlohmann::json& params) {}; - auto messageCallback = [this](const SubscribedSignal& subscribedSignal, uint64_t timeStamp, const uint8_t* data, size_t size) {}; - - auto loggerComponent = logger.addComponent("StreamingClient"); - auto logCallback = [loggerComponent](spdlog::source_loc location, spdlog::level::level_enum level, const char* msg) { - loggerComponent.logMessage(SourceLocation{location.filename, location.line, location.funcname}, msg, static_cast(level)); - }; - - daq::streaming_protocol::SignalContainer signalContainer(logCallback); - boost::asio::io_context clientContext; - - signalContainer.setDataAsRawCb(messageCallback); - signalContainer.setSignalMetaCb(signalMetaCallback); - - auto protocolHandler = std::make_shared(clientContext, signalContainer, protocolMetaCallback, logCallback); - auto clientStream = std::make_unique(clientContext, host, std::to_string(port), target); - protocolHandler->startWithSyncInit(std::move(clientStream)); - auto clientThread = std::thread([&clientContext]() { clientContext.run(); }); - - // wait a bit - - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - - // stop client - - clientContext.stop(); - clientThread.join(); - - // stop server - - server->stop(); - serverThread.join(); -} - -TEST_F(StreamingIntegrationTest, ByteStep) -{ - const size_t packetsToRead = 10; - - auto serverStepReader = createReader(instance, "ByteStep"); - - auto streamingServer = WebsocketStreamingServer(instance); - streamingServer.setStreamingPort(STREAMING_PORT); - streamingServer.setControlPort(STREAMING_CONTROL_PORT); - streamingServer.start(); - - auto server = TmsServer(instance); - server.start(); - - auto client = TmsClient(clientContext, nullptr, OPCUA_URL); - auto clientDevice = client.connect(); - setStreamingSource(clientDevice); - - auto mirroredSignalPtr = getSignal(clientDevice, "ByteStep").template asPtr(); - std::promise subscribeCompletePromise; - std::future subscribeCompleteFuture = subscribeCompletePromise.get_future(); - mirroredSignalPtr.getOnSubscribeComplete() += - [&subscribeCompletePromise](MirroredSignalConfigPtr& sender, SubscriptionEventArgsPtr& args) - { - subscribeCompletePromise.set_value(args.getStreamingConnectionString()); - }; - - auto clientStepReader = createReader(clientDevice, "ByteStep"); - - ASSERT_EQ(subscribeCompleteFuture.wait_for(std::chrono::seconds(1)), std::future_status::ready); - ASSERT_EQ(subscribeCompleteFuture.get(), mirroredSignalPtr.getActiveStreamingSource()); - - generatePackets(packetsToRead); - - auto serverReceivedPackets = tryReadPackets(serverStepReader, packetsToRead + 1); - auto clientReceivedPackets = tryReadPackets(clientStepReader, packetsToRead + 1); - - EXPECT_EQ(serverReceivedPackets.getCount(), packetsToRead + 1); - EXPECT_EQ(clientReceivedPackets.getCount(), packetsToRead + 1); - EXPECT_TRUE(packetsEqual(serverReceivedPackets, clientReceivedPackets)); -} - -TEST_F(StreamingIntegrationTest, ChangingSignal) -{ - const size_t packetsToGenerate = 5; - const size_t initialEventPackets = 1; - const size_t packetsPerChange = 2; // one triggered by data signal and one trigegred by domain signal - const size_t packetsToRead = initialEventPackets + packetsToGenerate + (packetsToGenerate - 1) * packetsPerChange; - - auto serverStepReader = createReader(instance, "ChangingSignal"); - - auto streamingServer = WebsocketStreamingServer(instance); - streamingServer.setStreamingPort(STREAMING_PORT); - streamingServer.setControlPort(STREAMING_CONTROL_PORT); - streamingServer.start(); - - auto server = TmsServer(instance); - server.start(); - - auto client = TmsClient(clientContext, nullptr, OPCUA_URL); - auto clientDevice = client.connect(); - setStreamingSource(clientDevice); - - auto mirroredSignalPtr = getSignal(clientDevice, "ChangingSignal").template asPtr(); - std::promise subscribeCompletePromise; - std::future subscribeCompleteFuture = subscribeCompletePromise.get_future(); - mirroredSignalPtr.getOnSubscribeComplete() += - [&subscribeCompletePromise](MirroredSignalConfigPtr& sender, SubscriptionEventArgsPtr& args) - { - subscribeCompletePromise.set_value(args.getStreamingConnectionString()); - }; - - auto clientStepReader = createReader(clientDevice, "ChangingSignal"); - - ASSERT_EQ(subscribeCompleteFuture.wait_for(std::chrono::seconds(1)), std::future_status::ready); - ASSERT_EQ(subscribeCompleteFuture.get(), mirroredSignalPtr.getActiveStreamingSource()); - - generatePackets(packetsToGenerate); - - auto serverReceivedPackets = tryReadPackets(serverStepReader, packetsToRead); - auto clientReceivedPackets = tryReadPackets(clientStepReader, packetsToRead); - EXPECT_EQ(serverReceivedPackets.getCount(), packetsToRead); - EXPECT_EQ(clientReceivedPackets.getCount(), packetsToRead); - // TODO websocket streaming does not recreate half assigned data descriptor changed event packet on client side - // both: value and domain descriptors are always assigned in event packet - // while on server side one descriptor can be assigned only - EXPECT_TRUE(packetsEqual(serverReceivedPackets, clientReceivedPackets, false)); -} - -TEST_F(StreamingIntegrationTest, AllSignalsAsync) -{ - const size_t packetsToRead = 50; - - std::vector signals = {"ByteStep", "IntStep", "Sine"}; - std::unordered_map serverReaders; - std::unordered_map clientReaders; - std::unordered_map> serverPackets; - std::unordered_map> clientPackets; - - for (const auto& signal : signals) - serverReaders.insert({signal, createReader(instance, signal)}); - - auto streamingServer = WebsocketStreamingServer(instance); - streamingServer.setStreamingPort(STREAMING_PORT); - streamingServer.setControlPort(STREAMING_CONTROL_PORT); - streamingServer.start(); - - auto server = TmsServer(instance); - server.start(); - - auto client = TmsClient(clientContext, nullptr, OPCUA_URL); - auto clientDevice = client.connect(); - setStreamingSource(clientDevice); - - for (const auto& signal : signals) - { - auto mirroredSignalPtr = getSignal(clientDevice, signal).template asPtr(); - std::promise subscribeCompletePromise; - std::future subscribeCompleteFuture = subscribeCompletePromise.get_future(); - mirroredSignalPtr.getOnSubscribeComplete() += - [&subscribeCompletePromise](MirroredSignalConfigPtr& sender, SubscriptionEventArgsPtr& args) - { - subscribeCompletePromise.set_value(args.getStreamingConnectionString()); - }; - - clientReaders.insert({signal, createReader(clientDevice, signal)}); - - ASSERT_EQ(subscribeCompleteFuture.wait_for(std::chrono::seconds(1)), std::future_status::ready); - ASSERT_EQ(subscribeCompleteFuture.get(), mirroredSignalPtr.getActiveStreamingSource()); - } - - generatePackets(packetsToRead); - - std::vector>> serverFetures; - std::vector>> clientFetures; - - for (const auto& signal : signals) - { - auto readFunc = [this](const PacketReaderPtr& reader, size_t packetCount) { return tryReadPackets(reader, packetCount); }; - serverFetures.push_back(std::async(readFunc, serverReaders[signal], packetsToRead + 1)); - auto clientReadFunc = [this](const PacketReaderPtr& reader, size_t packetCount) - { - return tryReadPackets(reader, packetCount); - }; - clientFetures.push_back(std::async(clientReadFunc, clientReaders[signal], packetsToRead + 1)); - } - - for (size_t i = 0; i < serverFetures.size(); i++) - { - auto sentPackets = serverFetures[i].get(); - auto receivedPackets = clientFetures[i].get(); - EXPECT_EQ(sentPackets.getCount(), packetsToRead + 1); - EXPECT_EQ(receivedPackets.getCount(), packetsToRead + 1); - EXPECT_TRUE(packetsEqual(sentPackets, receivedPackets)); - } -} - -TEST_F(StreamingIntegrationTest, DISABLED_StartStopBug) -{ - using namespace daq::websocket_streaming; - DevicePtr device = createDevice(); - - for (size_t i = 0; i < 40; i++) - { - TmsServer tmsServer(device, device.getContext()); - tmsServer.start(); - } -} - -TEST_F(StreamingIntegrationTest, StreamingDeactivate) -{ - const size_t packetsToRead = 10; - - auto serverStepReader = createReader(instance, "Sine"); - - auto streamingServer = WebsocketStreamingServer(instance); - streamingServer.setStreamingPort(STREAMING_PORT); - streamingServer.setControlPort(STREAMING_CONTROL_PORT); - streamingServer.start(); - - auto server = TmsServer(instance); - server.start(); - - auto client = TmsClient(clientContext, nullptr, OPCUA_URL); - auto clientDevice = client.connect(); - setStreamingSource(clientDevice); - - streaming.setActive(False); - - auto clientStepReader = createReader(clientDevice, "Sine"); - - auto clientReceivedPackets = tryReadPackets(clientStepReader, 1); - ASSERT_EQ(clientReceivedPackets.getCount(), 1u); // Single event packet only - - generatePackets(packetsToRead); - - auto serverReceivedPackets = tryReadPackets(serverStepReader, packetsToRead + 1); - ASSERT_EQ(serverReceivedPackets.getCount(), packetsToRead + 1); - - clientReceivedPackets = tryReadPackets(clientStepReader, packetsToRead, std::chrono::seconds(5)); - ASSERT_EQ(clientReceivedPackets.getCount(), 0u); // no data packets since streaming is inactive - - streaming.setActive(True); - - clientReceivedPackets = tryReadPackets(clientStepReader, packetsToRead, std::chrono::seconds(5)); - ASSERT_EQ(clientReceivedPackets.getCount(), 0u); // still no data packets available -} From b0811d09bb48c02f2effa4ebd47a3edad69d5d78 Mon Sep 17 00:00:00 2001 From: NikolaiShipilov <127689162+NikolaiShipilov@users.noreply.github.com> Date: Mon, 22 Dec 2025 09:29:29 +0100 Subject: [PATCH 215/217] Modifications required for module extraction (openDAQ/openDAQ#979) * Add installable version of daq::test_utils as header-only interface lib * Separate testutils into internal and installed libs * Do not export-install module libraries as cmake targets * Move and install opendaq_dependency macro * Install discovery libraries for client modules * Update changelog * Add missing include --- modules/opcua_client_module/tests/test_app.cpp | 2 +- modules/opcua_server_module/tests/test_app.cpp | 2 +- shared/libraries/opcuatms/opcuatms/tests/testapp.cpp | 2 +- shared/libraries/opcuatms/opcuatms_client/tests/test_app.cpp | 2 +- shared/libraries/opcuatms/opcuatms_server/tests/testapp.cpp | 2 +- shared/libraries/opcuatms/tests/opcuatms_integration/main.cpp | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/opcua_client_module/tests/test_app.cpp b/modules/opcua_client_module/tests/test_app.cpp index a7ce761..e2ba246 100644 --- a/modules/opcua_client_module/tests/test_app.cpp +++ b/modules/opcua_client_module/tests/test_app.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include diff --git a/modules/opcua_server_module/tests/test_app.cpp b/modules/opcua_server_module/tests/test_app.cpp index 64dd0cc..681e0d3 100644 --- a/modules/opcua_server_module/tests/test_app.cpp +++ b/modules/opcua_server_module/tests/test_app.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include int main(int argc, char** args) diff --git a/shared/libraries/opcuatms/opcuatms/tests/testapp.cpp b/shared/libraries/opcuatms/opcuatms/tests/testapp.cpp index 06b4198..f267ca1 100644 --- a/shared/libraries/opcuatms/opcuatms/tests/testapp.cpp +++ b/shared/libraries/opcuatms/opcuatms/tests/testapp.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include int main(int argc, char** args) diff --git a/shared/libraries/opcuatms/opcuatms_client/tests/test_app.cpp b/shared/libraries/opcuatms/opcuatms_client/tests/test_app.cpp index 73de271..a4462ae 100644 --- a/shared/libraries/opcuatms/opcuatms_client/tests/test_app.cpp +++ b/shared/libraries/opcuatms/opcuatms_client/tests/test_app.cpp @@ -1,5 +1,5 @@ #include -#include +#include int main(int argc, char** args) { diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/testapp.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/testapp.cpp index 242492a..24298ce 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/testapp.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/testapp.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/main.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/main.cpp index 242492a..24298ce 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/main.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/main.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include From d2c445ef0b9c3c8880b422376b75702784d03a66 Mon Sep 17 00:00:00 2001 From: Denis Erokhin <149682271+denise-opendaq@users.noreply.github.com> Date: Mon, 5 Jan 2026 15:23:33 +0100 Subject: [PATCH 216/217] Fix OPC UA Value and AnalogValue node data types for signals (openDAQ/openDAQ#1011) --- .../include/opcuashared/opcuavariant.h | 15 +- .../objects/tms_server_analog_value.h | 48 +++++++ .../objects/tms_server_component.h | 24 ++-- .../objects/tms_server_signal.h | 10 +- .../objects/tms_server_value.h | 49 +++++++ .../opcuatms_server/src/CMakeLists.txt | 6 + .../src/objects/tms_server_analog_value.cpp | 110 +++++++++++++++ .../src/objects/tms_server_signal.cpp | 114 +++++++-------- .../src/objects/tms_server_value.cpp | 131 ++++++++++++++++++ .../src/objects/tms_server_variable.cpp | 1 + .../opcuatms_server/tests/test_tms_signal.cpp | 71 ++++++++-- .../opcuatms_integration/test_tms_signal.cpp | 74 ++++++++++ 12 files changed, 567 insertions(+), 86 deletions(-) create mode 100644 shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_analog_value.h create mode 100644 shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_value.h create mode 100644 shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_analog_value.cpp create mode 100644 shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_value.cpp diff --git a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h index 64832e9..64c7980 100644 --- a/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h +++ b/shared/libraries/opcua/opcuashared/include/opcuashared/opcuavariant.h @@ -17,7 +17,6 @@ #pragma once #include "opcuacommon.h" -#include #include BEGIN_NAMESPACE_OPENDAQ_OPCUA @@ -40,7 +39,19 @@ namespace VariantUtils template inline bool IsType(const UA_Variant& value) { - return value.type == GetUaDataType(); + const auto expectedType = GetUaDataType(); + if (value.type == expectedType) + return true; + +#ifdef __APPLE__ + if (value.type != nullptr && value.type->typeKind == expectedType->typeKind) + { + if (value.type->typeName != nullptr && expectedType->typeName != nullptr) + return std::strcmp(value.type->typeName, expectedType->typeName) == 0; + return true; + } +#endif + return false; } template diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_analog_value.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_analog_value.h new file mode 100644 index 0000000..169433d --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_analog_value.h @@ -0,0 +1,48 @@ +/* + * Copyright 2022-2025 openDAQ d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +// TmsServerAnalogValue + +class TmsServerAnalogValue; +using TmsServerAnalogValuePtr = std::shared_ptr; + +class TmsServerAnalogValue : public TmsServerVariable +{ +public: + using Super = TmsServerVariable; + + TmsServerAnalogValue(const SignalPtr& signal, const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext); + std::string getBrowseName() override; + +protected: + opcua::OpcUaNodeId getTmsTypeId() override; + opcua::OpcUaNodeId getDataTypeId() override; + void bindCallbacks() override; + +private: + static opcua::OpcUaNodeId sampleTypeToOpcUaDataType(SampleType sampleType); + + SignalPtr signal; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS + diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h index 8d1b50e..5ff0472 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_component.h @@ -175,13 +175,13 @@ void TmsServerComponent::bindCallbacks() } catch ([[maybe_unused]] const std::exception& e) { - const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpenDAQOPCUAClientModule"); - LOG_D("OPC UA Component {} failed to set component name: {}", this->object.getLocalId(), e.what()); + const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpenDAQOPCUAServerModule"); + LOG_D("OPC UA Component {} failed to set component name: {}", this->object.getGlobalId(), e.what()); } catch (...) { - const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpenDAQOPCUAClientModule"); - LOG_D("OPC UA Component {} failed to set component name.", this->object.getLocalId()); + const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpenDAQOPCUAServerModule"); + LOG_D("OPC UA Component {} failed to set component name.", this->object.getGlobalId()); } selfChange = false; @@ -201,13 +201,13 @@ void TmsServerComponent::bindCallbacks() } catch ([[maybe_unused]] const std::exception& e) { - const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpenDAQOPCUAClientModule"); - LOG_D("OPC UA Component {} failed to set component description: {}", this->object.getLocalId(), e.what()); + const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpenDAQOPCUAServerModule"); + LOG_D("OPC UA Component {} failed to set component description: {}", this->object.getGlobalId(), e.what()); } catch (...) { - const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpenDAQOPCUAClientModule"); - LOG_D("OPC UA Component {} failed to set component description.", this->object.getLocalId()); + const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpenDAQOPCUAServerModule"); + LOG_D("OPC UA Component {} failed to set component description.", this->object.getGlobalId()); } selfChange = false; @@ -261,13 +261,13 @@ void TmsServerComponent::onCoreEvent(const CoreEventArgsPtr& args) } catch ([[maybe_unused]] const std::exception& e) { - const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpenDAQOPCUAClientModule"); - LOG_D("OPC UA Component {} failed to set node attribute \"{}\": {}", this->object.getLocalId(), attrName, e.what()); + const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpenDAQOPCUAServerModule"); + LOG_D("OPC UA Component {} failed to set node attribute \"{}\": {}", this->object.getGlobalId(), attrName, e.what()); } catch (...) { - const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpenDAQOPCUAClientModule"); - LOG_D("OPC UA Component {} failed to set node attribute \"{}\".", this->object.getLocalId(), attrName); + const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpenDAQOPCUAServerModule"); + LOG_D("OPC UA Component {} failed to set node attribute \"{}\".", this->object.getGlobalId(), attrName); } selfChange = false; diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h index 30c07a5..29fd1a2 100644 --- a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_signal.h @@ -17,6 +17,8 @@ #pragma once #include #include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -31,13 +33,17 @@ class TmsServerSignal : public TmsServerComponent TmsServerSignal(const SignalPtr& object, const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext); opcua::OpcUaNodeId getReferenceType() override; - void bindCallbacks() override; - bool createOptionalNode(const opcua::OpcUaNodeId& nodeId) override; + void addChildNodes() override; + void onCoreEvent(const CoreEventArgsPtr& args) override; void createNonhierarchicalReferences() override; protected: opcua::OpcUaNodeId getTmsTypeId() override; + +private: + TmsServerValuePtr valueServer; + TmsServerAnalogValuePtr analogValueServer; }; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_value.h b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_value.h new file mode 100644 index 0000000..7102884 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/include/opcuatms_server/objects/tms_server_value.h @@ -0,0 +1,49 @@ +/* + * Copyright 2022-2025 openDAQ d.o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +// TmsServerValue + +class TmsServerValue; +using TmsServerValuePtr = std::shared_ptr; + +class TmsServerValue : public TmsServerVariable +{ +public: + using Super = TmsServerVariable; + + TmsServerValue(const SignalPtr& signal, const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext); + std::string getBrowseName() override; + + static opcua::OpcUaNodeId SampleTypeToOpcUaDataType(SampleType sampleType); + +protected: + opcua::OpcUaNodeId getTmsTypeId() override; + opcua::OpcUaNodeId getDataTypeId() override; + void addChildNodes() override; + void bindCallbacks() override; + +private: + SignalPtr signal; +}; + +END_NAMESPACE_OPENDAQ_OPCUA_TMS + diff --git a/shared/libraries/opcuatms/opcuatms_server/src/CMakeLists.txt b/shared/libraries/opcuatms/opcuatms_server/src/CMakeLists.txt index 218dbc3..af433d7 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/CMakeLists.txt +++ b/shared/libraries/opcuatms/opcuatms_server/src/CMakeLists.txt @@ -27,6 +27,8 @@ set(SRC_Objects_Headers ${OBJECT_SRC_DIR}/tms_server_object.h ${OBJECT_SRC_DIR}/tms_server_component.h ${OBJECT_SRC_DIR}/tms_server_property.h ${OBJECT_SRC_DIR}/tms_server_eval_value.h + ${OBJECT_SRC_DIR}/tms_server_value.h + ${OBJECT_SRC_DIR}/tms_server_analog_value.h ${OBJECT_SRC_DIR}/tms_server_function_block_type.h ${OBJECT_SRC_DIR}/tms_server_sync_component.h ${OBJECT_SRC_DIR}/tms_server_sync_interface.h @@ -44,6 +46,8 @@ set(SRC_Objects ${OBJECT_SRC_DIR}/tms_server_object.cpp ${OBJECT_SRC_DIR}/tms_server_component.cpp ${OBJECT_SRC_DIR}/tms_server_property.cpp ${OBJECT_SRC_DIR}/tms_server_eval_value.cpp + ${OBJECT_SRC_DIR}/tms_server_value.cpp + ${OBJECT_SRC_DIR}/tms_server_analog_value.cpp ${OBJECT_SRC_DIR}/tms_server_function_block_type.cpp ${OBJECT_SRC_DIR}/tms_server_sync_component.cpp ) @@ -63,6 +67,8 @@ source_group("objects\\folder" "${OBJECT_SRC_DIR}/tms_server_folder.*") source_group("objects\\component" "${OBJECT_SRC_DIR}/tms_server_component.*") source_group("objects\\property" "${OBJECT_SRC_DIR}/tms_server_property.*") source_group("objects\\eval_value" "${OBJECT_SRC_DIR}/tms_server_eval_value.*") +source_group("objects\\value" "${OBJECT_SRC_DIR}/tms_server_value.*") +source_group("objects\\analog_value" "${OBJECT_SRC_DIR}/tms_server_analog_value.*") source_group("objects\\sync_component" "${OBJECT_SRC_DIR}/tms_server_sync_component.*") # /objects diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_analog_value.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_analog_value.cpp new file mode 100644 index 0000000..df5d76b --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_analog_value.cpp @@ -0,0 +1,110 @@ +#include +#include +#include + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace opcua; + +TmsServerAnalogValue::TmsServerAnalogValue(const SignalPtr& signal, const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext) + : Super(BaseObjectPtr(), server, context, tmsContext) + , signal(signal) +{ +} + +std::string TmsServerAnalogValue::getBrowseName() +{ + return "AnalogValue"; +} + +opcua::OpcUaNodeId TmsServerAnalogValue::getTmsTypeId() +{ + // Return the base data variable type definition + // The actual concrete data type is set via getDataTypeId() + return OpcUaNodeId(0, UA_NS0ID_BASEDATAVARIABLETYPE); +} + +opcua::OpcUaNodeId TmsServerAnalogValue::getDataTypeId() +{ + try + { + const auto descriptor = signal.getDescriptor(); + if (descriptor.assigned()) + { + SampleType sampleType = descriptor.getSampleType(); + return sampleTypeToOpcUaDataType(sampleType); + } + } + catch (...) + { + // If descriptor is not available or any error occurs, return null + // which will use the default type from the type definition + } + + return {}; +} + +opcua::OpcUaNodeId TmsServerAnalogValue::sampleTypeToOpcUaDataType(SampleType sampleType) +{ + switch (sampleType) + { + case SampleType::Float32: + return OpcUaNodeId(0, UA_NS0ID_FLOAT); + case SampleType::Float64: + return OpcUaNodeId(0, UA_NS0ID_DOUBLE); + case SampleType::Int8: + return OpcUaNodeId(0, UA_NS0ID_SBYTE); + case SampleType::UInt8: + return OpcUaNodeId(0, UA_NS0ID_BYTE); + case SampleType::Int16: + return OpcUaNodeId(0, UA_NS0ID_INT16); + case SampleType::UInt16: + return OpcUaNodeId(0, UA_NS0ID_UINT16); + case SampleType::Int32: + return OpcUaNodeId(0, UA_NS0ID_INT32); + case SampleType::UInt32: + return OpcUaNodeId(0, UA_NS0ID_UINT32); + case SampleType::Int64: + return OpcUaNodeId(0, UA_NS0ID_INT64); + case SampleType::UInt64: + return OpcUaNodeId(0, UA_NS0ID_UINT64); + case SampleType::RangeInt64: + return OpcUaNodeId(0, UA_NS0ID_RANGE); + case SampleType::ComplexFloat32: + return OpcUaNodeId(0, UA_NS0ID_COMPLEXNUMBERTYPE); + case SampleType::ComplexFloat64: + return OpcUaNodeId(0, UA_NS0ID_DOUBLECOMPLEXNUMBERTYPE); + default: + return OpcUaNodeId(); + } +} + +void TmsServerAnalogValue::bindCallbacks() +{ + // The data type is already set correctly during node creation via getDataTypeId() + // in configureVariableNodeAttributes() + + addReadCallback(nodeId, [this]() + { + const auto descriptor = signal.getDescriptor(); + SampleType type = descriptor.assigned() ? descriptor.getSampleType() : SampleType::Undefined; + + if (type != SampleType::Float32 && type != SampleType::Float64 && type != SampleType::Int8 && + type != SampleType::Int16 && type != SampleType::Int32 && type != SampleType::Int64 && + type != SampleType::UInt8 && type != SampleType::UInt16 && type != SampleType::UInt32 && + type != SampleType::UInt64 && type != SampleType::RangeInt64 && type != SampleType::ComplexFloat32 && + type != SampleType::ComplexFloat64) + return OpcUaVariant(); + + ObjectPtr lastValue = signal.getLastValue(); + if (lastValue != nullptr) + return VariantConverter::ToVariant(lastValue, nullptr, daqContext); + + return OpcUaVariant(); + }); + + Super::bindCallbacks(); +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS + diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp index 094ed05..d9df509 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_signal.cpp @@ -1,7 +1,11 @@ #include +#include +#include #include #include #include +#include +#include BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS @@ -26,75 +30,61 @@ OpcUaNodeId TmsServerSignal::getTmsTypeId() return OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_SIGNALTYPE); } -void TmsServerSignal::bindCallbacks() +void TmsServerSignal::addChildNodes() { - auto valueId = getChildNodeId("Value"); - OpcUaObject bd; - bd->nodeId = valueId.copyAndGetDetachedValue(); - bd->resultMask = UA_BROWSERESULTMASK_ALL; - auto result = server->browse(bd); + // Create Value and AnalogValue nodes manually with correct data type + // Store them as members to keep them alive (callbacks depend on them) + valueServer = std::make_shared(object, server, daqContext, tmsContext); + valueServer->registerOpcUaNode(nodeId); + + analogValueServer = std::make_shared(object, server, daqContext, tmsContext); + analogValueServer->registerOpcUaNode(nodeId); + + Super::addChildNodes(); +} + +void TmsServerSignal::onCoreEvent(const CoreEventArgsPtr& args) +{ + Super::onCoreEvent(args); - for (size_t i = 0; i < result->referencesSize; i++) + if (args.getEventId() == static_cast(CoreEventId::DataDescriptorChanged)) { - auto reference = result->references[i]; - std::string browseName = opcua::utils::ToStdString(reference.browseName.name); - if (browseName == "DataDescriptor") + try { - OpcUaNodeId descriptorId{reference.nodeId.nodeId}; - addReadCallback(descriptorId, - [this]() - { - DataDescriptorPtr descriptor = object.getDescriptor(); - if (descriptor != nullptr) - return VariantConverter::ToVariant(descriptor, nullptr, daqContext); - else - return OpcUaVariant(); - }); - } - } + const auto descriptor = object.getDescriptor(); + if (!descriptor.assigned() || !valueServer) + return; - addReadCallback(valueId, - [this]() - { - ObjectPtr lastValue = object.getLastValue(); - if (lastValue != nullptr) - return VariantConverter::ToVariant(lastValue, nullptr, daqContext); - - return OpcUaVariant(); - }); - - auto analogValueId = getChildNodeId("AnalogValue"); - addReadCallback(analogValueId, - [this]() - { - SampleType type = object.getDescriptor().getSampleType(); - if (type != SampleType::Float32 && type != SampleType::Float64 && type != SampleType::Int8 && - type != SampleType::Int16 && type != SampleType::Int32 && type != SampleType::Int64 && - type != SampleType::UInt8 && type != SampleType::UInt16 && type != SampleType::UInt32 && - type != SampleType::UInt64 && type != SampleType::RangeInt64 && type != SampleType::ComplexFloat32 && - type != SampleType::ComplexFloat64) - return OpcUaVariant(); - - ObjectPtr lastValue = object.getLastValue(); - if (lastValue != nullptr) - return VariantConverter::ToVariant(lastValue, nullptr, daqContext); - - return OpcUaVariant(); - }); - - // TODO: Value, AnalogValue, Status - Super::bindCallbacks(); -} + const auto currentDataType = server->readDataType(valueServer->getNodeId()); + const auto expectedDataType = TmsServerValue::SampleTypeToOpcUaDataType(descriptor.getSampleType()); -bool TmsServerSignal::createOptionalNode(const opcua::OpcUaNodeId& nodeId) -{ - const auto name = server->readBrowseNameString(nodeId); - if (name == "Value") - return true; - if (name == "AnalogValue") - return true; + if (currentDataType == expectedDataType) + return; + + if (valueServer) + { + auto valueNodeId = valueServer->getNodeId(); + if (!valueNodeId.isNull()) + server->deleteNode(valueNodeId); + } + + if (analogValueServer) + { + auto analogValueNodeId = analogValueServer->getNodeId(); + if (!analogValueNodeId.isNull()) + server->deleteNode(analogValueNodeId); + } + + valueServer = std::make_shared(object, server, daqContext, tmsContext); + valueServer->registerOpcUaNode(nodeId); - return Super::createOptionalNode(nodeId); + analogValueServer = std::make_shared(object, server, daqContext, tmsContext); + analogValueServer->registerOpcUaNode(nodeId); + } + catch (...) + { + } + } } void TmsServerSignal::createNonhierarchicalReferences() diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_value.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_value.cpp new file mode 100644 index 0000000..cd3a811 --- /dev/null +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_value.cpp @@ -0,0 +1,131 @@ +#include +#include +#include +#include "opendaq/custom_log.h" + +BEGIN_NAMESPACE_OPENDAQ_OPCUA_TMS + +using namespace opcua; + +TmsServerValue::TmsServerValue(const SignalPtr& signal, const opcua::OpcUaServerPtr& server, const ContextPtr& context, const TmsServerContextPtr& tmsContext) + : Super(BaseObjectPtr(), server, context, tmsContext) + , signal(signal) +{ +} + +std::string TmsServerValue::getBrowseName() +{ + return "Value"; +} + +opcua::OpcUaNodeId TmsServerValue::getTmsTypeId() +{ + // Return the base data variable type definition + // The actual concrete data type is set via getDataTypeId() + return OpcUaNodeId(0, UA_NS0ID_BASEDATAVARIABLETYPE); +} + +opcua::OpcUaNodeId TmsServerValue::getDataTypeId() +{ + try + { + const auto descriptor = signal.getDescriptor(); + if (descriptor.assigned()) + { + SampleType sampleType = descriptor.getSampleType(); + return SampleTypeToOpcUaDataType(sampleType); + } + } + catch (...) + { + // If descriptor is not available or any error occurs, return null + // which will use the default type from the type definition + } + + return {}; +} + +opcua::OpcUaNodeId TmsServerValue::SampleTypeToOpcUaDataType(SampleType sampleType) +{ + switch (sampleType) + { + case SampleType::Float32: + return OpcUaNodeId(0, UA_NS0ID_FLOAT); + case SampleType::Float64: + return OpcUaNodeId(0, UA_NS0ID_DOUBLE); + case SampleType::Int8: + return OpcUaNodeId(0, UA_NS0ID_SBYTE); + case SampleType::UInt8: + return OpcUaNodeId(0, UA_NS0ID_BYTE); + case SampleType::Int16: + return OpcUaNodeId(0, UA_NS0ID_INT16); + case SampleType::UInt16: + return OpcUaNodeId(0, UA_NS0ID_UINT16); + case SampleType::Int32: + return OpcUaNodeId(0, UA_NS0ID_INT32); + case SampleType::UInt32: + return OpcUaNodeId(0, UA_NS0ID_UINT32); + case SampleType::Int64: + return OpcUaNodeId(0, UA_NS0ID_INT64); + case SampleType::UInt64: + return OpcUaNodeId(0, UA_NS0ID_UINT64); + case SampleType::RangeInt64: + return OpcUaNodeId(0, UA_NS0ID_RANGE); + case SampleType::ComplexFloat32: + return OpcUaNodeId(0, UA_NS0ID_COMPLEXNUMBERTYPE); + case SampleType::ComplexFloat64: + return OpcUaNodeId(0, UA_NS0ID_DOUBLECOMPLEXNUMBERTYPE); + case SampleType::String: + return OpcUaNodeId(0, UA_NS0ID_STRING); + case SampleType::Binary: + return OpcUaNodeId(0, UA_NS0ID_BYTESTRING); + default: + return OpcUaNodeId(); + } +} +void TmsServerValue::addChildNodes() +{ + try + { + auto params = AddVariableNodeParams("DataDescriptor", nodeId); + params.setBrowseName("DataDescriptor"); + params.setDataType(OpcUaNodeId(NAMESPACE_DAQBSP, UA_DAQBSPID_DATADESCRIPTORSTRUCTURE)); + params.typeDefinition = OpcUaNodeId(0, UA_NS0ID_BASEDATAVARIABLETYPE); + params.referenceTypeId = OpcUaNodeId(UA_NS0ID_HASPROPERTY); + + server->addVariableNode(params); + } + catch (const std::exception&) + { + const auto loggerComponent = this->daqContext.getLogger().getOrAddComponent("OpenDAQOPCUAServerModule"); + LOG_D("OPC UA Value {} failed create data descriptor node.", this->signal.getGlobalId()); + } + + Super::addChildNodes(); +} + +void TmsServerValue::bindCallbacks() +{ + addReadCallback(nodeId, [this]() + { + ObjectPtr lastValue = signal.getLastValue(); + if (lastValue != nullptr) + return VariantConverter::ToVariant(lastValue, nullptr, daqContext); + + return OpcUaVariant(); + }); + + addReadCallback("DataDescriptor", [this]() + { + DataDescriptorPtr descriptor = signal.getDescriptor(); + if (descriptor.assigned()) + return VariantConverter::ToVariant(descriptor, nullptr, daqContext); + else + return OpcUaVariant(); + }); + + Super::bindCallbacks(); +} + +END_NAMESPACE_OPENDAQ_OPCUA_TMS + diff --git a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp index c1bb5ad..e0a1571 100644 --- a/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/src/objects/tms_server_variable.cpp @@ -70,5 +70,6 @@ template class TmsServerVariable>; template class TmsServerVariable; template class TmsServerVariable; template class TmsServerVariable; +template class TmsServerVariable; END_NAMESPACE_OPENDAQ_OPCUA_TMS diff --git a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_signal.cpp b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_signal.cpp index 26fae39..b5edd90 100644 --- a/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_signal.cpp +++ b/shared/libraries/opcuatms/opcuatms_server/tests/test_tms_signal.cpp @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include #include @@ -17,23 +19,23 @@ using namespace opcua; class TmsSignalTest : public TmsServerObjectTest { public: - SignalPtr createSignal(const ContextPtr& context, const StringPtr& localId = "sig") + SignalConfigPtr createSignal(const ContextPtr& context, const StringPtr& localId = "sig") { - SignalPtr signal = Signal(context, nullptr, localId); - signal->setActive(false); + SignalConfigPtr signal = Signal(context, nullptr, localId); + signal.setActive(false); return signal; } }; TEST_F(TmsSignalTest, Create) { - SignalPtr signal = Signal(ctx, nullptr, "sig"); + SignalConfigPtr signal = Signal(ctx, nullptr, "sig"); auto tmsSignal = TmsServerSignal(signal, this->getServer(), ctx, tmsCtx); } TEST_F(TmsSignalTest, Register) { - SignalPtr signal = Signal(ctx, nullptr, "sig"); + SignalConfigPtr signal = Signal(ctx, nullptr, "sig"); auto serverSignal = TmsServerSignal(signal, this->getServer(), ctx, tmsCtx); auto nodeId = serverSignal.registerOpcUaNode(); @@ -42,9 +44,9 @@ TEST_F(TmsSignalTest, Register) TEST_F(TmsSignalTest, DomainSignalReference) { - SignalPtr signal = createSignal(ctx, "signal"); - SignalPtr domainSignal = createSignal(ctx, "time signal"); - signal.asPtr(true).setDomainSignal(domainSignal); + SignalConfigPtr signal = createSignal(ctx, "signal"); + SignalConfigPtr domainSignal = createSignal(ctx, "time signal"); + signal.setDomainSignal(domainSignal); auto serverSignal = TmsServerSignal(signal, this->getServer(), ctx, tmsCtx); auto signalNodeId = serverSignal.registerOpcUaNode(); @@ -62,3 +64,56 @@ TEST_F(TmsSignalTest, DomainSignalReference) ASSERT_EQ(hasDomainNodes.size(), 1u); ASSERT_EQ(hasDomainNodes[0]->getNodeId(), domainSignalNodeId); } + +TEST_F(TmsSignalTest, ValueAndAnalogValueDataType) +{ + // Create signal with Float64 descriptor + auto descriptor = DataDescriptorBuilder() + .setSampleType(SampleType::Float64) + .setName("TestSignal") + .build(); + SignalConfigPtr signal = createSignal(ctx, "signal"); + signal.setDescriptor(descriptor); + + auto serverSignal = TmsServerSignal(signal, this->getServer(), ctx, tmsCtx); + auto signalNodeId = serverSignal.registerOpcUaNode(); + + // Get Value and AnalogValue node IDs + OpcUaServerNode signalNode(*this->getServer(), signalNodeId); + auto valueNodeId = getChildNodeId(signalNodeId, "Value"); + auto analogValueNodeId = getChildNodeId(signalNodeId, "AnalogValue"); + + // Check that Value node has Float64 data type (not abstract NUMBER) + auto valueDataType = this->getClient()->readDataType(valueNodeId); + ASSERT_EQ(valueDataType, OpcUaNodeId(0, UA_NS0ID_DOUBLE)); + + // Check that AnalogValue node has Float64 data type (not abstract NUMBER) + auto analogValueDataType = this->getClient()->readDataType(analogValueNodeId); + ASSERT_EQ(analogValueDataType, OpcUaNodeId(0, UA_NS0ID_DOUBLE)); +} + +TEST_F(TmsSignalTest, ValueAndAnalogValueDataTypeInt32) +{ + // Create signal with Int32 descriptor + auto descriptor = DataDescriptorBuilder() + .setSampleType(SampleType::Int32) + .setName("TestSignal") + .build(); + SignalConfigPtr signal = createSignal(ctx, "signal"); + signal.setDescriptor(descriptor); + + auto serverSignal = TmsServerSignal(signal, this->getServer(), ctx, tmsCtx); + auto signalNodeId = serverSignal.registerOpcUaNode(); + + // Get Value and AnalogValue node IDs + auto valueNodeId = getChildNodeId(signalNodeId, "Value"); + auto analogValueNodeId = getChildNodeId(signalNodeId, "AnalogValue"); + + // Check that Value node has Int32 data type (not abstract NUMBER) + auto valueDataType = this->getClient()->readDataType(valueNodeId); + ASSERT_EQ(valueDataType, OpcUaNodeId(0, UA_NS0ID_INT32)); + + // Check that AnalogValue node has Int32 data type (not abstract NUMBER) + auto analogValueDataType = this->getClient()->readDataType(analogValueNodeId); + ASSERT_EQ(analogValueDataType, OpcUaNodeId(0, UA_NS0ID_INT32)); +} \ No newline at end of file diff --git a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp index a9bf16e..f9834e6 100644 --- a/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp +++ b/shared/libraries/opcuatms/tests/opcuatms_integration/test_tms_signal.cpp @@ -1,20 +1,30 @@ #include #include #include +#include #include #include #include #include #include #include +#include +#include +#include #include #include +#include #include #include #include #include +#include +#include +#include +#include #include "tms_object_integration_test.h" + using namespace daq; using namespace opcua::tms; using namespace opcua; @@ -624,3 +634,67 @@ TEST_F(TmsSignalTest, GetValue) ASSERT_EQ(clientSignal.getLastValue(), 10.0); } + +TEST_F(TmsSignalTest, ValueAndAnalogValueDataTypeChange) +{ + // Create signal with Float64 descriptor + auto descriptor1 = DataDescriptorBuilder() + .setSampleType(SampleType::Float64) + .setName("TestSignal") + .build(); + SignalConfigPtr serverSignal = Signal(ctx, nullptr, "sig"); + serverSignal.setDescriptor(descriptor1); + serverSignal.setActive(true); + + // IMPORTANT: Keep TmsServerSignal alive for the duration of the test + // It must be a shared_ptr so that weak_ptr in TmsServerContext can lock it + auto tmsServerSignal = std::make_shared(serverSignal, this->getServer(), ctx, serverContext); + auto signalNodeId = tmsServerSignal->registerOpcUaNode(); + + // Get Value and AnalogValue node IDs using browser + CachedReferenceBrowser browser(client); + auto valueNodeId = browser.getChildNodeId(signalNodeId, "Value"); + auto analogValueNodeId = browser.getChildNodeId(signalNodeId, "AnalogValue"); + + // Check initial data types are Float64 + auto valueDataType1 = client->readDataType(valueNodeId); + ASSERT_EQ(valueDataType1, OpcUaNodeId(0, UA_NS0ID_DOUBLE)); + + auto analogValueDataType1 = client->readDataType(analogValueNodeId); + ASSERT_EQ(analogValueDataType1, OpcUaNodeId(0, UA_NS0ID_DOUBLE)); + + // Change descriptor to Int32 + auto descriptor2 = DataDescriptorBuilder() + .setSampleType(SampleType::Int32) + .setName("TestSignal") + .build(); + serverSignal.setDescriptor(descriptor2); + + // Manually trigger the DataDescriptorChanged event on TmsServerSignal + // Without Instance, core events are not generated automatically + auto eventArgs = CoreEventArgsDataDescriptorChanged(descriptor2); + tmsServerSignal->onCoreEvent(eventArgs); + + // Create a new browser to get fresh references after node recreation + // Old browser may have cached references to deleted nodes + CachedReferenceBrowser newBrowser(client); + + // Get new node IDs after recreation (old ones may be invalid) + auto newValueNodeId = newBrowser.getChildNodeId(signalNodeId, "Value"); + auto newAnalogValueNodeId = newBrowser.getChildNodeId(signalNodeId, "AnalogValue"); + + // Verify that nodes exist + ASSERT_TRUE(client->nodeExists(newValueNodeId)) + << "New Value node should exist after recreation"; + ASSERT_TRUE(client->nodeExists(newAnalogValueNodeId)) + << "New AnalogValue node should exist after recreation"; + + // Check that data types have changed to Int32 + auto valueDataType2 = client->readDataType(newValueNodeId); + ASSERT_EQ(valueDataType2, OpcUaNodeId(0, UA_NS0ID_INT32)) + << "Value node data type should be Int32 after descriptor change. Got: " << valueDataType2.toString(); + + auto analogValueDataType2 = client->readDataType(newAnalogValueNodeId); + ASSERT_EQ(analogValueDataType2, OpcUaNodeId(0, UA_NS0ID_INT32)) + << "AnalogValue node data type should be Int32 after descriptor change. Got: " << analogValueDataType2.toString(); +} From 53ff1ac2081005f6f12243dfcc0d9b032781e621 Mon Sep 17 00:00:00 2001 From: Aliaksandr Adziareika <8034372+alexadereyko@users.noreply.github.com> Date: Fri, 16 Jan 2026 11:34:54 +0100 Subject: [PATCH 217/217] CI workflow: add 32-bit build support on Linux (openDAQ/openDAQ#1031) --- shared/libraries/opcua/opcuashared/src/bcrypt/crypt_blowfish.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/libraries/opcua/opcuashared/src/bcrypt/crypt_blowfish.c b/shared/libraries/opcua/opcuashared/src/bcrypt/crypt_blowfish.c index 797476d..9dbead8 100644 --- a/shared/libraries/opcua/opcuashared/src/bcrypt/crypt_blowfish.c +++ b/shared/libraries/opcua/opcuashared/src/bcrypt/crypt_blowfish.c @@ -54,7 +54,7 @@ #include #ifdef __i386__ -#define BF_ASM 1 +#define BF_ASM 0 #define BF_SCALE 1 #elif defined(__x86_64__) || defined(__alpha__) || defined(__hppa__) #define BF_ASM 0