From 15cd47f1eb90e995fa3d2e959368f74e16a59807 Mon Sep 17 00:00:00 2001 From: Rex Schilasky <49162693+rex-schilasky@users.noreply.github.com> Date: Fri, 2 Aug 2024 16:06:56 +0200 Subject: [PATCH] sync-with-eclipse-ecal-2024-08-02 (#77) * sync-with-eclipse-ecal-2024-08-02 --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- .github/workflows/build-macos.yml | 24 +- .github/workflows/build-ubuntu.yml | 24 +- .github/workflows/build-windows.yml | 24 +- .github/workflows/clang-tidy-review.yml | 2 +- .gitmodules | 3 - CMakeLists.txt | 6 +- DEPENDENCIES.txt | 10 +- README.md | 6 +- build/linux/02_build_full.sh | 2 +- build/linux/03_build_pubsub.sh | 2 +- build/linux/04_build_pubsub_proto.sh | 2 +- build/linux/05_build_pubsub_udp_only.sh | 2 +- build/linux/06_build_pubsub_tcp_only.sh | 2 +- build/linux/07_build_pubsub_shm_only.sh | 2 +- build/linux/08_build_clientserver.sh | 2 +- build/linux/09_build_clientserver_proto.sh | 2 +- build/linux/10_build_monitoring_only.sh | 2 +- build/windows/02_build_full.bat | 2 +- build/windows/03_build_pubsub.bat | 2 +- build/windows/04_build_pubsub_proto.bat | 2 +- build/windows/05_build_pubsub_udp_only.bat | 2 +- build/windows/06_build_pubsub_tcp_only.bat | 2 +- build/windows/07_build_pubsub_shm_only.bat | 2 +- build/windows/08_build_clientserver.bat | 2 +- build/windows/09_build_clientserver_proto.bat | 2 +- build/windows/10_build_monitoring_only.bat | 2 +- contrib/ecaltime/CMakeLists.txt | 4 - contrib/ecaltime/linuxptp/CMakeLists.txt | 57 -- contrib/ecaltime/linuxptp/src/clock.h | 74 -- contrib/ecaltime/linuxptp/src/config/config.h | 51 -- .../ecaltime/linuxptp/src/config/ecaltime.ini | 15 - contrib/ecaltime/linuxptp/src/convert_utf.cpp | 539 ------------- contrib/ecaltime/linuxptp/src/convert_utf.h | 149 ---- .../linuxptp/src/ecal_time_linuxptp.cpp | 146 ---- .../linuxptp/src/ecal_time_linuxptp.h | 90 --- contrib/ecaltime/linuxptp/src/ecaltime.cpp | 79 -- ecal/CMakeLists.txt | 3 + ecal/core/CMakeLists.txt | 36 +- ecal/core/cfg/CMakeLists.txt | 21 +- ecal/core/cfg/ecal.ini | 187 ----- ecal/core/cfg/gen/CMakeLists.txt | 77 ++ .../cfg/gen/generate_configuration_yaml.cpp | 11 + ecal/core/include/ecal/config/application.h | 8 +- ecal/core/include/ecal/config/configuration.h | 38 +- ecal/core/include/ecal/config/logging.h | 55 +- ecal/core/include/ecal/config/monitoring.h | 25 +- ecal/core/include/ecal/config/publisher.h | 70 +- ecal/core/include/ecal/config/registration.h | 61 +- ecal/core/include/ecal/config/service.h | 4 +- ecal/core/include/ecal/config/subscriber.h | 51 +- ecal/core/include/ecal/config/time.h | 16 +- .../include/ecal/config/transport_layer.h | 75 +- .../core/include/ecal/config/user_arguments.h | 8 +- ecal/core/include/ecal/ecal_config.h | 6 +- ecal/core/include/ecal/ecal_util.h | 2 +- .../include/ecal/msg/protobuf/publisher.h | 3 +- .../ecal/types/ecal_custom_data_types.h | 23 +- ecal/core/src/config/configuration_reader.cpp | 122 +++ ecal/core/src/config/configuration_reader.h | 60 ++ .../core/src/config/configuration_to_yaml.cpp | 721 ++++++++++++++++++ ecal/core/src/config/configuration_to_yaml.h | 365 +++++++++ .../core/src/config/default_configuration.cpp | 367 +++++++++ ecal/core/src/config/default_configuration.h | 16 + ecal/core/src/config/ecal_cmd_parser.cpp | 197 +---- ecal/core/src/config/ecal_cmd_parser.h | 10 +- ecal/core/src/config/ecal_config.cpp | 125 +-- .../src/config/ecal_config_initializer.cpp | 524 ++++++++----- ecal/core/src/config/ecal_config_reader.cpp | 455 ----------- ecal/core/src/config/ecal_config_reader.h | 57 -- ecal/core/src/config/ecal_config_reader_hlp.h | 32 - ecal/core/src/ecal.cpp | 15 +- ecal/core/src/ecal_def.h | 151 +--- ecal/core/src/ecal_global_accessors.cpp | 3 +- ecal/core/src/ecal_globals.cpp | 8 +- ecal/core/src/ecal_process.cpp | 9 +- ecal/core/src/io/shm/ecal_memfile_pool.cpp | 26 +- .../src/io/udp/ecal_udp_configurations.cpp | 10 + .../core/src/io/udp/ecal_udp_configurations.h | 15 + ecal/core/src/logging/ecal_log_impl.cpp | 4 +- .../src/monitoring/ecal_monitoring_impl.cpp | 8 +- ecal/core/src/pubsub/ecal_pubgate.cpp | 7 +- ecal/core/src/pubsub/ecal_pubgate.h | 2 +- ecal/core/src/pubsub/ecal_subgate.cpp | 11 +- ecal/core/src/pubsub/ecal_subgate.h | 4 +- .../src/pubsub/ecal_subscriber_config.cpp | 36 - ecal/core/src/readwrite/ecal_reader.cpp | 145 ++-- ecal/core/src/readwrite/ecal_reader.h | 14 +- ecal/core/src/readwrite/ecal_writer.cpp | 160 ++-- ecal/core/src/readwrite/ecal_writer.h | 12 +- .../src/readwrite/shm/ecal_writer_shm.cpp | 7 +- ecal/core/src/readwrite/shm/ecal_writer_shm.h | 4 +- .../src/readwrite/tcp/ecal_reader_tcp.cpp | 5 +- ecal/core/src/readwrite/tcp/ecal_reader_tcp.h | 2 + .../src/readwrite/tcp/ecal_writer_tcp.cpp | 3 +- ecal/core/src/readwrite/tcp/ecal_writer_tcp.h | 4 +- .../src/readwrite/udp/ecal_reader_udp.cpp | 2 +- .../src/readwrite/udp/ecal_writer_udp.cpp | 5 +- ecal/core/src/readwrite/udp/ecal_writer_udp.h | 4 +- .../ecal_registration_provider.cpp | 122 ++- .../registration/ecal_registration_provider.h | 32 +- .../ecal_registration_receiver.cpp | 271 +------ .../registration/ecal_registration_receiver.h | 32 +- .../ecal_registration_sample_applier.cpp | 161 ++++ .../ecal_registration_sample_applier.h | 72 ++ ...ecal_registration_sample_applier_gates.cpp | 74 ++ .../ecal_registration_sample_applier_gates.h} | 18 +- .../ecal_registration_sample_applier_user.cpp | 120 +++ .../ecal_registration_sample_applier_user.h | 57 ++ .../shm/ecal_registration_sender_shm.cpp | 7 +- .../shm/ecal_registration_sender_shm.h | 1 - .../udp/ecal_registration_receiver_udp.cpp | 2 +- .../udp/ecal_registration_sender_udp.cpp | 7 +- .../udp/ecal_registration_sender_udp.h | 1 - .../serialization/ecal_serialize_logging.cpp | 4 +- .../ecal_serialize_monitoring.cpp | 1 + .../ecal_serialize_sample_payload.cpp | 3 +- .../ecal_serialize_sample_registration.cpp | 4 +- .../serialization/ecal_serialize_service.cpp | 4 +- ecal/core/src/service/ecal_clientgate.cpp | 11 +- ecal/core/src/service/ecal_clientgate.h | 2 +- .../src/service/ecal_service_client_impl.cpp | 132 ++-- .../src/service/ecal_service_client_impl.h | 16 +- .../src/service/ecal_service_server_impl.cpp | 91 ++- .../src/service/ecal_service_server_impl.h | 17 +- ecal/core/src/service/ecal_servicegate.cpp | 8 +- ecal/core/src/service/ecal_servicegate.h | 5 +- ecal/core/src/time/ecal_timegate.cpp | 1 - .../core/src/types/ecal_custom_data_types.cpp | 20 +- .../src/types/ecal_registration_options.cpp | 60 -- ecal/core/src/util/ecal_thread.h | 33 +- ecal/ecal-core-options.cmake | 2 +- .../datarate_snd/src/datarate_snd.cpp | 6 +- .../latency_snd/src/latency_snd.cpp | 6 +- .../performance_snd/src/performance_snd.cpp | 6 +- .../src/pubsub_throughput.cpp | 16 +- .../src/binary_zero_copy_snd.cpp | 2 +- .../protobuf/person_rec/src/person_rec.cpp | 6 +- .../person_snd_tcp/src/person_snd_tcp.cpp | 6 +- .../person_snd_udp/src/person_snd_udp.cpp | 6 +- .../src/clientserver_test_proto.cpp | 8 +- .../src/clientserver_test.cpp | 26 +- ecal/tests/cpp/config_test/CMakeLists.txt | 21 +- .../tests/cpp/config_test/src/config_test.cpp | 256 ++++--- ecal/tests/cpp/config_test/src/ini_file.h | 418 +++++----- .../src/proto_subscriber_test.cpp | 23 +- .../pubsub_test/src/pubsub_acknowledge.cpp | 2 +- .../pubsub_test/src/pubsub_multibuffer.cpp | 10 +- .../pubsub_test/src/pubsub_receive_test.cpp | 2 +- .../cpp/pubsub_test/src/pubsub_test_shm.cpp | 40 +- .../cpp/pubsub_test/src/pubsub_test_udp.cpp | 12 +- .../cpp/util_test/src/util_getclients.cpp | 34 +- .../cpp/util_test/src/util_getservices.cpp | 34 +- .../cpp/util_test/src/util_gettopics.cpp | 20 +- submodule_dependencies.cmake | 1 + thirdparty/simpleini/CMakeLists.txt | 3 - thirdparty/simpleini/build-simpleini.cmake | 3 - thirdparty/simpleini/simpleini | 1 - thirdparty/yaml-cpp/yaml-cpp | 2 +- 159 files changed, 4112 insertions(+), 4097 deletions(-) delete mode 100644 contrib/ecaltime/linuxptp/CMakeLists.txt delete mode 100644 contrib/ecaltime/linuxptp/src/clock.h delete mode 100644 contrib/ecaltime/linuxptp/src/config/config.h delete mode 100644 contrib/ecaltime/linuxptp/src/config/ecaltime.ini delete mode 100644 contrib/ecaltime/linuxptp/src/convert_utf.cpp delete mode 100644 contrib/ecaltime/linuxptp/src/convert_utf.h delete mode 100644 contrib/ecaltime/linuxptp/src/ecal_time_linuxptp.cpp delete mode 100644 contrib/ecaltime/linuxptp/src/ecal_time_linuxptp.h delete mode 100644 contrib/ecaltime/linuxptp/src/ecaltime.cpp delete mode 100644 ecal/core/cfg/ecal.ini create mode 100644 ecal/core/cfg/gen/CMakeLists.txt create mode 100644 ecal/core/cfg/gen/generate_configuration_yaml.cpp create mode 100644 ecal/core/src/config/configuration_reader.cpp create mode 100644 ecal/core/src/config/configuration_reader.h create mode 100644 ecal/core/src/config/configuration_to_yaml.cpp create mode 100644 ecal/core/src/config/configuration_to_yaml.h create mode 100644 ecal/core/src/config/default_configuration.cpp create mode 100644 ecal/core/src/config/default_configuration.h delete mode 100644 ecal/core/src/config/ecal_config_reader.cpp delete mode 100644 ecal/core/src/config/ecal_config_reader.h delete mode 100644 ecal/core/src/config/ecal_config_reader_hlp.h delete mode 100644 ecal/core/src/pubsub/ecal_subscriber_config.cpp create mode 100644 ecal/core/src/registration/ecal_registration_sample_applier.cpp create mode 100644 ecal/core/src/registration/ecal_registration_sample_applier.h create mode 100644 ecal/core/src/registration/ecal_registration_sample_applier_gates.cpp rename ecal/core/src/{pubsub/ecal_publisher_config.cpp => registration/ecal_registration_sample_applier_gates.h} (71%) create mode 100644 ecal/core/src/registration/ecal_registration_sample_applier_user.cpp create mode 100644 ecal/core/src/registration/ecal_registration_sample_applier_user.h delete mode 100644 ecal/core/src/types/ecal_registration_options.cpp delete mode 100644 thirdparty/simpleini/CMakeLists.txt delete mode 100644 thirdparty/simpleini/build-simpleini.cmake delete mode 160000 thirdparty/simpleini/simpleini diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index c08d6564..43ff1de8 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -103,7 +103,7 @@ body: Platform : x64 ------------------------- CONFIGURATION -------------------------- - Default INI : C:\ProgramData\eCAL\ecal.ini + Default INI : C:\ProgramData\eCAL\ecal.yaml ------------------------- NETWORK -------------------------------- Host name : MYHOST diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index 36baf403..e39bac55 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -20,7 +20,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "OFF" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "ON" + ECAL_CORE_CONFIGURATION: "ON" ECAL_CORE_COMMAND_LINE: "ON" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "ON" @@ -42,7 +42,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "ON" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "ON" + ECAL_CORE_CONFIGURATION: "ON" ECAL_CORE_COMMAND_LINE: "ON" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "ON" @@ -64,7 +64,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "OFF" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "OFF" + ECAL_CORE_CONFIGURATION: "OFF" ECAL_CORE_COMMAND_LINE: "OFF" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "ON" @@ -86,7 +86,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "ON" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "OFF" + ECAL_CORE_CONFIGURATION: "OFF" ECAL_CORE_COMMAND_LINE: "OFF" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "ON" @@ -108,7 +108,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "OFF" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "OFF" + ECAL_CORE_CONFIGURATION: "OFF" ECAL_CORE_COMMAND_LINE: "OFF" ECAL_CORE_REGISTRATION: "OFF" ECAL_CORE_REGISTRATION_SHM: "OFF" @@ -130,7 +130,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "OFF" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "OFF" + ECAL_CORE_CONFIGURATION: "OFF" ECAL_CORE_COMMAND_LINE: "OFF" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "OFF" @@ -152,7 +152,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "OFF" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "OFF" + ECAL_CORE_CONFIGURATION: "OFF" ECAL_CORE_COMMAND_LINE: "OFF" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "OFF" @@ -174,7 +174,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "OFF" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "OFF" + ECAL_CORE_CONFIGURATION: "OFF" ECAL_CORE_COMMAND_LINE: "OFF" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "ON" @@ -196,7 +196,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "ON" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "OFF" + ECAL_CORE_CONFIGURATION: "OFF" ECAL_CORE_COMMAND_LINE: "OFF" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "ON" @@ -218,7 +218,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "ON" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "OFF" + ECAL_CORE_CONFIGURATION: "OFF" ECAL_CORE_COMMAND_LINE: "OFF" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "OFF" @@ -254,7 +254,7 @@ jobs: -DECAL_CORE_HAS_PROTOBUF=${{ matrix.build_configuration.ECAL_CORE_HAS_PROTOBUF }} \ -DECAL_CORE_BUILD_SAMPLES=${{ matrix.build_configuration.ECAL_CORE_BUILD_SAMPLES }} \ -DECAL_CORE_BUILD_TESTS=${{ matrix.build_configuration.ECAL_CORE_BUILD_TESTS }} \ - -DECAL_CORE_CONFIG_INIFILE=${{ matrix.build_configuration.ECAL_CORE_CONFIG_INIFILE }} \ + -DECAL_CORE_CONFIGURATION=${{ matrix.build_configuration.ECAL_CORE_CONFIGURATION }} \ -DECAL_CORE_COMMAND_LINE=${{ matrix.build_configuration.ECAL_CORE_COMMAND_LINE }} \ -DECAL_CORE_REGISTRATION=${{ matrix.build_configuration.ECAL_CORE_REGISTRATION }} \ -DECAL_CORE_REGISTRATION_SHM=${{ matrix.build_configuration.ECAL_CORE_REGISTRATION_SHM }} \ @@ -272,8 +272,6 @@ jobs: -DCMAKE_BUILD_TYPE=${{ matrix.build_configuration.CMAKE_BUILD_TYPE }} \ -DCMAKE_CXX_STANDARD=17 \ -DCMAKE_FIND_PACKAGE_PREFER_CONFIG=ON - sudo mkdir /etc/ecal - sudo cp "$GITHUB_WORKSPACE/ecal/core/cfg/ecal.ini" /etc/ecal shell: bash - name: Build Release diff --git a/.github/workflows/build-ubuntu.yml b/.github/workflows/build-ubuntu.yml index 7911fdeb..7ee9e5ca 100644 --- a/.github/workflows/build-ubuntu.yml +++ b/.github/workflows/build-ubuntu.yml @@ -20,7 +20,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "OFF" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "ON" + ECAL_CORE_CONFIGURATION: "ON" ECAL_CORE_COMMAND_LINE: "ON" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "ON" @@ -42,7 +42,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "ON" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "ON" + ECAL_CORE_CONFIGURATION: "ON" ECAL_CORE_COMMAND_LINE: "ON" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "ON" @@ -64,7 +64,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "OFF" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "OFF" + ECAL_CORE_CONFIGURATION: "OFF" ECAL_CORE_COMMAND_LINE: "OFF" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "ON" @@ -86,7 +86,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "ON" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "OFF" + ECAL_CORE_CONFIGURATION: "OFF" ECAL_CORE_COMMAND_LINE: "OFF" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "ON" @@ -108,7 +108,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "OFF" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "OFF" + ECAL_CORE_CONFIGURATION: "OFF" ECAL_CORE_COMMAND_LINE: "OFF" ECAL_CORE_REGISTRATION: "OFF" ECAL_CORE_REGISTRATION_SHM: "OFF" @@ -130,7 +130,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "OFF" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "OFF" + ECAL_CORE_CONFIGURATION: "OFF" ECAL_CORE_COMMAND_LINE: "OFF" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "OFF" @@ -152,7 +152,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "OFF" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "OFF" + ECAL_CORE_CONFIGURATION: "OFF" ECAL_CORE_COMMAND_LINE: "OFF" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "OFF" @@ -174,7 +174,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "OFF" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "OFF" + ECAL_CORE_CONFIGURATION: "OFF" ECAL_CORE_COMMAND_LINE: "OFF" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "ON" @@ -196,7 +196,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "ON" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "OFF" + ECAL_CORE_CONFIGURATION: "OFF" ECAL_CORE_COMMAND_LINE: "OFF" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "ON" @@ -218,7 +218,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "ON" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "OFF" + ECAL_CORE_CONFIGURATION: "OFF" ECAL_CORE_COMMAND_LINE: "OFF" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "OFF" @@ -258,7 +258,7 @@ jobs: -DECAL_CORE_HAS_PROTOBUF=${{ matrix.build_configuration.ECAL_CORE_HAS_PROTOBUF }} \ -DECAL_CORE_BUILD_SAMPLES=${{ matrix.build_configuration.ECAL_CORE_BUILD_SAMPLES }} \ -DECAL_CORE_BUILD_TESTS=${{ matrix.build_configuration.ECAL_CORE_BUILD_TESTS }} \ - -DECAL_CORE_CONFIG_INIFILE=${{ matrix.build_configuration.ECAL_CORE_CONFIG_INIFILE }} \ + -DECAL_CORE_CONFIGURATION=${{ matrix.build_configuration.ECAL_CORE_CONFIGURATION }} \ -DECAL_CORE_COMMAND_LINE=${{ matrix.build_configuration.ECAL_CORE_COMMAND_LINE }} \ -DECAL_CORE_REGISTRATION=${{ matrix.build_configuration.ECAL_CORE_REGISTRATION }} \ -DECAL_CORE_REGISTRATION_SHM=${{ matrix.build_configuration.ECAL_CORE_REGISTRATION_SHM }} \ @@ -278,8 +278,6 @@ jobs: -DCMAKE_INSTALL_PREFIX=/usr \ -DCMAKE_INSTALL_LOCALSTATEDIR=/var \ -DCMAKE_INSTALL_LIBDIR=lib/x86_64-linux-gnu - sudo mkdir /etc/ecal - sudo cp "$GITHUB_WORKSPACE/ecal/core/cfg/ecal.ini" /etc/ecal shell: bash - name: Build Release diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index fcd2beda..763f13cf 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -20,7 +20,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "OFF" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "ON" + ECAL_CORE_CONFIGURATION: "ON" ECAL_CORE_COMMAND_LINE: "ON" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "ON" @@ -41,7 +41,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "ON" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "ON" + ECAL_CORE_CONFIGURATION: "ON" ECAL_CORE_COMMAND_LINE: "ON" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "ON" @@ -62,7 +62,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "OFF" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "OFF" + ECAL_CORE_CONFIGURATION: "OFF" ECAL_CORE_COMMAND_LINE: "OFF" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "ON" @@ -83,7 +83,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "ON" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "OFF" + ECAL_CORE_CONFIGURATION: "OFF" ECAL_CORE_COMMAND_LINE: "OFF" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "ON" @@ -104,7 +104,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "OFF" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "OFF" + ECAL_CORE_CONFIGURATION: "OFF" ECAL_CORE_COMMAND_LINE: "OFF" ECAL_CORE_REGISTRATION: "OFF" ECAL_CORE_REGISTRATION_SHM: "OFF" @@ -125,7 +125,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "OFF" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "OFF" + ECAL_CORE_CONFIGURATION: "OFF" ECAL_CORE_COMMAND_LINE: "OFF" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "OFF" @@ -146,7 +146,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "OFF" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "OFF" + ECAL_CORE_CONFIGURATION: "OFF" ECAL_CORE_COMMAND_LINE: "OFF" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "OFF" @@ -167,7 +167,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "OFF" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "OFF" + ECAL_CORE_CONFIGURATION: "OFF" ECAL_CORE_COMMAND_LINE: "OFF" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "ON" @@ -188,7 +188,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "ON" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "OFF" + ECAL_CORE_CONFIGURATION: "OFF" ECAL_CORE_COMMAND_LINE: "OFF" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "ON" @@ -209,7 +209,7 @@ jobs: ECAL_CORE_HAS_PROTOBUF: "ON" ECAL_CORE_BUILD_SAMPLES: "ON" ECAL_CORE_BUILD_TESTS: "ON" - ECAL_CORE_CONFIG_INIFILE: "OFF" + ECAL_CORE_CONFIGURATION: "OFF" ECAL_CORE_COMMAND_LINE: "OFF" ECAL_CORE_REGISTRATION: "ON" ECAL_CORE_REGISTRATION_SHM: "OFF" @@ -241,7 +241,7 @@ jobs: -DECAL_CORE_HAS_PROTOBUF=${{ matrix.build_configuration.ECAL_CORE_HAS_PROTOBUF }} ^ -DECAL_CORE_BUILD_SAMPLES=${{ matrix.build_configuration.ECAL_CORE_BUILD_SAMPLES }} ^ -DECAL_CORE_BUILD_TESTS=${{ matrix.build_configuration.ECAL_CORE_BUILD_TESTS }} ^ - -DECAL_CORE_CONFIG_INIFILE=${{ matrix.build_configuration.ECAL_CORE_CONFIG_INIFILE }} ^ + -DECAL_CORE_CONFIGURATION=${{ matrix.build_configuration.ECAL_CORE_CONFIGURATION }} ^ -DECAL_CORE_COMMAND_LINE=${{ matrix.build_configuration.ECAL_CORE_COMMAND_LINE }} ^ -DECAL_CORE_REGISTRATION=${{ matrix.build_configuration.ECAL_CORE_REGISTRATION }} ^ -DECAL_CORE_REGISTRATION_SHM=${{ matrix.build_configuration.ECAL_CORE_REGISTRATION_SHM }} ^ @@ -256,8 +256,6 @@ jobs: -DECAL_CORE_NPCAP_SUPPORT=${{ matrix.build_configuration.ECAL_CORE_NPCAP_SUPPORT }} ^ -DBUILD_SHARED_LIBS=${{ matrix.build_configuration.BUILD_SHARED_LIBS }} ^ -DCMAKE_BUILD_TYPE=${{ matrix.build_configuration.CMAKE_BUILD_TYPE }} - mkdir "%ALLUSERSPROFILE%\eCAL" - copy "%GITHUB_WORKSPACE%\ecal\core\cfg\ecal.ini" "%ALLUSERSPROFILE%\eCAL" shell: cmd - name: Build Release diff --git a/.github/workflows/clang-tidy-review.yml b/.github/workflows/clang-tidy-review.yml index 7178fe79..7c86f468 100644 --- a/.github/workflows/clang-tidy-review.yml +++ b/.github/workflows/clang-tidy-review.yml @@ -43,7 +43,7 @@ jobs: -DECAL_CORE_HAS_PROTOBUF=ON \ -DECAL_CORE_BUILD_SAMPLES=ON \ -DECAL_CORE_BUILD_TESTS=ON \ - -DECAL_CORE_CONFIG_INIFILE=ON \ + -DECAL_CORE_CONFIGURATION=ON \ -DECAL_CORE_COMMAND_LINE=ON \ -DECAL_CORE_REGISTRATION=ON \ -DECAL_CORE_REGISTRATION_SHM=ON \ diff --git a/.gitmodules b/.gitmodules index 9a5b1fb5..aa61530a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,9 +7,6 @@ [submodule "thirdparty/protobuf/protobuf"] path = thirdparty/protobuf/protobuf url = https://github.com/protocolbuffers/protobuf.git -[submodule "thirdparty/simpleini/simpleini"] - path = thirdparty/simpleini/simpleini - url = https://github.com/brofield/simpleini.git [submodule "thirdparty/tclap/tclap"] path = thirdparty/tclap/tclap url = https://github.com/xguerin/tclap.git diff --git a/CMakeLists.txt b/CMakeLists.txt index f02ccc3e..1f467986 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,7 +65,7 @@ endif() # ------------------------------------------------------------------------------------------------------------------------------------------------------------------ # configurable build options -# command line usage: cmake .. -DBUILD_SAMPLES=ON -DBUILD_ECAL_TESTS=OFF -DECAL_CORE_CONFIG_INIFILE=OFF +# command line usage: cmake .. -DBUILD_SAMPLES=ON -DBUILD_ECAL_TESTS=OFF -DECAL_CORE_CONFIGURATION=OFF # ------------------------------------------------------------------------------------------------------------------------------------------------------------------ include(${CMAKE_CURRENT_SOURCE_DIR}/ecal/ecal-core-options.cmake) @@ -259,7 +259,7 @@ message(STATUS "---------------------------------------------------------------- message(STATUS "ECAL_CORE_BUILD_SAMPLES : ${ECAL_CORE_BUILD_SAMPLES}") message(STATUS "ECAL_CORE_BUILD_TESTS : ${ECAL_CORE_BUILD_TESTS}") message(STATUS "--------------------------------------------------------------------------------") -message(STATUS "ECAL_CORE_CONFIG_INIFILE : ${ECAL_CORE_CONFIG_INIFILE}") +message(STATUS "ECAL_CORE_CONFIGURATION : ${ECAL_CORE_CONFIGURATION}") message(STATUS "ECAL_CORE_COMMAND_LINE : ${ECAL_CORE_COMMAND_LINE}") message(STATUS "ECAL_CORE_REGISTRATION : ${ECAL_CORE_REGISTRATION}") message(STATUS "ECAL_CORE_MONITORING : ${ECAL_CORE_MONITORING}") @@ -279,8 +279,8 @@ message(STATUS "ECAL_THIRDPARTY_BUILD_ASIO : ${ECAL_THIRDPAR message(STATUS "ECAL_THIRDPARTY_BUILD_CMAKEFUNCTIONS : ${ECAL_THIRDPARTY_BUILD_CMAKEFUNCTIONS}") message(STATUS "ECAL_THIRDPARTY_BUILD_GTEST : ${ECAL_THIRDPARTY_BUILD_GTEST}") message(STATUS "ECAL_THIRDPARTY_BUILD_PROTOBUF : ${ECAL_THIRDPARTY_BUILD_PROTOBUF}") -message(STATUS "ECAL_THIRDPARTY_BUILD_SIMPLEINI : ${ECAL_THIRDPARTY_BUILD_SIMPLEINI}") message(STATUS "ECAL_THIRDPARTY_BUILD_TCLAP : ${ECAL_THIRDPARTY_BUILD_TCLAP}") message(STATUS "ECAL_THIRDPARTY_BUILD_UDPCAP : ${ECAL_THIRDPARTY_BUILD_UDPCAP}") message(STATUS "ECAL_THIRDPARTY_BUILD_ECALUDP : ${ECAL_THIRDPARTY_BUILD_ECALUDP}") +message(STATUS "ECAL_THIRDPARTY_BUILD_YAML-CPP : ${ECAL_THIRDPARTY_BUILD_YAML-CPP}") message(STATUS "--------------------------------------------------------------------------------") diff --git a/DEPENDENCIES.txt b/DEPENDENCIES.txt index 3bbf7891..3663b9f3 100644 --- a/DEPENDENCIES.txt +++ b/DEPENDENCIES.txt @@ -23,11 +23,6 @@ recycle: url = https://github.com/steinwurf/recycle.git version = 7.0.0 -simpleini: - path = thirdparty/simpleini/simpleini - url = https://github.com/brofield/simpleini.git - version = v4.20 - tclap: path = thirdparty/tclap/tclap url = https://github.com/xguerin/tclap.git @@ -42,3 +37,8 @@ udpcap: path = thirdparty/udpcap/udpcap url = https://github.com/eclipse-ecal/udpcap version = 1.0.2 + +yaml-cpp: + path = thirdparty/yaml-cpp/yaml-cpp + url = https://github.com/jbeder/yaml-cpp + version = 0.8.0 diff --git a/README.md b/README.md index caad7fdd..e78a485e 100644 --- a/README.md +++ b/README.md @@ -52,9 +52,9 @@ This section provides documentation for the CMake options used in configuring th #### Core Internal Feature Configuration -##### `ECAL_CORE_CONFIG_INIFILE` -- Enabling this option allows eCAL to be configured via an `ecal.ini` file. This file is used to set various configuration parameters for eCAL, providing flexibility in adjusting its behavior without modifying the source code. -- Requires simpleini library. +##### `ECAL_CORE_CONFIGURATION` +- Enabling this option allows eCAL to be configured via an `ecal.yaml` file. This file is used to set various configuration parameters for eCAL, providing flexibility in adjusting its behavior without modifying the source code. +- Requires yaml-cpp library. ##### `ECAL_CORE_COMMAND_LINE` - Enabling this option includes support for eCAL application command-line interfaces (cmd line). This allows you to interact with eCAL applications through the command line, providing additional runtime configuration options. diff --git a/build/linux/02_build_full.sh b/build/linux/02_build_full.sh index 47ca3382..58ae0c02 100644 --- a/build/linux/02_build_full.sh +++ b/build/linux/02_build_full.sh @@ -7,7 +7,7 @@ CMAKE_OPTIONS="-DCMAKE_INSTALL_PREFIX=_install \ -DECAL_CORE_HAS_PROTOBUF=ON \ -DECAL_CORE_BUILD_SAMPLES=ON \ -DECAL_CORE_BUILD_TESTS=ON \ --DECAL_CORE_CONFIG_INIFILE=ON \ +-DECAL_CORE_CONFIGURATION=ON \ -DECAL_CORE_COMMAND_LINE=ON \ -DECAL_CORE_REGISTRATION=ON \ -DECAL_CORE_REGISTRATION_SHM=ON \ diff --git a/build/linux/03_build_pubsub.sh b/build/linux/03_build_pubsub.sh index c50b118d..83bf8bed 100644 --- a/build/linux/03_build_pubsub.sh +++ b/build/linux/03_build_pubsub.sh @@ -7,7 +7,7 @@ CMAKE_OPTIONS="-DCMAKE_INSTALL_PREFIX=_install \ -DECAL_CORE_HAS_PROTOBUF=OFF \ -DECAL_CORE_BUILD_SAMPLES=ON \ -DECAL_CORE_BUILD_TESTS=ON \ --DECAL_CORE_CONFIG_INIFILE=OFF \ +-DECAL_CORE_CONFIGURATION=OFF \ -DECAL_CORE_COMMAND_LINE=OFF \ -DECAL_CORE_REGISTRATION=ON \ -DECAL_CORE_REGISTRATION_SHM=ON \ diff --git a/build/linux/04_build_pubsub_proto.sh b/build/linux/04_build_pubsub_proto.sh index 8769cd6b..b0aa4dd8 100644 --- a/build/linux/04_build_pubsub_proto.sh +++ b/build/linux/04_build_pubsub_proto.sh @@ -7,7 +7,7 @@ CMAKE_OPTIONS="-DCMAKE_INSTALL_PREFIX=_install \ -DECAL_CORE_HAS_PROTOBUF=ON \ -DECAL_CORE_BUILD_SAMPLES=ON \ -DECAL_CORE_BUILD_TESTS=ON \ --DECAL_CORE_CONFIG_INIFILE=OFF \ +-DECAL_CORE_CONFIGURATION=OFF \ -DECAL_CORE_COMMAND_LINE=OFF \ -DECAL_CORE_REGISTRATION=ON \ -DECAL_CORE_REGISTRATION_SHM=ON \ diff --git a/build/linux/05_build_pubsub_udp_only.sh b/build/linux/05_build_pubsub_udp_only.sh index 8a897d47..f672de4c 100644 --- a/build/linux/05_build_pubsub_udp_only.sh +++ b/build/linux/05_build_pubsub_udp_only.sh @@ -7,7 +7,7 @@ CMAKE_OPTIONS="-DCMAKE_INSTALL_PREFIX=_install \ -DECAL_CORE_HAS_PROTOBUF=OFF \ -DECAL_CORE_BUILD_SAMPLES=ON \ -DECAL_CORE_BUILD_TESTS=ON \ --DECAL_CORE_CONFIG_INIFILE=OFF \ +-DECAL_CORE_CONFIGURATION=OFF \ -DECAL_CORE_COMMAND_LINE=OFF \ -DECAL_CORE_REGISTRATION=OFF \ -DECAL_CORE_REGISTRATION_SHM=OFF \ diff --git a/build/linux/06_build_pubsub_tcp_only.sh b/build/linux/06_build_pubsub_tcp_only.sh index 803b64cf..ef85fb1e 100644 --- a/build/linux/06_build_pubsub_tcp_only.sh +++ b/build/linux/06_build_pubsub_tcp_only.sh @@ -7,7 +7,7 @@ CMAKE_OPTIONS="-DCMAKE_INSTALL_PREFIX=_install \ -DECAL_CORE_HAS_PROTOBUF=OFF \ -DECAL_CORE_BUILD_SAMPLES=ON \ -DECAL_CORE_BUILD_TESTS=ON \ --DECAL_CORE_CONFIG_INIFILE=OFF \ +-DECAL_CORE_CONFIGURATION=OFF \ -DECAL_CORE_COMMAND_LINE=OFF \ -DECAL_CORE_REGISTRATION=ON \ -DECAL_CORE_REGISTRATION_SHM=OFF \ diff --git a/build/linux/07_build_pubsub_shm_only.sh b/build/linux/07_build_pubsub_shm_only.sh index 341c6d45..146f1795 100644 --- a/build/linux/07_build_pubsub_shm_only.sh +++ b/build/linux/07_build_pubsub_shm_only.sh @@ -7,7 +7,7 @@ CMAKE_OPTIONS="-DCMAKE_INSTALL_PREFIX=_install \ -DECAL_CORE_HAS_PROTOBUF=OFF \ -DECAL_CORE_BUILD_SAMPLES=ON \ -DECAL_CORE_BUILD_TESTS=ON \ --DECAL_CORE_CONFIG_INIFILE=OFF \ +-DECAL_CORE_CONFIGURATION=OFF \ -DECAL_CORE_COMMAND_LINE=OFF \ -DECAL_CORE_REGISTRATION=ON \ -DECAL_CORE_REGISTRATION_SHM=OFF \ diff --git a/build/linux/08_build_clientserver.sh b/build/linux/08_build_clientserver.sh index b2133776..c176e82a 100644 --- a/build/linux/08_build_clientserver.sh +++ b/build/linux/08_build_clientserver.sh @@ -7,7 +7,7 @@ CMAKE_OPTIONS="-DCMAKE_INSTALL_PREFIX=_install \ -DECAL_CORE_HAS_PROTOBUF=OFF \ -DECAL_CORE_BUILD_SAMPLES=ON \ -DECAL_CORE_BUILD_TESTS=ON \ --DECAL_CORE_CONFIG_INIFILE=OFF \ +-DECAL_CORE_CONFIGURATION=OFF \ -DECAL_CORE_COMMAND_LINE=OFF \ -DECAL_CORE_REGISTRATION=ON \ -DECAL_CORE_REGISTRATION_SHM=ON \ diff --git a/build/linux/09_build_clientserver_proto.sh b/build/linux/09_build_clientserver_proto.sh index 7746e9c7..0166698d 100644 --- a/build/linux/09_build_clientserver_proto.sh +++ b/build/linux/09_build_clientserver_proto.sh @@ -7,7 +7,7 @@ CMAKE_OPTIONS="-DCMAKE_INSTALL_PREFIX=_install \ -DECAL_CORE_HAS_PROTOBUF=ON \ -DECAL_CORE_BUILD_SAMPLES=ON \ -DECAL_CORE_BUILD_TESTS=ON \ --DECAL_CORE_CONFIG_INIFILE=OFF \ +-DECAL_CORE_CONFIGURATION=OFF \ -DECAL_CORE_COMMAND_LINE=OFF \ -DECAL_CORE_REGISTRATION=ON \ -DECAL_CORE_REGISTRATION_SHM=ON \ diff --git a/build/linux/10_build_monitoring_only.sh b/build/linux/10_build_monitoring_only.sh index 3af03bdb..c68ca555 100644 --- a/build/linux/10_build_monitoring_only.sh +++ b/build/linux/10_build_monitoring_only.sh @@ -7,7 +7,7 @@ CMAKE_OPTIONS="-DCMAKE_INSTALL_PREFIX=_install \ -DECAL_CORE_HAS_PROTOBUF=ON \ -DECAL_CORE_BUILD_SAMPLES=ON \ -DECAL_CORE_BUILD_TESTS=ON \ --DECAL_CORE_CONFIG_INIFILE=OFF \ +-DECAL_CORE_CONFIGURATION=OFF \ -DECAL_CORE_COMMAND_LINE=OFF \ -DECAL_CORE_REGISTRATION=ON \ -DECAL_CORE_REGISTRATION_SHM=OFF \ diff --git a/build/windows/02_build_full.bat b/build/windows/02_build_full.bat index 20f79f69..f2fa4b34 100644 --- a/build/windows/02_build_full.bat +++ b/build/windows/02_build_full.bat @@ -7,7 +7,7 @@ set CMAKE_OPTIONS=-DCMAKE_INSTALL_PREFIX=_install ^ -DECAL_CORE_HAS_PROTOBUF=ON ^ -DECAL_CORE_BUILD_SAMPLES=ON ^ -DECAL_CORE_BUILD_TESTS=ON ^ --DECAL_CORE_CONFIG_INIFILE=ON ^ +-DECAL_CORE_CONFIGURATION=ON ^ -DECAL_CORE_COMMAND_LINE=ON ^ -DECAL_CORE_REGISTRATION=ON ^ -DECAL_CORE_REGISTRATION_SHM=ON ^ diff --git a/build/windows/03_build_pubsub.bat b/build/windows/03_build_pubsub.bat index 7e378cbe..02fe58e4 100644 --- a/build/windows/03_build_pubsub.bat +++ b/build/windows/03_build_pubsub.bat @@ -7,7 +7,7 @@ set CMAKE_OPTIONS=-DCMAKE_INSTALL_PREFIX=_install ^ -DECAL_CORE_HAS_PROTOBUF=OFF ^ -DECAL_CORE_BUILD_SAMPLES=ON ^ -DECAL_CORE_BUILD_TESTS=ON ^ --DECAL_CORE_CONFIG_INIFILE=OFF ^ +-DECAL_CORE_CONFIGURATION=OFF ^ -DECAL_CORE_COMMAND_LINE=OFF ^ -DECAL_CORE_REGISTRATION=ON ^ -DECAL_CORE_REGISTRATION_SHM=ON ^ diff --git a/build/windows/04_build_pubsub_proto.bat b/build/windows/04_build_pubsub_proto.bat index e4a4fb2a..ab320681 100644 --- a/build/windows/04_build_pubsub_proto.bat +++ b/build/windows/04_build_pubsub_proto.bat @@ -7,7 +7,7 @@ set CMAKE_OPTIONS=-DCMAKE_INSTALL_PREFIX=_install ^ -DECAL_CORE_HAS_PROTOBUF=ON ^ -DECAL_CORE_BUILD_SAMPLES=ON ^ -DECAL_CORE_BUILD_TESTS=ON ^ --DECAL_CORE_CONFIG_INIFILE=OFF ^ +-DECAL_CORE_CONFIGURATION=OFF ^ -DECAL_CORE_COMMAND_LINE=OFF ^ -DECAL_CORE_REGISTRATION=ON ^ -DECAL_CORE_REGISTRATION_SHM=ON ^ diff --git a/build/windows/05_build_pubsub_udp_only.bat b/build/windows/05_build_pubsub_udp_only.bat index eeb8be6a..725a0395 100644 --- a/build/windows/05_build_pubsub_udp_only.bat +++ b/build/windows/05_build_pubsub_udp_only.bat @@ -7,7 +7,7 @@ set CMAKE_OPTIONS=-DCMAKE_INSTALL_PREFIX=_install ^ -DECAL_CORE_HAS_PROTOBUF=OFF ^ -DECAL_CORE_BUILD_SAMPLES=ON ^ -DECAL_CORE_BUILD_TESTS=ON ^ --DECAL_CORE_CONFIG_INIFILE=OFF ^ +-DECAL_CORE_CONFIGURATION=OFF ^ -DECAL_CORE_COMMAND_LINE=OFF ^ -DECAL_CORE_REGISTRATION=ON ^ -DECAL_CORE_REGISTRATION_SHM=OFF ^ diff --git a/build/windows/06_build_pubsub_tcp_only.bat b/build/windows/06_build_pubsub_tcp_only.bat index 56bd0c16..01e51d2b 100644 --- a/build/windows/06_build_pubsub_tcp_only.bat +++ b/build/windows/06_build_pubsub_tcp_only.bat @@ -7,7 +7,7 @@ set CMAKE_OPTIONS=-DCMAKE_INSTALL_PREFIX=_install ^ -DECAL_CORE_HAS_PROTOBUF=OFF ^ -DECAL_CORE_BUILD_SAMPLES=ON ^ -DECAL_CORE_BUILD_TESTS=ON ^ --DECAL_CORE_CONFIG_INIFILE=OFF ^ +-DECAL_CORE_CONFIGURATION=OFF ^ -DECAL_CORE_COMMAND_LINE=OFF ^ -DECAL_CORE_REGISTRATION=ON ^ -DECAL_CORE_REGISTRATION_SHM=OFF ^ diff --git a/build/windows/07_build_pubsub_shm_only.bat b/build/windows/07_build_pubsub_shm_only.bat index 17e62596..d48963f8 100644 --- a/build/windows/07_build_pubsub_shm_only.bat +++ b/build/windows/07_build_pubsub_shm_only.bat @@ -7,7 +7,7 @@ set CMAKE_OPTIONS=-DCMAKE_INSTALL_PREFIX=_install ^ -DECAL_CORE_HAS_PROTOBUF=OFF ^ -DECAL_CORE_BUILD_SAMPLES=ON ^ -DECAL_CORE_BUILD_TESTS=ON ^ --DECAL_CORE_CONFIG_INIFILE=OFF ^ +-DECAL_CORE_CONFIGURATION=OFF ^ -DECAL_CORE_COMMAND_LINE=OFF ^ -DECAL_CORE_REGISTRATION=ON ^ -DECAL_CORE_REGISTRATION_SHM=OFF ^ diff --git a/build/windows/08_build_clientserver.bat b/build/windows/08_build_clientserver.bat index 14478733..0010d22a 100644 --- a/build/windows/08_build_clientserver.bat +++ b/build/windows/08_build_clientserver.bat @@ -7,7 +7,7 @@ set CMAKE_OPTIONS=-DCMAKE_INSTALL_PREFIX=_install ^ -DECAL_CORE_HAS_PROTOBUF=OFF ^ -DECAL_CORE_BUILD_SAMPLES=ON ^ -DECAL_CORE_BUILD_TESTS=ON ^ --DECAL_CORE_CONFIG_INIFILE=OFF ^ +-DECAL_CORE_CONFIGURATION=OFF ^ -DECAL_CORE_COMMAND_LINE=OFF ^ -DECAL_CORE_REGISTRATION=ON ^ -DECAL_CORE_REGISTRATION_SHM=ON ^ diff --git a/build/windows/09_build_clientserver_proto.bat b/build/windows/09_build_clientserver_proto.bat index 8aba418e..16e1cd60 100644 --- a/build/windows/09_build_clientserver_proto.bat +++ b/build/windows/09_build_clientserver_proto.bat @@ -7,7 +7,7 @@ set CMAKE_OPTIONS=-DCMAKE_INSTALL_PREFIX=_install ^ -DECAL_CORE_HAS_PROTOBUF=ON ^ -DECAL_CORE_BUILD_SAMPLES=ON ^ -DECAL_CORE_BUILD_TESTS=ON ^ --DECAL_CORE_CONFIG_INIFILE=OFF ^ +-DECAL_CORE_CONFIGURATION=OFF ^ -DECAL_CORE_COMMAND_LINE=OFF ^ -DECAL_CORE_REGISTRATION=ON ^ -DECAL_CORE_REGISTRATION_SHM=ON ^ diff --git a/build/windows/10_build_monitoring_only.bat b/build/windows/10_build_monitoring_only.bat index beec7dda..acf1c5b2 100644 --- a/build/windows/10_build_monitoring_only.bat +++ b/build/windows/10_build_monitoring_only.bat @@ -7,7 +7,7 @@ set CMAKE_OPTIONS=-DCMAKE_INSTALL_PREFIX=_install ^ -DECAL_CORE_HAS_PROTOBUF=ON ^ -DECAL_CORE_BUILD_SAMPLES=ON ^ -DECAL_CORE_BUILD_TESTS=ON ^ --DECAL_CORE_CONFIG_INIFILE=OFF ^ +-DECAL_CORE_CONFIGURATION=OFF ^ -DECAL_CORE_COMMAND_LINE=OFF ^ -DECAL_CORE_REGISTRATION=ON ^ -DECAL_CORE_REGISTRATION_SHM=OFF ^ diff --git a/contrib/ecaltime/CMakeLists.txt b/contrib/ecaltime/CMakeLists.txt index 06bdf265..a24cd015 100644 --- a/contrib/ecaltime/CMakeLists.txt +++ b/contrib/ecaltime/CMakeLists.txt @@ -16,8 +16,4 @@ # # ========================= eCAL LICENSE ================================= -if(CMAKE_SYSTEM_NAME STREQUAL "Linux") - add_subdirectory(linuxptp) -endif() - add_subdirectory(localtime) diff --git a/contrib/ecaltime/linuxptp/CMakeLists.txt b/contrib/ecaltime/linuxptp/CMakeLists.txt deleted file mode 100644 index 01b1f698..00000000 --- a/contrib/ecaltime/linuxptp/CMakeLists.txt +++ /dev/null @@ -1,57 +0,0 @@ -# ========================= eCAL LICENSE ================================= -# -# Copyright (C) 2016 - 2019 Continental Corporation -# -# 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. -# -# ========================= eCAL LICENSE ================================= - -project(ecaltime-linuxptp) - -find_package(simpleini REQUIRED) - -set(ecal_time_linuxptp_src - src/ecal_time_linuxptp.cpp - src/ecaltime.cpp - src/convert_utf.cpp -) - -set(ecal_time_linuxptp_header - ../include/ecaltime.h - src/ecal_time_linuxptp.h - src/config/config.h -) - -if(UNIX) - set_source_files_properties(src/convert_utf.cpp PROPERTIES COMPILE_FLAGS -Wno-implicit-fallthrough) -endif() - -ecal_add_time_plugin(${PROJECT_NAME} SHARED ${ecal_time_linuxptp_src} ${ecal_time_linuxptp_header}) - -target_link_libraries(${PROJECT_NAME} eCAL::core simpleini::simpleini) - -target_include_directories(${PROJECT_NAME} - PRIVATE - $ - $) - -ecal_install_time_plugin(${PROJECT_NAME}) - -set(ECALTIME_CONFIG_FILES - ${ECALTIME_CONFIG_FILES} - ${CMAKE_CURRENT_SOURCE_DIR}/src/config/ecaltime.ini - PARENT_SCOPE) - -set_target_properties(${PROJECT_NAME} PROPERTIES - FOLDER contrib/ecaltime - RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/${ECAL_TIME_PLUGIN_DIR}) diff --git a/contrib/ecaltime/linuxptp/src/clock.h b/contrib/ecaltime/linuxptp/src/clock.h deleted file mode 100644 index 13e8debf..00000000 --- a/contrib/ecaltime/linuxptp/src/clock.h +++ /dev/null @@ -1,74 +0,0 @@ -/* ========================= eCAL LICENSE ================================= - * - * Copyright (C) 2016 - 2019 Continental Corporation - * - * 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. - * - * ========================= eCAL LICENSE ================================= -*/ - -#include -#include -#include -#include - -#define CLOCKFD 3 -#define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD) -#define CLOCKID_TO_FD(clk) ((unsigned int) ~((clk) >> 3)) - -namespace linuxptp{ -/** - * @brief Queries the Capabilities of the given PTP Clock - * @param[in] clockId The PTP Clock of interest - * @param[out] caps The capabilities of the PTP Clock - * @return 0 if succeeded or -1 if failed. If the function fails, errno is set accordingly. - */ -static int getPtpClockCaps(const clockid_t clockId, struct ptp_clock_caps *caps){ - int err = ioctl(CLOCKID_TO_FD(clockId), PTP_CLOCK_GETCAPS, caps); - return err; -} - -/** - * @brief opens the (PTP) hardware clock - * @param[in] device A path to the clock to open (e.g. /dev/ptp0) - * @param[out] clockId The ID to access the clock. Only valid if the function succeeded. - * @return 0 if succeeded or -1 if failed. If the function fails, errno is set accordingly. - */ -int openClock(const char *device, clockid_t *clockId){ - - struct ptp_clock_caps caps; - int file_descriptor = open(device, O_RDONLY); - - if (file_descriptor == -1){ - return -1; - }else{ - *clockId = FD_TO_CLOCKID(file_descriptor); - // Check if the 'thing' we just opened actually is a PTP clock - if(getPtpClockCaps(*clockId, &caps)){ - close(file_descriptor); - return -1; - }else{ - return 0; - } - } -} - -/** - * @brief closes the (PTP) clock - * @param[in] clockId the clock ID to close - * @return 0 on success or -1 if failed. If the function fails, errno is set accordingly. - */ -int closeClock(clockid_t clockId){ - return close(CLOCKID_TO_FD(clockId)); -} -} diff --git a/contrib/ecaltime/linuxptp/src/config/config.h b/contrib/ecaltime/linuxptp/src/config/config.h deleted file mode 100644 index 096686bb..00000000 --- a/contrib/ecaltime/linuxptp/src/config/config.h +++ /dev/null @@ -1,51 +0,0 @@ -/* ========================= eCAL LICENSE ================================= - * - * Copyright (C) 2016 - 2019 Continental Corporation - * - * 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. - * - * ========================= eCAL LICENSE ================================= -*/ - -#pragma once - -#include - -#include -#include -#include -#include - -namespace LinuxPtpConfig { - - /** - * @brief reads the file ~/.ecal/ecaltime.ini to get the device - * @return the device value from the linuxptp section - */ - std::string getDevice() { - CSimpleIniA ini; - - std::string path_to_ini = eCAL::Util::GeteCALConfigPath(); - path_to_ini += "ecaltime.ini"; - - int err = ini.LoadFile(path_to_ini.c_str()); - if (err != SI_OK){ - std::cerr << "Error reading ecaltime config file" << std::endl; - } - - const char * pVal = ini.GetValue("linuxptp", "device", "/dev/ptp0"); - - std::string device(pVal); - return device; - } -} diff --git a/contrib/ecaltime/linuxptp/src/config/ecaltime.ini b/contrib/ecaltime/linuxptp/src/config/ecaltime.ini deleted file mode 100644 index 31c0dc00..00000000 --- a/contrib/ecaltime/linuxptp/src/config/ecaltime.ini +++ /dev/null @@ -1,15 +0,0 @@ -; --------------------------------------------- -; ecaltime-linuxptp Settings -; --------------------------------------------- -; -; device = /dev/ptp0 The device can be any ptp clock. -; Alternatively, you can use: -; - CLOCK_MONOTONIC (a steady clock with undefined epoche) -; - CLOCK_REALTIME (the current system time) -; - CLOCK_TAI (Like CLOCK_REALTIME but in International Atomic Time) -; -; --------------------------------------------- -[linuxptp] -device = /dev/ptp0 - - diff --git a/contrib/ecaltime/linuxptp/src/convert_utf.cpp b/contrib/ecaltime/linuxptp/src/convert_utf.cpp deleted file mode 100644 index ce5ed667..00000000 --- a/contrib/ecaltime/linuxptp/src/convert_utf.cpp +++ /dev/null @@ -1,539 +0,0 @@ -/* - * Copyright 2001-2004 Unicode, Inc. - * - * Disclaimer - * - * This source code is provided as is by Unicode, Inc. No claims are - * made as to fitness for any particular purpose. No warranties of any - * kind are expressed or implied. The recipient agrees to determine - * applicability of information provided. If this file has been - * purchased on magnetic or optical media from Unicode, Inc., the - * sole remedy for any claim will be exchange of defective media - * within 90 days of receipt. - * - * Limitations on Rights to Redistribute This Code - * - * Unicode, Inc. hereby grants the right to freely use the information - * supplied in this file in the creation of products supporting the - * Unicode Standard, and to make copies of this file in any form - * for internal or external distribution as long as this notice - * remains attached. - */ - -/* --------------------------------------------------------------------- - - Conversions between UTF32, UTF-16, and UTF-8. Source code file. - Author: Mark E. Davis, 1994. - Rev History: Rick McGowan, fixes & updates May 2001. - Sept 2001: fixed const & error conditions per - mods suggested by S. Parent & A. Lillich. - June 2002: Tim Dodd added detection and handling of incomplete - source sequences, enhanced error detection, added casts - to eliminate compiler warnings. - July 2003: slight mods to back out aggressive FFFE detection. - Jan 2004: updated switches in from-UTF8 conversions. - Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions. - - See the header file "ConvertUTF.h" for complete documentation. - ------------------------------------------------------------------------- */ - - -#include "convert_utf.h" -#ifdef CVTUTF_DEBUG -#include -#endif - -static const int halfShift = 10; /* used for shifting by 10 bits */ - -static const UTF32 halfBase = 0x0010000UL; -static const UTF32 halfMask = 0x3FFUL; - -#define UNI_SUR_HIGH_START (UTF32)0xD800 -#define UNI_SUR_HIGH_END (UTF32)0xDBFF -#define UNI_SUR_LOW_START (UTF32)0xDC00 -#define UNI_SUR_LOW_END (UTF32)0xDFFF -#define false 0 -#define true 1 - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF32toUTF16 ( - const UTF32** sourceStart, const UTF32* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF32* source = *sourceStart; - UTF16* target = *targetStart; - while (source < sourceEnd) { - UTF32 ch; - if (target >= targetEnd) { - result = targetExhausted; break; - } - ch = *source++; - if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ - /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { - if (flags == strictConversion) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - *target++ = (UTF16)ch; /* normal case */ - } - } else if (ch > UNI_MAX_LEGAL_UTF32) { - if (flags == strictConversion) { - result = sourceIllegal; - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - /* target is a character in range 0xFFFF - 0x10FFFF. */ - if (target + 1 >= targetEnd) { - --source; /* Back up source pointer! */ - result = targetExhausted; break; - } - ch -= halfBase; - *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); - *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); - } - } - *sourceStart = source; - *targetStart = target; - return result; -} - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF16toUTF32 ( - const UTF16** sourceStart, const UTF16* sourceEnd, - UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF16* source = *sourceStart; - UTF32* target = *targetStart; - UTF32 ch, ch2; - while (source < sourceEnd) { - const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ - ch = *source++; - /* If we have a surrogate pair, convert to UTF32 first. */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { - /* If the 16 bits following the high surrogate are in the source buffer... */ - if (source < sourceEnd) { - ch2 = *source; - /* If it's a low surrogate, convert to UTF32. */ - if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { - ch = ((ch - UNI_SUR_HIGH_START) << halfShift) - + (ch2 - UNI_SUR_LOW_START) + halfBase; - ++source; - } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } else { /* We don't have the 16 bits following the high surrogate. */ - --source; /* return to the high surrogate */ - result = sourceExhausted; - break; - } - } else if (flags == strictConversion) { - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } - if (target >= targetEnd) { - source = oldSource; /* Back up source pointer! */ - result = targetExhausted; break; - } - *target++ = ch; - } - *sourceStart = source; - *targetStart = target; -#ifdef CVTUTF_DEBUG -if (result == sourceIllegal) { - fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2); - fflush(stderr); -} -#endif - return result; -} - -/* --------------------------------------------------------------------- */ - -/* - * Index into the table below with the first byte of a UTF-8 sequence to - * get the number of trailing bytes that are supposed to follow it. - * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is - * left as-is for anyone who may want to do such conversion, which was - * allowed in earlier algorithms. - */ -static const char trailingBytesForUTF8[256] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 -}; - -/* - * Magic values subtracted from a buffer value during UTF8 conversion. - * This table contains as many values as there might be trailing bytes - * in a UTF-8 sequence. - */ -static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, - 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; - -/* - * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed - * into the first byte, depending on how many bytes follow. There are - * as many entries in this table as there are UTF-8 sequence types. - * (I.e., one byte sequence, two byte... etc.). Remember that sequencs - * for *legal* UTF-8 will be 4 or fewer bytes total. - */ -static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - -/* --------------------------------------------------------------------- */ - -/* The interface converts a whole buffer to avoid function-call overhead. - * Constants have been gathered. Loops & conditionals have been removed as - * much as possible for efficiency, in favor of drop-through switches. - * (See "Note A" at the bottom of the file for equivalent code.) - * If your compiler supports it, the "isLegalUTF8" call can be turned - * into an inline function. - */ - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF16toUTF8 ( - const UTF16** sourceStart, const UTF16* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF16* source = *sourceStart; - UTF8* target = *targetStart; - while (source < sourceEnd) { - UTF32 ch; - unsigned short bytesToWrite = 0; - const UTF32 byteMask = 0xBF; - const UTF32 byteMark = 0x80; - const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ - ch = *source++; - /* If we have a surrogate pair, convert to UTF32 first. */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { - /* If the 16 bits following the high surrogate are in the source buffer... */ - if (source < sourceEnd) { - UTF32 ch2 = *source; - /* If it's a low surrogate, convert to UTF32. */ - if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { - ch = ((ch - UNI_SUR_HIGH_START) << halfShift) - + (ch2 - UNI_SUR_LOW_START) + halfBase; - ++source; - } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } else { /* We don't have the 16 bits following the high surrogate. */ - --source; /* return to the high surrogate */ - result = sourceExhausted; - break; - } - } else if (flags == strictConversion) { - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } - /* Figure out how many bytes the result will require */ - if (ch < (UTF32)0x80) { bytesToWrite = 1; - } else if (ch < (UTF32)0x800) { bytesToWrite = 2; - } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; - } else if (ch < (UTF32)0x110000) { bytesToWrite = 4; - } else { bytesToWrite = 3; - ch = UNI_REPLACEMENT_CHAR; - } - - target += bytesToWrite; - if (target > targetEnd) { - source = oldSource; /* Back up source pointer! */ - target -= bytesToWrite; result = targetExhausted; break; - } - switch (bytesToWrite) { /* note: everything falls through. */ - case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); - } - target += bytesToWrite; - } - *sourceStart = source; - *targetStart = target; - return result; -} - -/* --------------------------------------------------------------------- */ - -/* - * Utility routine to tell whether a sequence of bytes is legal UTF-8. - * This must be called with the length pre-determined by the first byte. - * If not calling this from ConvertUTF8to*, then the length can be set by: - * length = trailingBytesForUTF8[*source]+1; - * and the sequence is illegal right away if there aren't that many bytes - * available. - * If presented with a length > 4, this returns false. The Unicode - * definition of UTF-8 goes up to 4-byte sequences. - */ - -static Boolean isLegalUTF8(const UTF8 *source, int length) { - UTF8 a; - const UTF8 *srcptr = source+length; - switch (length) { - default: return false; - /* Everything else falls through when "true"... */ - case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; - case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; - case 2: if ((a = (*--srcptr)) > 0xBF) return false; - - switch (*source) { - /* no fall-through in this inner switch */ - case 0xE0: if (a < 0xA0) return false; break; - case 0xED: if (a > 0x9F) return false; break; - case 0xF0: if (a < 0x90) return false; break; - case 0xF4: if (a > 0x8F) return false; break; - default: if (a < 0x80) return false; - } - - case 1: if (*source >= 0x80 && *source < 0xC2) return false; - } - if (*source > 0xF4) return false; - return true; -} - -/* --------------------------------------------------------------------- */ - -/* - * Exported function to return whether a UTF-8 sequence is legal or not. - * This is not used here; it's just exported. - */ -Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { - int length = trailingBytesForUTF8[*source]+1; - if (source+length > sourceEnd) { - return false; - } - return isLegalUTF8(source, length); -} - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF8toUTF16 ( - const UTF8** sourceStart, const UTF8* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF8* source = *sourceStart; - UTF16* target = *targetStart; - while (source < sourceEnd) { - UTF32 ch = 0; - unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; - if (source + extraBytesToRead >= sourceEnd) { - result = sourceExhausted; break; - } - /* Do this check whether lenient or strict */ - if (! isLegalUTF8(source, extraBytesToRead+1)) { - result = sourceIllegal; - break; - } - /* - * The cases all fall through. See "Note A" below. - */ - switch (extraBytesToRead) { - case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ - case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ - case 3: ch += *source++; ch <<= 6; - case 2: ch += *source++; ch <<= 6; - case 1: ch += *source++; ch <<= 6; - case 0: ch += *source++; - } - ch -= offsetsFromUTF8[extraBytesToRead]; - - if (target >= targetEnd) { - source -= (extraBytesToRead+1); /* Back up source pointer! */ - result = targetExhausted; break; - } - if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { - if (flags == strictConversion) { - source -= (extraBytesToRead+1); /* return to the illegal value itself */ - result = sourceIllegal; - break; - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - *target++ = (UTF16)ch; /* normal case */ - } - } else if (ch > UNI_MAX_UTF16) { - if (flags == strictConversion) { - result = sourceIllegal; - source -= (extraBytesToRead+1); /* return to the start */ - break; /* Bail out; shouldn't continue */ - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - /* target is a character in range 0xFFFF - 0x10FFFF. */ - if (target + 1 >= targetEnd) { - source -= (extraBytesToRead+1); /* Back up source pointer! */ - result = targetExhausted; break; - } - ch -= halfBase; - *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); - *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); - } - } - *sourceStart = source; - *targetStart = target; - return result; -} - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF32toUTF8 ( - const UTF32** sourceStart, const UTF32* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF32* source = *sourceStart; - UTF8* target = *targetStart; - while (source < sourceEnd) { - UTF32 ch; - unsigned short bytesToWrite = 0; - const UTF32 byteMask = 0xBF; - const UTF32 byteMark = 0x80; - ch = *source++; - if (flags == strictConversion ) { - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } - /* - * Figure out how many bytes the result will require. Turn any - * illegally large UTF32 things (> Plane 17) into replacement chars. - */ - if (ch < (UTF32)0x80) { bytesToWrite = 1; - } else if (ch < (UTF32)0x800) { bytesToWrite = 2; - } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; - } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; - } else { bytesToWrite = 3; - ch = UNI_REPLACEMENT_CHAR; - result = sourceIllegal; - } - - target += bytesToWrite; - if (target > targetEnd) { - --source; /* Back up source pointer! */ - target -= bytesToWrite; result = targetExhausted; break; - } - switch (bytesToWrite) { /* note: everything falls through. */ - case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); - } - target += bytesToWrite; - } - *sourceStart = source; - *targetStart = target; - return result; -} - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF8toUTF32 ( - const UTF8** sourceStart, const UTF8* sourceEnd, - UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF8* source = *sourceStart; - UTF32* target = *targetStart; - while (source < sourceEnd) { - UTF32 ch = 0; - unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; - if (source + extraBytesToRead >= sourceEnd) { - result = sourceExhausted; break; - } - /* Do this check whether lenient or strict */ - if (! isLegalUTF8(source, extraBytesToRead+1)) { - result = sourceIllegal; - break; - } - /* - * The cases all fall through. See "Note A" below. - */ - switch (extraBytesToRead) { - case 5: ch += *source++; ch <<= 6; - case 4: ch += *source++; ch <<= 6; - case 3: ch += *source++; ch <<= 6; - case 2: ch += *source++; ch <<= 6; - case 1: ch += *source++; ch <<= 6; - case 0: ch += *source++; - } - ch -= offsetsFromUTF8[extraBytesToRead]; - - if (target >= targetEnd) { - source -= (extraBytesToRead+1); /* Back up the source pointer! */ - result = targetExhausted; break; - } - if (ch <= UNI_MAX_LEGAL_UTF32) { - /* - * UTF-16 surrogate values are illegal in UTF-32, and anything - * over Plane 17 (> 0x10FFFF) is illegal. - */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { - if (flags == strictConversion) { - source -= (extraBytesToRead+1); /* return to the illegal value itself */ - result = sourceIllegal; - break; - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - *target++ = ch; - } - } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ - result = sourceIllegal; - *target++ = UNI_REPLACEMENT_CHAR; - } - } - *sourceStart = source; - *targetStart = target; - return result; -} - -/* --------------------------------------------------------------------- - - Note A. - The fall-through switches in UTF-8 reading code save a - temp variable, some decrements & conditionals. The switches - are equivalent to the following loop: - { - int tmpBytesToRead = extraBytesToRead+1; - do { - ch += *source++; - --tmpBytesToRead; - if (tmpBytesToRead) ch <<= 6; - } while (tmpBytesToRead > 0); - } - In UTF-8 writing code, the switches on "bytesToWrite" are - similarly unrolled loops. - - --------------------------------------------------------------------- */ diff --git a/contrib/ecaltime/linuxptp/src/convert_utf.h b/contrib/ecaltime/linuxptp/src/convert_utf.h deleted file mode 100644 index 14d7b70d..00000000 --- a/contrib/ecaltime/linuxptp/src/convert_utf.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2001-2004 Unicode, Inc. - * - * Disclaimer - * - * This source code is provided as is by Unicode, Inc. No claims are - * made as to fitness for any particular purpose. No warranties of any - * kind are expressed or implied. The recipient agrees to determine - * applicability of information provided. If this file has been - * purchased on magnetic or optical media from Unicode, Inc., the - * sole remedy for any claim will be exchange of defective media - * within 90 days of receipt. - * - * Limitations on Rights to Redistribute This Code - * - * Unicode, Inc. hereby grants the right to freely use the information - * supplied in this file in the creation of products supporting the - * Unicode Standard, and to make copies of this file in any form - * for internal or external distribution as long as this notice - * remains attached. - */ - -/* --------------------------------------------------------------------- - - Conversions between UTF32, UTF-16, and UTF-8. Header file. - - Several funtions are included here, forming a complete set of - conversions between the three formats. UTF-7 is not included - here, but is handled in a separate source file. - - Each of these routines takes pointers to input buffers and output - buffers. The input buffers are const. - - Each routine converts the text between *sourceStart and sourceEnd, - putting the result into the buffer between *targetStart and - targetEnd. Note: the end pointers are *after* the last item: e.g. - *(sourceEnd - 1) is the last item. - - The return result indicates whether the conversion was successful, - and if not, whether the problem was in the source or target buffers. - (Only the first encountered problem is indicated.) - - After the conversion, *sourceStart and *targetStart are both - updated to point to the end of last text successfully converted in - the respective buffers. - - Input parameters: - sourceStart - pointer to a pointer to the source buffer. - The contents of this are modified on return so that - it points at the next thing to be converted. - targetStart - similarly, pointer to pointer to the target buffer. - sourceEnd, targetEnd - respectively pointers to the ends of the - two buffers, for overflow checking only. - - These conversion functions take a ConversionFlags argument. When this - flag is set to strict, both irregular sequences and isolated surrogates - will cause an error. When the flag is set to lenient, both irregular - sequences and isolated surrogates are converted. - - Whether the flag is strict or lenient, all illegal sequences will cause - an error return. This includes sequences such as: , , - or in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code - must check for illegal sequences. - - When the flag is set to lenient, characters over 0x10FFFF are converted - to the replacement character; otherwise (when the flag is set to strict) - they constitute an error. - - Output parameters: - The value "sourceIllegal" is returned from some routines if the input - sequence is malformed. When "sourceIllegal" is returned, the source - value will point to the illegal value that caused the problem. E.g., - in UTF-8 when a sequence is malformed, it points to the start of the - malformed sequence. - - Author: Mark E. Davis, 1994. - Rev History: Rick McGowan, fixes & updates May 2001. - Fixes & updates, Sept 2001. - ------------------------------------------------------------------------- */ - -/* --------------------------------------------------------------------- - The following 4 definitions are compiler-specific. - The C standard does not guarantee that wchar_t has at least - 16 bits, so wchar_t is no less portable than unsigned short! - All should be unsigned values to avoid sign extension during - bit mask & shift operations. ------------------------------------------------------------------------- */ - -typedef unsigned int UTF32; /* at least 32 bits */ -typedef unsigned short UTF16; /* at least 16 bits */ -typedef unsigned char UTF8; /* typically 8 bits */ -typedef unsigned char Boolean; /* 0 or 1 */ - -/* Some fundamental constants */ -#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD -#define UNI_MAX_BMP (UTF32)0x0000FFFF -#define UNI_MAX_UTF16 (UTF32)0x0010FFFF -#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF -#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF - -typedef enum { - conversionOK, /* conversion successful */ - sourceExhausted, /* partial character in source, but hit end */ - targetExhausted, /* insuff. room in target for conversion */ - sourceIllegal /* source sequence is illegal/malformed */ -} ConversionResult; - -typedef enum { - strictConversion = 0, - lenientConversion -} ConversionFlags; - -/* This is for C++ and does no harm in C */ -#ifdef __cplusplus -extern "C" { -#endif - -ConversionResult ConvertUTF8toUTF16 ( - const UTF8** sourceStart, const UTF8* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); - -ConversionResult ConvertUTF16toUTF8 ( - const UTF16** sourceStart, const UTF16* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); - -ConversionResult ConvertUTF8toUTF32 ( - const UTF8** sourceStart, const UTF8* sourceEnd, - UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); - -ConversionResult ConvertUTF32toUTF8 ( - const UTF32** sourceStart, const UTF32* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); - -ConversionResult ConvertUTF16toUTF32 ( - const UTF16** sourceStart, const UTF16* sourceEnd, - UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); - -ConversionResult ConvertUTF32toUTF16 ( - const UTF32** sourceStart, const UTF32* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); - -Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); - -#ifdef __cplusplus -} -#endif - -/* --------------------------------------------------------------------- */ diff --git a/contrib/ecaltime/linuxptp/src/ecal_time_linuxptp.cpp b/contrib/ecaltime/linuxptp/src/ecal_time_linuxptp.cpp deleted file mode 100644 index 0d36e569..00000000 --- a/contrib/ecaltime/linuxptp/src/ecal_time_linuxptp.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* ========================= eCAL LICENSE ================================= - * - * Copyright (C) 2016 - 2019 Continental Corporation - * - * 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. - * - * ========================= eCAL LICENSE ================================= -*/ - -#include "ecal_time_linuxptp.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -Linuxptp::Linuxptp(): - is_initialized(false), - status_message("linuxptp adapter has not been initialized"), - error_code(-1) -{} - -int Linuxptp::initialize(std::string device){ - std::unique_lock lk (clock_mutex); - - if(is_initialized){ - return 0; - } - - int err; - - if (device == "CLOCK_REALTIME"){ - clock_id = CLOCK_REALTIME; - err = 0; - } else if (device == "CLOCK_MONOTONIC"){ - clock_id = CLOCK_MONOTONIC; - err = 0; - } -#ifdef CLOCK_TAI - else if (device == "CLOCK_TAI"){ - clock_id = CLOCK_TAI; - err = 0; - } -#endif /* CLOCK_TAI */ - else { - err = openClock(device.c_str(), &clock_id); - } - - { - std::unique_lock status_lk(status_mutex); - if (err){ - error_code = errno; - }else{ - error_code = 0; - } - - if(err){ - status_message.assign("Failed to open clock "); - status_message += "\""; - status_message += device; - status_message += "\": "; - status_message += strerror(errno); - std::cerr << status_message << std::endl; - - is_initialized = false; - } else { - status_message.assign("Linux PTP Adapter is OK. Using device \""); - status_message += device + "\"."; - is_initialized = true; - } - } - return err; -} - -int Linuxptp::finalize(){ - std::unique_lock lk (clock_mutex); - is_initialized = false; - int err = close(CLOCKID_TO_FD(clock_id)); - if (err){ - perror("Error closing clock"); - } - return err; -} - -long long Linuxptp::getCurrentNsecs(){ - std::unique_lock lk (clock_mutex); - if(is_initialized){ - timespec ts; - int err = clock_gettime(clock_id, &ts); - long long nanoseconds = (long long)ts.tv_nsec + (long long)ts.tv_sec * 1000000000LL; - if(err){ - error_code = errno; - status_message.assign("An error occured getting the current time: "); - status_message += strerror(errno); - } - return nanoseconds; - } else{ - return 0; - } -} - -int Linuxptp::openClock(const char *device, clockid_t *clockId){ - - struct ptp_clock_caps caps; - int file_descriptor = open(device, O_RDONLY); - - if (file_descriptor == -1){ - return -1; - }else{ - *clockId = FD_TO_CLOCKID(file_descriptor); - // Check if the 'thing' we just opened actually is a PTP clock - if(getPtpClockCaps(*clockId, &caps)){ - close(file_descriptor); - return -1; - }else{ - return 0; - } - } -} - -void Linuxptp::getStatus(int& error_, std::string* status_message_){ - std::unique_lock status_lk(status_mutex); - error_ = error_code; - if(status_message_){ - status_message_->assign(status_message.c_str()); - } -} - -int Linuxptp::getPtpClockCaps(const clockid_t clockId, struct ptp_clock_caps *caps){ - int err = ioctl(CLOCKID_TO_FD(clockId), PTP_CLOCK_GETCAPS, caps); - return err; -} diff --git a/contrib/ecaltime/linuxptp/src/ecal_time_linuxptp.h b/contrib/ecaltime/linuxptp/src/ecal_time_linuxptp.h deleted file mode 100644 index d70c24ae..00000000 --- a/contrib/ecaltime/linuxptp/src/ecal_time_linuxptp.h +++ /dev/null @@ -1,90 +0,0 @@ -/* ========================= eCAL LICENSE ================================= - * - * Copyright (C) 2016 - 2019 Continental Corporation - * - * 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. - * - * ========================= eCAL LICENSE ================================= -*/ - -#pragma once - -#include -#include -#include - -#define CLOCKFD 3 -#define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD) -#define CLOCKID_TO_FD(clk) ((unsigned int) ~((clk) >> 3)) - -class Linuxptp -{ -public: - Linuxptp(); - - /** - * @brief opens the (PTP) hardware clock - * @param[in] device A path to the clock to open (e.g. /dev/ptp0) - * @return 0 if succeeded or -1 if failed. If the function fails, the error is written as stderr. - */ - int initialize(std::string device); - - /** - * @brief closes the (PTP) clock - * @return 0 on success or -1 if failed. If the function fails, the error is written as stderr - */ - int finalize(); - - /** - * @brief queries the clock and returns it's duration since the epoch in nanoseconds - * @return the current time (or 0, if an error occurred) - */ - long long getCurrentNsecs(); - - /** - * @brief Get the current error code and status message - * - * An error code of 0 is considered to be OK. Any other error code is - * considered to indicate a problem. - * The Status message may be a nullpointer. - * - * @param error_ [out] the error code - * @param status_message_ [out] a human-readable status message. May be nullptr. - */ - void getStatus(int& error_, std::string* status_message_); - -private: - clockid_t clock_id; /** < A handle to the current clock */ - bool is_initialized; /** < Wether this time adapter has been successfully initialized */ - std::mutex clock_mutex; /** < Mutex to prevent different threads from simultaniously initializing or using the clock */ - - std::string status_message; /** < The last status message */ - int error_code; /** < The last error code */ - std::mutex status_mutex; /** < Mutex for protecting the status message and error code*/ - - /** - * @brief Queries the Capabilities of the given PTP Clock - * @param[in] clockId The PTP Clock of interest - * @param[out] caps The capabilities of the PTP Clock - * @return 0 if succeeded or -1 if failed. If the function fails, errno is set accordingly. - */ - static int getPtpClockCaps(const clockid_t clockId, struct ptp_clock_caps *caps); - - /** - * @brief opens the (PTP) hardware clock - * @param[in] device A path to the clock to open (e.g. /dev/ptp0) - * @param[out] clockId The ID to access the clock. Only valid if the function succeeded. - * @return 0 if succeeded or -1 if failed. If the function fails, errno is set accordingly. - */ - int openClock(const char *device, clockid_t *clockId); -}; diff --git a/contrib/ecaltime/linuxptp/src/ecaltime.cpp b/contrib/ecaltime/linuxptp/src/ecaltime.cpp deleted file mode 100644 index cc249b87..00000000 --- a/contrib/ecaltime/linuxptp/src/ecaltime.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* ========================= eCAL LICENSE ================================= - * - * Copyright (C) 2016 - 2019 Continental Corporation - * - * 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. - * - * ========================= eCAL LICENSE ================================= -*/ - -#include -#include -#include - -#include "ecal_time_linuxptp.h" -#include "config/config.h" - -Linuxptp linuxptp_adapter; - -ECALTIME_API int etime_initialize(void) -{ - std::string device = LinuxPtpConfig::getDevice(); - return linuxptp_adapter.initialize(device); -} - -ECALTIME_API int etime_finalize(void) -{ - return linuxptp_adapter.finalize(); -} - -ECALTIME_API long long etime_get_nanoseconds() -{ - return linuxptp_adapter.getCurrentNsecs(); -} - -ECALTIME_API int etime_set_nanoseconds(long long /*time_*/) -{ - return -1; -} - -ECALTIME_API int etime_is_synchronized() -{ - return 1; -} - -ECALTIME_API int etime_is_master() -{ - return 0; -} - -ECALTIME_API void etime_sleep_for_nanoseconds(long long duration_nsecs_) { - std::chrono::nanoseconds duration(duration_nsecs_); - std::this_thread::sleep_for(duration); -} - -ECALTIME_API void etime_get_status(int* error_, char* status_message_, int max_len_) { - int error; - if (status_message_ && max_len_ > 0) { - std::string status_message; - linuxptp_adapter.getStatus(error, &status_message); - strncpy(status_message_, status_message.c_str(), max_len_ - 1); - status_message_[max_len_ - 1] = (char)0x0; - } - else { - linuxptp_adapter.getStatus(error, nullptr); - } - if (error_) { - *error_ = error; - } -} diff --git a/ecal/CMakeLists.txt b/ecal/CMakeLists.txt index 8463fa41..d24ef206 100644 --- a/ecal/CMakeLists.txt +++ b/ecal/CMakeLists.txt @@ -34,6 +34,9 @@ endif() # core config # -------------------------------------------------------- add_subdirectory(core/cfg) +if(NOT CMAKE_CROSSCOMPILING) + add_subdirectory(core/cfg/gen) +endif() # -------------------------------------------------------- # services diff --git a/ecal/core/CMakeLists.txt b/ecal/core/CMakeLists.txt index 00207c3e..09caa9e9 100644 --- a/ecal/core/CMakeLists.txt +++ b/ecal/core/CMakeLists.txt @@ -22,8 +22,10 @@ find_package(asio REQUIRED) find_package(Threads REQUIRED) find_package(ecaludp REQUIRED) -if (ECAL_CORE_CONFIG_INIFILE) - find_package(simpleini REQUIRED) +if (ECAL_CORE_CONFIGURATION) + find_package(yaml-cpp REQUIRED) + include(${ECAL_PROJECT_ROOT}/thirdparty/yaml-cpp/compatibility-yaml-cpp.cmake) + yaml_cpp_create_compatibility_targets() endif() if (ECAL_CORE_COMMAND_LINE) @@ -63,18 +65,18 @@ endif() # config ###################################### set(ecal_config_src + src/config/default_configuration.cpp src/config/ecal_cmd_parser.cpp src/config/ecal_config.cpp src/config/ecal_config_initializer.cpp - src/config/ecal_config_reader.cpp - src/config/ecal_config_reader.h - src/config/ecal_config_reader_hlp.h - src/pubsub/ecal_publisher_config.cpp - src/pubsub/ecal_subscriber_config.cpp src/types/ecal_custom_data_types.cpp - src/types/ecal_registration_options.cpp ) - +if (ECAL_CORE_CONFIGURATION) + list(APPEND ecal_config_src + src/config/configuration_to_yaml.cpp + src/config/configuration_reader.cpp + ) +endif() ###################################### # io/mtx ###################################### @@ -288,6 +290,12 @@ if (ECAL_CORE_REGISTRATION) src/registration/ecal_registration_provider.h src/registration/ecal_registration_receiver.cpp src/registration/ecal_registration_receiver.h + src/registration/ecal_registration_sample_applier.cpp + src/registration/ecal_registration_sample_applier.h + src/registration/ecal_registration_sample_applier_gates.cpp + src/registration/ecal_registration_sample_applier_gates.h + src/registration/ecal_registration_sample_applier_user.cpp + src/registration/ecal_registration_sample_applier_user.h src/registration/ecal_registration_sender.h src/registration/udp/ecal_registration_receiver_udp.cpp src/registration/udp/ecal_registration_receiver_udp.h @@ -559,6 +567,10 @@ ecal_add_ecal_shared_library(${PROJECT_NAME} ${CMAKE_CURRENT_BINARY_DIR}/include/ecal/ecal_defs.h ) +if (ECAL_CORE_CONFIGURATION) + target_compile_definitions(${PROJECT_NAME} PRIVATE ECAL_CORE_CONFIGURATION) +endif() + if(UNIX) set_source_files_properties(src/util/convert_utf.cpp PROPERTIES COMPILE_FLAGS -Wno-implicit-fallthrough) endif() @@ -601,7 +613,7 @@ target_compile_definitions(${PROJECT_NAME} ) set(ECAL_CORE_FEATURES - ECAL_CORE_CONFIG_INIFILE + ECAL_CORE_CONFIGURATION ECAL_CORE_COMMAND_LINE ECAL_CORE_REGISTRATION ECAL_CORE_MONITORING @@ -625,10 +637,10 @@ foreach(CORE_FEATURE ${ECAL_CORE_FEATURES}) endif() endforeach() -if(ECAL_CORE_CONFIG_INIFILE) +if(ECAL_CORE_CONFIGURATION) target_link_libraries(${PROJECT_NAME} PRIVATE - simpleini::simpleini + yaml-cpp::yaml-cpp ) endif() diff --git a/ecal/core/cfg/CMakeLists.txt b/ecal/core/cfg/CMakeLists.txt index e577b778..bf3456e4 100644 --- a/ecal/core/cfg/CMakeLists.txt +++ b/ecal/core/cfg/CMakeLists.txt @@ -1,6 +1,6 @@ # ========================= eCAL LICENSE ================================= # -# Copyright (C) 2016 - 2019 Continental Corporation +# Copyright (C) 2016 - 2024 Continental Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -16,12 +16,14 @@ # # ========================= eCAL LICENSE ================================= +set(ECALTIME_INI "ecaltime.ini") + # Merge all ecaltime config files # -> The ecaltime.ini will only contain valid settings for the time modules that were actually compiled. -file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/ecaltime.ini "") +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${ECALTIME_INI} "") foreach(ECALTIME_CONFIG ${ECALTIME_CONFIG_FILES}) file(READ ${ECALTIME_CONFIG} CONTENTS) - file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/ecaltime.ini "${CONTENTS}") + file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/${ECALTIME_INI} "${CONTENTS}") endforeach() # Select the correct ecal config directory on Linux and Windows @@ -33,24 +35,13 @@ else() message(STATUS "Unsupported OS, not installing configs") endif() -configure_file( - ecal.ini - ecal.ini -) # Install the configs if(ECAL_SHARED_CONFIG AND NOT CMAKE_CROSSCOMPILING) - install( - FILES - ${CMAKE_CURRENT_BINARY_DIR}/ecal.ini - DESTINATION - ${ECAL_SHARED_CONFIG} - COMPONENT configuration - ) if(BUILD_TIME) install( FILES - ${CMAKE_CURRENT_BINARY_DIR}/ecaltime.ini + ${CMAKE_CURRENT_BINARY_DIR}/${ECALTIME_INI} DESTINATION ${ECAL_SHARED_CONFIG} COMPONENT configuration diff --git a/ecal/core/cfg/ecal.ini b/ecal/core/cfg/ecal.ini deleted file mode 100644 index 5bad09ad..00000000 --- a/ecal/core/cfg/ecal.ini +++ /dev/null @@ -1,187 +0,0 @@ -; -------------------------------------------------- -; NETWORK SETTINGS -; -------------------------------------------------- -; network_enabled = true / false true = all eCAL components communicate over network boundaries (registration over udp) -; false = local host only communication (registration over shm) -; -; multicast_config_version = v1 / v2 UDP configuration version (Since eCAL 5.12.) -; v1: default behavior -; v2: new behavior, comes with a bit more intuitive handling regarding masking of the groups -; multicast_group = 239.0.0.1 UDP multicast group base -; All registration and logging is sent on this address -; multicast_mask = 0.0.0.1-0.0.0.255 v1: Mask maximum number of dynamic multicast group -; 255.0.0.0-255.255.255.255 v2: masks are now considered like routes masking -; -; multicast_port = 14000 + x UDP multicast port number (eCAL will use at least the 2 following port -; numbers too, so please modify in steps of 10 (e.g. 1010, 1020 ...) -; -; multicast_ttl = 0 + x UDP ttl value, also known as hop limit, is used in determining -; the intermediate routers being traversed towards the destination -; -; multicast_sndbuf = 1024 * x UDP send buffer in bytes -; -; multicast_rcvbuf = 1024 * x UDP receive buffer in bytes -; -; multicast_join_all_if = false Linux specific setting to enable joining multicast groups on all network interfacs -; independent of their link state. Enabling this makes sure that eCAL processes -; receive data if they are started before network devices are up and running. -; -; shm_rec_enabled = true Enable to receive on eCAL shared memory layer -; tcp_rec_enabled = true Enable to receive on eCAL tcp layer -; udp_mc_rec_enabled = true Enable to receive on eCAL udp multicast layer -; -; npcap_enabled = false Enable to receive UDP traffic with the Npcap based receiver -; -; tcp_pubsub_num_executor_reader = 4 Tcp_pubsub reader amount of threads that shall execute workload -; tcp_pubsub_num_executor_writer = 4 Tcp_pubsub writer amount of threads that shall execute workload -; tcp_pubsub_max_reconnections = 5 Tcp_pubsub reconnection attemps the session will try to reconnect in -; case of an issue (a negative value means infinite reconnection attemps) -; -; host_group_name = Common host group name that enables interprocess mechanisms across -; (virtual) host borders (e.g, Docker); by default equivalent to local host name -; -------------------------------------------------- - -[network] -network_enabled = false -shm_registration_enabled = false -multicast_config_version = v1 -multicast_group = 239.0.0.1 -multicast_mask = 0.0.0.15 -multicast_port = 14000 -multicast_ttl = 2 -multicast_sndbuf = 5242880 -multicast_rcvbuf = 5242880 - -multicast_join_all_if = false - -shm_rec_enabled = true -tcp_rec_enabled = true -udp_mc_rec_enabled = true - -npcap_enabled = false - -tcp_pubsub_num_executor_reader = 4 -tcp_pubsub_num_executor_writer = 4 -tcp_pubsub_max_reconnections = 5 - -host_group_name = - -; -------------------------------------------------- -; COMMON SETTINGS -; -------------------------------------------------- -; registration_timeout = 60000 Timeout for topic registration in ms (internal) -; registration_refresh = 1000 Topic registration refresh cylce (has to be smaller then registration timeout !) - -; -------------------------------------------------- -[common] -registration_timeout = 60000 -registration_refresh = 1000 - -; -------------------------------------------------- -; TIME SETTINGS -; -------------------------------------------------- -; timesync_module_rt = ecaltime-localtime Time synchronisation interface name (dynamic library) -; The name will be extended with platform suffix (32|64), debug suffix (d) and platform extension (.dll|.so) -; -; Available modules are: -; - ecaltime-localtime local system time without synchronization -; - ecaltime-linuxptp For PTP / gPTP synchronization over ethernet on Linux -; (device configuration in ecaltime.ini) -; -------------------------------------------------- -[time] -timesync_module_rt = ecaltime-localtime - -; --------------------------------------------- -; PROCESS SETTINGS -; --------------------------------------------- -; -; terminal_emulator = /usr/bin/x-terminal-emulator -e command for starting applications with an external terminal emulator. If empty, the command will be ignored. Ignored on Windows. -; e.g. /usr/bin/x-terminal-emulator -e -; /usr/bin/gnome-terminal -x -; /usr/bin/xterm -e -; -; --------------------------------------------- -[process] -terminal_emulator = - -; -------------------------------------------------- -; PUBLISHER SETTINGS -; -------------------------------------------------- -; use_shm = 0, 1, 2 Use shared memory transport layer (0 = off, 1 = on, 2 = auto, default = 2) -; use_tcp = 0, 1, 2 Use tcp transport layer (0 = off, 1 = on, 2 = auto, default = 0) -; use_udp_mc = 0, 1, 2 Use udp multicast transport layer (0 = off, 1 = on, 2 = auto, default = 2) -; -; memfile_minsize = x * 4096 kB Default memory file size for new publisher -; -; memfile_reserve = 50 .. x % Dynamic file size reserve before recreating memory file if topic size changes -; -; memfile_ack_timeout = 0 .. x ms Publisher timeout for ack event from subscriber that memory file content is processed -; -; memfile_buffer_count = 1 .. x Number of parallel used memory file buffers for 1:n publish/subscribe ipc connections (default = 1) -; memfile_zero_copy = 0, 1 Allow matching subscriber to access memory file without copying its content in advance (blocking mode) -; -; share_ttype = 0, 1 Share topic type via registration layer -; share_tdesc = 0, 1 Share topic description via registration layer (switch off to disable reflection) -; -------------------------------------------------- -[publisher] -use_shm = 2 -use_tcp = 0 -use_udp_mc = 2 - -memfile_minsize = 4096 -memfile_reserve = 50 -memfile_ack_timeout = 0 -memfile_buffer_count = 1 -memfile_zero_copy = 0 - -share_ttype = 1 -share_tdesc = 1 - -; -------------------------------------------------- -; SERVICE SETTINGS -; -------------------------------------------------- -; protocol_v0 = 0, 1 Support service protocol v0, eCAL 5.11 and older (0 = off, 1 = on) -; protocol_v1 = 0, 1 Support service protocol v1, eCAL 5.12 and newer (0 = off, 1 = on) -; -------------------------------------------------- -[service] -protocol_v0 = 1 -protocol_v1 = 1 - -; -------------------------------------------------- -; MONITORING SETTINGS -; -------------------------------------------------- -; timeout = 1000 + (x * 1000) Timeout for topic monitoring in ms -; filter_excl = __.* Topics blacklist as regular expression (will not be monitored) -; filter_incl = Topics whitelist as regular expression (will be monitored only) -; filter_log_con = info, warning, error, fatal Log messages logged to console (all, info, warning, error, fatal, debug1, debug2, debug3, debug4) -; filter_log_file = Log messages to logged into file system -; filter_log_udp = info, warning, error, fatal Log messages logged via udp network -; -------------------------------------------------- -[monitoring] -timeout = 5000 -filter_excl = __.* -filter_incl = -filter_log_con = info, warning, error, fatal -filter_log_file = -filter_log_udp = info, warning, error, fatal - -; -------------------------------------------------- -; SYS SETTINGS -; -------------------------------------------------- -; filter_excl = App1,App2 Apps blacklist to be excluded when importing tasks from cloud -; -------------------------------------------------- -[sys] -filter_excl = ^eCALSysClient$|^eCALSysGUI$|^eCALSys$ - -; -------------------------------------------------- -; EXPERIMENTAL SETTINGS -; -------------------------------------------------- -; shm_monitoring_domain = ecal_monitoring Domain name for shared memory based monitoring/registration -; shm_monitoring_queue_size = 1024 Queue size of monitoring/registration events -; -; drop_out_of_order_messages = false Enable dropping of payload messages that arrive out of order -; -------------------------------------------------- -[experimental] -shm_monitoring_domain = ecal_mon -shm_monitoring_queue_size = 1024 -drop_out_of_order_messages = false diff --git a/ecal/core/cfg/gen/CMakeLists.txt b/ecal/core/cfg/gen/CMakeLists.txt new file mode 100644 index 00000000..76d0ca35 --- /dev/null +++ b/ecal/core/cfg/gen/CMakeLists.txt @@ -0,0 +1,77 @@ +# ========================= eCAL LICENSE ================================= +# +# Copyright (C) 2016 - 2024 Continental Corporation +# +# 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. +# +# ========================= eCAL LICENSE ================================= + +project(generate_config) + +# Set the name of the YAML file to be generated +set(ECAL_YAML "ecal.yaml") + +add_executable(${PROJECT_NAME} + ${ECAL_CORE_PROJECT_ROOT}/core/cfg/gen/generate_configuration_yaml.cpp + ${ECAL_CORE_PROJECT_ROOT}/core/src/config/default_configuration.cpp +) + +# Set the output path for the generated YAML file +set(YAML_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/${ECAL_YAML}) + +# Add a custom command to generate the YAML file +add_custom_command( + OUTPUT ${YAML_OUTPUT_PATH} # Specify the output file + COMMAND $ # Command to run the executable + DEPENDS ${PROJECT_NAME} # Ensure the executable is built before running the command + COMMENT "Generating ${YAML_OUTPUT_PATH}" # Comment to display during the build process + VERBATIM # Ensure command arguments are passed as-is +) + +# Add a custom target that depends on the generated YAML file +add_custom_target(run_${PROJECT_NAME} ALL + DEPENDS ${YAML_OUTPUT_PATH} # Ensure the custom command is executed +) + +# Ensure the executable is built before running the custom target +add_dependencies(run_${PROJECT_NAME} ${PROJECT_NAME}) + +# Specify include directories for the executable +target_include_directories(${PROJECT_NAME} PRIVATE + ${ECAL_CORE_PROJECT_ROOT}/core/src + ${ECAL_CORE_PROJECT_ROOT}/core/include +) + +target_link_libraries(${PROJECT_NAME} PRIVATE + eCAL::core +) + +# Select the correct ecal config directory on Linux and Windows +if(UNIX) + set(ECAL_SHARED_CONFIG ${eCAL_install_config_dir}) +elseif(WIN32) + set(ECAL_SHARED_CONFIG ${eCAL_install_config_dir}) +else() + message(STATUS "Unsupported OS, not installing configs") +endif() + +# Install the generated YAML file if not cross-compiling +if(ECAL_SHARED_CONFIG) + install( + FILES + ${YAML_OUTPUT_PATH} # File to install + DESTINATION + ${ECAL_SHARED_CONFIG} # Destination directory + COMPONENT configuration # Installation component + ) +endif() \ No newline at end of file diff --git a/ecal/core/cfg/gen/generate_configuration_yaml.cpp b/ecal/core/cfg/gen/generate_configuration_yaml.cpp new file mode 100644 index 00000000..c8a83e97 --- /dev/null +++ b/ecal/core/cfg/gen/generate_configuration_yaml.cpp @@ -0,0 +1,11 @@ +#include "config/default_configuration.h" + +int main() { + if (!eCAL::Config::dumpConfigToFile()) + { + std::cerr << "Failed to write default configuration to file." << std::endl; + return 1; + } + + return 0; +} \ No newline at end of file diff --git a/ecal/core/include/ecal/config/application.h b/ecal/core/include/ecal/config/application.h index e08367a2..8628ec22 100644 --- a/ecal/core/include/ecal/config/application.h +++ b/ecal/core/include/ecal/config/application.h @@ -36,7 +36,7 @@ namespace eCAL { struct Configuration { - std::string filter_excl; //!< + std::string filter_excl { "^eCALSysClient$|^eCALSysGUI$|^eCALSys$" }; //!< Apps blacklist to be excluded when importing tasks from cloud }; } @@ -44,14 +44,14 @@ namespace eCAL { struct Configuration { - std::string terminal_emulator; //!< + std::string terminal_emulator { "" }; //!< Linux only command for starting applications with an external terminal emulator }; } struct Configuration { - Sys::Configuration sys; //!< - Startup::Configuration startup; //!< + Sys::Configuration sys; + Startup::Configuration startup; }; } } \ No newline at end of file diff --git a/ecal/core/include/ecal/config/configuration.h b/ecal/core/include/ecal/config/configuration.h index e016d897..47c4b3fc 100644 --- a/ecal/core/include/ecal/config/configuration.h +++ b/ecal/core/include/ecal/config/configuration.h @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -49,32 +48,27 @@ namespace eCAL { struct Configuration { - Registration::Configuration registration{}; - TransportLayer::Configuration transport_layer{}; - Monitoring::Configuration monitoring{}; - Subscriber::Configuration subscriber{}; - Publisher::Configuration publisher{}; - Time::Configuration timesync{}; - Service::Configuration service{}; - Application::Configuration application{}; - Logging::Configuration logging{}; - Cli::Configuration command_line_arguments{}; + TransportLayer::Configuration transport_layer; + Registration::Configuration registration; + Monitoring::Configuration monitoring; + Subscriber::Configuration subscriber; + Publisher::Configuration publisher; + Time::Configuration timesync; + Service::Configuration service; + Application::Configuration application; + Logging::Configuration logging; + Cli::Configuration command_line_arguments; ECAL_API Configuration(); ECAL_API Configuration(int argc_, char** argv_); - ECAL_API Configuration(std::vector& args_); + ECAL_API Configuration(const std::vector& args_); - ECAL_API void InitConfigWithDefaultIni(); - ECAL_API void InitConfig(std::string ini_path_ = std::string("")); + ECAL_API void InitFromConfig(); + ECAL_API void InitFromFile(const std::string& yaml_path_); - ECAL_API std::string GetIniFilePath(); + ECAL_API std::string GetYamlFilePath(); - friend class CmdParser; - - protected: - std::string ecal_ini_file_path{}; - - private: - ECAL_API void Init(std::vector& args_); + protected: + std::string ecal_yaml_file_path; }; } diff --git a/ecal/core/include/ecal/config/logging.h b/ecal/core/include/ecal/config/logging.h index bb1ae9ef..d5a82f32 100644 --- a/ecal/core/include/ecal/config/logging.h +++ b/ecal/core/include/ecal/config/logging.h @@ -26,16 +26,63 @@ #include +#include +#include + +namespace +{ + // After switchting to c++17, this can be replaced by an inline constexpr + static const eCAL_Logging_Filter log_level_default = log_level_info | log_level_warning | log_level_error | log_level_fatal; +} + namespace eCAL { namespace Logging { + namespace Sinks + { + namespace Console + { + struct Configuration + { + bool enable { true }; //!< Enable console logging (Default: true) + eCAL_Logging_Filter filter_log_con { log_level_error | log_level_fatal }; /*!< Log messages logged to console (all, info, warning, error, fatal, debug1, debug2, debug3, debug4) + (Default: info, warning, error, fatal)*/ + }; + } + + namespace File + { + struct Configuration + { + bool enable { false }; //!< Enable file logging (Default: false) + std::string path { "" }; //!< Path to log file (Default: "") + eCAL_Logging_Filter filter_log_file { log_level_none }; /*!< Log messages logged into file system (all, info, warning, error, fatal, debug1, debug2, debug3, debug4) + (Default: info, warning, error, fatal)*/ + }; + } + + namespace UDP + { + struct Configuration + { + bool enable { true }; //!< Enable UDP logging (Default: false) + unsigned int port { 14001 }; //!< UDP port number (Default: 14001) + eCAL_Logging_Filter filter_log_udp { log_level_default }; //!< Log messages logged via udp network (Default: info, warning, error, fatal) + }; + } + + struct Configuration + { + Console::Configuration console; + File::Configuration file; + UDP::Configuration udp; + }; + } + struct Configuration { - eCAL_Logging_Filter filter_log_con{}; /*!< Log messages logged to console (all, info, warning, error, fatal, debug1, debug2, debug3, debug4) - (Default: info, warning, error, fatal)*/ - eCAL_Logging_Filter filter_log_file{}; //!< Log messages to logged into file system (Default: "") - eCAL_Logging_Filter filter_log_udp{}; //!< Log messages logged via udp network (Default: info, warning, error, fatal) + Sinks::Configuration sinks; }; } } \ No newline at end of file diff --git a/ecal/core/include/ecal/config/monitoring.h b/ecal/core/include/ecal/config/monitoring.h index bf67687b..5a905a80 100644 --- a/ecal/core/include/ecal/config/monitoring.h +++ b/ecal/core/include/ecal/config/monitoring.h @@ -30,30 +30,11 @@ namespace eCAL { namespace Monitoring { - namespace UDP - { - struct Configuration - { - }; - } - - namespace SHM - { - struct Configuration - { - std::string shm_monitoring_domain{}; //!< Domain name for shared memory based monitoring/registration (Default: ecal_mon) - size_t shm_monitoring_queue_size{}; //!< Queue size of monitoring/registration events (Default: 1024) - }; - } - struct Configuration { - eCAL::Types::ConstrainedInteger<1000, 1000> monitoring_timeout{}; //!< Timeout for topic monitoring in ms (Default: 5000) - UDP::Configuration udp_options{}; - SHM::Configuration shm_options{}; - - std::string filter_excl{}; //!< Topics blacklist as regular expression (will not be monitored) (Default: "__.*") - std::string filter_incl{}; //!< Topics whitelist as regular expression (will be monitored only) (Default: "") + eCAL::Types::ConstrainedInteger<1000, 1000> timeout { 5000U }; //!< Timeout for topic monitoring in ms (Default: 5000) + std::string filter_excl { "^__.*$" }; //!< Topics blacklist as regular expression (will not be monitored) (Default: "^__.*$") + std::string filter_incl { "" }; //!< Topics whitelist as regular expression (will be monitored only) (Default: "") }; } } \ No newline at end of file diff --git a/ecal/core/include/ecal/config/publisher.h b/ecal/core/include/ecal/config/publisher.h index 01795595..802c9329 100644 --- a/ecal/core/include/ecal/config/publisher.h +++ b/ecal/core/include/ecal/config/publisher.h @@ -88,9 +88,9 @@ #pragma once -#include #include #include +#include #include #include @@ -99,55 +99,55 @@ namespace eCAL { namespace Publisher { - namespace SHM + namespace Layer { - struct Configuration + namespace SHM { - bool enable; //!< enable layer - bool zero_copy_mode; //!< enable zero copy shared memory transport mode - unsigned int acknowledge_timeout_ms; /*!< force connected subscribers to send acknowledge event after processing the message - the publisher send call is blocked on this event with this timeout (0 == no handshake) */ - Types::ConstrainedInteger<4096, 4096> memfile_min_size_bytes; //!< default memory file size for new publisher - Types::ConstrainedInteger<50, 1, 100> memfile_reserve_percent; //!< dynamic file size reserve before recreating memory file if topic size changes - Types::ConstrainedInteger<1, 1> memfile_buffer_count; //!< maximum number of used buffers (needs to be greater than 1, default = 1) - }; - } + struct Configuration + { + bool enable { true }; //!< enable layer - namespace UDP - { - struct Configuration + bool zero_copy_mode { false }; //!< Enable zero copy shared memory transport mode + unsigned int acknowledge_timeout_ms { 0U }; /*!< Force connected subscribers to send acknowledge event after processing the message. + The publisher send call is blocked on this event with this timeout (0 == no handshake).*/ + unsigned int memfile_buffer_count { 1U }; /*!< Maximum number of used buffers (needs to be greater than 1, default = 1) */ + }; + } + + namespace UDP { - bool enable; //!< enable layer - bool loopback; //!< enable to receive udp messages on the same local machine - Types::ConstrainedInteger<5242880, 1024> sndbuf_size_bytes; //!< udp send buffer size in bytes (default 5MB) - }; - } + struct Configuration + { + bool enable { true }; //!< enable layer + }; + } - namespace TCP - { - struct Configuration + namespace TCP { - bool enable; //!< enable layer + struct Configuration + { + bool enable { true }; //!< enable layer + }; + } - size_t num_executor_reader{}; //!< reader amount of threads that shall execute workload (Default: 4) - size_t num_executor_writer{}; //!< writer amount of threads that shall execute workload (Default: 4) + struct Configuration + { + SHM::Configuration shm; + UDP::Configuration udp; + TCP::Configuration tcp; }; } struct Configuration { - ECAL_API Configuration(); - - SHM::Configuration shm; - UDP::Configuration udp; - TCP::Configuration tcp; + Layer::Configuration layer; //!< Layer configuration using LayerPriorityVector = std::vector; - LayerPriorityVector layer_priority_local = { TLayer::tlayer_shm, TLayer::tlayer_udp_mc, TLayer::tlayer_tcp }; - LayerPriorityVector layer_priority_remote = { TLayer::tlayer_udp_mc, TLayer::tlayer_tcp }; + LayerPriorityVector layer_priority_local { TLayer::tlayer_shm, TLayer::tlayer_udp_mc, TLayer::tlayer_tcp }; + LayerPriorityVector layer_priority_remote { TLayer::tlayer_udp_mc, TLayer::tlayer_tcp }; - bool share_topic_type; //!< share topic type via registration - bool share_topic_description; //!< share topic description via registration + bool share_topic_type { true }; //!< share topic type via registration + bool share_topic_description { true }; //!< share topic description via registration }; } } diff --git a/ecal/core/include/ecal/config/registration.h b/ecal/core/include/ecal/config/registration.h index a521501f..d01421b5 100644 --- a/ecal/core/include/ecal/config/registration.h +++ b/ecal/core/include/ecal/config/registration.h @@ -33,36 +33,45 @@ namespace eCAL { namespace Registration { - /** - * @brief Struct for storing RegistrationOptions. - * If not specified, registration timeout and refresh times from eCAL predefines will be used. - * When specifying: reg_timeout >= reg_refresh. If not, an invalid_argument exception will be thrown. - * By default, share_ttype and share_tdesc is true based on eCAL predefines. - * - * @param reg_timeout_ Timeout for topic registration in ms - * @param reg_refresh_ Topic registration refresh cylce in ms - * - * @throws std::invalid_argument exception. - **/ - struct Configuration + namespace Layer { - public: - ECAL_API Configuration(); - ECAL_API Configuration(unsigned int reg_timeout_, unsigned int reg_refresh_); + namespace SHM + { + struct Configuration + { + bool enable { false }; /*!< Enable shared memory based registration (Default: false) */ + std::string domain { "ecal_mon" }; //!< Domain name for shared memory based registration (Default: ecal_mon) + size_t queue_size { 1024 }; //!< Queue size of registration events (Default: 1024) + }; + } + + namespace UDP + { + struct Configuration + { + bool enable { true }; /*!< Enable UDP based registration (Default: true) */ + unsigned int port { 14000 }; /*!< UDP multicast port number (Default: 14000) */ + }; + } - ECAL_API unsigned int getTimeoutMS() const; //!< Timeout for topic registration in ms (internal) (Default: 60000) - ECAL_API unsigned int getRefreshMS() const; //!< Topic registration refresh cylce (has to be smaller then registration timeout!) (Default: 1000) + struct Configuration + { + SHM::Configuration shm; /*!< Shared memory based registration configuration */ + UDP::Configuration udp; /*!< UDP based registration configuration */ + }; + } - bool network_enabled; /*!< true = all eCAL components communicate over network boundaries - false = local host only communication (Default: false) */ - bool shm_registration_enabled; /*!< true = registration layer is based on shm - false = registration layer is based on udp (Default: false) */ - bool share_ttype; //!< Share topic type via registration layer (Default: true) - bool share_tdesc; //!< Share topic description via registration layer (switch off to disable reflection) (Default: true) + struct Configuration + { + unsigned int registration_timeout { 60000U }; //!< Timeout for topic registration in ms (internal) (Default: 60000) + unsigned int registration_refresh { 1000U }; //!< Topic registration refresh cylce (has to be smaller then registration timeout!) (Default: 1000) - private: - unsigned int m_registration_timeout; - unsigned int m_registration_refresh; + bool network_enabled { false }; /*!< true = all eCAL components communicate over network boundaries + false = local host only communication (Default: false) */ + bool loopback { true }; //!< enable to receive udp messages on the same local machine (Default: true) + std::string host_group_name { "" }; /*!< Common host group name that enables interprocess mechanisms across + (virtual) host borders (e.g, Docker); by default equivalent to local host name (Default: "") */ + Layer::Configuration layer; }; } } \ No newline at end of file diff --git a/ecal/core/include/ecal/config/service.h b/ecal/core/include/ecal/config/service.h index 74f4b542..3082a6c5 100644 --- a/ecal/core/include/ecal/config/service.h +++ b/ecal/core/include/ecal/config/service.h @@ -32,8 +32,8 @@ namespace eCAL { struct Configuration { - bool protocol_v0{}; //!< Support service protocol v0, eCAL 5.11 and older (Default: true) - bool protocol_v1{}; //!< Support service protocol v1, eCAL 5.12 and newer (Default: true) + bool protocol_v0 { false }; //!< Support service protocol v0, eCAL 5.11 and older (Default: false) + bool protocol_v1 { true }; //!< Support service protocol v1, eCAL 5.12 and newer (Default: true) }; } } \ No newline at end of file diff --git a/ecal/core/include/ecal/config/subscriber.h b/ecal/core/include/ecal/config/subscriber.h index 9b283a4b..121f5f65 100644 --- a/ecal/core/include/ecal/config/subscriber.h +++ b/ecal/core/include/ecal/config/subscriber.h @@ -24,7 +24,7 @@ #pragma once -#include +#include #include @@ -32,42 +32,45 @@ namespace eCAL { namespace Subscriber { - namespace SHM + namespace Layer { - struct Configuration + namespace SHM { - bool enable; //!< enable layer - }; - } + struct Configuration + { + bool enable { true }; //!< enable layer (Default: true) + }; + } - namespace UDP - { - struct Configuration + namespace UDP { - bool enable; //!< enable layer - }; - } + struct Configuration + { + bool enable { true }; //!< enable layer (Default: true) + }; + } - namespace TCP - { - struct Configuration + namespace TCP { - bool enable; //!< enable layer + struct Configuration + { + bool enable { false }; //!< enable layer (Default: false) + }; + } - size_t num_executor_reader{}; //!< reader amount of threads that shall execute workload (Default: 4) - size_t num_executor_writer{}; //!< writer amount of threads that shall execute workload (Default: 4) - - size_t max_reconnections{}; //!< reconnection attemps the session will try to reconnect in (Default: 5) + struct Configuration + { + SHM::Configuration shm; + UDP::Configuration udp; + TCP::Configuration tcp; }; } struct Configuration { - ECAL_API Configuration(); + Layer::Configuration layer; - SHM::Configuration shm; - UDP::Configuration udp; - TCP::Configuration tcp; + bool drop_out_of_order_messages { true }; //!< Enable dropping of payload messages that arrive out of order }; } } diff --git a/ecal/core/include/ecal/config/time.h b/ecal/core/include/ecal/config/time.h index dbe62028..3c88e4a4 100644 --- a/ecal/core/include/ecal/config/time.h +++ b/ecal/core/include/ecal/config/time.h @@ -32,14 +32,14 @@ namespace eCAL { struct Configuration { - std::string timesync_module_rt{}; /*!< Time synchronisation interface name (dynamic library) - The name will be extended with platform suffix (32|64), debug suffix (d) and platform extension (.dll|.so) - Available modules are: - - ecaltime-localtime local system time without synchronization - - ecaltime-linuxptp For PTP / gPTP synchronization over ethernet on Linux - (device configuration in ecaltime.ini) - (Default: ecaltime-localtime)*/ - std::string timesync_module_replay{}; //!< (Default: "") + std::string timesync_module_rt { "ecaltime-localtime" }; /*!< Time synchronisation interface name (dynamic library) + The name will be extended with platform suffix (32|64), debug suffix (d) and platform extension (.dll|.so) + Available modules are: + - ecaltime-localtime local system time without synchronization + - ecaltime-linuxptp For PTP / gPTP synchronization over ethernet on Linux + (device configuration in ecaltime.ini) + (Default: ecaltime-localtime)*/ + std::string timesync_module_replay { "" }; //!< (Default: "") }; } } diff --git a/ecal/core/include/ecal/config/transport_layer.h b/ecal/core/include/ecal/config/transport_layer.h index fac354b5..eb89062e 100644 --- a/ecal/core/include/ecal/config/transport_layer.h +++ b/ecal/core/include/ecal/config/transport_layer.h @@ -22,7 +22,6 @@ * @brief eCAL configuration for the transport layer **/ -// TODO PG: Deprecated when configuration is implemented in all modules? #pragma once #include @@ -31,44 +30,64 @@ namespace eCAL { namespace TransportLayer { - namespace SHM - { + namespace UDP + { + namespace Network + { + struct Configuration + { + Types::IpAddressV4 group { "239.0.0.1" }; //!< UDP multicast group base (Default: 239.0.0.1) + unsigned int ttl { 3U }; /*!< UDP ttl value, also known as hop limit, is used in determining + the intermediate routers being traversed towards the destination (Default: 3) */ + }; + } + struct Configuration { - std::string host_group_name{}; /*!< Common host group name that enables interprocess mechanisms across - (virtual) host borders (e.g, Docker); by default equivalent to local host name (Default: "")*/ }; + Types::UdpConfigVersion config_version { Types::UdpConfigVersion::V2 }; /*!< UDP configuration version (Since eCAL 5.12.) + v1: default behavior + v2: new behavior, comes with a bit more intuitive handling regarding masking of the groups (Default: v2) */ + unsigned int port { 14002 }; /*!< UDP multicast port number (Default: 14002) */ + Types::UDPMode mode { Types::UDPMode::LOCAL }; /*!< Valid modes: local, network (Default: local)*/ + Types::IpAddressV4 mask { "255.255.255.240" }; /*!< v1: Mask maximum number of dynamic multicast group (Default: 0.0.0.1-0.0.0.255) + v2: masks are now considered like routes masking (Default: 255.0.0.0-255.255.255.255)*/ + + // TODO PG: are these minimum limits correct? + Types::ConstrainedInteger<5242880, 1024> send_buffer { 5242880 }; //!< UDP send buffer in bytes (Default: 5242880) + Types::ConstrainedInteger<5242880, 1024> receive_buffer { 5242880 }; //!< UDP receive buffer in bytes (Default: 5242880) + bool join_all_interfaces { false }; /*!< Linux specific setting to enable joining multicast groups on all network interfacs + independent of their link state. Enabling this makes sure that eCAL processes + receive data if they are started before network devices are up and running. (Default: false)*/ + bool npcap_enabled { false }; //!< Enable to receive UDP traffic with the Npcap based receiver (Default: false) + + Network::Configuration network; + }; } - namespace UDPMC + namespace TCP { struct Configuration { - Types::UdpConfigVersion config_version{}; /*!< UDP configuration version (Since eCAL 5.12.) - v1: default behavior - v2: new behavior, comes with a bit more intuitive handling regarding masking of the groups (Default: v1) */ - Types::IpAddressV4 group{}; //!< UDP multicast group base (Default: 239.0.0.1) - Types::IpAddressV4 mask{}; /*!< v1: Mask maximum number of dynamic multicast group (Default: 0.0.0.1-0.0.0.255) - v2: masks are now considered like routes masking (Default: 255.0.0.0-255.255.255.255)*/ - Types::ConstrainedInteger<14000, 10> port{}; /*!< UDP multicast port number (eCAL will use at least the 2 following port - numbers too, so modify in steps of 10 (e.g. 1010, 1020 ...)(Default: 14000) */ - unsigned int ttl{}; /*!< UDP ttl value, also known as hop limit, is used in determining - the intermediate routers being traversed towards the destination(Default: 2) */ - // TODO PG: are these minimum limits correct? - Types::ConstrainedInteger<5242880, 1024> sndbuf{}; //!< UDP send buffer in bytes (Default: 5242880) - Types::ConstrainedInteger<5242880, 1024> recbuf{}; //!< UDP receive buffer in bytes (Default: 5242880) - bool join_all_interfaces{}; /*!< Linux specific setting to enable joining multicast groups on all network interfacs - independent of their link state. Enabling this makes sure that eCAL processes - receive data if they are started before network devices are up and running. (Default: false)*/ + size_t number_executor_reader { 4 }; //!< Reader amount of threads that shall execute workload (Default: 4) + size_t number_executor_writer { 4 }; //!< Writer amount of threads that shall execute workload (Default: 4) + size_t max_reconnections { 5 }; //!< Reconnection attemps the session will try to reconnect in (Default: 5) + }; + } - bool npcap_enabled{}; //!< Enable to receive UDP traffic with the Npcap based receiver (Default: false) - }; + namespace SHM + { + struct Configuration + { + Types::ConstrainedInteger<4096, 4096> memfile_min_size_bytes { 4096 }; //!< Default memory file size for new publisher (Default: 4096) + Types::ConstrainedInteger<50, 1, 100> memfile_reserve_percent { 50 }; //!< Dynamic file size reserve before recreating memory file if topic size changes (Default: 50) + }; } - + struct Configuration { - bool drop_out_of_order_messages{}; //!< Enable dropping of payload messages that arrive out of order (Default: false) - UDPMC::Configuration mc_options{}; - SHM::Configuration shm_options{}; + UDP::Configuration udp; + TCP::Configuration tcp; + SHM::Configuration shm; }; } } \ No newline at end of file diff --git a/ecal/core/include/ecal/config/user_arguments.h b/ecal/core/include/ecal/config/user_arguments.h index 6f64cdf1..a5af1446 100644 --- a/ecal/core/include/ecal/config/user_arguments.h +++ b/ecal/core/include/ecal/config/user_arguments.h @@ -32,14 +32,10 @@ namespace eCAL { namespace Cli { - using ConfigKey2DMap = std::map>; //!< Config key storage: Map[Section][Option] = Value - struct Configuration { - std::vector config_keys{}; //!< will be deprecated soon - ConfigKey2DMap config_keys_map; //!< The config keys given via command line and the --config-keys parameter (Default: empty) - std::string specified_config{}; //!< The used eCAL ini file (Default: "") - bool dump_config{}; //!< If specified, output configuration via standart output (Default: false) + std::string user_yaml { "" }; //!< The used eCAL yaml file (Default: "") + bool dump_config { false }; //!< If specified, output configuration via standart output (Default: false) }; } } \ No newline at end of file diff --git a/ecal/core/include/ecal/ecal_config.h b/ecal/core/include/ecal/ecal_config.h index 7d0cc9cc..19c5ec0e 100644 --- a/ecal/core/include/ecal/ecal_config.h +++ b/ecal/core/include/ecal/ecal_config.h @@ -65,9 +65,9 @@ namespace eCAL ECAL_API bool IsNpcapEnabled (); - ECAL_API int GetTcpPubsubReaderThreadpoolSize (); - ECAL_API int GetTcpPubsubWriterThreadpoolSize (); - ECAL_API int GetTcpPubsubMaxReconnectionAttemps (); + ECAL_API size_t GetTcpPubsubReaderThreadpoolSize (); + ECAL_API size_t GetTcpPubsubWriterThreadpoolSize (); + ECAL_API size_t GetTcpPubsubMaxReconnectionAttemps (); ECAL_API int GetTcpPubReaderThreadpoolSize (); ECAL_API int GetTcpPubWriterThreadpoolSize (); diff --git a/ecal/core/include/ecal/ecal_util.h b/ecal/core/include/ecal/ecal_util.h index 0a666ee3..6bb6471f 100644 --- a/ecal/core/include/ecal/ecal_util.h +++ b/ecal/core/include/ecal/ecal_util.h @@ -100,7 +100,7 @@ namespace eCAL /** * @brief Retrieve eCAL configuration path. * This is path is for the global eCAL configuration files - * like ecal.ini. + * like ecal.yaml. * This path is read only for standard users. * * @return eCAL configuration path. diff --git a/ecal/core/include/ecal/msg/protobuf/publisher.h b/ecal/core/include/ecal/msg/protobuf/publisher.h index b6b79bd8..78cd42ca 100644 --- a/ecal/core/include/ecal/msg/protobuf/publisher.h +++ b/ecal/core/include/ecal/msg/protobuf/publisher.h @@ -160,8 +160,7 @@ namespace eCAL size_t Send(const T& msg_, long long time_ = DEFAULT_TIME_ARGUMENT) { CPayload payload{ msg_ }; - eCAL::CPublisher::Send(payload, time_); - return(0); + return eCAL::CPublisher::Send(payload, time_); } private: diff --git a/ecal/core/include/ecal/types/ecal_custom_data_types.h b/ecal/core/include/ecal/types/ecal_custom_data_types.h index 8162c099..12218f12 100644 --- a/ecal/core/include/ecal/types/ecal_custom_data_types.h +++ b/ecal/core/include/ecal/types/ecal_custom_data_types.h @@ -46,13 +46,18 @@ namespace eCAL class IpAddressV4 { public: - ECAL_API IpAddressV4(); ECAL_API IpAddressV4(const std::string& ip_address_); - std::string Get() const; + ECAL_API std::string Get() const; - ECAL_API IpAddressV4& operator=(const std::string& ip_string); + ECAL_API IpAddressV4& operator=(const std::string& ip_string_); + ECAL_API IpAddressV4& operator=(const char* ip_string_); ECAL_API operator std::string(); + ECAL_API bool operator==(const eCAL::Types::IpAddressV4& rhs) const; + ECAL_API friend bool operator==(eCAL::Types::IpAddressV4 lhs, const char* ip_string_); + ECAL_API friend bool operator==(const char* ip_string_, eCAL::Types::IpAddressV4 rhs); + ECAL_API friend bool operator==(eCAL::Types::IpAddressV4 lhs, const std::string& ip_string_); + ECAL_API friend bool operator==(const std::string& ip_string_, eCAL::Types::IpAddressV4 rhs); private: ECAL_API void validateIpString(const std::string& ip_address_); @@ -89,7 +94,10 @@ namespace eCAL }; operator int() const { return m_size; }; - bool operator==(const ConstrainedInteger& other) const { return this->m_size == other; }; + bool operator==(const ConstrainedInteger& other) const { return this->m_size == other; }; + bool operator==(const unsigned int value) const { return this->m_size == static_cast(value); }; + bool operator==(const int value) const { return this->m_size == value; }; + private: int m_size{}; @@ -100,5 +108,12 @@ namespace eCAL V1 = 1, V2 = 2 }; + + enum class UDPMode + { + NETWORK, + LOCAL + }; + } } \ No newline at end of file diff --git a/ecal/core/src/config/configuration_reader.cpp b/ecal/core/src/config/configuration_reader.cpp new file mode 100644 index 00000000..13559d7c --- /dev/null +++ b/ecal/core/src/config/configuration_reader.cpp @@ -0,0 +1,122 @@ +#include "configuration_reader.h" + +namespace +{ + void MapConfiguration(const YAML::Node& node_, eCAL::Configuration& config_) + { + YAML::AssignValue(config_.transport_layer, node_, "transport_layer"); + YAML::AssignValue(config_.publisher, node_, "publisher"); + YAML::AssignValue(config_.subscriber, node_, "subscriber"); + YAML::AssignValue(config_.registration, node_, "registration"); + YAML::AssignValue(config_.monitoring, node_, "monitoring"); + YAML::AssignValue(config_.timesync, node_, "time"); + YAML::AssignValue(config_.service, node_, "service"); + YAML::AssignValue(config_.application, node_, "application"); + YAML::AssignValue(config_.logging, node_, "logging"); + } +} + + +namespace eCAL +{ + namespace Config + { + void YamlFileToConfig(const std::string& filename_, eCAL::Configuration& config_) + { + const YAML::Node yaml = YAML::LoadFile(filename_); + + MapConfiguration(yaml, config_); + }; + + void YamlStringToConfig(const std::string& yaml_string_, eCAL::Configuration& config_) + { + const YAML::Node yaml = YAML::Load(yaml_string_); + + MapConfiguration(yaml, config_); + }; + + bool ConfigToYamlFile(const std::string& file_name_, const eCAL::Configuration& config_) + { + const YAML::Node node(config_); + std::ofstream file(file_name_); + if (file.is_open()) + { + file << node; + file.close(); + return true; + } + + return false; + }; + + void MergeYamlNodes(YAML::Node& base, const YAML::Node& other) + { + std::stack> nodes; + nodes.emplace(base, other); + + while (!nodes.empty()) + { + const std::pair nodePair = nodes.top(); + nodes.pop(); + + YAML::Node baseNode = nodePair.first; + YAML::Node otherNode = nodePair.second; + + for (YAML::const_iterator it = otherNode.begin(); it != otherNode.end(); ++it) + { + const YAML::Node key = it->first; + const YAML::Node value = it->second; + + std::string key_as_string; + + switch (key.Type()) + { + case YAML::NodeType::Scalar: + key_as_string = key.as(); + break; + default: + continue; + break; + } + + if (baseNode[key_as_string]) + { + if (value.IsMap() && baseNode[key_as_string].IsMap()) + { + nodes.emplace(baseNode[key_as_string], value); // Push nested nodes to stack + } + else + { + baseNode[key_as_string] = value; // Overwrite value for non-map nodes + } + } + else + { + baseNode[key_as_string] = value; // Add new key-value pairs + } + } + } + }; + + bool MergeYamlIntoConfiguration(const std::string& file_name_ , eCAL::Configuration& config_) + { + YAML::Node config_node(config_); + + YAML::Node node_to_merge; + try + { + node_to_merge = YAML::LoadFile(file_name_); + } + catch (std::exception& e) + { + std::cout << "Error during reading yml file: " << e.what() << "\n"; + return false; + } + + eCAL::Config::MergeYamlNodes(config_node, node_to_merge); + MapConfiguration(config_node, config_); + + return true; + } + } +} \ No newline at end of file diff --git a/ecal/core/src/config/configuration_reader.h b/ecal/core/src/config/configuration_reader.h new file mode 100644 index 00000000..c92abb89 --- /dev/null +++ b/ecal/core/src/config/configuration_reader.h @@ -0,0 +1,60 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * 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. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @brief Global eCAL configuration interface +**/ + +#ifndef ECAL_CONFIGURATION_READER +#define ECAL_CONFIGURATION_READER + +#include +#ifndef YAML_CPP_STATIC_DEFINE +#define YAML_CPP_STATIC_DEFINE +#endif +#include + +#include "configuration_to_yaml.h" + +#include +#include +#include + +namespace eCAL +{ + namespace Config + { + // Read a yaml file and convert it to an eCAL configuration + void YamlFileToConfig(const std::string& filename_, eCAL::Configuration& config_); + + // Read a yaml string and convert it to an eCAL configuration + void YamlStringToConfig(const std::string& yaml_string_, eCAL::Configuration& config_); + + // Write an eCAL configuration to a yaml file + bool ConfigToYamlFile(const std::string& file_name_, const eCAL::Configuration& config_); + + // Merge two yaml nodes, priority second parameter + void MergeYamlNodes(YAML::Node& base, const YAML::Node& other); + + // Merge a yaml file into an existing eCAL configuration + bool MergeYamlIntoConfiguration(const std::string& file_name_ , eCAL::Configuration& config_); + } +} + +#endif // ECAL_CONFIGURATION_READER \ No newline at end of file diff --git a/ecal/core/src/config/configuration_to_yaml.cpp b/ecal/core/src/config/configuration_to_yaml.cpp new file mode 100644 index 00000000..94ff0189 --- /dev/null +++ b/ecal/core/src/config/configuration_to_yaml.cpp @@ -0,0 +1,721 @@ +#include "configuration_to_yaml.h" + +// utility functions for yaml node handling +namespace YAML +{ + template + void AssignValue(MEM& member, const YAML::Node& node_, const char* key) + { + if (node_[key]) + member = node_[key].as(); + } + + // Operator overload for assigning a ConstrainedInteger to a YAML::Node + template + YAML::Node operator<<(YAML::Node node, const eCAL::Types::ConstrainedInteger& constrainedInt) + { + node = static_cast(constrainedInt); + return node; + } + + eCAL_Logging_Filter ParseLogLevel(const std::vector& filter_) + { + // create excluding filter list + char filter_mask = log_level_none; + for (const auto& it : filter_) + { + if (it == "all") filter_mask |= log_level_all; + if (it == "info") filter_mask |= log_level_info; + if (it == "warning") filter_mask |= log_level_warning; + if (it == "error") filter_mask |= log_level_error; + if (it == "fatal") filter_mask |= log_level_fatal; + if (it == "debug1") filter_mask |= log_level_debug1; + if (it == "debug2") filter_mask |= log_level_debug2; + if (it == "debug3") filter_mask |= log_level_debug3; + if (it == "debug4") filter_mask |= log_level_debug4; + } + + return(filter_mask); + }; + + std::vector LogLevelToVector(eCAL_Logging_Filter filter_mask) + { + std::vector filter; + if ((filter_mask & log_level_all) != 0) filter.emplace_back("all"); + if ((filter_mask & log_level_info) != 0) filter.emplace_back("info"); + if ((filter_mask & log_level_warning) != 0) filter.emplace_back("warning"); + if ((filter_mask & log_level_error) != 0) filter.emplace_back("error"); + if ((filter_mask & log_level_fatal) != 0) filter.emplace_back("fatal"); + if ((filter_mask & log_level_debug1) != 0) filter.emplace_back("debug1"); + if ((filter_mask & log_level_debug2) != 0) filter.emplace_back("debug2"); + if ((filter_mask & log_level_debug3) != 0) filter.emplace_back("debug3"); + if ((filter_mask & log_level_debug4) != 0) filter.emplace_back("debug4"); + + return filter; + } + + eCAL::Publisher::Configuration::LayerPriorityVector transformLayerStrToEnum(const std::vector& string_vector_) + { + eCAL::Publisher::Configuration::LayerPriorityVector layer_priority_vector; + for (const auto& layer_as_string : string_vector_) + { + if (layer_as_string == "shm") layer_priority_vector.emplace_back(eCAL::TLayer::tlayer_shm); + if (layer_as_string == "udp") layer_priority_vector.emplace_back(eCAL::TLayer::tlayer_udp_mc); + if (layer_as_string == "tcp") layer_priority_vector.emplace_back(eCAL::TLayer::tlayer_tcp); + } + + return layer_priority_vector; + } + + std::vector transformLayerEnumToStr(const eCAL::Publisher::Configuration::LayerPriorityVector& enum_vector_) + { + std::vector layer_priority_vector; + for (const auto& layer_as_enum : enum_vector_) + { + switch (layer_as_enum) + { + case eCAL::TLayer::tlayer_shm: + layer_priority_vector.emplace_back("shm"); + break; + case eCAL::TLayer::tlayer_udp_mc: + layer_priority_vector.emplace_back("udp"); + break; + case eCAL::TLayer::tlayer_tcp: + layer_priority_vector.emplace_back("tcp"); + break; + default: + break; + } + } + + return layer_priority_vector; + } +} + +namespace YAML +{ + /* + ___ _ __ __ _ + / _ \___ ___ _(_)__ / /________ _/ /_(_)__ ___ + / , _/ -_) _ `/ (_-::encode(const eCAL::Registration::Layer::UDP::Configuration& config_) + { + Node node; + node["enable"] = config_.enable; + node["port"] = config_.port; + return node; + } + + bool convert::decode(const Node& node_, eCAL::Registration::Layer::UDP::Configuration& config_) + { + AssignValue(config_.enable, node_, "enable"); + AssignValue(config_.port, node_, "port"); + return true; + } + + + Node convert::encode(const eCAL::Registration::Layer::SHM::Configuration& config_) + { + Node node; + node["enable"] = config_.enable; + node["domain"] = config_.domain; + node["queue_size"] = config_.queue_size; + return node; + } + + bool convert::decode(const Node& node_, eCAL::Registration::Layer::SHM::Configuration& config_) + { + AssignValue(config_.enable, node_, "enable"); + AssignValue(config_.domain, node_, "domain"); + AssignValue(config_.queue_size, node_, "queue_size"); + return true; + } + + Node convert::encode(const eCAL::Registration::Layer::Configuration& config_) + { + Node node; + node["shm"] = config_.shm; + node["udp"] = config_.udp; + return node; + } + + bool convert::decode(const Node& node_, eCAL::Registration::Layer::Configuration& config_) + { + AssignValue(config_.shm, node_, "shm"); + AssignValue(config_.udp, node_, "udp"); + return true; + } + + Node convert::encode(const eCAL::Registration::Configuration& config_) + { + Node node; + node["registration_timeout"] = config_.registration_timeout; + node["registration_refresh"] = config_.registration_refresh; + node["network_enabled"] = config_.network_enabled; + node["loopback"] = config_.loopback; + node["host_group_name"] = config_.host_group_name; + return node; + } + + bool convert::decode(const Node& node_, eCAL::Registration::Configuration& config_) + { + AssignValue(config_.registration_timeout, node_, "registration_timeout"); + AssignValue(config_.registration_refresh, node_, "registration_refresh"); + AssignValue(config_.network_enabled, node_, "network_enabled"); + AssignValue(config_.loopback, node_, "loopback"); + AssignValue(config_.host_group_name, node_, "host_group_name"); + AssignValue(config_.layer, node_, "layer"); + return true; + } + + + /* + __ ___ _ __ _ + / |/ /__ ___ (_) /____ ____(_)__ ___ _ + / /|_/ / _ \/ _ \/ / __/ _ \/ __/ / _ \/ _ `/ + /_/ /_/\___/_//_/_/\__/\___/_/ /_/_//_/\_, / + /___/ + */ + + Node convert::encode(const eCAL::Monitoring::Configuration& config_) + { + Node node; + node["timeout"] << config_.timeout; + node["filter_excl"] = config_.filter_excl; + node["filter_incl"] = config_.filter_incl; + + return node; + } + + bool convert::decode(const Node& node_, eCAL::Monitoring::Configuration& config_) + { + AssignValue(config_.timeout, node_, "timeout"); + AssignValue(config_.filter_excl, node_, "filter_excl"); + AssignValue(config_.filter_incl, node_, "filter_incl"); + return true; + } + + + /* + ______ __ __ + /_ __/______ ____ ___ ___ ___ ____/ /_/ / ___ ___ _____ ____ + / / / __/ _ `/ _ \(_-::encode(const eCAL::TransportLayer::SHM::Configuration& config_) + { + Node node; + node["memfile_min_size_bytes"] << config_.memfile_min_size_bytes; + node["memfile_reserve_percent"] << config_.memfile_reserve_percent; + return node; + } + + bool convert::decode(const Node& node_, eCAL::TransportLayer::SHM::Configuration& config_) + { + AssignValue(config_.memfile_min_size_bytes, node_, "memfile_min_size_bytes"); + AssignValue(config_.memfile_reserve_percent, node_, "memfile_reserve_percent"); + return true; + } + + Node convert::encode(const eCAL::TransportLayer::TCP::Configuration& config_) + { + Node node; + node["number_executor_reader"] = config_.number_executor_reader; + node["number_executor_writer"] = config_.number_executor_writer; + node["max_reconnections"] = config_.max_reconnections; + + return node; + } + + bool convert::decode(const Node& node_, eCAL::TransportLayer::TCP::Configuration& config_) + { + AssignValue(config_.number_executor_reader, node_, "number_executor_reader"); + AssignValue(config_.number_executor_writer, node_, "number_executor_writer"); + AssignValue(config_.max_reconnections, node_, "max_reconnections"); + return true; + } + + Node convert::encode(const eCAL::TransportLayer::UDP::Network::Configuration& config_) + { + Node node; + node["group"] = config_.group.Get(); + node["ttl"] = config_.ttl; + return node; + } + + bool convert::decode(const Node& node_, eCAL::TransportLayer::UDP::Network::Configuration& config_) + { + AssignValue(config_.group, node_, "group"); + AssignValue(config_.ttl, node_, "ttl"); + return true; + } + + Node convert::encode(const eCAL::TransportLayer::UDP::Configuration& config_) + { + Node node; + node["config_version"] = config_.config_version == eCAL::Types::UdpConfigVersion::V1 ? "v1" : "v2"; + node["mode"] = config_.mode == eCAL::Types::UDPMode::LOCAL ? "local" : "network"; + node["port"] = config_.port; + node["mask"] = config_.mask.Get(); + node["send_buffer"] << config_.send_buffer; + node["receive_buffer"] << config_.receive_buffer; + node["join_all_interfaces"] = config_.join_all_interfaces; + node["npcap_enabled"] = config_.npcap_enabled; + node["network"] = config_.network; + return node; + } + + bool convert::decode(const Node& node_, eCAL::TransportLayer::UDP::Configuration& config_) + { + std::string temp_string = "v2"; + AssignValue(temp_string, node_, "config_version"); + config_.config_version = temp_string == "v2" ? eCAL::Types::UdpConfigVersion::V2 : eCAL::Types::UdpConfigVersion::V1; + temp_string = "local"; + AssignValue(temp_string, node_, "mode"); + config_.mode = temp_string == "local" ? eCAL::Types::UDPMode::LOCAL : eCAL::Types::UDPMode::NETWORK; + AssignValue(config_.port, node_, "port"); + AssignValue(config_.mask, node_, "mask"); + AssignValue(config_.send_buffer, node_, "send_buffer"); + AssignValue(config_.receive_buffer, node_, "receive_buffer"); + AssignValue(config_.join_all_interfaces, node_, "join_all_interfaces"); + AssignValue(config_.npcap_enabled, node_, "npcap_enabled"); + + AssignValue(config_.network, node_, "network"); + return true; + } + + Node convert::encode(const eCAL::TransportLayer::Configuration& config_) + { + Node node; + node["shm"] = config_.shm; + node["udp"] = config_.udp; + node["tcp"] = config_.tcp; + + return node; + } + + bool convert::decode(const Node& node_, eCAL::TransportLayer::Configuration& config_) + { + AssignValue(config_.shm, node_, "shm"); + AssignValue(config_.udp, node_, "udp"); + AssignValue(config_.tcp, node_, "tcp"); + return true; + } + + + /* + ___ __ ___ __ + / _ \__ __/ / / (_)__ / / ___ ____ + / ___/ // / _ \/ / (_-::encode(const eCAL::Publisher::Layer::SHM::Configuration& config_) + { + Node node; + node["enable"] = config_.enable; + node["zero_copy_mode"] = config_.zero_copy_mode; + node["acknowledge_timeout_ms"] = config_.acknowledge_timeout_ms; + node["memfile_buffer_count"] = config_.memfile_buffer_count; + return node; + } + + bool convert::decode(const Node& node_, eCAL::Publisher::Layer::SHM::Configuration& config_) + { + AssignValue(config_.enable, node_, "enable"); + AssignValue(config_.zero_copy_mode, node_, "zero_copy_mode"); + AssignValue(config_.acknowledge_timeout_ms, node_, "acknowledge_timeout_ms"); + AssignValue(config_.memfile_buffer_count, node_, "memfile_buffer_count"); + return true; + } + + Node convert::encode(const eCAL::Publisher::Layer::UDP::Configuration& config_) + { + Node node; + node["enable"] = config_.enable; + + return node; + } + + bool convert::decode(const Node& node_, eCAL::Publisher::Layer::UDP::Configuration& config_) + { + AssignValue(config_.enable, node_, "enable"); + return true; + } + + Node convert::encode(const eCAL::Publisher::Layer::TCP::Configuration& config_) + { + Node node; + node["enable"] = config_.enable; + + return node; + } + + bool convert::decode(const Node& node_, eCAL::Publisher::Layer::TCP::Configuration& config_) + { + AssignValue(config_.enable, node_, "enable"); + return true; + } + + Node convert::encode(const eCAL::Publisher::Layer::Configuration& config_) + { + Node node; + node["shm"] = config_.shm; + node["udp"] = config_.udp; + node["tcp"] = config_.tcp; + return node; + } + + bool convert::decode(const Node& node_, eCAL::Publisher::Layer::Configuration& config_) + { + AssignValue(config_.shm, node_, "shm"); + AssignValue(config_.udp, node_, "udp"); + AssignValue(config_.tcp, node_, "tcp"); + return true; + } + + Node convert::encode(const eCAL::Publisher::Configuration& config_) + { + Node node; + node["share_topic_description"] = config_.share_topic_description; + node["share_topic_type"] = config_.share_topic_type; + node["layer"] = config_.layer; + node["priority_local"] = transformLayerEnumToStr(config_.layer_priority_local); + node["priority_network"] = transformLayerEnumToStr(config_.layer_priority_remote); + return node; + } + + bool convert::decode(const Node& node_, eCAL::Publisher::Configuration& config_) + { + AssignValue(config_.share_topic_description, node_, "share_topic_description"); + AssignValue(config_.share_topic_type, node_, "share_topic_type"); + + std::vector tmp; + AssignValue>(tmp, node_, "priority_local"); + config_.layer_priority_local = transformLayerStrToEnum(tmp); + tmp.clear(); + AssignValue>(tmp, node_, "priority_network"); + config_.layer_priority_remote = transformLayerStrToEnum(tmp); + + AssignValue(config_.layer, node_, "layer"); + return true; + } + + + /* + ____ __ _ __ + / __/_ __/ / ___ ________(_) / ___ ____ + _\ \/ // / _ \(_-::encode(const eCAL::Subscriber::Layer::SHM::Configuration& config_) + { + Node node; + node["enable"] = config_.enable; + return node; + } + + bool convert::decode(const Node& node_, eCAL::Subscriber::Layer::SHM::Configuration& config_) + { + AssignValue(config_.enable, node_, "enable"); + return true; + } + + Node convert::encode(const eCAL::Subscriber::Layer::UDP::Configuration& config_) + { + Node node; + node["enable"] = config_.enable; + return node; + } + + bool convert::decode(const Node& node_, eCAL::Subscriber::Layer::UDP::Configuration& config_) + { + AssignValue(config_.enable, node_, "enable"); + return true; + } + + Node convert::encode(const eCAL::Subscriber::Layer::TCP::Configuration& config_) + { + Node node; + node["enable"] = config_.enable; + return node; + } + + bool convert::decode(const Node& node_, eCAL::Subscriber::Layer::TCP::Configuration& config_) + { + AssignValue(config_.enable, node_, "enable"); + return true; + } + + Node convert::encode(const eCAL::Subscriber::Layer::Configuration& config_) + { + Node node; + node["shm"] = config_.shm; + node["udp"] = config_.udp; + node["tcp"] = config_.tcp; + return node; + } + + bool convert::decode(const Node& node_, eCAL::Subscriber::Layer::Configuration& config_) + { + AssignValue(config_.shm, node_, "shm"); + AssignValue(config_.udp, node_, "udp"); + AssignValue(config_.tcp, node_, "tcp"); + return true; + } + + Node convert::encode(const eCAL::Subscriber::Configuration& config_) + { + Node node; + node["layer"] = config_.layer; + node["drop_out_of_order_message"] = config_.drop_out_of_order_messages; + return node; + } + + bool convert::decode(const Node& node_, eCAL::Subscriber::Configuration& config_) + { + AssignValue(config_.layer, node_, "layer"); + AssignValue(config_.drop_out_of_order_messages, node_, "dropt_out_of_order_messages"); + return true; + } + + + /* + _______ + /_ __(_)_ _ ___ + / / / / ' \/ -_) + /_/ /_/_/_/_/\__/ + */ + + Node convert::encode(const eCAL::Time::Configuration& config_) + { + Node node; + node["replay"] = config_.timesync_module_replay; + node["rt"] = config_.timesync_module_rt; + + return node; + } + + bool convert::decode(const Node& node_, eCAL::Time::Configuration& config_) + { + AssignValue(config_.timesync_module_replay, node_, "replay"); + AssignValue(config_.timesync_module_rt, node_, "rt"); + return true; + } + + + /* + ____ _ + / __/__ _____ __(_)______ + _\ \/ -_) __/ |/ / / __/ -_) + /___/\__/_/ |___/_/\__/\__/ + */ + + Node convert::encode(const eCAL::Service::Configuration& config_) + { + Node node; + node["protocol_v0"] = config_.protocol_v0; + node["protocol_v1"] = config_.protocol_v1; + + return node; + } + + bool convert::decode(const Node& node_, eCAL::Service::Configuration& config_) + { + AssignValue(config_.protocol_v0, node_, "protocol_v0"); + AssignValue(config_.protocol_v1, node_, "protocol_v1"); + return true; + } + + + /* + ___ ___ __ _ + / _ | ___ ___ / (_)______ _/ /_(_)__ ___ + / __ |/ _ \/ _ \/ / / __/ _ `/ __/ / _ \/ _ \ + /_/ |_/ .__/ .__/_/_/\__/\_,_/\__/_/\___/_//_/ + /_/ /_/ + */ + + Node convert::encode(const eCAL::Application::Startup::Configuration& config_) + { + Node node; + node["emulator"] = config_.terminal_emulator; + + return node; + } + + bool convert::decode(const Node& node_, eCAL::Application::Startup::Configuration& config_) + { + AssignValue(config_.terminal_emulator, node_, "emulator"); + + return true; + } + + Node convert::encode(const eCAL::Application::Sys::Configuration& config_) + { + Node node; + node["filter_excl"] = config_.filter_excl; + + return node; + } + + bool convert::decode(const Node& node_, eCAL::Application::Sys::Configuration& config_) + { + AssignValue(config_.filter_excl, node_, "filter_excl"); + return true; + } + + Node convert::encode(const eCAL::Application::Configuration& config_) + { + Node node; + node["terminal"] = config_.startup; + node["sys"] = config_.sys; + + return node; + } + + bool convert::decode(const Node& node_, eCAL::Application::Configuration& config_) + { + AssignValue(config_.startup, node_, "terminal"); + AssignValue(config_.sys, node_, "sys"); + return true; + } + + /* + __ _ + / / ___ ___ ____ _(_)__ ___ _ + / /__/ _ \/ _ `/ _ `/ / _ \/ _ `/ + /____/\___/\_, /\_, /_/_//_/\_, / + /___//___/ /___/ + */ + + Node convert::encode(const eCAL::Logging::Sinks::UDP::Configuration& config_) + { + Node node; + node["enable"] = config_.enable; + node["port"] = config_.port; + node["level"] = LogLevelToVector(config_.filter_log_udp); + return node; + } + + bool convert::decode(const Node& node_, eCAL::Logging::Sinks::UDP::Configuration& config_) + { + AssignValue(config_.enable, node_, "enable"); + AssignValue(config_.port, node_, "port"); + + std::vector tmp; + AssignValue>(tmp, node_, "level"); + config_.filter_log_udp = ParseLogLevel(tmp); + return true; + } + + Node convert::encode(const eCAL::Logging::Sinks::Console::Configuration& config_) + { + Node node; + node["enable"] = config_.enable; + node["level"] = LogLevelToVector(config_.filter_log_con); + return node; + } + + bool convert::decode(const Node& node_, eCAL::Logging::Sinks::Console::Configuration& config_) + { + AssignValue(config_.enable, node_, "enable"); + std::vector tmp; + AssignValue>(tmp, node_, "level"); + config_.filter_log_con = ParseLogLevel(tmp); + return true; + } + + Node convert::encode(const eCAL::Logging::Sinks::File::Configuration& config_) + { + Node node; + node["enable"] = config_.enable; + node["path"] = config_.path; + node["level"] = LogLevelToVector(config_.filter_log_file); + return node; + } + + bool convert::decode(const Node& node_, eCAL::Logging::Sinks::File::Configuration& config_) + { + AssignValue(config_.enable, node_, "enable"); + AssignValue(config_.path, node_, "path"); + + std::vector tmp; + AssignValue>(tmp, node_, "level"); + config_.filter_log_file = ParseLogLevel(tmp); + return true; + } + + Node convert::encode(const eCAL::Logging::Sinks::Configuration& config_) + { + Node node; + node["console"] = config_.console; + node["file"] = config_.file; + node["udp"] = config_.udp; + return node; + } + + bool convert::decode(const Node& node_, eCAL::Logging::Sinks::Configuration& config_) + { + AssignValue(config_.console, node_, "console"); + AssignValue(config_.file, node_, "file"); + AssignValue(config_.udp, node_, "udp"); + return true; + } + + Node convert::encode(const eCAL::Logging::Configuration& config_) + { + Node node; + node["sinks"] = config_.sinks; + return node; + } + + bool convert::decode(const Node& node_, eCAL::Logging::Configuration& config_) + { + AssignValue(config_.sinks, node_, "sinks"); + return true; + } + + + /* + __ ___ _ ____ __ _ + / |/ /__ _(_)__ _______ ___ / _(_)__ ___ _________ _/ /_(_)__ ___ + / /|_/ / _ `/ / _ \ / __/ _ \/ _ \/ _/ / _ `/ // / __/ _ `/ __/ / _ \/ _ \ + /_/ /_/\_,_/_/_//_/ \__/\___/_//_/_//_/\_, /\_,_/_/ \_,_/\__/_/\___/_//_/ + /___/ + */ + + Node convert::encode(const eCAL::Configuration& config_) + { + Node node; + node["publisher"] = config_.publisher; + node["subscriber"] = config_.subscriber; + node["registration"] = config_.registration; + node["monitoring"] = config_.monitoring; + node["time"] = config_.timesync; + node["service"] = config_.service; + node["application"] = config_.application; + node["logging"] = config_.logging; + return node; + } + + bool convert::decode(const Node& node_, eCAL::Configuration& config_) + { + AssignValue(config_.transport_layer, node_, "transport_layer"); + AssignValue(config_.publisher, node_, "publisher"); + AssignValue(config_.subscriber, node_, "subscriber"); + AssignValue(config_.registration, node_, "registration"); + AssignValue(config_.monitoring, node_, "monitoring"); + AssignValue(config_.timesync, node_, "time"); + AssignValue(config_.service, node_, "service"); + AssignValue(config_.application, node_, "application"); + AssignValue(config_.logging, node_, "logging"); + return true; + } +} \ No newline at end of file diff --git a/ecal/core/src/config/configuration_to_yaml.h b/ecal/core/src/config/configuration_to_yaml.h new file mode 100644 index 00000000..d6930d7a --- /dev/null +++ b/ecal/core/src/config/configuration_to_yaml.h @@ -0,0 +1,365 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * 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. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @brief Utility class for parsing cmd line arguments into eCAL useful structures. +**/ + +#ifndef CONFIGURATION_TO_YAML_H +#define CONFIGURATION_TO_YAML_H + +#include + +#ifndef YAML_CPP_STATIC_DEFINE +#define YAML_CPP_STATIC_DEFINE +#endif +#include + +namespace YAML +{ + // Utility function to be used also in other files + template + void AssignValue(MEM& member, const YAML::Node& node_, const char* key); + + + /* + ___ _ __ __ _ + / _ \___ ___ _(_)__ / /________ _/ /_(_)__ ___ + / , _/ -_) _ `/ (_- + struct convert + { + static Node encode(const eCAL::Registration::Layer::UDP::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Registration::Layer::UDP::Configuration& config_); + }; + + template<> + struct convert + { + static Node encode(const eCAL::Registration::Layer::SHM::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Registration::Layer::SHM::Configuration& config_); + }; + + template<> + struct convert + { + static Node encode(const eCAL::Registration::Layer::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Registration::Layer::Configuration& config_); + }; + + template<> + struct convert + { + static Node encode(const eCAL::Registration::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Registration::Configuration& config_); + }; + + + /* + __ ___ _ __ _ + / |/ /__ ___ (_) /____ ____(_)__ ___ _ + / /|_/ / _ \/ _ \/ / __/ _ \/ __/ / _ \/ _ `/ + /_/ /_/\___/_//_/_/\__/\___/_/ /_/_//_/\_, / + /___/ + */ + template<> + struct convert + { + static Node encode(const eCAL::Monitoring::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Monitoring::Configuration& config_); + }; + + + /* + ______ __ __ + /_ __/______ ____ ___ ___ ___ ____/ /_/ / ___ ___ _____ ____ + / / / __/ _ `/ _ \(_- + struct convert + { + static Node encode(const eCAL::TransportLayer::SHM::Configuration& config_); + + static bool decode(const Node& node_, eCAL::TransportLayer::SHM::Configuration& config_); + }; + + template<> + struct convert + { + static Node encode(const eCAL::TransportLayer::TCP::Configuration& config_); + + static bool decode(const Node& node_, eCAL::TransportLayer::TCP::Configuration& config_); + }; + + template<> + struct convert + { + static Node encode(const eCAL::TransportLayer::UDP::Network::Configuration& config_); + + static bool decode(const Node& node_, eCAL::TransportLayer::UDP::Network::Configuration& config_); + }; + + template<> + struct convert + { + static Node encode(const eCAL::TransportLayer::UDP::Configuration& config_); + + static bool decode(const Node& node_, eCAL::TransportLayer::UDP::Configuration& config_); + }; + + template<> + struct convert + { + static Node encode(const eCAL::TransportLayer::Configuration& config_); + + static bool decode(const Node& node_, eCAL::TransportLayer::Configuration& config_); + }; + + + /* + ___ __ ___ __ + / _ \__ __/ / / (_)__ / / ___ ____ + / ___/ // / _ \/ / (_- + struct convert + { + static Node encode(const eCAL::Publisher::Layer::SHM::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Publisher::Layer::SHM::Configuration& config_); + }; + + template<> + struct convert + { + static Node encode(const eCAL::Publisher::Layer::UDP::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Publisher::Layer::UDP::Configuration& config_); + }; + + template<> + struct convert + { + static Node encode(const eCAL::Publisher::Layer::TCP::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Publisher::Layer::TCP::Configuration& config_); + }; + + template<> + struct convert + { + static Node encode(const eCAL::Publisher::Layer::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Publisher::Layer::Configuration& config_); + }; + + template<> + struct convert + { + static Node encode(const eCAL::Publisher::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Publisher::Configuration& config_); + }; + + + /* + ____ __ _ __ + / __/_ __/ / ___ ________(_) / ___ ____ + _\ \/ // / _ \(_- + struct convert + { + static Node encode(const eCAL::Subscriber::Layer::SHM::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Subscriber::Layer::SHM::Configuration& config_); + }; + + template<> + struct convert + { + static Node encode(const eCAL::Subscriber::Layer::UDP::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Subscriber::Layer::UDP::Configuration& config_); + }; + + template<> + struct convert + { + static Node encode(const eCAL::Subscriber::Layer::TCP::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Subscriber::Layer::TCP::Configuration& config_); + }; + + template<> + struct convert + { + static Node encode(const eCAL::Subscriber::Layer::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Subscriber::Layer::Configuration& config_); + }; + + template<> + struct convert + { + static Node encode(const eCAL::Subscriber::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Subscriber::Configuration& config_); + }; + + + /* + _______ + /_ __(_)_ _ ___ + / / / / ' \/ -_) + /_/ /_/_/_/_/\__/ + */ + template<> + struct convert + { + static Node encode(const eCAL::Time::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Time::Configuration& config_); + }; + + + /* + ____ _ + / __/__ _____ __(_)______ + _\ \/ -_) __/ |/ / / __/ -_) + /___/\__/_/ |___/_/\__/\__/ + */ + template<> + struct convert + { + static Node encode(const eCAL::Service::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Service::Configuration& config_); + }; + + + /* + ___ ___ __ _ + / _ | ___ ___ / (_)______ _/ /_(_)__ ___ + / __ |/ _ \/ _ \/ / / __/ _ `/ __/ / _ \/ _ \ + /_/ |_/ .__/ .__/_/_/\__/\_,_/\__/_/\___/_//_/ + /_/ /_/ + */ + template<> + struct convert + { + static Node encode(const eCAL::Application::Startup::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Application::Startup::Configuration& config_); + }; + + template<> + struct convert + { + static Node encode(const eCAL::Application::Sys::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Application::Sys::Configuration& config_); + }; + + + template<> + struct convert + { + static Node encode(const eCAL::Application::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Application::Configuration& config_); + }; + + /* + __ _ + / / ___ ___ ____ _(_)__ ___ _ + / /__/ _ \/ _ `/ _ `/ / _ \/ _ `/ + /____/\___/\_, /\_, /_/_//_/\_, / + /___//___/ /___/ + */ + template<> + struct convert + { + static Node encode(const eCAL::Logging::Sinks::UDP::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Logging::Sinks::UDP::Configuration& config_); + }; + + template<> + struct convert + { + static Node encode(const eCAL::Logging::Sinks::Console::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Logging::Sinks::Console::Configuration& config_); + }; + + template<> + struct convert + { + static Node encode(const eCAL::Logging::Sinks::File::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Logging::Sinks::File::Configuration& config_); + }; + + template<> + struct convert + { + static Node encode(const eCAL::Logging::Sinks::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Logging::Sinks::Configuration& config_); + }; + + template<> + struct convert + { + static Node encode(const eCAL::Logging::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Logging::Configuration& config_); + }; + + + /* + __ ___ _ ____ __ _ + / |/ /__ _(_)__ _______ ___ / _(_)__ ___ _________ _/ /_(_)__ ___ + / /|_/ / _ `/ / _ \ / __/ _ \/ _ \/ _/ / _ `/ // / __/ _ `/ __/ / _ \/ _ \ + /_/ /_/\_,_/_/_//_/ \__/\___/_//_/_//_/\_, /\_,_/_/ \_,_/\__/_/\___/_//_/ + /___/ + */ + template<> + struct convert + { + static Node encode(const eCAL::Configuration& config_); + + static bool decode(const Node& node_, eCAL::Configuration& config_); + }; +} + +#endif // CONFIGURATION_TO_YAML_H \ No newline at end of file diff --git a/ecal/core/src/config/default_configuration.cpp b/ecal/core/src/config/default_configuration.cpp new file mode 100644 index 00000000..f8cbff2f --- /dev/null +++ b/ecal/core/src/config/default_configuration.cpp @@ -0,0 +1,367 @@ +#include "default_configuration.h" + +#include "ecal/ecal_config.h" + +#include +#include + +namespace +{ + std::string quoteString(const char* str_) { + return std::string("\"") + std::string(str_) + std::string("\""); + } + + std::string quoteString(const std::string& str_) { + return std::string("\"") + str_ + std::string("\""); + } + + std::string logToArray(const eCAL_Logging_Filter& filter_) + { + std::string result = "["; + if ((filter_ & log_level_info) != 0) result += "\"info\", "; + if ((filter_ & log_level_warning) != 0) result += "\"warning\", "; + if ((filter_ & log_level_error) != 0) result += "\"error\", "; + if ((filter_ & log_level_fatal) != 0) result += "\"fatal\", "; + if ((filter_ & log_level_debug1) != 0) result += "\"debug1\", "; + if ((filter_ & log_level_debug2) != 0) result += "\"debug2\", "; + if ((filter_ & log_level_debug3) != 0) result += "\"debug3\", "; + if ((filter_ & log_level_debug4) != 0) result += "\"debug4\", "; + + if (result.size() == 1 && (filter_ & log_level_all) != 0) + { + result += "\"all\", "; + } + + if (result.size() > 1) + { + // remove the last ", " + result.pop_back(); + result.pop_back(); + } + + result += "]"; + return result; + } + + std::string quoteString(const eCAL::Publisher::Configuration::LayerPriorityVector& vector_) + { + std::string result = "["; + for (const auto& elem : vector_ ) + { + switch (elem) + { + case eCAL::TLayer::tlayer_shm: + result += "\"shm\", "; + break; + case eCAL::TLayer::tlayer_udp_mc: + result += "\"udp\", "; + break; + case eCAL::TLayer::tlayer_tcp: + result += "\"tcp\", "; + break; + default: + break; + } + } + + if (!vector_.empty()) + { + // remove the last ", " + result.pop_back(); + result.pop_back(); + } + + result += "]"; + return result; + } + + std::string quoteString(const eCAL::Types::UdpConfigVersion config_version_) { + switch (config_version_) + { + case eCAL::Types::UdpConfigVersion::V1: + return "\"v1\""; + break; + case eCAL::Types::UdpConfigVersion::V2: + return "\"v2\""; + break; + + default: + return ""; + break; + } + } + + std::string quoteString(const eCAL::Types::UDPMode mode_) + { + switch (mode_) + { + case eCAL::Types::UDPMode::LOCAL: + return "\"local\""; + break; + case eCAL::Types::UDPMode::NETWORK: + return "\"network\""; + break; + + default: + return ""; + break; + } + } + + std::string quoteString(const eCAL::Types::IpAddressV4& ip_) + { + return std::string("\"") + ip_.Get() + std::string("\""); + } +} + +namespace eCAL +{ + namespace Config + { + std::stringstream getConfigAsYamlSS(const eCAL::Configuration& config_) + { + std::stringstream ss; + ss << std::boolalpha; + ss << R"(# _____ _ _ ____ _ _ )" << "\n"; + ss << R"(# | ____|___| (_)_ __ ___ ___ ___ / ___| / \ | | )" << "\n"; + ss << R"(# | _| / __| | | '_ \/ __|/ _ \ _____ / _ \ | / _ \ | | )" << "\n"; + ss << R"(# | |__| (__| | | |_) \__ \ __/ |_____| | __/ |___ / ___ \| |___ )" << "\n"; + ss << R"(# |_____\___|_|_| .__/|___/\___| \___|\____/_/ \_\_____| )" << "\n"; + ss << R"(# |_| )" << "\n"; + ss << R"(# _ _ _ __ _ _ _ )" << "\n"; + ss << R"(# __ _| | ___ | |__ __ _| | ___ ___ _ __ / _(_) __ _ _ _ _ __ __ _| |_(_) ___ _ __ )" << "\n"; + ss << R"(# / _` | |/ _ \| '_ \ / _` | | / __/ _ \| '_ \| |_| |/ _` | | | | '__/ _` | __| |/ _ \| '_ \ )" << "\n"; + ss << R"(# | (_| | | (_) | |_) | (_| | | | (_| (_) | | | | _| | (_| | |_| | | | (_| | |_| | (_) | | | |)" << "\n"; + ss << R"(# \__, |_|\___/|_.__/ \__,_|_| \___\___/|_| |_|_| |_|\__, |\__,_|_| \__,_|\__|_|\___/|_| |_|)" << "\n"; + ss << R"(# |___/ |___/ )" << "\n"; + ss << R"()" << "\n"; + ss << R"()" << "\n"; + ss << R"(# Registration layer configuration)" << "\n"; + ss << R"(registration:)" << "\n"; + ss << R"( # Topic registration refresh cylce (has to be smaller then registration timeout! Default: 1000))" << "\n"; + ss << R"( registration_refresh: )" << config_.registration.registration_refresh << "\n"; + ss << R"( # Timeout for topic registration in ms (internal, Default: 60000))" << "\n"; + ss << R"( registration_timeout: )" << config_.registration.registration_timeout << "\n"; + ss << R"( # Enable to receive registration information on the same local machine)" << "\n"; + ss << R"( loopback: )" << config_.registration.loopback << "\n"; + ss << R"( # Host group name that enables interprocess mechanisms across (virtual))" << "\n"; + ss << R"( # host borders (e.g, Docker); by default equivalent to local host name)" << "\n"; + ss << R"( host_group_name: )" << quoteString(config_.registration.host_group_name) << "\n"; + ss << R"( # true = all eCAL components communicate over network boundaries)" << "\n"; + ss << R"( # false = local host only communication (Default: false))" << "\n"; + ss << R"( network_enabled: )" << config_.registration.network_enabled << "\n"; + ss << R"()" << "\n"; + ss << R"( layer:)" << "\n"; + ss << R"( shm:)" << "\n"; + ss << R"( enable: )" << config_.registration.layer.shm.enable << "\n"; + ss << R"( # Domain name for shared memory based registration)" << "\n"; + ss << R"( domain: )" << quoteString(config_.registration.layer.shm.domain) << "\n"; + ss << R"( # Queue size of registration events)" << "\n"; + ss << R"( queue_size: )" << config_.registration.layer.shm.queue_size << "\n"; + ss << R"()" << "\n"; + ss << R"( udp:)" << "\n"; + ss << R"( enable: )" << config_.registration.layer.udp.enable << "\n"; + ss << R"( port: )" << config_.registration.layer.udp.port << "\n"; + ss << R"()" << "\n"; + ss << R"()" << "\n"; + ss << R"(# Monitoring configuration)" << "\n"; + ss << R"(monitoring:)" << "\n"; + ss << R"( # Timeout for topic monitoring in ms (Default: 5000), increase in 1000er steps)" << "\n"; + ss << R"( timeout: )" << config_.monitoring.timeout << "\n"; + ss << R"( # Topics blacklist as regular expression (will not be monitored))" << "\n"; + ss << R"( filter_excl: )" << quoteString(config_.monitoring.filter_excl) << "\n"; + ss << R"( # Topics whitelist as regular expression (will be monitored only) (Default: ""))" << "\n"; + ss << R"( filter_incl: )" << quoteString(config_.monitoring.filter_incl) << "\n"; + ss << R"()" << "\n"; + ss << R"()" << "\n"; + ss << R"(# Transport layer configuration)" << "\n"; + ss << R"(transport_layer:)" << "\n"; + ss << R"( udp:)" << "\n"; + ss << R"( # UDP configuration version (Since eCAL 5.12.))" << "\n"; + ss << R"( # v1: default behavior)" << "\n"; + ss << R"( # v2: new behavior, comes with a bit more intuitive handling regarding masking of the groups)" << "\n"; + ss << R"( config_version: )" << quoteString(config_.transport_layer.udp.config_version) << "\n"; + ss << R"( # Valid modes: local, network (Default: local))" << "\n"; + ss << R"( mode: )" << quoteString(config_.transport_layer.udp.mode) << "\n"; + ss << R"( # Multicast port number)" << "\n"; + ss << R"( port: )" << config_.transport_layer.udp.port << "\n"; + ss << R"( # v1: Mask maximum number of dynamic multicast group (range 0.0.0.1-0.0.0.255))" << "\n"; + ss << R"( # v2: Masks are now considered like routes masking (range 255.0.0.0-255.255.255.255))" << "\n"; + ss << R"( mask: )" << quoteString(config_.transport_layer.udp.mask) << "\n"; + ss << R"( # Send buffer in bytes)" << "\n"; + ss << R"( send_buffer: )" << config_.transport_layer.udp.send_buffer << "\n"; + ss << R"( # Receive buffer in bytes)" << "\n"; + ss << R"( receive_buffer: )" << config_.transport_layer.udp.receive_buffer << "\n"; + ss << R"( # Linux specific setting to join all network interfaces independend of their link state.)" << "\n"; + ss << R"( # Enabling ensures that eCAL processes receive data when they are started before the)" << "\n"; + ss << R"( # network devices are up and running.)" << "\n"; + ss << R"( join_all_interfaces: )" << config_.transport_layer.udp.join_all_interfaces << "\n"; + ss << R"( # Windows specific setting to enable receiving UDP traffic with the Npcap based receiver)" << "\n"; + ss << R"( npcap_enabled: )" << config_.transport_layer.udp.npcap_enabled << "\n"; + ss << R"()" << "\n"; + ss << R"( # In local mode multicast group and ttl are set by default and are not adjustable)" << "\n"; + ss << R"( local:)" << "\n"; + ss << R"( # Multicast group base. All registration and logging is sent on this address)" << "\n"; + ss << R"( # group: "127.0.0.1")" << "\n"; + ss << R"( # TTL (hop limit) is used to determine the amount of routers being traversed towards the destination)" << "\n"; + ss << R"( # ttl: 0)" << "\n"; + ss << R"()" << "\n"; + ss << R"( network:)" << "\n"; + ss << R"( # Multicast group base. All registration and logging is sent on this address)" << "\n"; + ss << R"( group: )" << quoteString(config_.transport_layer.udp.network.group) << "\n"; + ss << R"( # TTL (hop limit) is used to determine the amount of routers being traversed towards the destination)" << "\n"; + ss << R"( ttl: )" << config_.transport_layer.udp.network.ttl << "\n"; + ss << R"()" << "\n"; + ss << R"( tcp: )" << "\n"; + ss << R"( # Reader amount of threads that shall execute workload)" << "\n"; + ss << R"( number_executor_reader: )" << config_.transport_layer.tcp.number_executor_reader << "\n"; + ss << R"( # Writer amount of threads that shall execute workload)" << "\n"; + ss << R"( number_executor_writer: )" << config_.transport_layer.tcp.number_executor_writer << "\n"; + ss << R"( # Reconnection attemps the session will try to reconnect in case of an issue)" << "\n"; + ss << R"( max_reconnections: )" << config_.transport_layer.tcp.max_reconnections << "\n"; + ss << R"()" << "\n"; + ss << R"( shm:)" << "\n"; + ss << R"( # Default memory file size for new publisher)" << "\n"; + ss << R"( memfile_min_size_bytes: )" << config_.transport_layer.shm.memfile_min_size_bytes << "\n"; + ss << R"( # Dynamic file size reserve before recreating memory file if topic size changes)" << "\n"; + ss << R"( memfile_reserve_percent: )" << config_.transport_layer.shm.memfile_reserve_percent << "\n"; + ss << R"()" << "\n"; + ss << R"()" << "\n"; + ss << R"(# Publisher specific base settings)" << "\n"; + ss << R"(publisher:)" << "\n"; + ss << R"( layer:)" << "\n"; + ss << R"( # Base configuration for shared memory publisher)" << "\n"; + ss << R"( shm:)" << "\n"; + ss << R"( # Enable layer)" << "\n"; + ss << R"( enable: )" << config_.publisher.layer.shm.enable << "\n"; + ss << R"( # Enable zero copy shared memory transport mode)" << "\n"; + ss << R"( zero_copy_mode: )" << config_.publisher.layer.shm.zero_copy_mode << "\n"; + ss << R"( # Force connected subscribers to send acknowledge event after processing the message.)" << "\n"; + ss << R"( # The publisher send call is blocked on this event with this timeout (0 == no handshake).)" << "\n"; + ss << R"( acknowledge_timeout_ms: )" << config_.publisher.layer.shm.acknowledge_timeout_ms << "\n"; + ss << R"( # Maximum number of used buffers (needs to be greater than 1, default = 1))" << "\n"; + ss << R"( memfile_buffer_count: )" << config_.publisher.layer.shm.memfile_buffer_count << "\n"; + ss << R"()" << "\n"; + ss << R"( # Base configuration for UDP publisher)" << "\n"; + ss << R"( udp:)" << "\n"; + ss << R"( # Enable layer)" << "\n"; + ss << R"( enable: )" << config_.publisher.layer.udp.enable << "\n"; + ss << R"()" << "\n"; + ss << R"( # Base configuration for TCP publisher)" << "\n"; + ss << R"( tcp:)" << "\n"; + ss << R"( # Enable layer)" << "\n"; + ss << R"( enable: )" << config_.publisher.layer.shm.enable << "\n"; + ss << R"()" << "\n"; + ss << R"( # Share topic type via registration)" << "\n"; + ss << R"( share_topic_type: )" << config_.publisher.share_topic_type << "\n"; + ss << R"( # Share topic description via registration)" << "\n"; + ss << R"( share_topic_description: )" << config_.publisher.share_topic_description << "\n"; + ss << R"( # Priority list for layer usage in local mode (Default: SHM > UDP > TCP))" << "\n"; + ss << R"( priority_local: )" << quoteString(config_.publisher.layer_priority_local) << "\n"; + ss << R"( # Priority list for layer usage in cloud mode (Default: UDP > TCP))" << "\n"; + ss << R"( priority_network: )" << quoteString(config_.publisher.layer_priority_remote) << "\n"; + ss << R"()" << "\n"; + ss << R"()" << "\n"; + ss << R"(# Subscriber specific base configuration)" << "\n"; + ss << R"(subscriber:)" << "\n"; + ss << R"( layer:)" << "\n"; + ss << R"( # Base configuration for shared memory subscriber)" << "\n"; + ss << R"( shm:)" << "\n"; + ss << R"( # Enable layer)" << "\n"; + ss << R"( enable: )" << config_.subscriber.layer.shm.enable << "\n"; + ss << R"()" << "\n"; + ss << R"( # Base configuration for UDP subscriber)" << "\n"; + ss << R"( udp:)" << "\n"; + ss << R"( # Enabler layer)" << "\n"; + ss << R"( enable: )" << config_.subscriber.layer.udp.enable << "\n"; + ss << R"()" << "\n"; + ss << R"( # Base configuration for TCP subscriber)" << "\n"; + ss << R"( tcp:)" << "\n"; + ss << R"( # Enable layer)" << "\n"; + ss << R"( enable: )" << config_.subscriber.layer.tcp.enable << "\n"; + ss << R"()" << "\n"; + ss << R"( # Enable dropping of payload messages that arrive out of order)" << "\n"; + ss << R"( drop_out_of_order_messages: )" << config_.subscriber.drop_out_of_order_messages << "\n"; + ss << R"()" << "\n"; + ss << R"()" << "\n"; + ss << R"(# Time configuration)" << "\n"; + ss << R"(time:)" << "\n"; + ss << R"( # Time synchronisation interface name (dynamic library))" << "\n"; + ss << R"( # The name will be extended with platform suffix (32|64), debug suffix (d) and platform extension (.dll|.so))" << "\n"; + ss << R"( # Available modules are:)" << "\n"; + ss << R"( # - ecaltime-localtime local system time without synchronization)" << "\n"; + ss << R"( # - ecaltime-linuxptp For PTP / gPTP synchronization over ethernet on Linux)" << "\n"; + ss << R"( # (device configuration in ecaltime.ini))" << "\n"; + ss << R"( rt: )" << quoteString(config_.timesync.timesync_module_rt) << "\n"; + ss << R"( # Specify the module name for replaying)" << "\n"; + ss << R"( replay: )" << quoteString(config_.timesync.timesync_module_replay) << "\n"; + ss << R"()" << "\n"; + ss << R"()" << "\n"; + ss << R"(# Service configuration)" << "\n"; + ss << R"(service:)" << "\n"; + ss << R"( # Support service protocol v0, eCAL 5.11 and older)" << "\n"; + ss << R"( protocol_v0: )" << config_.service.protocol_v0 << "\n"; + ss << R"( # Support service protocol v1, eCAL 5.12 and newer)" << "\n"; + ss << R"( protocol_v1: )" << config_.service.protocol_v1 << "\n"; + ss << R"()" << "\n"; + ss << R"()" << "\n"; + ss << R"(# eCAL Application Configuration)" << "\n"; + ss << R"(application:)" << "\n"; + ss << R"( # Configuration for eCAL Sys)" << "\n"; + ss << R"( sys:)" << "\n"; + ss << R"( # Apps blacklist to be excluded when importing tasks from cloud)" << "\n"; + ss << R"( filter_excl: )" << quoteString(config_.application.sys.filter_excl) << "\n"; + ss << R"( # Process specific configuration)" << "\n"; + ss << R"( terminal:)" << "\n"; + ss << R"( # Linux only command for starting applications with an external terminal emulator. )" << "\n"; + ss << R"( # e.g. /usr/bin/x-terminal-emulator -e)" << "\n"; + ss << R"( # /usr/bin/gnome-terminal -x)" << "\n"; + ss << R"( # /usr/bin/xterm -e)" << "\n"; + ss << R"( # If empty, the command will be ignored.)" << "\n"; + ss << R"( emulator: )" << quoteString(config_.application.startup.terminal_emulator) << "\n"; + ss << R"()" << "\n"; + ss << R"()" << "\n"; + ss << R"(# Logging configuration)" << "\n"; + ss << R"(logging:)" << "\n"; + ss << R"( sinks:)" << "\n"; + ss << R"( # Console logging configuration)" << "\n"; + ss << R"( console:)" << "\n"; + ss << R"( # Enable console logging)" << "\n"; + ss << R"( enable: )" << config_.logging.sinks.console.enable << "\n"; + ss << R"( # Log level for console output)" << "\n"; + ss << R"( level: )" << logToArray(config_.logging.sinks.console.filter_log_con) << "\n"; + ss << R"( # File logging configuration)" << "\n"; + ss << R"( file:)" << "\n"; + ss << R"( # Enable file logging)" << "\n"; + ss << R"( enable: )" << config_.logging.sinks.file.enable << "\n"; + ss << R"( # Log level for file output)" << "\n"; + ss << R"( level: )" << logToArray(config_.logging.sinks.file.filter_log_file) << "\n"; + ss << R"( # Log file path)" << "\n"; + ss << R"( path: )" << quoteString(config_.logging.sinks.file.path) << "\n"; + ss << R"( # UDP logging configuration)" << "\n"; + ss << R"( udp:)" << "\n"; + ss << R"( # Enable UDP logging)" << "\n"; + ss << R"( enable: )" << config_.logging.sinks.udp.enable << "\n"; + ss << R"( # Log level for UDP output)" << "\n"; + ss << R"( level: )" << logToArray(config_.logging.sinks.udp.filter_log_udp) << "\n"; + ss << R"( # UDP)" << "\n"; + ss << R"( port: )" << config_.logging.sinks.udp.port << "\n"; + ss << R"()" << "\n"; + + return ss; + } + + bool dumpConfigToFile(const eCAL::Configuration& config_, const std::string& file_path_) + { + std::ofstream file(file_path_); + if (!file.is_open()) + { + return false; + } + + file << getConfigAsYamlSS(config_).str(); + file.close(); + return true; + } + } +} \ No newline at end of file diff --git a/ecal/core/src/config/default_configuration.h b/ecal/core/src/config/default_configuration.h new file mode 100644 index 00000000..2ff7b09b --- /dev/null +++ b/ecal/core/src/config/default_configuration.h @@ -0,0 +1,16 @@ +#pragma once + +#include "ecal/ecal_config.h" + +#include +#include + +namespace eCAL +{ + namespace Config + { + std::stringstream getConfigAsYamlSS(const eCAL::Configuration& config_ = eCAL::GetConfiguration()); + + bool dumpConfigToFile(const eCAL::Configuration& config_ = eCAL::GetConfiguration(), const std::string& file_path_ = ECAL_DEFAULT_CFG); + } +} \ No newline at end of file diff --git a/ecal/core/src/config/ecal_cmd_parser.cpp b/ecal/core/src/config/ecal_cmd_parser.cpp index 82b483c7..babfef68 100644 --- a/ecal/core/src/config/ecal_cmd_parser.cpp +++ b/ecal/core/src/config/ecal_cmd_parser.cpp @@ -21,8 +21,6 @@ #include "ecal/ecal_defs.h" #include "ecal_def.h" -#include "ecal_utils/filesystem.h" -#include "util/getenvvar.h" #if ECAL_CORE_COMMAND_LINE #include "util/advanced_tclap_output.h" @@ -30,179 +28,6 @@ #include -// for cwd -#ifdef ECAL_OS_WINDOWS - #include - // to remove deprecated warning - #define getcwd _getcwd -#endif -#ifdef ECAL_OS_LINUX - #include -#endif - -namespace -{ - // copied and adapted from ecal_config_reader.cpp -#ifdef ECAL_OS_WINDOWS - const char path_separator('\\'); -#endif /* ECAL_OS_WINDOWS */ -#ifdef ECAL_OS_LINUX - const char path_separator('/'); -#endif /* ECAL_OS_LINUX */ - - bool setPathSep(std::string& file_path_) - { - if (!file_path_.empty()) - { - if (file_path_.back() != path_separator) - { - file_path_ += path_separator; - } - return true; - } - - return false; - } - - std::string eCALDataEnvPath() - { - std::string ecal_data_path = getEnvVar("ECAL_DATA"); - setPathSep(ecal_data_path); - return ecal_data_path; - } - - std::string cwdPath() - { - std::string cwd_path = { getcwd(nullptr, 0) }; - - if (cwd_path.empty()) - throw std::runtime_error("getcwd() : cannot read current working directory."); - - setPathSep(cwd_path); - return cwd_path; - } - - std::string eCALDataCMakePath() - { - std::string cmake_data_path; -#ifdef ECAL_OS_LINUX - const std::string ecal_install_config_dir(ECAL_INSTALL_CONFIG_DIR); - const std::string ecal_install_prefix(ECAL_INSTALL_PREFIX); - - if ((!ecal_install_config_dir.empty() && (ecal_install_config_dir[0] == path_separator)) - || ecal_install_prefix.empty()) - { - cmake_data_path = ecal_install_config_dir; - } - else if (!ecal_install_prefix.empty()) - { - cmake_data_path = ecal_install_prefix + path_separator + ecal_install_config_dir; - } - setPathSep(cmake_data_path); -#endif /* ECAL_OS_LINUX */ - return cmake_data_path; - } - - std::string eCALDataSystemPath() - { - std::string system_data_path; -#ifdef ECAL_OS_WINDOWS - system_data_path = getEnvVar("ProgramData"); - if(setPathSep(system_data_path)) - { - system_data_path += std::string("eCAL"); - setPathSep(system_data_path); - } -#endif /* ECAL_OS_WINDOWS */ - -#ifdef ECAL_OS_LINUX - system_data_path = "/etc/ecal"; - setPathSep(system_data_path); -#endif /* ECAL_OS_LINUX */ - return system_data_path; - } - - void appendFileNameToPathIfPathIsValid(std::string& path_, const std::string& file_name_) - { - if (!path_.empty()) - path_ += file_name_; - } - - void parseConfigKeysToMap(const std::vector& config_keys_, eCAL::Cli::ConfigKey2DMap& map_) - { - // each string has the format "section/key:value" - for (const auto& full_key : config_keys_) - { - auto sec_pos = full_key.find_last_of('/'); - if (sec_pos == std::string::npos) continue; - const std::string section = full_key.substr(0, sec_pos); - std::string key = full_key.substr(sec_pos+1); - - auto val_pos = key.find_first_of(':'); - if (val_pos == std::string::npos) continue; - const std::string value = key.substr(val_pos+1); - key = key.substr(0, val_pos); - - map_[section][key] = value; - } - } - - bool isValidConfigFilePath(const std::string& file_path_) - { - // check existence of user defined file - const EcalUtils::Filesystem::FileStatus ecal_ini_status(file_path_, EcalUtils::Filesystem::Current); - return ecal_ini_status.IsOk() && (ecal_ini_status.GetType() == EcalUtils::Filesystem::Type::RegularFile); - } - - std::string checkForValidConfigFilePath(const std::string& config_file_) - { - // differences to ecal_config_reader implementation are: - // 1. does not use the default ini file name, instead uses the specified file - // 2. searches relative to the executable path and takes it as highest priority - // 3. throws a runtime error, if it cannot find the specified file - - // ----------------------------------------------------------- - // precedence 1: relative path to executable - // ----------------------------------------------------------- - std::string cwd_directory_path = cwdPath(); - appendFileNameToPathIfPathIsValid(cwd_directory_path, config_file_); - - // ----------------------------------------------------------- - // precedence 2: ECAL_DATA variable (windows and linux) - // ----------------------------------------------------------- - std::string ecal_data_path = eCALDataEnvPath(); - appendFileNameToPathIfPathIsValid(ecal_data_path, config_file_); - - // ----------------------------------------------------------- - // precedence 3: cmake configured data paths (linux only) - // ----------------------------------------------------------- - std::string cmake_data_path = eCALDataCMakePath(); - appendFileNameToPathIfPathIsValid(cmake_data_path, config_file_); - - // ----------------------------------------------------------- - // precedence 4: system data path - // ----------------------------------------------------------- - std::string system_data_path = eCALDataSystemPath(); - appendFileNameToPathIfPathIsValid(system_data_path, config_file_); - - // Check for first directory which contains the ini file. - std::vector search_directories{ cwd_directory_path, ecal_data_path, cmake_data_path, system_data_path }; - - auto it = std::find_if(search_directories.begin(), search_directories.end(), isValidConfigFilePath); - // We should have encountered a valid path - if (it != search_directories.end()) - return (*it); - - // Check if user specified complete path, in case all other precedence paths exist - if (isValidConfigFilePath(config_file_)) - { - return std::string(config_file_); - } - - // If valid path is not encountered, throw error - throw std::runtime_error("[CMD Parser] Specified config file: \"" + config_file_ + "\" not found."); - } -} namespace eCAL { @@ -212,13 +37,13 @@ namespace eCAL : m_dump_config{false} {} - CmdParser::CmdParser(std::vector& arguments_) + CmdParser::CmdParser(const std::vector& arguments_) : CmdParser() { parseArguments(arguments_); } - void CmdParser::parseArguments(std::vector& arguments_) + void CmdParser::parseArguments(const std::vector& arguments_) { #if ECAL_CORE_COMMAND_LINE if (!arguments_.empty()) @@ -228,22 +53,21 @@ namespace eCAL // define command line arguments TCLAP::SwitchArg dump_config_arg ("", "ecal-dump-config", "Dump current configuration.", false); - TCLAP::ValueArg default_ini_file_arg("", "ecal-ini-file", "Load default configuration from that file.", false, ECAL_DEFAULT_CFG, "string"); - TCLAP::MultiArg set_config_key_arg ("", "ecal-set-config-key", "Overwrite a specific configuration key (ecal-set-config-key \"section/key:value\".", false, "string"); + TCLAP::ValueArg default_ini_file_arg("", "ecal-config-file", "Load default configuration from that file.", false, ECAL_DEFAULT_CFG, "string"); TCLAP::UnlabeledMultiArg dummy_arg("__dummy__", "Dummy", false, ""); // Dummy arg to eat all unrecognized arguments cmd.add(dump_config_arg); cmd.add(default_ini_file_arg); - cmd.add(set_config_key_arg); cmd.add(dummy_arg); CustomTclap::AdvancedTclapOutput advanced_tclap_output(&std::cout, 75); advanced_tclap_output.setArgumentHidden(&dummy_arg, true); cmd.setOutput(&advanced_tclap_output); + std::vector arguments = arguments_; // parse command line - cmd.parse(arguments_); + cmd.parse(arguments); // set globals if (dump_config_arg.isSet()) @@ -252,22 +76,13 @@ namespace eCAL } if (default_ini_file_arg.isSet()) { - m_user_ini = checkForValidConfigFilePath(default_ini_file_arg.getValue()); - } - if (set_config_key_arg.isSet()) - { - m_config_keys = set_config_key_arg.getValue(); - parseConfigKeysToMap(set_config_key_arg.getValue(), m_config_key_map); + m_user_ini = default_ini_file_arg.getValue(); } } #endif - m_task_parameter = arguments_; } bool CmdParser::getDumpConfig() const { return m_dump_config; }; - std::vector& CmdParser::getConfigKeys() { return m_config_keys; }; - std::vector& CmdParser::getTaskParameter() { return m_task_parameter; }; std::string& CmdParser::getUserIni() { return m_user_ini; }; - Cli::ConfigKey2DMap& CmdParser::getConfigKeysMap() { return m_config_key_map; }; } } diff --git a/ecal/core/src/config/ecal_cmd_parser.h b/ecal/core/src/config/ecal_cmd_parser.h index dd1ed957..bc0dec7c 100644 --- a/ecal/core/src/config/ecal_cmd_parser.h +++ b/ecal/core/src/config/ecal_cmd_parser.h @@ -44,22 +44,16 @@ namespace eCAL class CmdParser { public: - CmdParser(std::vector& arguments_); + CmdParser(const std::vector& arguments_); CmdParser(); - void parseArguments(std::vector& arguments_); + void parseArguments(const std::vector& arguments_); bool getDumpConfig() const; - std::vector& getConfigKeys(); - std::vector& getTaskParameter(); std::string& getUserIni(); - Cli::ConfigKey2DMap& getConfigKeysMap(); private: - std::vector m_config_keys; - Cli::ConfigKey2DMap m_config_key_map; bool m_dump_config; - std::vector m_task_parameter; std::string m_user_ini; }; } diff --git a/ecal/core/src/config/ecal_config.cpp b/ecal/core/src/config/ecal_config.cpp index 61a28ae3..81c8a650 100644 --- a/ecal/core/src/config/ecal_config.cpp +++ b/ecal/core/src/config/ecal_config.cpp @@ -21,65 +21,6 @@ #include #include -#include "ecal_config_reader_hlp.h" -#include "ecal_def.h" - - -namespace -{ - void tokenize(const std::string& str, std::vector& tokens, - const std::string& delimiters = " ", bool trimEmpty = false) - { - std::string::size_type pos, lastPos = 0; - - for (;;) - { - pos = str.find_first_of(delimiters, lastPos); - if (pos == std::string::npos) - { - pos = str.length(); - if (pos != lastPos || !trimEmpty) - { - tokens.emplace_back(std::string(str.data() + lastPos, pos - lastPos)); - } - break; - } - else - { - if (pos != lastPos || !trimEmpty) - { - tokens.emplace_back(std::string(str.data() + lastPos, pos - lastPos)); - } - } - lastPos = pos + 1; - } - } - - - eCAL_Logging_Filter ParseLogLevel(const std::string& filter_) - { - // tokenize it - std::vector token_filter_; - tokenize(filter_, token_filter_, " ,;"); - // create excluding filter list - char filter_mask = log_level_none; - for (auto& it : token_filter_) - { - if (it == "all") filter_mask |= log_level_all; - if (it == "info") filter_mask |= log_level_info; - if (it == "warning") filter_mask |= log_level_warning; - if (it == "error") filter_mask |= log_level_error; - if (it == "fatal") filter_mask |= log_level_fatal; - if (it == "debug1") filter_mask |= log_level_debug1; - if (it == "debug2") filter_mask |= log_level_debug2; - if (it == "debug3") filter_mask |= log_level_debug3; - if (it == "debug4") filter_mask |= log_level_debug4; - } - return(filter_mask); - } - -} - namespace eCAL { @@ -89,47 +30,39 @@ namespace eCAL // common ///////////////////////////////////// - ECAL_API std::string GetLoadedEcalIniPath () { return GetConfiguration().GetIniFilePath(); } - ECAL_API int GetRegistrationTimeoutMs () { return GetConfiguration().registration.getTimeoutMS(); } - ECAL_API int GetRegistrationRefreshMs () { return GetConfiguration().registration.getRefreshMS(); } + ECAL_API std::string GetLoadedEcalIniPath () { return GetConfiguration().GetYamlFilePath(); } + ECAL_API int GetRegistrationTimeoutMs () { return GetConfiguration().registration.registration_timeout; } + ECAL_API int GetRegistrationRefreshMs () { return GetConfiguration().registration.registration_refresh; } ///////////////////////////////////// // network ///////////////////////////////////// ECAL_API bool IsNetworkEnabled () { return GetConfiguration().registration.network_enabled; } - ECAL_API bool IsShmRegistrationEnabled () { return GetConfiguration().registration.shm_registration_enabled; } - - ECAL_API Types::UdpConfigVersion GetUdpMulticastConfigVersion () { return GetConfiguration().transport_layer.mc_options.config_version; } - - ECAL_API std::string GetUdpMulticastGroup () { return GetConfiguration().transport_layer.mc_options.group; } - ECAL_API std::string GetUdpMulticastMask () { return GetConfiguration().transport_layer.mc_options.mask; } - ECAL_API int GetUdpMulticastPort () { return GetConfiguration().transport_layer.mc_options.port; } - ECAL_API int GetUdpMulticastTtl () { return GetConfiguration().transport_layer.mc_options.ttl; } + ECAL_API bool IsShmRegistrationEnabled () { return GetConfiguration().registration.layer.shm.enable; } - ECAL_API int GetUdpMulticastSndBufSizeBytes () { return GetConfiguration().transport_layer.mc_options.sndbuf; } - ECAL_API int GetUdpMulticastRcvBufSizeBytes () { return GetConfiguration().transport_layer.mc_options.recbuf; } - ECAL_API bool IsUdpMulticastJoinAllIfEnabled () { return GetConfiguration().transport_layer.mc_options.join_all_interfaces; } + ECAL_API Types::UdpConfigVersion GetUdpMulticastConfigVersion () { return GetConfiguration().transport_layer.udp.config_version; } - ECAL_API bool IsUdpMulticastRecEnabled () { return GetConfiguration().subscriber.udp.enable; } - ECAL_API bool IsShmRecEnabled () { return GetConfiguration().subscriber.shm.enable; } - ECAL_API bool IsTcpRecEnabled () { return GetConfiguration().subscriber.tcp.enable; } + ECAL_API std::string GetUdpMulticastGroup () { return GetConfiguration().transport_layer.udp.network.group; } + ECAL_API std::string GetUdpMulticastMask () { return GetConfiguration().transport_layer.udp.mask; } + ECAL_API int GetUdpMulticastPort () { return GetConfiguration().transport_layer.udp.port; } + ECAL_API int GetUdpMulticastTtl () { return GetConfiguration().transport_layer.udp.network.ttl; } - ECAL_API bool IsNpcapEnabled () { return GetConfiguration().transport_layer.mc_options.npcap_enabled; } + ECAL_API int GetUdpMulticastSndBufSizeBytes () { return GetConfiguration().transport_layer.udp.send_buffer; } + ECAL_API int GetUdpMulticastRcvBufSizeBytes () { return GetConfiguration().transport_layer.udp.receive_buffer; } + ECAL_API bool IsUdpMulticastJoinAllIfEnabled () { return GetConfiguration().transport_layer.udp.join_all_interfaces; } - ECAL_API int GetTcpPubReaderThreadpoolSize () { return static_cast(GetConfiguration().publisher.tcp.num_executor_reader); } - ECAL_API int GetTcpPubWriterThreadpoolSize () { return static_cast(GetConfiguration().publisher.tcp.num_executor_writer); } + ECAL_API bool IsUdpMulticastRecEnabled () { return GetConfiguration().subscriber.layer.udp.enable; } + ECAL_API bool IsShmRecEnabled () { return GetConfiguration().subscriber.layer.shm.enable; } + ECAL_API bool IsTcpRecEnabled () { return GetConfiguration().subscriber.layer.tcp.enable; } - ECAL_API int GetTcpSubReaderThreadpoolSize () { return static_cast(GetConfiguration().subscriber.tcp.num_executor_reader); } - ECAL_API int GetTcpSubWriterThreadpoolSize () { return static_cast(GetConfiguration().subscriber.tcp.num_executor_writer); } - ECAL_API int GetTcpSubMaxReconnectionAttemps () { return static_cast(GetConfiguration().subscriber.tcp.max_reconnections); } + ECAL_API bool IsNpcapEnabled () { return GetConfiguration().transport_layer.udp.npcap_enabled; } - // Keep this until new logic is implemented - ECAL_API int GetTcpPubsubReaderThreadpoolSize () { return GetTcpSubReaderThreadpoolSize(); }; - ECAL_API int GetTcpPubsubWriterThreadpoolSize () { return GetTcpSubWriterThreadpoolSize(); }; - ECAL_API int GetTcpPubsubMaxReconnectionAttemps () { return GetTcpSubMaxReconnectionAttemps();}; + ECAL_API size_t GetTcpPubsubReaderThreadpoolSize () { return GetConfiguration().transport_layer.tcp.number_executor_reader;}; + ECAL_API size_t GetTcpPubsubWriterThreadpoolSize () { return GetConfiguration().transport_layer.tcp.number_executor_writer;}; + ECAL_API size_t GetTcpPubsubMaxReconnectionAttemps () { return GetConfiguration().transport_layer.tcp.max_reconnections;}; - ECAL_API std::string GetHostGroupName () { return GetConfiguration().transport_layer.shm_options.host_group_name; } + ECAL_API std::string GetHostGroupName () { return GetConfiguration().registration.host_group_name; } ///////////////////////////////////// // time @@ -148,12 +81,12 @@ namespace eCAL // monitoring ///////////////////////////////////// - ECAL_API int GetMonitoringTimeoutMs () { return GetConfiguration().monitoring.monitoring_timeout; } + ECAL_API int GetMonitoringTimeoutMs () { return GetConfiguration().monitoring.timeout; } ECAL_API std::string GetMonitoringFilterExcludeList () { return GetConfiguration().monitoring.filter_excl; } ECAL_API std::string GetMonitoringFilterIncludeList () { return GetConfiguration().monitoring.filter_incl; } - ECAL_API eCAL_Logging_Filter GetConsoleLogFilter () { return GetConfiguration().logging.filter_log_con; } - ECAL_API eCAL_Logging_Filter GetFileLogFilter () { return GetConfiguration().logging.filter_log_file; } - ECAL_API eCAL_Logging_Filter GetUdpLogFilter () { return GetConfiguration().logging.filter_log_udp; } + ECAL_API eCAL_Logging_Filter GetConsoleLogFilter () { return GetConfiguration().logging.sinks.console.filter_log_con; } + ECAL_API eCAL_Logging_Filter GetFileLogFilter () { return GetConfiguration().logging.sinks.file.filter_log_file; } + ECAL_API eCAL_Logging_Filter GetUdpLogFilter () { return GetConfiguration().logging.sinks.udp.filter_log_udp; } ///////////////////////////////////// // sys @@ -164,8 +97,8 @@ namespace eCAL ///////////////////////////////////// // publisher ///////////////////////////////////// - ECAL_API bool IsTopicTypeSharingEnabled () { return GetConfiguration().registration.share_ttype; } - ECAL_API bool IsTopicDescriptionSharingEnabled () { return GetConfiguration().registration.share_tdesc; } + ECAL_API bool IsTopicTypeSharingEnabled () { return GetConfiguration().publisher.share_topic_type; } + ECAL_API bool IsTopicDescriptionSharingEnabled () { return GetConfiguration().publisher.share_topic_description; } ///////////////////////////////////// // service @@ -179,9 +112,9 @@ namespace eCAL namespace Experimental { - ECAL_API size_t GetShmMonitoringQueueSize () { return GetConfiguration().monitoring.shm_options.shm_monitoring_queue_size; } - ECAL_API std::string GetShmMonitoringDomain () { return GetConfiguration().monitoring.shm_options.shm_monitoring_domain;} - ECAL_API bool GetDropOutOfOrderMessages () { return GetConfiguration().transport_layer.drop_out_of_order_messages; } + ECAL_API size_t GetShmMonitoringQueueSize () { return GetConfiguration().registration.layer.shm.queue_size; } + ECAL_API std::string GetShmMonitoringDomain () { return GetConfiguration().registration.layer.shm.domain;} + ECAL_API bool GetDropOutOfOrderMessages () { return GetConfiguration().subscriber.drop_out_of_order_messages; } } } } diff --git a/ecal/core/src/config/ecal_config_initializer.cpp b/ecal/core/src/config/ecal_config_initializer.cpp index 6c838620..2718470b 100644 --- a/ecal/core/src/config/ecal_config_initializer.cpp +++ b/ecal/core/src/config/ecal_config_initializer.cpp @@ -25,238 +25,390 @@ #include "ecal_global_accessors.h" #include "ecal_def.h" -#include "config/ecal_config_reader.h" #include "ecal/ecal_process.h" #include "config/ecal_cmd_parser.h" +#ifdef ECAL_CORE_CONFIGURATION + #include "configuration_reader.h" + #include "configuration_to_yaml.h" +#endif + +// for cwd +#ifdef ECAL_OS_WINDOWS + #include + // to remove deprecated warning + #define getcwd _getcwd +#endif +#ifdef ECAL_OS_LINUX + #include + #include + #include + #include +#endif + +#include "ecal_utils/filesystem.h" +#include "util/getenvvar.h" +#include "ecal_utils/ecal_utils.h" +#include "ecal/ecal_log.h" + #include +#include -constexpr const char* COMMON = "common"; -constexpr const char* MONITORING = "monitoring"; -constexpr const char* NETWORK = "network"; -constexpr const char* EXPERIMENTAL = "experimental"; -constexpr const char* PUBLISHER = "publisher"; -constexpr const char* SYS = "sys"; -constexpr const char* TIME = "time"; -constexpr const char* SERVICE = "service"; -constexpr const char* PROCESS = "process"; - -namespace { - void tokenize(const std::string& str, std::vector& tokens, - const std::string& delimiters = " ", bool trimEmpty = false) +namespace +{ + // copied and adapted from ecal_config_reader.cpp +#ifdef ECAL_OS_WINDOWS + const char path_separator('\\'); +#endif /* ECAL_OS_WINDOWS */ +#ifdef ECAL_OS_LINUX + const char path_separator('/'); +#endif /* ECAL_OS_LINUX */ + + bool setPathSep(std::string& file_path_) { - std::string::size_type pos = 0; - std::string::size_type lastPos = 0; - - for (;;) + if (!file_path_.empty()) { - pos = str.find_first_of(delimiters, lastPos); - if (pos == std::string::npos) + if (file_path_.back() != path_separator) { - pos = str.length(); - if (pos != lastPos || !trimEmpty) - { - tokens.emplace_back(str.data() + lastPos, pos - lastPos); - } - break; + file_path_ += path_separator; } - else - { - if (pos != lastPos || !trimEmpty) - { - tokens.emplace_back(str.data() + lastPos, pos - lastPos); - } - } - lastPos = pos + 1; + return true; } + + return false; + } + + std::string eCALDataEnvPath() + { + std::string ecal_data_path = getEnvVar("ECAL_DATA"); + setPathSep(ecal_data_path); + return ecal_data_path; + } + + std::string cwdPath() + { + std::string cwd_path = { getcwd(nullptr, 0) }; + + setPathSep(cwd_path); + return cwd_path; } - eCAL_Logging_Filter ParseLogLevel(const std::string& filter_) + std::string eCALDataCMakePath() { - // tokenize it - std::vector token_filter_; - tokenize(filter_, token_filter_, " ,;"); - // create excluding filter list - char filter_mask = log_level_none; - for (auto& it : token_filter_) + std::string cmake_data_path; +#ifdef ECAL_OS_LINUX + const std::string ecal_install_config_dir(ECAL_INSTALL_CONFIG_DIR); + const std::string ecal_install_prefix(ECAL_INSTALL_PREFIX); + + if ((!ecal_install_config_dir.empty() && (ecal_install_config_dir[0] == path_separator)) + || ecal_install_prefix.empty()) { - if (it == "all") filter_mask |= log_level_all; - if (it == "info") filter_mask |= log_level_info; - if (it == "warning") filter_mask |= log_level_warning; - if (it == "error") filter_mask |= log_level_error; - if (it == "fatal") filter_mask |= log_level_fatal; - if (it == "debug1") filter_mask |= log_level_debug1; - if (it == "debug2") filter_mask |= log_level_debug2; - if (it == "debug3") filter_mask |= log_level_debug3; - if (it == "debug4") filter_mask |= log_level_debug4; + cmake_data_path = ecal_install_config_dir; } - return(filter_mask); - }; -} + else if (!ecal_install_prefix.empty()) + { + cmake_data_path = ecal_install_prefix + path_separator + ecal_install_config_dir; + } + setPathSep(cmake_data_path); +#endif /* ECAL_OS_LINUX */ + return cmake_data_path; + } -namespace eCAL -{ - void Configuration::InitConfig(std::string ini_path_ /*= std::string("")*/) + std::string eCALDataSystemPath() + { + std::string system_data_path; +#ifdef ECAL_OS_WINDOWS + system_data_path = getEnvVar("ProgramData"); + if(setPathSep(system_data_path)) { - CConfig iniConfig; - if (!command_line_arguments.config_keys.empty()) - iniConfig.OverwriteKeys(command_line_arguments.config_keys); + system_data_path += std::string("eCAL"); + setPathSep(system_data_path); + } +#endif /* ECAL_OS_WINDOWS */ - if (!ini_path_.empty()) - { - iniConfig.AddFile(ini_path_); - ecal_ini_file_path = ini_path_; - } +#ifdef ECAL_OS_LINUX + system_data_path = "/etc/ecal"; + setPathSep(system_data_path); +#endif /* ECAL_OS_LINUX */ + return system_data_path; + } - // transport layer options - auto& transportLayerOptions = transport_layer; - transportLayerOptions.drop_out_of_order_messages = iniConfig.get(EXPERIMENTAL, "drop_out_of_order_messages", EXP_DROP_OUT_OF_ORDER_MESSAGES); + bool isValidConfigFilePath(const std::string& path_, const std::string& file_name_) + { + const std::string file_path = path_ + file_name_; + const EcalUtils::Filesystem::FileStatus ecal_ini_status(file_path, EcalUtils::Filesystem::Current); + return ecal_ini_status.IsOk() && (ecal_ini_status.GetType() == EcalUtils::Filesystem::Type::RegularFile); + } - auto& multicastOptions = transportLayerOptions.mc_options; - - const std::string udp_config_version_string = iniConfig.get(NETWORK, "multicast_config_version", "v1"); - if (udp_config_version_string == "v1") - multicastOptions.config_version = Types::UdpConfigVersion::V1; - if (udp_config_version_string == "v2") - multicastOptions.config_version = Types::UdpConfigVersion::V2; - - multicastOptions.group = iniConfig.get(NETWORK, "multicast_group", NET_UDP_MULTICAST_GROUP); - multicastOptions.mask = iniConfig.get(NETWORK, "multicast_mask", NET_UDP_MULTICAST_MASK); - multicastOptions.port = iniConfig.get(NETWORK, "multicast_port", NET_UDP_MULTICAST_PORT); - multicastOptions.ttl = iniConfig.get(NETWORK, "multicast_ttl", NET_UDP_MULTICAST_TTL); - multicastOptions.recbuf = iniConfig.get(NETWORK, "multicast_rcvbuf", NET_UDP_MULTICAST_RCVBUF); - multicastOptions.sndbuf = iniConfig.get(NETWORK, "multicast_sndbuf", NET_UDP_MULTICAST_SNDBUF); - multicastOptions.join_all_interfaces = iniConfig.get(NETWORK, "multicast_join_all_if", NET_UDP_MULTICAST_JOIN_ALL_IF_ENABLED); - multicastOptions.npcap_enabled = iniConfig.get(NETWORK, "npcap_enabled", NET_NPCAP_ENABLED); - - auto& shmOptions = transportLayerOptions.shm_options; - shmOptions.host_group_name = iniConfig.get(NETWORK, "host_group_name", NET_HOST_GROUP_NAME); - - // registration options - auto registrationTimeout = iniConfig.get(COMMON, "registration_timeout", CMN_REGISTRATION_TO); - auto registrationRefresh = iniConfig.get(COMMON, "registration_refresh", CMN_REGISTRATION_REFRESH); - registration = Registration::Configuration(registrationTimeout, registrationRefresh); - auto& registrationOptions = registration; - registrationOptions.network_enabled = iniConfig.get(NETWORK, "network_enabled", NET_ENABLED); - registrationOptions.shm_registration_enabled = iniConfig.get(NETWORK, "shm_registration_enabled", SHM_REGISTRATION_ENABLED); - registrationOptions.share_tdesc = iniConfig.get(PUBLISHER, "share_tdesc", PUB_SHARE_TDESC); - registrationOptions.share_ttype = iniConfig.get(PUBLISHER, "share_ttype", PUB_SHARE_TTYPE); - - // monitoring options - auto& monitoringOptions = monitoring; - monitoringOptions.monitoring_timeout = iniConfig.get(MONITORING, "timeout", MON_TIMEOUT);; - monitoringOptions.filter_excl = iniConfig.get(MONITORING, "filter_excl", MON_FILTER_EXCL); - monitoringOptions.filter_incl = iniConfig.get(MONITORING, "filter_incl", MON_FILTER_INCL); - - // auto& udpMonitoringOptions = monitoringOptions.udp_options; - // TODO: Nothing here yet - - auto& shmMonitoringOptions = monitoringOptions.shm_options; - shmMonitoringOptions.shm_monitoring_domain = iniConfig.get(EXPERIMENTAL, "shm_monitoring_domain", EXP_SHM_MONITORING_DOMAIN); - shmMonitoringOptions.shm_monitoring_queue_size = iniConfig.get(EXPERIMENTAL, "shm_monitoring_queue_size", EXP_SHM_MONITORING_QUEUE_SIZE); - - // subscriber options - auto& subscriberOptions = subscriber; - subscriberOptions.shm.enable = iniConfig.get(NETWORK, "shm_rec_enabled", NET_SHM_REC_ENABLED) != 0; - - subscriberOptions.tcp.enable = iniConfig.get(NETWORK, "tcp_rec_enabled", NET_TCP_REC_ENABLED) != 0; - subscriberOptions.tcp.max_reconnections = iniConfig.get(NETWORK, "tcp_pubsup_max_reconnections", NET_TCP_PUBSUB_MAX_RECONNECTIONS); - subscriberOptions.tcp.num_executor_reader = iniConfig.get(NETWORK, "tcp_pubsup_num_executor_reader", NET_TCP_PUBSUB_NUM_EXECUTOR_READER); - subscriberOptions.tcp.num_executor_writer = iniConfig.get(NETWORK, "tcp_pubsup_num_executor_writer", NET_TCP_PUBSUB_NUM_EXECUTOR_WRITER); - - subscriberOptions.udp.enable = iniConfig.get(NETWORK, "udp_mc_rec_enabled", NET_UDP_MC_REC_ENABLED) != 0; + std::string findValidConfigPath(std::vector paths_, const std::string& file_name_) + { + auto it = std::find_if(paths_.begin(), paths_.end(), [&file_name_](const std::string& path_) + { + return isValidConfigFilePath(path_, file_name_); + }); - // publisher options - auto& publisherOptions = publisher; - publisherOptions.shm.enable = iniConfig.get(PUBLISHER, "use_shm", static_cast(PUB_USE_SHM)) != 0; - publisherOptions.shm.memfile_min_size_bytes = iniConfig.get(PUBLISHER, "memfile_minsize", PUB_MEMFILE_MINSIZE); - publisherOptions.shm.memfile_reserve_percent = iniConfig.get(PUBLISHER, "memfile_reserve", PUB_MEMFILE_RESERVE); - - publisherOptions.udp.enable = iniConfig.get(PUBLISHER, "use_udp_mc", static_cast(PUB_USE_UDP_MC)) != 0; - // TODO PG: Add here when its available in config file - publisherOptions.udp.loopback = false; - publisherOptions.udp.sndbuf_size_bytes = iniConfig.get(NETWORK, "multicast_sndbuf", NET_UDP_MULTICAST_SNDBUF); + // We should have encountered a valid path + if (it != paths_.end()) + return (*it); + + // If valid path is not encountered, defaults should be used + return std::string(""); + } + + std::vector getEcalDefaultPaths() + { + std::vector ecal_default_paths; + // ----------------------------------------------------------- + // precedence 1: ECAL_DATA variable (windows and linux) + // ----------------------------------------------------------- + ecal_default_paths.emplace_back(eCALDataEnvPath()); - publisherOptions.share_topic_description = iniConfig.get(PUBLISHER, "share_tdesc", PUB_SHARE_TDESC); - publisherOptions.share_topic_type = iniConfig.get(PUBLISHER, "share_ttype", PUB_SHARE_TTYPE); - - publisherOptions.tcp.enable = iniConfig.get(PUBLISHER, "use_tcp", static_cast(PUB_USE_TCP)) != 0; - publisherOptions.tcp.num_executor_reader = iniConfig.get(NETWORK, "tcp_pubsup_num_executor_reader", NET_TCP_PUBSUB_NUM_EXECUTOR_READER); - publisherOptions.tcp.num_executor_writer = iniConfig.get(NETWORK, "tcp_pubsup_num_executor_writer", NET_TCP_PUBSUB_NUM_EXECUTOR_WRITER); - - // timesync options - auto& timesyncOptions = timesync; - timesyncOptions.timesync_module_rt = iniConfig.get(TIME, "timesync_module_rt", TIME_SYNC_MODULE); - timesyncOptions.timesync_module_replay = iniConfig.get(TIME, "timesync_module_replay", TIME_SYNC_MOD_REPLAY); - - // service options - auto& serviceOptions = service; - serviceOptions.protocol_v0 = iniConfig.get(SERVICE, "protocol_v0", SERVICE_PROTOCOL_V0); - serviceOptions.protocol_v1 = iniConfig.get(SERVICE, "protocol_v1", SERVICE_PROTOCOL_V1); - - // sys options - auto& sysConfig = application.sys; - sysConfig.filter_excl = iniConfig.get(SYS, "filter_excl", SYS_FILTER_EXCL); - - // process options - auto& startupConfig = application.startup; - startupConfig.terminal_emulator = iniConfig.get(PROCESS, "terminal_emulator", PROCESS_TERMINAL_EMULATOR); - - auto& loggingOptions = logging; - // needs to be adapted when switching from simpleini - loggingOptions.filter_log_con = ParseLogLevel(iniConfig.get(MONITORING, "filter_log_con", "info,warning,error,fatal")); - loggingOptions.filter_log_file = ParseLogLevel(iniConfig.get(MONITORING, "filter_log_file", "")); - loggingOptions.filter_log_udp = ParseLogLevel(iniConfig.get(MONITORING, "filter_log_udp", "info,warning,error,fatal")); - }; + // ----------------------------------------------------------- + // precedence 2: cmake configured data paths (linux only) + // ----------------------------------------------------------- + ecal_default_paths.emplace_back(eCALDataCMakePath()); + + // ----------------------------------------------------------- + // precedence 3: system data path + // ----------------------------------------------------------- + ecal_default_paths.emplace_back(eCALDataSystemPath()); + return ecal_default_paths; + } - Configuration::Configuration(int argc_ , char **argv_) + std::string checkForValidConfigFilePath(const std::string& config_file_) + { + // ----------------------------------------------------------- + // precedence 0: relative path to executable + // ----------------------------------------------------------- + const std::string cwd_directory_path = cwdPath(); + + std::vector ecal_default_paths = getEcalDefaultPaths(); + ecal_default_paths.emplace(ecal_default_paths.begin(), cwd_directory_path); + + const std::string found_path = findValidConfigPath(ecal_default_paths, config_file_); + + // check in case user provided whole path + if (found_path.empty()) { - std::vector arguments; - if (argc_ > 0 && argv_ != nullptr) + return isValidConfigFilePath(config_file_, "") ? config_file_ : found_path; + } + + return found_path + config_file_; + } + + std::vector ConvertArgcArgvToVector(int argc_, char** argv_) + { + std::vector arguments; + if (argc_ > 0 && argv_ != nullptr) + { + for (size_t i = 0; i < static_cast(argc_); ++i) { - for (size_t i = 0; i < static_cast(argc_); ++i) - if (argv_[i] != nullptr) - arguments.emplace_back(argv_[i]); - } - Init(arguments); + if (argv_[i] != nullptr) + { + arguments.emplace_back(argv_[i]); + } + } } + return arguments; + } +} + +namespace eCAL +{ + void Configuration::InitFromFile(const std::string& yaml_path_) + { + const std::string yaml_path = checkForValidConfigFilePath(yaml_path_); + if (!yaml_path.empty()) + { +#ifdef ECAL_CORE_CONFIGURATION + eCAL::Config::YamlFileToConfig(yaml_path, *this); + ecal_yaml_file_path = yaml_path; +#else + eCAL::Logging::Log(log_level_warning, "Yaml file found at \"" + yaml_path + "\" but eCAL core configuration is not enabled."); +#endif + } + else + { + eCAL::Logging::Log(log_level_warning, "Specified yaml configuration path not valid:\"" + yaml_path_ + "\". Using default configuration."); + } + }; - Configuration::Configuration(std::vector& args_) - { - Init(args_); + Configuration::Configuration(int argc_ , char **argv_) + : Configuration(ConvertArgcArgvToVector(argc_, argv_)) + { } - void Configuration::Init(std::vector& arguments_) + Configuration::Configuration(const std::vector& args_) + : Configuration() { - Config::CmdParser parser(arguments_); + Config::CmdParser parser(args_); - command_line_arguments.config_keys = parser.getConfigKeys(); - command_line_arguments.specified_config = parser.getUserIni(); - command_line_arguments.dump_config = parser.getDumpConfig(); - command_line_arguments.config_keys_map = parser.getConfigKeysMap(); + command_line_arguments.user_yaml = parser.getUserIni(); + command_line_arguments.dump_config = parser.getDumpConfig(); - InitConfig(command_line_arguments.specified_config); + if (!command_line_arguments.user_yaml.empty()) + { + InitFromFile(command_line_arguments.user_yaml); + } + else + { + InitFromConfig(); + } } - void Configuration::InitConfigWithDefaultIni() + void Configuration::InitFromConfig() { - InitConfig(g_default_ini_file); + InitFromFile(g_default_ini_file); } Configuration::Configuration() - : Configuration(0, nullptr) { - InitConfig(); + eCAL::InitGlobals(); } - std::string Configuration::GetIniFilePath() + std::string Configuration::GetYamlFilePath() { - return ecal_ini_file_path; + return ecal_yaml_file_path; } Configuration& GetConfiguration() { return g_ecal_configuration; }; -} \ No newline at end of file +} + + +// Utils definitions from former ecal_config_reader.cpp +namespace +{ + bool fileexists(const std::string& fname_) + { + const std::ifstream infile(fname_); + return infile.good(); + } + + bool direxists(const std::string& path_) + { + const EcalUtils::Filesystem::FileStatus status(path_, EcalUtils::Filesystem::Current); + return (status.IsOk() && (status.GetType() == EcalUtils::Filesystem::Type::Dir)); + } + + void createdir(const std::string& path_) + { + EcalUtils::Filesystem::MkDir(path_, EcalUtils::Filesystem::Current); + } + +} + +namespace eCAL +{ + namespace Util + { + ECAL_API std::string GeteCALConfigPath() + { + // Check for first directory which contains the ini file. + const std::vector search_directories = getEcalDefaultPaths(); + + return findValidConfigPath(search_directories, ECAL_DEFAULT_CFG); + } + + ECAL_API std::string GeteCALHomePath() + { + std::string home_path; + +#ifdef ECAL_OS_WINDOWS + // check ECAL_HOME + home_path = getEnvVar("ECAL_HOME"); + if (!home_path.empty()) + { + if (*home_path.rbegin() != path_separator) home_path += path_separator; + } + if (!std::string(ECAL_HOME_PATH_WINDOWS).empty()) //-V815 + { + home_path += path_separator; + home_path += ECAL_HOME_PATH_WINDOWS; + } +#endif /* ECAL_OS_WINDOWS */ + +#ifdef ECAL_OS_LINUX + const char *hdir = nullptr; + hdir = getenv("HOME"); + if (hdir == nullptr) { + hdir = getpwuid(getuid())->pw_dir; + } + home_path += hdir; + if (!std::string(ECAL_HOME_PATH_LINUX).empty()) + { + home_path += "/"; + home_path += ECAL_HOME_PATH_LINUX; + } +#endif /* ECAL_OS_LINUX */ + + // create if not exists + if (!direxists(home_path)) + { + createdir(home_path); + } + + home_path += path_separator; + return(home_path); + } + + ECAL_API std::string GeteCALUserSettingsPath() + { + std::string settings_path; +#ifdef ECAL_OS_WINDOWS + settings_path = GeteCALConfigPath(); +#endif /* ECAL_OS_WINDOWS */ + +#ifdef ECAL_OS_LINUX + settings_path = GeteCALHomePath(); +#endif /* ECAL_OS_LINUX */ + settings_path += std::string(ECAL_SETTINGS_PATH); + + if (!direxists(settings_path)) + { + createdir(settings_path); + } + + settings_path += path_separator; + return(settings_path); + } + + ECAL_API std::string GeteCALLogPath() + { + std::string log_path; +#ifdef ECAL_OS_WINDOWS + log_path = GeteCALConfigPath(); +#endif /* ECAL_OS_WINDOWS */ + +#ifdef ECAL_OS_LINUX + log_path = GeteCALHomePath(); +#endif /* ECAL_OS_LINUX */ + + log_path += std::string(ECAL_LOG_PATH); + + if (!direxists(log_path)) + { + createdir(log_path); + } + + log_path += path_separator; + return(log_path); + } + + ECAL_API std::string GeteCALActiveIniFile() + { + std::string ini_file = GeteCALConfigPath(); + ini_file += ECAL_DEFAULT_CFG; + return ini_file; + } + + ECAL_API std::string GeteCALDefaultIniFile() + { + return GeteCALActiveIniFile(); + } + + } +} \ No newline at end of file diff --git a/ecal/core/src/config/ecal_config_reader.cpp b/ecal/core/src/config/ecal_config_reader.cpp deleted file mode 100644 index 4c88f107..00000000 --- a/ecal/core/src/config/ecal_config_reader.cpp +++ /dev/null @@ -1,455 +0,0 @@ -/* ========================= eCAL LICENSE ================================= - * - * Copyright (C) 2016 - 2024 Continental Corporation - * - * 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. - * - * ========================= eCAL LICENSE ================================= -*/ - -/** - * @brief Global config class -**/ - -#include -#include -#include - -#include "ecal_def.h" -#include "ecal_config_reader.h" -#include "ecal_global_accessors.h" -#include "util/getenvvar.h" - -#include -#include -#include -#include - -#include -#include -#include - -#ifdef ECAL_OS_LINUX -#include -#include -#include -#include -#endif - -#if ECAL_CORE_CONFIG_INIFILE -#include -#endif - -namespace -{ -#ifdef ECAL_OS_WINDOWS - const char path_sep('\\'); -#endif /* ECAL_OS_WINDOWS */ -#ifdef ECAL_OS_LINUX - const char path_sep('/'); -#endif /* ECAL_OS_LINUX */ - - bool fileexists(const std::string& fname_) - { - const std::ifstream infile(fname_); - return infile.good(); - } - - bool direxists(const std::string& path_) - { - const EcalUtils::Filesystem::FileStatus status(path_, EcalUtils::Filesystem::Current); - return (status.IsOk() && (status.GetType() == EcalUtils::Filesystem::Type::Dir)); - } - - void createdir(const std::string& path_) - { - EcalUtils::Filesystem::MkDir(path_, EcalUtils::Filesystem::Current); - } - - std::string eCALDataEnvPath() - { - std::string ecal_data_path = getEnvVar("ECAL_DATA"); - if (!ecal_data_path.empty()) - { - if (ecal_data_path.back() != path_sep) - ecal_data_path += path_sep; - } - return ecal_data_path; - } - - std::string eCALDataCMakePath() - { - std::string cmake_data_path; -#ifdef ECAL_OS_LINUX - std::string ecal_install_config_dir(ECAL_INSTALL_CONFIG_DIR); - std::string ecal_install_prefix(ECAL_INSTALL_PREFIX); - - if ((!ecal_install_config_dir.empty() && (ecal_install_config_dir[0] == path_sep)) - || ecal_install_prefix.empty()) - { - cmake_data_path = ecal_install_config_dir; - } - else if (!ecal_install_prefix.empty()) - { - cmake_data_path = ecal_install_prefix + path_sep + ecal_install_config_dir; - } - if (cmake_data_path.back() != path_sep) { cmake_data_path += path_sep; } -#endif /* ECAL_OS_LINUX */ - return cmake_data_path; - } - - std::string eCALDataSystemPath() - { - std::string system_data_path; -#ifdef ECAL_OS_WINDOWS - system_data_path = getEnvVar("ProgramData"); - if (!system_data_path.empty()) - { - if (system_data_path.back() != path_sep) - { - system_data_path += path_sep; - } - system_data_path += std::string("eCAL") + path_sep; - } -#endif /* ECAL_OS_WINDOWS */ - -#ifdef ECAL_OS_LINUX - system_data_path = "/etc/ecal/"; -#endif /* ECAL_OS_LINUX */ - return system_data_path; - } - - - // 1. The path is not empty - // 2. The ecal.ini exists in that directory - bool IsValidConfigFilePath(const std::string& path) - { - if (path.empty()) { return false; } - - // check existence of ecal.ini file - const EcalUtils::Filesystem::FileStatus ecal_ini_status(path + std::string(ECAL_DEFAULT_CFG), EcalUtils::Filesystem::Current); - if (ecal_ini_status.IsOk() && (ecal_ini_status.GetType() == EcalUtils::Filesystem::Type::RegularFile)) - { - return true; - } - - return false; - } - -} - -namespace eCAL -{ - namespace Util - { - ECAL_API std::string GeteCALHomePath() - { - std::string home_path; - -#ifdef ECAL_OS_WINDOWS - // check ECAL_HOME - home_path = getEnvVar("ECAL_HOME"); - if (!home_path.empty()) - { - if (*home_path.rbegin() != path_sep) home_path += path_sep; - } - if (!std::string(ECAL_HOME_PATH_WINDOWS).empty()) //-V815 - { - home_path += path_sep; - home_path += ECAL_HOME_PATH_WINDOWS; - } -#endif /* ECAL_OS_WINDOWS */ - -#ifdef ECAL_OS_LINUX - const char *hdir; - if ((hdir = getenv("HOME")) == NULL) { - hdir = getpwuid(getuid())->pw_dir; - } - home_path += hdir; - if (!std::string(ECAL_HOME_PATH_LINUX).empty()) - { - home_path += "/"; - home_path += ECAL_HOME_PATH_LINUX; - } -#endif /* ECAL_OS_LINUX */ - - // create if not exists - if (!direxists(home_path)) - { - createdir(home_path); - } - - home_path += path_sep; - return(home_path); - } - - ECAL_API std::string GeteCALConfigPath() - { - // ----------------------------------------------------------- - // precedence 1: ECAL_DATA variable (windows and linux) - // ----------------------------------------------------------- - const std::string ecal_data_path{ eCALDataEnvPath() }; - - // ----------------------------------------------------------- - // precedence 2: cmake configured data paths (linux only) - // ----------------------------------------------------------- - const std::string cmake_data_path{ eCALDataCMakePath() }; - - // ----------------------------------------------------------- - // precedence 3: system data path - // ----------------------------------------------------------- - const std::string system_data_path(eCALDataSystemPath()); - - // Check for first directory which contains the ini file. - std::vector search_directories{ ecal_data_path, cmake_data_path, system_data_path }; - - auto it = std::find_if(search_directories.begin(), search_directories.end(), IsValidConfigFilePath); - // We should have encountered a valid path - if (it != search_directories.end()) - return (*it); - - // If valid path is not encountered, defaults should be used - return std::string(""); - } - - ECAL_API std::string GeteCALUserSettingsPath() - { - std::string settings_path; -#ifdef ECAL_OS_WINDOWS - settings_path = GeteCALConfigPath(); -#endif /* ECAL_OS_WINDOWS */ - -#ifdef ECAL_OS_LINUX - settings_path = GeteCALHomePath(); -#endif /* ECAL_OS_LINUX */ - settings_path += std::string(ECAL_SETTINGS_PATH); - - if (!direxists(settings_path)) - { - createdir(settings_path); - } - - settings_path += path_sep; - return(settings_path); - } - - ECAL_API std::string GeteCALLogPath() - { - std::string log_path; -#ifdef ECAL_OS_WINDOWS - log_path = GeteCALConfigPath(); -#endif /* ECAL_OS_WINDOWS */ - -#ifdef ECAL_OS_LINUX - log_path = GeteCALHomePath(); -#endif /* ECAL_OS_LINUX */ - - log_path += std::string(ECAL_LOG_PATH); - - if (!direxists(log_path)) - { - createdir(log_path); - } - - log_path += path_sep; - return(log_path); - } - - ECAL_API std::string GeteCALActiveIniFile() - { - std::string ini_file = GeteCALConfigPath(); - ini_file += ECAL_DEFAULT_CFG; - return ini_file; - } - - ECAL_API std::string GeteCALDefaultIniFile() - { - return GeteCALActiveIniFile(); - } - } - - //////////////////////////////////////////////////////// - // CConfigImpl - //////////////////////////////////////////////////////// -#if ECAL_CORE_CONFIG_INIFILE - - class CConfigImpl : public CSimpleIni - { - public: - CConfigImpl() = default; - virtual ~CConfigImpl() = default; - - void OverwriteKeys(const std::vector& key_vec_) - { - m_overwrite_keys = key_vec_; - OverwriteKeysNow(); - } - - void OverwriteKeysNow() - { - // update command line keys - for (const auto& full_key : m_overwrite_keys) - { - auto sec_pos = full_key.find_last_of('/'); - if (sec_pos == std::string::npos) continue; - const std::string section = full_key.substr(0, sec_pos); - std::string key = full_key.substr(sec_pos+1); - - auto val_pos = key.find_first_of(':'); - if (val_pos == std::string::npos) continue; - const std::string value = key.substr(val_pos+1); - key = key.substr(0, val_pos); - - const SI_Error err = SetValue(section.c_str(), key.c_str(), value.c_str()); - if (err == SI_FAIL) - { - std::cout << "Error: Could not overwrite key " << key << " in section " << section << "."; - } - } - } - - bool AddFile(std::string& file_name_) - { - std::string cfg_fname = file_name_; - if (!fileexists(cfg_fname)) - { - cfg_fname = Util::GeteCALConfigPath() + cfg_fname; - } - - // load settings config file - bool loaded(false); - if (fileexists(cfg_fname)) - { - // apply file name to manager - loaded = LoadFile(cfg_fname.c_str()) == 0; - } - - // load error ? - if(!loaded) - { - std::cout << "eCAL::Config - Could not load ini file, using defaults. File name : " << cfg_fname << std::endl; - } - else - { - // return full name - file_name_ = cfg_fname; - } - - OverwriteKeysNow(); - - return loaded; - } - protected: - std::vector m_overwrite_keys; - }; - -#else // ECAL_CORE_CONFIG_INIFILE - - class CConfigImpl - { - public: - CConfigImpl() = default; - virtual ~CConfigImpl() = default; - - void OverwriteKeys(const std::vector& /*key_vec_*/) {} - bool AddFile(std::string& /*file_name_*/) {return false;} - - std::string GetValue(const std::string& /*section_*/, const std::string& /*key_*/, const std::string& default_) { return default_;} - long GetLongValue(const std::string& /*section_*/, const std::string& /*key_*/, long default_) { return default_; } - double GetDoubleValue(const std::string& /*section_*/, const std::string& /*key_*/, double default_) { return default_; } - }; - -#endif // ECAL_CORE_CONFIG_INIFILE - - //////////////////////////////////////////////////////// - // CConfigBase - //////////////////////////////////////////////////////// - CConfig::CConfig() : - m_impl(nullptr) - { - m_impl = std::make_unique(); - } - - CConfig::~CConfig() = default; - - void CConfig::OverwriteKeys(const std::vector& key_vec_) - { - m_impl->OverwriteKeys(key_vec_); - } - - bool CConfig::AddFile(std::string& ini_file_) - { - return m_impl->AddFile(ini_file_); - } - - bool CConfig::Validate() - { - // ------------------------------------------------------------------ - // UDP and TCP publlisher mode should not set to "auto (2)" both - // - // [publisher] - // use_tcp = 2 - // use_udp_mc = 2 - // ------------------------------------------------------------------ - { - const int use_tcp = get("publisher", "use_tcp", 0); - const int use_udp_mc = get("publisher", "use_udp_mc", 0); - if ((use_tcp == 2) && (use_udp_mc == 2)) - { - std::cerr << "eCAL config error: to set [publisher/use_tcp] and [publisher/use_udp_mc] both on auto mode (2) is not allowed" << std::endl; - return false; - } - } - - return true; - } - - bool CConfig::get(const std::string& section_, const std::string& key_, bool default_) - { - std::string default_s("false"); - if (default_) default_s = "true"; - std::string value_s = m_impl->GetValue(section_.c_str(), key_.c_str(), default_s.c_str()); - // cause warning C4244 with VS2017 - //std::transform(value_s.begin(), value_s.end(), value_s.begin(), tolower); - std::transform(value_s.begin(), value_s.end(), value_s.begin(), - [](char c) {return static_cast(::tolower(c)); }); - - if ((value_s == "true") || (value_s == "1")) return true; - return false; - } - - int CConfig::get(const std::string& section_, const std::string& key_, int default_) - { - return static_cast(m_impl->GetLongValue(section_.c_str(), key_.c_str(), static_cast(default_))); - } - - unsigned int CConfig::get(const std::string& section_, const std::string& key_, unsigned int default_) - { - return static_cast(m_impl->GetLongValue(section_.c_str(), key_.c_str(), static_cast(default_))); - } - - size_t CConfig::get(const std::string& section_, const std::string& key_, size_t default_) - { - return static_cast(m_impl->GetLongValue(section_.c_str(), key_.c_str(), static_cast(default_))); - } - - double CConfig::get(const std::string& section_, const std::string& key_, double default_) - { - return m_impl->GetDoubleValue(section_.c_str(), key_.c_str(), default_); - } - - std::string CConfig::get(const std::string& section_, const std::string& key_, const char* default_) - { - return m_impl->GetValue(section_.c_str(), key_.c_str(), default_); - } -} diff --git a/ecal/core/src/config/ecal_config_reader.h b/ecal/core/src/config/ecal_config_reader.h deleted file mode 100644 index a08fbea3..00000000 --- a/ecal/core/src/config/ecal_config_reader.h +++ /dev/null @@ -1,57 +0,0 @@ -/* ========================= eCAL LICENSE ================================= - * - * Copyright (C) 2016 - 2024 Continental Corporation - * - * 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. - * - * ========================= eCAL LICENSE ================================= -*/ - -/** - * @brief Global eCAL configuration interface -**/ - -#pragma once - -#include - -#include -#include -#include - -namespace eCAL -{ - class CConfigImpl; - class CConfig - { - public: - CConfig(); - virtual ~CConfig(); - - void OverwriteKeys(const std::vector& key_vec_); - bool AddFile(std::string& ini_file_); - - bool Validate(); - - // common getter - bool get(const std::string& section_, const std::string& key_, bool default_); - int get(const std::string& section_, const std::string& key_, int default_); - double get(const std::string& section_, const std::string& key_, double default_); - std::string get(const std::string& section_, const std::string& key_, const char* default_); - unsigned int get(const std::string& section_, const std::string& key_, unsigned int default_); - size_t get(const std::string& section_, const std::string& key_, size_t default_); - - private: - std::unique_ptr m_impl; - }; -} diff --git a/ecal/core/src/config/ecal_config_reader_hlp.h b/ecal/core/src/config/ecal_config_reader_hlp.h deleted file mode 100644 index 14bb5cb9..00000000 --- a/ecal/core/src/config/ecal_config_reader_hlp.h +++ /dev/null @@ -1,32 +0,0 @@ -/* ========================= eCAL LICENSE ================================= - * - * Copyright (C) 2016 - 2019 Continental Corporation - * - * 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. - * - * ========================= eCAL LICENSE ================================= -*/ - -/** - * @brief Global database class helper -**/ - -#pragma once - -#include "ecal_config_reader.h" -#include "ecal_def_ini.h" -#include "ecal_global_accessors.h" - -// macro to simplify configuration parameter access (internal use only) -// eCALPAR(GROUP,PAR) -> eCAL::g_config()->get(GROUP_SECTION_S, GROUP_PAR_S, GROUP_PAR) -#define eCALPAR(x,y) eCAL::g_config()->get(x##_SECTION_S, x##_##y##_S, x##_##y) diff --git a/ecal/core/src/ecal.cpp b/ecal/core/src/ecal.cpp index 03c2e1a4..54a5cf90 100644 --- a/ecal/core/src/ecal.cpp +++ b/ecal/core/src/ecal.cpp @@ -101,10 +101,6 @@ namespace eCAL int Initialize(int argc_ , char **argv_, const char *unit_name_, unsigned int components_) { eCAL::Configuration config(argc_, argv_); - - // Default behaviour: If not specified, try to use the default ini file - if (config.GetIniFilePath().empty()) - config.InitConfigWithDefaultIni(); return Initialize(config, unit_name_, components_); } @@ -121,10 +117,6 @@ namespace eCAL int Initialize(std::vector args_, const char *unit_name_, unsigned int components_) //-V826 { eCAL::Configuration config(args_); - - // Default behaviour: If not specified, try to use the default ini file - if (config.GetIniFilePath().empty()) - config.InitConfigWithDefaultIni(); return Initialize(config, unit_name_, components_); } @@ -140,11 +132,6 @@ namespace eCAL **/ int Initialize(eCAL::Configuration& config_, const char *unit_name_ /*= nullptr*/, unsigned int components_ /*= Init::Default*/) { - if (g_globals() == nullptr) - { - InitGlobals(); - } - g_ecal_configuration = config_; if (unit_name_ != nullptr) @@ -155,7 +142,7 @@ namespace eCAL g_globals_ctx_ref_cnt++; // (post)initialize single components - const int success = g_globals()->Initialize(components_, &GetConfiguration().command_line_arguments.config_keys); + const int success = g_globals()->Initialize(components_); if (config_.command_line_arguments.dump_config) { diff --git a/ecal/core/src/ecal_def.h b/ecal/core/src/ecal_def.h index fcfb23a3..4690ab5e 100644 --- a/ecal/core/src/ecal_def.h +++ b/ecal/core/src/ecal_def.h @@ -38,146 +38,19 @@ constexpr const char* ECAL_LOG_PATH = "logs"; constexpr const char* ECAL_SETTINGS_PATH = "cfg"; /* ini file name */ -constexpr const char* ECAL_DEFAULT_CFG = "ecal.ini"; - -/**********************************************************************************************/ -/* monitor settings */ -/**********************************************************************************************/ -/* timeout for automatic removing monitoring topics in ms */ -constexpr unsigned int MON_TIMEOUT = 5000U; -/* topics blacklist as regular expression (will not be monitored) */ -constexpr const char* MON_FILTER_EXCL = "^__.*$"; -/* topics whitelist as regular expression (will be monitored only) */ -constexpr const char* MON_FILTER_INCL = ""; - -/* logging filter settings */ -constexpr eCAL_Logging_Filter MON_LOG_FILTER_CON = (log_level_info | log_level_warning | log_level_error | log_level_fatal); -constexpr eCAL_Logging_Filter MON_LOG_FILTER_FILE = log_level_none; -constexpr eCAL_Logging_Filter MON_LOG_FILTER_UDP = (log_level_info | log_level_warning | log_level_error | log_level_fatal); - - -/**********************************************************************************************/ -/* sys settings */ -/**********************************************************************************************/ -/* sys app witch will not be imported from cloud */ -constexpr const char* SYS_FILTER_EXCL = "^eCALSysClient$|^eCALSysGUI$|^eCALSys$*"; - -/**********************************************************************************************/ -/* network settings */ -/**********************************************************************************************/ -/* network switch */ -constexpr bool NET_ENABLED = false; -constexpr bool SHM_REGISTRATION_ENABLED = false; +constexpr const char* ECAL_DEFAULT_CFG = "ecal.yaml"; /* eCAL udp multicast defines */ -constexpr eCAL::Types::UdpConfigVersion NET_UDP_MULTICAST_CONFIG_VERSION = eCAL::Types::UdpConfigVersion::V1; -constexpr const char* NET_UDP_MULTICAST_GROUP = "239.0.0.1"; -constexpr const char* NET_UDP_MULTICAST_MASK = "0.0.0.15"; -constexpr unsigned int NET_UDP_MULTICAST_PORT = 14000U; -constexpr unsigned int NET_UDP_MULTICAST_TTL = 3U; -constexpr unsigned int NET_UDP_MULTICAST_PORT_REG_OFF = 0U; -constexpr unsigned int NET_UDP_MULTICAST_PORT_LOG_OFF = 1U; -constexpr unsigned int NET_UDP_MULTICAST_PORT_SAMPLE_OFF = 2U; -constexpr unsigned int NET_UDP_MULTICAST_SNDBUF = (5U*1024U*1024U); /* 5 MByte */ -constexpr unsigned int NET_UDP_MULTICAST_RCVBUF = (5U*1024U*1024U); /* 5 MByte */ -constexpr bool NET_UDP_MULTICAST_JOIN_ALL_IF_ENABLED = false; - -constexpr unsigned int NET_UDP_RECBUFFER_TIMEOUT = 1000U; /* ms */ -constexpr unsigned int NET_UDP_RECBUFFER_CLEANUP = 10U; /* ms */ - -/* overall udp multicast bandwidth limitation in bytes/s, -1 == no limitation*/ -constexpr int NET_BANDWIDTH_MAX_UDP = (-1); - -constexpr bool NET_TCP_REC_ENABLED = true; -constexpr bool NET_SHM_REC_ENABLED = true; - -constexpr bool NET_UDP_MC_REC_ENABLED = true; - -constexpr bool NET_NPCAP_ENABLED = false; - -constexpr unsigned int NET_TCP_PUBSUB_NUM_EXECUTOR_READER = 4U; -constexpr unsigned int NET_TCP_PUBSUB_NUM_EXECUTOR_WRITER = 4U; -constexpr unsigned int NET_TCP_PUBSUB_MAX_RECONNECTIONS = 5U; - -/* common host group name that enables interprocess mechanisms across (virtual) host borders (e.g, Docker); by default equivalent to local host name */ -constexpr const char* NET_HOST_GROUP_NAME = ""; - -/**********************************************************************************************/ -/* publisher settings */ -/**********************************************************************************************/ -/* use shared memory transport layer [auto = 2, on = 1, off = 0] */ -constexpr eCAL::TLayer::eSendMode PUB_USE_SHM = eCAL::TLayer::eSendMode::smode_auto; -/* use tcp transport layer [auto = 2, on = 1, off = 0] */ -constexpr eCAL::TLayer::eSendMode PUB_USE_TCP = eCAL::TLayer::eSendMode::smode_off; -/* use udp multicast transport layer [auto = 2, on = 1, off = 0] */ -constexpr eCAL::TLayer::eSendMode PUB_USE_UDP_MC = eCAL::TLayer::eSendMode::smode_auto; - -/* share topic type [ on = 1, off = 0] */ -constexpr bool PUB_SHARE_TTYPE = true; -/* share topic description [ on = 1, off = 0] */ -constexpr bool PUB_SHARE_TDESC = true; - -/* minimum size for created shared memory files */ -constexpr unsigned int PUB_MEMFILE_MINSIZE = (4U*1024U); -/* reserve buffer size before reallocation in % */ -constexpr unsigned int PUB_MEMFILE_RESERVE = 50U; +constexpr unsigned int NET_UDP_MULTICAST_PORT_REG_OFF = 0U; // to delete +constexpr unsigned int NET_UDP_MULTICAST_PORT_LOG_OFF = 1U; // to delete +constexpr unsigned int NET_UDP_MULTICAST_PORT_SAMPLE_OFF = 2U; // to delete /* timeout for create / open a memory file using mutex lock in ms */ constexpr unsigned int PUB_MEMFILE_CREATE_TO = 200U; constexpr unsigned int PUB_MEMFILE_OPEN_TO = 200U; +/* memory file access timeout */ +constexpr unsigned int EXP_MEMFILE_ACCESS_TIMEOUT = 100U; -/* timeout for memory read acknowledge signal from data reader in ms */ -constexpr unsigned int PUB_MEMFILE_ACK_TO = 0U; /* ms */ - -/* defines number of memory files handle by the publisher for a 1:n connection - a higher number will increase data throughput, but will also increase the size of used memory, number of semaphores - and number of memory file observer threads on subscription side, default = 1, double buffering = 2 - higher values than 3 are not recommended - values > 1 will break local IPC compatibility to eCAL 5.9 and older -*/ -constexpr unsigned int PUB_MEMFILE_BUF_COUNT = 1U; - -/* allow subscriber to access memory file without copying content in advance (zero copy) - this memory file is blocked for other readers wihle processed by the user callback function - this option is fully IPC compatible to all eCAL 5.x versions -*/ -constexpr bool PUB_MEMFILE_ZERO_COPY = false; - -/**********************************************************************************************/ -/* service settings */ -/**********************************************************************************************/ -/* support service protocol v0, eCAL 5.11 and older (0 = off, 1 = on) */ -constexpr bool SERVICE_PROTOCOL_V0 = true; - -/* support service protocol v1, eCAL 5.12 and newer (0 = off, 1 = on) */ -constexpr bool SERVICE_PROTOCOL_V1 = true; - -/**********************************************************************************************/ -/* time settings */ -/**********************************************************************************************/ -constexpr const char* TIME_SYNC_MOD_RT = ""; -constexpr const char* TIME_SYNC_MOD_REPLAY = ""; -constexpr const char* TIME_SYNC_MODULE = "ecaltime-localtime"; - -/**********************************************************************************************/ -/* process settings */ -/**********************************************************************************************/ -constexpr const char* PROCESS_TERMINAL_EMULATOR = ""; - -/**********************************************************************************************/ -/* ecal internal timings */ -/**********************************************************************************************/ -/* timeout for automatic removing registered topics and memory files in global database in ms */ -constexpr unsigned int CMN_REGISTRATION_TO = (60U*1000U); - -/* time for resend registration info from publisher/subscriber in ms */ -constexpr unsigned int CMN_REGISTRATION_REFRESH = 1000U; - -/* delta time to check timeout for data readers in ms */ -constexpr unsigned int CMN_DATAREADER_TIMEOUT_RESOLUTION_MS = 100U; - -/* cylce time udp receive threads in ms */ -constexpr unsigned int CMN_UDP_RECEIVE_THREAD_CYCLE_TIME_MS = 1000U; /**********************************************************************************************/ /* events */ @@ -185,15 +58,3 @@ constexpr unsigned int CMN_UDP_RECEIVE_THREAD_CYCLE_TIME_MS = 1000U; /* common stop event prefix to shut down a local user process */ constexpr const char* EVENT_SHUTDOWN_PROC = "ecal_shutdown_process"; -/**********************************************************************************************/ -/* experimental */ -/**********************************************************************************************/ -/* queue size of monitoring/registration events */ -constexpr unsigned int EXP_SHM_MONITORING_QUEUE_SIZE = 1024U; -/* domain name for shared memory based monitoring/registration */ -constexpr const char* EXP_SHM_MONITORING_DOMAIN = "ecal_monitoring"; -/* memory file access timeout */ -constexpr unsigned int EXP_MEMFILE_ACCESS_TIMEOUT = 100U; - -/* enable dropping of payload messages that arrive out of order */ -constexpr bool EXP_DROP_OUT_OF_ORDER_MESSAGES = false; diff --git a/ecal/core/src/ecal_global_accessors.cpp b/ecal/core/src/ecal_global_accessors.cpp index e5353c74..f2befc53 100644 --- a/ecal/core/src/ecal_global_accessors.cpp +++ b/ecal/core/src/ecal_global_accessors.cpp @@ -53,7 +53,8 @@ namespace eCAL void InitGlobals() { - g_globals_ctx = new CGlobals; + if (g_globals_ctx == nullptr) + g_globals_ctx = new CGlobals; } void SetGlobalUnitName(const char *unit_name_) diff --git a/ecal/core/src/ecal_globals.cpp b/ecal/core/src/ecal_globals.cpp index 088bfc60..56634748 100644 --- a/ecal/core/src/ecal_globals.cpp +++ b/ecal/core/src/ecal_globals.cpp @@ -23,8 +23,6 @@ #include "ecal_globals.h" -#include "config/ecal_config_reader.h" - #include #include #include @@ -206,8 +204,7 @@ namespace eCAL if (descgate_instance) { #if ECAL_CORE_REGISTRATION - // utilize registration provider and receiver to get descriptions - g_registration_provider()->SetCustomApplySampleCallback("descgate", [](const auto& sample_) {g_descgate()->ApplySample(sample_, tl_none); }); + // utilize registration receiver to get descriptions g_registration_receiver()->SetCustomApplySampleCallback("descgate", [](const auto& sample_) {g_descgate()->ApplySample(sample_, tl_none); }); #endif } @@ -305,8 +302,7 @@ namespace eCAL if (descgate_instance) { #if ECAL_CORE_REGISTRATION - // stop registration provider and receiver utilization to get descriptions - g_registration_provider()->RemCustomApplySampleCallback("descgate"); + // stop registration receiver utilization to get descriptions g_registration_receiver()->RemCustomApplySampleCallback("descgate"); #endif } diff --git a/ecal/core/src/ecal_process.cpp b/ecal/core/src/ecal_process.cpp index d5e933a6..13dcb2fe 100644 --- a/ecal/core/src/ecal_process.cpp +++ b/ecal/core/src/ecal_process.cpp @@ -31,7 +31,6 @@ #include "ecal_utils/command_line.h" #include "ecal_utils/str_convert.h" -#include "config/ecal_config_reader_hlp.h" #include "io/udp/ecal_udp_configurations.h" #include @@ -630,7 +629,7 @@ namespace // Check whether we are able to use a terminal emulator. The requirements // are: // - the DISPLAY variable must be set - // - the terminal_emulator must be set in the ecal.ini + // - the terminal_emulator must be set in the ecal.yaml // - ecal_process_stub bust be available AND print the correct version // ------------------------ DISPLAY variable check ------------------------- @@ -651,11 +650,11 @@ namespace const std::string terminal_emulator_command = eCAL::Config::GetTerminalEmulatorCommand(); if (!terminal_emulator_command.empty()) { - STD_COUT_DEBUG("[PID " << getpid() << "]: " << "ecal.ini terminal emulator command is: " << terminal_emulator_command << std::endl); + STD_COUT_DEBUG("[PID " << getpid() << "]: " << "ecal.yaml terminal emulator command is: " << terminal_emulator_command << std::endl); } else { - STD_COUT_DEBUG("[PID " << getpid() << "]: " << "ecal.ini terminal emulator command is not set. Not using terminal emulator." << std::endl); + STD_COUT_DEBUG("[PID " << getpid() << "]: " << "ecal.yaml terminal emulator command is not set. Not using terminal emulator." << std::endl); return ""; } @@ -996,7 +995,7 @@ namespace eCAL // terminal emulator, when: // - The process_mode_ is not set to hidden // - the DISPLAY variable indicates that we have a display attached - // - the terminal_emulator is set in the ecal.ini + // - the terminal_emulator is set in the ecal.yaml // - ecal_process_stub is available AND prints the correct version std::string terminal_emulator_command; diff --git a/ecal/core/src/io/shm/ecal_memfile_pool.cpp b/ecal/core/src/io/shm/ecal_memfile_pool.cpp index 3e3a778e..e2a1ed81 100644 --- a/ecal/core/src/io/shm/ecal_memfile_pool.cpp +++ b/ecal/core/src/io/shm/ecal_memfile_pool.cpp @@ -211,14 +211,26 @@ namespace eCAL // ------------------------------------------------------------------------- if (zero_copy_allowed) { - // acquire memory file payload pointer (no copying here) - const void* buf(nullptr); - if (m_memfile.GetReadAddress(buf, mfile_hdr.data_size) > 0) + if (m_data_callback) { - // calculate data buffer offset - const char* data_buf = static_cast(buf) + mfile_hdr.hdr_size; - // add sample to data reader (and call user callback function) - if (m_data_callback) m_data_callback(topic_name_, topic_id_, data_buf, mfile_hdr.data_size, (long long)mfile_hdr.id, (long long)mfile_hdr.clock, (long long)mfile_hdr.time, (size_t)mfile_hdr.hash); + const char* data_buf = nullptr; + if (mfile_hdr.data_size > 0) + { + // acquire memory file payload pointer (no copying here) + const void* buf(nullptr); + if (m_memfile.GetReadAddress(buf, mfile_hdr.data_size) > 0) + { + // calculate user payload address + data_buf = static_cast(buf) + mfile_hdr.hdr_size; + // call user callback function + m_data_callback(topic_name_, topic_id_, data_buf, mfile_hdr.data_size, (long long)mfile_hdr.id, (long long)mfile_hdr.clock, (long long)mfile_hdr.time, (size_t)mfile_hdr.hash); + } + } + else + { + // call user callback function + m_data_callback(topic_name_, topic_id_, data_buf, mfile_hdr.data_size, (long long)mfile_hdr.id, (long long)mfile_hdr.clock, (long long)mfile_hdr.time, (size_t)mfile_hdr.hash); + } } } // ------------------------------------------------------------------------- diff --git a/ecal/core/src/io/udp/ecal_udp_configurations.cpp b/ecal/core/src/io/udp/ecal_udp_configurations.cpp index d3e81cf4..ac29ca59 100644 --- a/ecal/core/src/io/udp/ecal_udp_configurations.cpp +++ b/ecal/core/src/io/udp/ecal_udp_configurations.cpp @@ -175,5 +175,15 @@ namespace eCAL // if network is enabled, return the configured UDP multicast TTL value return Config::GetUdpMulticastTtl(); } + + int GetReceiveBufferSize() + { + return Config::GetUdpMulticastRcvBufSizeBytes(); + } + + int GetSendBufferSize() + { + return Config::GetUdpMulticastSndBufSizeBytes(); + } } } diff --git a/ecal/core/src/io/udp/ecal_udp_configurations.h b/ecal/core/src/io/udp/ecal_udp_configurations.h index 62d919a5..988b168e 100644 --- a/ecal/core/src/io/udp/ecal_udp_configurations.h +++ b/ecal/core/src/io/udp/ecal_udp_configurations.h @@ -147,5 +147,20 @@ namespace eCAL * @return The TTL value for UDP multicast communication based on the network configuration. */ int GetMulticastTtl(); + + /** + * @brief GetReceiveBufferSize retrieves the receive buffer size for UDP multicast communication. + * + * @return The receive buffer size in bytes. + */ + int GetReceiveBufferSize(); + + /** + * @brief GetSendBufferSize retrieves the send buffer size for UDP multicast communication. + * + * @return The send buffer size in bytes. + */ + int GetSendBufferSize(); + } } diff --git a/ecal/core/src/logging/ecal_log_impl.cpp b/ecal/core/src/logging/ecal_log_impl.cpp index 3a8ee306..17da3e85 100644 --- a/ecal/core/src/logging/ecal_log_impl.cpp +++ b/ecal/core/src/logging/ecal_log_impl.cpp @@ -145,7 +145,7 @@ namespace eCAL attr.ttl = UDP::GetMulticastTtl(); attr.broadcast = UDP::IsBroadcast(); attr.loopback = true; - attr.sndbuf = Config::GetUdpMulticastSndBufSizeBytes(); + attr.sndbuf = UDP::GetSendBufferSize(); // create udp logging sender m_udp_logging_sender = std::make_unique(attr); @@ -157,7 +157,7 @@ namespace eCAL attr.port = UDP::GetLoggingPort(); attr.broadcast = UDP::IsBroadcast(); attr.loopback = true; - attr.rcvbuf = Config::GetUdpMulticastRcvBufSizeBytes(); + attr.rcvbuf = UDP::GetReceiveBufferSize(); // start logging receiver m_log_receiver = std::make_shared(attr, std::bind(&CLog::HasSample, this, std::placeholders::_1), std::bind(&CLog::ApplySample, this, std::placeholders::_1, std::placeholders::_2)); diff --git a/ecal/core/src/monitoring/ecal_monitoring_impl.cpp b/ecal/core/src/monitoring/ecal_monitoring_impl.cpp index b70799de..e0cc7c13 100644 --- a/ecal/core/src/monitoring/ecal_monitoring_impl.cpp +++ b/ecal/core/src/monitoring/ecal_monitoring_impl.cpp @@ -25,8 +25,8 @@ #include #include "io/udp/ecal_udp_configurations.h" -#include "config/ecal_config_reader_hlp.h" #include "ecal_monitoring_impl.h" +#include "ecal_global_accessors.h" #include @@ -58,8 +58,7 @@ namespace eCAL // get name of this host m_host_name = Process::GetHostName(); - // utilize registration provider and receiver to enrich monitor information - g_registration_provider()->SetCustomApplySampleCallback("monitoring", [this](const auto& sample_) {this->ApplySample(sample_, tl_none); }); + // utilize registration receiver to enrich monitor information g_registration_receiver()->SetCustomApplySampleCallback("monitoring", [this](const auto& sample_){this->ApplySample(sample_, tl_none);}); // setup blacklist and whitelist filter strings# @@ -74,8 +73,7 @@ namespace eCAL void CMonitoringImpl::Destroy() { - // stop registration provider and receiver utilization to enrich monitor information - g_registration_provider()->RemCustomApplySampleCallback("monitoring"); + // stop registration receiver utilization to enrich monitor information g_registration_receiver()->RemCustomApplySampleCallback("monitoring"); m_init = false; } diff --git a/ecal/core/src/pubsub/ecal_pubgate.cpp b/ecal/core/src/pubsub/ecal_pubgate.cpp index 3c696ea8..84e92f1d 100644 --- a/ecal/core/src/pubsub/ecal_pubgate.cpp +++ b/ecal/core/src/pubsub/ecal_pubgate.cpp @@ -194,16 +194,15 @@ namespace eCAL } } - void CPubGate::RefreshRegistrations() + void CPubGate::GetRegistrations(Registration::SampleList& reg_sample_list_) { if (!m_created) return; - // refresh publisher registrations + // read reader registrations const std::shared_lock lock(m_topic_name_datawriter_sync); for (const auto& iter : m_topic_name_datawriter_map) { - // force data writer to (re)register itself on registration provider - iter.second->RefreshRegistration(); + reg_sample_list_.samples.emplace_back(iter.second->GetRegistration()); } } } diff --git a/ecal/core/src/pubsub/ecal_pubgate.h b/ecal/core/src/pubsub/ecal_pubgate.h index 2714bbec..0db416cc 100644 --- a/ecal/core/src/pubsub/ecal_pubgate.h +++ b/ecal/core/src/pubsub/ecal_pubgate.h @@ -56,7 +56,7 @@ namespace eCAL void ApplySubRegistration(const Registration::Sample& ecal_sample_); void ApplySubUnregistration(const Registration::Sample& ecal_sample_); - void RefreshRegistrations(); + void GetRegistrations(Registration::SampleList& reg_sample_list_); protected: static std::atomic m_created; diff --git a/ecal/core/src/pubsub/ecal_subgate.cpp b/ecal/core/src/pubsub/ecal_subgate.cpp index aabe5af9..cdac6281 100644 --- a/ecal/core/src/pubsub/ecal_subgate.cpp +++ b/ecal/core/src/pubsub/ecal_subgate.cpp @@ -52,10 +52,6 @@ namespace eCAL void CSubGate::Start() { if(m_created) return; - - // initialize data reader layers - CDataReader::InitializeLayers(); - m_created = true; } @@ -300,16 +296,15 @@ namespace eCAL } } - void CSubGate::RefreshRegistrations() + void CSubGate::GetRegistrations(Registration::SampleList& reg_sample_list_) { if (!m_created) return; - // refresh reader registrations + // read reader registrations const std::shared_lock lock(m_topic_name_datareader_sync); for (const auto& iter : m_topic_name_datareader_map) { - // force data reader to (re)register itself on registration provider - iter.second->RefreshRegistration(); + reg_sample_list_.samples.emplace_back(iter.second->GetRegistration()); } } } diff --git a/ecal/core/src/pubsub/ecal_subgate.h b/ecal/core/src/pubsub/ecal_subgate.h index 1e78578a..cc1b589c 100644 --- a/ecal/core/src/pubsub/ecal_subgate.h +++ b/ecal/core/src/pubsub/ecal_subgate.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,7 +54,7 @@ namespace eCAL void ApplyPubRegistration(const Registration::Sample& ecal_sample_); void ApplyPubUnregistration(const Registration::Sample& ecal_sample_); - void RefreshRegistrations(); + void GetRegistrations(Registration::SampleList& reg_sample_list_); protected: static std::atomic m_created; diff --git a/ecal/core/src/pubsub/ecal_subscriber_config.cpp b/ecal/core/src/pubsub/ecal_subscriber_config.cpp deleted file mode 100644 index 1ecdea26..00000000 --- a/ecal/core/src/pubsub/ecal_subscriber_config.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* ========================= eCAL LICENSE ================================= - * - * Copyright (C) 2016 - 2024 Continental Corporation - * - * 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. - * - * ========================= eCAL LICENSE ================================= -*/ - -/** - * @brief eCAL subscriber configuration -**/ - -#include -#include - -namespace eCAL -{ - namespace Subscriber - { - Configuration::Configuration() - { - *this = GetConfiguration().subscriber; - } - } -} diff --git a/ecal/core/src/readwrite/ecal_reader.cpp b/ecal/core/src/readwrite/ecal_reader.cpp index cb19b572..97e937fa 100644 --- a/ecal/core/src/readwrite/ecal_reader.cpp +++ b/ecal/core/src/readwrite/ecal_reader.cpp @@ -94,13 +94,11 @@ namespace eCAL m_pub_map.set_expiration(registration_timeout); // start transport layers + InitializeLayers(); StartTransportLayer(); // mark as created m_created = true; - - // register - Register(false); } CDataReader::~CDataReader() @@ -256,9 +254,6 @@ namespace eCAL bool CDataReader::SetAttribute(const std::string& attr_name_, const std::string& attr_value_) { - auto current_val = m_attr.find(attr_name_); - - const bool force = current_val == m_attr.end() || current_val->second != attr_value_; m_attr[attr_name_] = attr_value_; #ifndef NDEBUG @@ -266,16 +261,11 @@ namespace eCAL Logging::Log(log_level_debug2, m_topic_name + "::CDataReader::SetAttribute"); #endif - // register it - Register(force); - return(true); } bool CDataReader::ClearAttribute(const std::string& attr_name_) { - auto force = m_attr.find(attr_name_) != m_attr.end(); - m_attr.erase(attr_name_); #ifndef NDEBUG @@ -283,9 +273,6 @@ namespace eCAL Logging::Log(log_level_debug2, m_topic_name + "::CDataReader::ClearAttribute"); #endif - // register it - Register(force); - return(true); } @@ -351,33 +338,11 @@ namespace eCAL } } - void CDataReader::RefreshRegistration() - { - if (!m_created) return; - - // ensure that registration is not called within zero nanoseconds - // normally it will be called from registration logic every second - - // register without send - Register(false); - - // check connection timeouts - { - const std::lock_guard lock(m_pub_map_mtx); - m_pub_map.erase_expired(); - - if (m_pub_map.empty()) - { - FireDisconnectEvent(); - } - } - } - void CDataReader::InitializeLayers() { // initialize udp layer #if ECAL_CORE_TRANSPORT_UDP - if (Config::IsUdpMulticastRecEnabled()) + if (m_config.layer.udp.enable) { CUDPReaderLayer::Get()->Initialize(); } @@ -385,7 +350,7 @@ namespace eCAL // initialize shm layer #if ECAL_CORE_TRANSPORT_SHM - if (Config::IsShmRecEnabled()) + if (m_config.layer.shm.enable) { CSHMReaderLayer::Get()->Initialize(); } @@ -393,7 +358,7 @@ namespace eCAL // initialize tcp layer #if ECAL_CORE_TRANSPORT_TCP - if (Config::IsTcpRecEnabled()) + if (m_config.layer.tcp.enable) { CTCPReaderLayer::Get()->Initialize(); } @@ -410,13 +375,13 @@ namespace eCAL switch (layer_) { case tl_ecal_udp: - if (!m_config.udp.enable) return 0; + if (!m_config.layer.udp.enable) return 0; break; case tl_ecal_shm: - if (!m_config.shm.enable) return 0; + if (!m_config.layer.shm.enable) return 0; break; case tl_ecal_tcp: - if (!m_config.tcp.enable) return 0; + if (!m_config.layer.tcp.enable) return 0; break; default: break; @@ -555,15 +520,56 @@ namespace eCAL return(out.str()); } - bool CDataReader::Register(const bool force_) + void CDataReader::Register() { #if ECAL_CORE_REGISTRATION - if (!m_created) return(false); - if(m_topic_name.empty()) return(false); + if (g_registration_provider() != nullptr) g_registration_provider()->RegisterSample(GetRegistrationSample()); + +#ifndef NDEBUG + // log it + Logging::Log(log_level_debug4, m_topic_name + "::CDataReader::Register"); +#endif +#endif // ECAL_CORE_REGISTRATION + } + + void CDataReader::Unregister() + { +#if ECAL_CORE_REGISTRATION + if (g_registration_provider() != nullptr) g_registration_provider()->UnregisterSample(GetUnregistrationSample()); + +#ifndef NDEBUG + // log it + Logging::Log(log_level_debug4, m_topic_name + "::CDataReader::Unregister"); +#endif +#endif // ECAL_CORE_REGISTRATION + } - // create command parameter + void CDataReader::CheckConnections() + { + const std::lock_guard lock(m_pub_map_mtx); + m_pub_map.erase_expired(); + + if (m_pub_map.empty()) + { + FireDisconnectEvent(); + } + } + + Registration::Sample CDataReader::GetRegistration() + { + // check connection timeouts + CheckConnections(); + + // return registration + return GetRegistrationSample(); + } + + Registration::Sample CDataReader::GetRegistrationSample() + { + // create registration sample Registration::Sample ecal_reg_sample; ecal_reg_sample.cmd_type = bct_reg_subscriber; + auto& ecal_reg_sample_topic = ecal_reg_sample.topic; ecal_reg_sample_topic.hname = m_host_name; ecal_reg_sample_topic.hgname = m_host_group_name; @@ -632,28 +638,15 @@ namespace eCAL ecal_reg_sample_topic.connections_loc = 0; ecal_reg_sample_topic.connections_ext = 0; - // register subscriber - if(g_registration_provider() != nullptr) g_registration_provider()->ApplySample(ecal_reg_sample, force_); -#ifndef NDEBUG - // log it - Logging::Log(log_level_debug4, m_topic_name + "::CDataReader::DoRegister"); -#endif - - return(true); -#else // ECAL_CORE_REGISTRATION - (void)force_; - return(false); -#endif // ECAL_CORE_REGISTRATION + return ecal_reg_sample; } - bool CDataReader::Unregister() + Registration::Sample CDataReader::GetUnregistrationSample() { -#if ECAL_CORE_REGISTRATION - if (m_topic_name.empty()) return(false); - - // create command parameter + // create unregistration sample Registration::Sample ecal_unreg_sample; ecal_unreg_sample.cmd_type = bct_unreg_subscriber; + auto& ecal_reg_sample_topic = ecal_unreg_sample.topic; ecal_reg_sample_topic.hname = m_host_name; ecal_reg_sample_topic.hgname = m_host_group_name; @@ -663,23 +656,13 @@ namespace eCAL ecal_reg_sample_topic.tid = m_topic_id; ecal_reg_sample_topic.uname = Process::GetUnitName(); - // unregister subscriber - if (g_registration_provider() != nullptr) g_registration_provider()->ApplySample(ecal_unreg_sample, false); -#ifndef NDEBUG - // log it - Logging::Log(log_level_debug4, m_topic_name + "::CDataReader::Unregister"); -#endif - - return(true); -#else // ECAL_CORE_REGISTRATION - return(false); -#endif // ECAL_CORE_REGISTRATION + return ecal_unreg_sample; } - + void CDataReader::StartTransportLayer() { #if ECAL_CORE_TRANSPORT_UDP - if (m_config.udp.enable) + if (m_config.layer.udp.enable) { // flag enabled m_layers.udp.read_enabled = true; @@ -690,7 +673,7 @@ namespace eCAL #endif #if ECAL_CORE_TRANSPORT_SHM - if (m_config.shm.enable) + if (m_config.layer.shm.enable) { // flag enabled m_layers.shm.read_enabled = true; @@ -701,7 +684,7 @@ namespace eCAL #endif #if ECAL_CORE_TRANSPORT_TCP - if (m_config.tcp.enable) + if (m_config.layer.tcp.enable) { // flag enabled m_layers.tcp.read_enabled = true; @@ -715,7 +698,7 @@ namespace eCAL void CDataReader::StopTransportLayer() { #if ECAL_CORE_TRANSPORT_UDP - if (m_config.udp.enable) + if (m_config.layer.udp.enable) { // flag disabled m_layers.udp.read_enabled = false; @@ -726,7 +709,7 @@ namespace eCAL #endif #if ECAL_CORE_TRANSPORT_SHM - if (m_config.shm.enable) + if (m_config.layer.shm.enable) { // flag disabled m_layers.shm.read_enabled = false; @@ -737,7 +720,7 @@ namespace eCAL #endif #if ECAL_CORE_TRANSPORT_TCP - if (m_config.tcp.enable) + if (m_config.layer.tcp.enable) { // flag disabled m_layers.tcp.read_enabled = false; diff --git a/ecal/core/src/readwrite/ecal_reader.h b/ecal/core/src/readwrite/ecal_reader.h index 13f2a502..c6955e2d 100644 --- a/ecal/core/src/readwrite/ecal_reader.h +++ b/ecal/core/src/readwrite/ecal_reader.h @@ -100,8 +100,7 @@ namespace eCAL void ApplyLayerParameter(const SPublicationInfo& publication_info_, eTLayerType type_, const Registration::ConnectionPar& parameter_); - void RefreshRegistration(); - + Registration::Sample GetRegistration(); bool IsCreated() const { return(m_created); } bool IsPublished() const @@ -120,14 +119,19 @@ namespace eCAL std::string GetTopicID() const { return(m_topic_id); } SDataTypeInformation GetDataTypeInformation() const { return(m_topic_info); } - static void InitializeLayers(); + void InitializeLayers(); size_t ApplySample(const std::string& tid_, const char* payload_, size_t size_, long long id_, long long clock_, long long time_, size_t hash_, eTLayerType layer_); std::string Dump(const std::string& indent_ = ""); protected: - bool Register(bool force_); - bool Unregister(); + void Register(); + void Unregister(); + + void CheckConnections(); + + Registration::Sample GetRegistrationSample(); + Registration::Sample GetUnregistrationSample(); void StartTransportLayer(); void StopTransportLayer(); diff --git a/ecal/core/src/readwrite/ecal_writer.cpp b/ecal/core/src/readwrite/ecal_writer.cpp index 24b81d5a..2639df18 100644 --- a/ecal/core/src/readwrite/ecal_writer.cpp +++ b/ecal/core/src/readwrite/ecal_writer.cpp @@ -26,8 +26,6 @@ #include #include -#include "config/ecal_config_reader_hlp.h" - #if ECAL_CORE_REGISTRATION #include "registration/ecal_registration_provider.h" #endif @@ -35,8 +33,10 @@ #include "ecal_writer.h" #include "ecal_writer_base.h" #include "ecal_writer_buffer_payload.h" +#include "ecal_global_accessors.h" #include "ecal_transport_layer.h" +#include #include #include #include @@ -121,9 +121,6 @@ namespace eCAL // mark as created m_created = true; - - // register - Register(false); } CDataWriter::~CDataWriter() @@ -176,7 +173,7 @@ namespace eCAL // are we allowed to perform zero copy writing? bool allow_zero_copy(false); #if ECAL_CORE_TRANSPORT_SHM - allow_zero_copy = m_config.shm.zero_copy_mode; // zero copy mode activated by user + allow_zero_copy = m_config.layer.shm.zero_copy_mode; // zero copy mode activated by user #endif #if ECAL_CORE_TRANSPORT_UDP // udp is active -> no zero copy @@ -221,14 +218,14 @@ namespace eCAL wattr.clock = m_clock; wattr.hash = snd_hash; wattr.time = time_; - wattr.zero_copy = m_config.shm.zero_copy_mode; - wattr.acknowledge_timeout_ms = m_config.shm.acknowledge_timeout_ms; + wattr.zero_copy = m_config.layer.shm.zero_copy_mode; + wattr.acknowledge_timeout_ms = m_config.layer.shm.acknowledge_timeout_ms; // prepare send if (m_writer_shm->PrepareWrite(wattr)) { // register new to update listening subscribers and rematch - Register(true); + Register(); Process::SleepMS(5); } @@ -286,13 +283,13 @@ namespace eCAL wattr.clock = m_clock; wattr.hash = snd_hash; wattr.time = time_; - wattr.loopback = m_config.udp.loopback; + wattr.loopback = eCAL::GetConfiguration().registration.loopback; // prepare send if (m_writer_udp->PrepareWrite(wattr)) { // register new to update listening subscribers and rematch - Register(true); + Register(); Process::SleepMS(5); } @@ -365,8 +362,6 @@ namespace eCAL bool CDataWriter::SetDataTypeInformation(const SDataTypeInformation& topic_info_) { - // Does it even make sense to register if the info is the same??? - const bool force = m_topic_info != topic_info_; m_topic_info = topic_info_; #ifndef NDEBUG @@ -374,17 +369,11 @@ namespace eCAL Logging::Log(log_level_debug2, m_topic_name + "::CDataWriter::SetDescription"); #endif - // register it - Register(force); - return(true); } bool CDataWriter::SetAttribute(const std::string& attr_name_, const std::string& attr_value_) { - auto current_val = m_attr.find(attr_name_); - - const bool force = current_val == m_attr.end() || current_val->second != attr_value_; m_attr[attr_name_] = attr_value_; #ifndef NDEBUG @@ -392,16 +381,11 @@ namespace eCAL Logging::Log(log_level_debug2, m_topic_name + "::CDataWriter::SetAttribute"); #endif - // register it - Register(force); - return(true); } bool CDataWriter::ClearAttribute(const std::string& attr_name_) { - auto force = m_attr.find(attr_name_) != m_attr.end(); - m_attr.erase(attr_name_); #ifndef NDEBUG @@ -409,9 +393,6 @@ namespace eCAL Logging::Log(log_level_debug2, m_topic_name + "::CDataWriter::ClearAttribute"); #endif - // register it - Register(force); - return(true); } @@ -457,19 +438,19 @@ namespace eCAL std::vector pub_layers; std::vector sub_layers; #if ECAL_CORE_TRANSPORT_UDP - if (m_config.udp.enable) pub_layers.push_back(tl_ecal_udp); + if (m_config.layer.udp.enable) pub_layers.push_back(tl_ecal_udp); if (sub_layer_states_.udp.read_enabled) sub_layers.push_back(tl_ecal_udp); m_layers.udp.read_enabled = sub_layer_states_.udp.read_enabled; // just for debugging/logging #endif #if ECAL_CORE_TRANSPORT_SHM - if (m_config.shm.enable) pub_layers.push_back(tl_ecal_shm); + if (m_config.layer.shm.enable) pub_layers.push_back(tl_ecal_shm); if (sub_layer_states_.shm.read_enabled) sub_layers.push_back(tl_ecal_shm); m_layers.shm.read_enabled = sub_layer_states_.shm.read_enabled; // just for debugging/logging #endif #if ECAL_CORE_TRANSPORT_TCP - if (m_config.tcp.enable) pub_layers.push_back(tl_ecal_tcp); + if (m_config.layer.tcp.enable) pub_layers.push_back(tl_ecal_tcp); if (sub_layer_states_.tcp.read_enabled) sub_layers.push_back(tl_ecal_tcp); m_layers.tcp.read_enabled = sub_layer_states_.tcp.read_enabled; // just for debugging/logging @@ -485,10 +466,10 @@ namespace eCAL StartUdpLayer(); break; case tl_ecal_shm: - if (StartShmLayer()) Register(true); + StartShmLayer(); break; case tl_ecal_tcp: - if (StartTcpLayer()) Register(true); + StartTcpLayer(); break; default: break; @@ -547,25 +528,6 @@ namespace eCAL #endif } - void CDataWriter::RefreshRegistration() - { - if (!m_created) return; - - // register without send - Register(false); - - // check connection timeouts - { - const std::lock_guard lock(m_sub_map_mtx); - m_sub_map.erase_expired(); - - if (m_sub_map.empty()) - { - FireDisconnectEvent(); - } - } - } - void CDataWriter::RefreshSendCounter() { // increase write clock @@ -605,13 +567,52 @@ namespace eCAL return(out.str()); } - bool CDataWriter::Register(bool force_) + void CDataWriter::Register() { #if ECAL_CORE_REGISTRATION - if (!m_created) return(false); - if (m_topic_name.empty()) return(false); + if (g_registration_provider() != nullptr) g_registration_provider()->RegisterSample(GetRegistrationSample()); + +#ifndef NDEBUG + // log it + Logging::Log(log_level_debug4, m_topic_name + "::CDataWriter::Register"); +#endif +#endif // ECAL_CORE_REGISTRATION + } + + void CDataWriter::Unregister() + { +#if ECAL_CORE_REGISTRATION + if (g_registration_provider() != nullptr) g_registration_provider()->UnregisterSample(GetUnregistrationSample()); + +#ifndef NDEBUG + // log it + Logging::Log(log_level_debug4, m_topic_name + "::CDataWriter::Unregister"); +#endif +#endif // ECAL_CORE_REGISTRATION + } - // create command parameter + void CDataWriter::CheckConnections() + { + const std::lock_guard lock(m_sub_map_mtx); + m_sub_map.erase_expired(); + + if (m_sub_map.empty()) + { + FireDisconnectEvent(); + } + } + + Registration::Sample CDataWriter::GetRegistration() + { + // check connection timeouts + CheckConnections(); + + return GetRegistrationSample(); + } + + Registration::Sample CDataWriter::GetRegistrationSample() + { + // create registration sample Registration::Sample ecal_reg_sample; ecal_reg_sample.cmd_type = bct_reg_publisher; @@ -701,27 +702,12 @@ namespace eCAL ecal_reg_sample_topic.connections_loc = static_cast(loc_connections); ecal_reg_sample_topic.connections_ext = static_cast(ext_connections); - // register publisher - if (g_registration_provider() != nullptr) g_registration_provider()->ApplySample(ecal_reg_sample, force_); - -#ifndef NDEBUG - // log it - Logging::Log(log_level_debug4, m_topic_name + "::CDataWriter::Register"); -#endif - - return(true); -#else // ECAL_CORE_REGISTRATION -(void)force_; -return(false); -#endif // ECAL_CORE_REGISTRATION + return ecal_reg_sample; } - bool CDataWriter::Unregister() + Registration::Sample CDataWriter::GetUnregistrationSample() { -#if ECAL_CORE_REGISTRATION - if (m_topic_name.empty()) return(false); - - // create command parameter + // create unregistration sample Registration::Sample ecal_unreg_sample; ecal_unreg_sample.cmd_type = bct_unreg_publisher; @@ -734,18 +720,7 @@ return(false); ecal_reg_sample_topic.tid = m_topic_id; ecal_reg_sample_topic.uname = Process::GetUnitName(); - // unregister publisher - if (g_registration_provider() != nullptr) g_registration_provider()->ApplySample(ecal_unreg_sample, false); - -#ifndef NDEBUG - // log it - Logging::Log(log_level_debug4, m_topic_name + "::CDataWriter::UnRegister"); -#endif - - return(true); -#else // ECAL_CORE_REGISTRATION - return(false); -#endif // ECAL_CORE_REGISTRATION + return ecal_unreg_sample; } void CDataWriter::FireConnectEvent(const std::string& tid_, const SDataTypeInformation& tinfo_) @@ -820,7 +795,10 @@ return(false); Logging::Log(log_level_debug2, m_topic_name + "::CDataWriter::ActivateUdpLayer::ACTIVATED"); // create writer - m_writer_udp = std::make_unique(m_host_name, m_topic_name, m_topic_id, m_config.udp); + m_writer_udp = std::make_unique(m_host_name, m_topic_name, m_topic_id, m_config.layer.udp); + + // register activated layer + Register(); #ifndef NDEBUG Logging::Log(log_level_debug2, m_topic_name + "::CDataWriter::ActivateUdpLayer::WRITER_CREATED"); @@ -843,7 +821,10 @@ return(false); Logging::Log(log_level_debug2, m_topic_name + "::CDataWriter::ActivateShmLayer::ACTIVATED"); // create writer - m_writer_shm = std::make_unique(m_host_name, m_topic_name, m_topic_id, m_config.shm); + m_writer_shm = std::make_unique(m_host_name, m_topic_name, m_topic_id, m_config.layer.shm); + + // register activated layer + Register(); #ifndef NDEBUG Logging::Log(log_level_debug2, m_topic_name + "::CDataWriter::ActivateShmLayer::WRITER_CREATED"); @@ -866,7 +847,10 @@ return(false); Logging::Log(log_level_debug2, m_topic_name + "::CDataWriter::ActivateTcpLayer::ACTIVATED"); // create writer - m_writer_tcp = std::make_unique(m_host_name, m_topic_name, m_topic_id, m_config.tcp); + m_writer_tcp = std::make_unique(m_host_name, m_topic_name, m_topic_id, m_config.layer.tcp); + + // register activated layer + Register(); #ifndef NDEBUG Logging::Log(log_level_debug2, m_topic_name + "::CDataWriter::ActivateTcpLayer::WRITER_CREATED"); diff --git a/ecal/core/src/readwrite/ecal_writer.h b/ecal/core/src/readwrite/ecal_writer.h index e4734906..1ea35da0 100644 --- a/ecal/core/src/readwrite/ecal_writer.h +++ b/ecal/core/src/readwrite/ecal_writer.h @@ -29,6 +29,7 @@ #include #include +#include "serialization/ecal_serialize_sample_registration.h" #include "util/ecal_expmap.h" #include "util/frequency_calculator.h" @@ -104,7 +105,7 @@ namespace eCAL void ApplySubscription(const SSubscriptionInfo& subscription_info_, const SDataTypeInformation& data_type_info_, const SLayerStates& sub_layer_states_, const std::string& reader_par_); void RemoveSubscription(const SSubscriptionInfo& subscription_info_); - void RefreshRegistration(); + Registration::Sample GetRegistration(); void RefreshSendCounter(); bool IsCreated() const { return(m_created); } @@ -127,8 +128,13 @@ namespace eCAL std::string Dump(const std::string& indent_ = ""); protected: - bool Register(bool force_); - bool Unregister(); + void Register(); + void Unregister(); + + void CheckConnections(); + + Registration::Sample GetRegistrationSample(); + Registration::Sample GetUnregistrationSample(); bool StartUdpLayer(); bool StartShmLayer(); diff --git a/ecal/core/src/readwrite/shm/ecal_writer_shm.cpp b/ecal/core/src/readwrite/shm/ecal_writer_shm.cpp index 9194569b..a53d329b 100644 --- a/ecal/core/src/readwrite/shm/ecal_writer_shm.cpp +++ b/ecal/core/src/readwrite/shm/ecal_writer_shm.cpp @@ -25,6 +25,7 @@ #include "ecal_def.h" #include "ecal_writer_shm.h" +#include "ecal/ecal_config.h" #include @@ -32,7 +33,7 @@ namespace eCAL { const std::string CDataWriterSHM::m_memfile_base_name = "ecal_"; - CDataWriterSHM::CDataWriterSHM(const std::string& host_name_, const std::string& topic_name_, const std::string& /*topic_id_*/, const Publisher::SHM::Configuration& shm_config_) : + CDataWriterSHM::CDataWriterSHM(const std::string& host_name_, const std::string& topic_name_, const std::string& /*topic_id_*/, const Publisher::Layer::SHM::Configuration& shm_config_) : m_config(shm_config_) { m_host_name = host_name_; @@ -124,8 +125,8 @@ namespace eCAL // prepare memfile attributes SSyncMemoryFileAttr memory_file_attr = {}; - memory_file_attr.min_size = m_config.memfile_min_size_bytes; - memory_file_attr.reserve = m_config.memfile_reserve_percent; + memory_file_attr.min_size = GetConfiguration().transport_layer.shm.memfile_min_size_bytes; + memory_file_attr.reserve = GetConfiguration().transport_layer.shm.memfile_reserve_percent; memory_file_attr.timeout_open_ms = PUB_MEMFILE_OPEN_TO; memory_file_attr.timeout_ack_ms = m_config.acknowledge_timeout_ms; diff --git a/ecal/core/src/readwrite/shm/ecal_writer_shm.h b/ecal/core/src/readwrite/shm/ecal_writer_shm.h index 0898cdac..8126f499 100644 --- a/ecal/core/src/readwrite/shm/ecal_writer_shm.h +++ b/ecal/core/src/readwrite/shm/ecal_writer_shm.h @@ -38,7 +38,7 @@ namespace eCAL class CDataWriterSHM : public CDataWriterBase { public: - CDataWriterSHM(const std::string& host_name_, const std::string& topic_name_, const std::string& topic_id_, const Publisher::SHM::Configuration& shm_config_); + CDataWriterSHM(const std::string& host_name_, const std::string& topic_name_, const std::string& topic_id_, const Publisher::Layer::SHM::Configuration& shm_config_); SWriterInfo GetInfo() override; @@ -53,7 +53,7 @@ namespace eCAL protected: bool SetBufferCount(size_t buffer_count_); - Publisher::SHM::Configuration m_config; + Publisher::Layer::SHM::Configuration m_config; size_t m_write_idx = 0; std::vector> m_memory_file_vec; diff --git a/ecal/core/src/readwrite/tcp/ecal_reader_tcp.cpp b/ecal/core/src/readwrite/tcp/ecal_reader_tcp.cpp index ed82df0f..e916fcdc 100644 --- a/ecal/core/src/readwrite/tcp/ecal_reader_tcp.cpp +++ b/ecal/core/src/readwrite/tcp/ecal_reader_tcp.cpp @@ -125,10 +125,13 @@ namespace eCAL //////////////// // LAYER //////////////// - CTCPReaderLayer::CTCPReaderLayer() = default; + CTCPReaderLayer::CTCPReaderLayer() : m_initialized(false) {} void CTCPReaderLayer::Initialize() { + if (m_initialized) return; + m_initialized = true; + const tcp_pubsub::logger::logger_t tcp_pubsub_logger = std::bind(TcpPubsubLogger, std::placeholders::_1, std::placeholders::_2); m_executor = std::make_shared(Config::GetTcpPubsubReaderThreadpoolSize(), tcp_pubsub_logger); } diff --git a/ecal/core/src/readwrite/tcp/ecal_reader_tcp.h b/ecal/core/src/readwrite/tcp/ecal_reader_tcp.h index 83fd64f5..2eae0b2a 100644 --- a/ecal/core/src/readwrite/tcp/ecal_reader_tcp.h +++ b/ecal/core/src/readwrite/tcp/ecal_reader_tcp.h @@ -30,6 +30,7 @@ #include "serialization/ecal_struct_sample_payload.h" +#include #include #include @@ -73,6 +74,7 @@ namespace eCAL void SetConnectionParameter(SReaderLayerPar& /*par_*/) override; private: + std::atomic m_initialized; std::shared_ptr m_executor; using DataReaderTCPMapT = std::unordered_map>; diff --git a/ecal/core/src/readwrite/tcp/ecal_writer_tcp.cpp b/ecal/core/src/readwrite/tcp/ecal_writer_tcp.cpp index 6334a400..c9f98bf1 100644 --- a/ecal/core/src/readwrite/tcp/ecal_writer_tcp.cpp +++ b/ecal/core/src/readwrite/tcp/ecal_writer_tcp.cpp @@ -23,7 +23,6 @@ #include -#include "config/ecal_config_reader_hlp.h" #include "serialization/ecal_serialize_sample_payload.h" #include "ecal_writer_tcp.h" @@ -38,7 +37,7 @@ namespace eCAL std::mutex CDataWriterTCP::g_tcp_writer_executor_mtx; std::shared_ptr CDataWriterTCP::g_tcp_writer_executor; - CDataWriterTCP::CDataWriterTCP(const std::string& host_name_, const std::string& topic_name_, const std::string& topic_id_, const Publisher::TCP::Configuration& tcp_config_) : + CDataWriterTCP::CDataWriterTCP(const std::string& host_name_, const std::string& topic_name_, const std::string& topic_id_, const Publisher::Layer::TCP::Configuration& tcp_config_) : m_config(tcp_config_) { { diff --git a/ecal/core/src/readwrite/tcp/ecal_writer_tcp.h b/ecal/core/src/readwrite/tcp/ecal_writer_tcp.h index 94a3e96f..2aeedf01 100644 --- a/ecal/core/src/readwrite/tcp/ecal_writer_tcp.h +++ b/ecal/core/src/readwrite/tcp/ecal_writer_tcp.h @@ -40,7 +40,7 @@ namespace eCAL class CDataWriterTCP : public CDataWriterBase { public: - CDataWriterTCP(const std::string& host_name_, const std::string& topic_name_, const std::string& topic_id_, const Publisher::TCP::Configuration& tcp_config_); + CDataWriterTCP(const std::string& host_name_, const std::string& topic_name_, const std::string& topic_id_, const Publisher::Layer::TCP::Configuration& tcp_config_); SWriterInfo GetInfo() override; @@ -49,7 +49,7 @@ namespace eCAL Registration::ConnectionPar GetConnectionParameter() override; private: - Publisher::TCP::Configuration m_config; + Publisher::Layer::TCP::Configuration m_config; std::vector m_header_buffer; diff --git a/ecal/core/src/readwrite/udp/ecal_reader_udp.cpp b/ecal/core/src/readwrite/udp/ecal_reader_udp.cpp index 1023bd8e..2036f6fe 100644 --- a/ecal/core/src/readwrite/udp/ecal_reader_udp.cpp +++ b/ecal/core/src/readwrite/udp/ecal_reader_udp.cpp @@ -63,7 +63,7 @@ namespace eCAL attr.port = UDP::GetPayloadPort(); attr.broadcast = UDP::IsBroadcast(); attr.loopback = true; - attr.rcvbuf = Config::GetUdpMulticastRcvBufSizeBytes(); + attr.rcvbuf = UDP::GetReceiveBufferSize(); // start payload sample receiver m_payload_receiver = std::make_shared(attr, std::bind(&CUDPReaderLayer::HasSample, this, std::placeholders::_1), std::bind(&CUDPReaderLayer::ApplySample, this, std::placeholders::_1, std::placeholders::_2)); diff --git a/ecal/core/src/readwrite/udp/ecal_writer_udp.cpp b/ecal/core/src/readwrite/udp/ecal_writer_udp.cpp index 8466a38f..efae1208 100644 --- a/ecal/core/src/readwrite/udp/ecal_writer_udp.cpp +++ b/ecal/core/src/readwrite/udp/ecal_writer_udp.cpp @@ -26,12 +26,13 @@ #include "ecal_writer_udp.h" #include "io/udp/ecal_udp_configurations.h" #include "serialization/ecal_serialize_sample_payload.h" +#include "ecal/ecal_config.h" #include namespace eCAL { - CDataWriterUdpMC::CDataWriterUdpMC(const std::string& host_name_, const std::string& topic_name_, const std::string& topic_id_, const Publisher::UDP::Configuration& udp_config_) : + CDataWriterUdpMC::CDataWriterUdpMC(const std::string& host_name_, const std::string& topic_name_, const std::string& topic_id_, const Publisher::Layer::UDP::Configuration& udp_config_) : m_config(udp_config_) { m_host_name = host_name_; @@ -44,7 +45,7 @@ namespace eCAL attr.port = UDP::GetPayloadPort(); attr.ttl = UDP::GetMulticastTtl(); attr.broadcast = UDP::IsBroadcast(); - attr.sndbuf = m_config.sndbuf_size_bytes; + attr.sndbuf = UDP::GetSendBufferSize(); // create udp/sample sender with activated loop-back attr.loopback = true; diff --git a/ecal/core/src/readwrite/udp/ecal_writer_udp.h b/ecal/core/src/readwrite/udp/ecal_writer_udp.h index 32a7ef78..8a76cc04 100644 --- a/ecal/core/src/readwrite/udp/ecal_writer_udp.h +++ b/ecal/core/src/readwrite/udp/ecal_writer_udp.h @@ -37,14 +37,14 @@ namespace eCAL class CDataWriterUdpMC : public CDataWriterBase { public: - CDataWriterUdpMC(const std::string& host_name_, const std::string& topic_name_, const std::string& topic_id_, const Publisher::UDP::Configuration& udp_config_); + CDataWriterUdpMC(const std::string& host_name_, const std::string& topic_name_, const std::string& topic_id_, const Publisher::Layer::UDP::Configuration& udp_config_); SWriterInfo GetInfo() override; bool Write(const void* buf_, const SWriterAttr& attr_) override; protected: - Publisher::UDP::Configuration m_config; + Publisher::Layer::UDP::Configuration m_config; std::vector m_sample_buffer; std::shared_ptr m_sample_sender_loopback; diff --git a/ecal/core/src/registration/ecal_registration_provider.cpp b/ecal/core/src/registration/ecal_registration_provider.cpp index 93d39163..b8816c2f 100644 --- a/ecal/core/src/registration/ecal_registration_provider.cpp +++ b/ecal/core/src/registration/ecal_registration_provider.cpp @@ -22,7 +22,7 @@ * * All process internal publisher/subscriber, server/clients register here with all their attributes. * - * These information will be send cyclic (registration refresh) via UDP to external eCAL processes. + * These information will be send cyclic (registration refresh) via UDP or SHM to external eCAL processes. * **/ #include "ecal_registration_provider.h" @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -93,114 +92,89 @@ namespace eCAL { if(!m_created) return; - // stop cyclic registration thread - m_reg_sample_snd_thread->stop(); + // add unregistration sample to registration loop + AddSingleSample(Registration::GetProcessUnregisterSample()); - // add process unregistration sample - AddSample2SampleList(Registration::GetProcessUnregisterSample()); + // wake up registration thread the last time + m_reg_sample_snd_thread->trigger(); - SendSampleList(); + // stop cyclic registration thread + m_reg_sample_snd_thread->stop(); + // delete registration sender m_reg_sender.reset(); m_created = false; } - bool CRegistrationProvider::ApplySample(const Registration::Sample& sample_, const bool force_) + // (re)register single sample + bool CRegistrationProvider::RegisterSample(const Registration::Sample& sample_) { if (!m_created) return(false); - // forward all registration samples to outside "customer" (e.g. monitoring, descgate) - { - const std::lock_guard lock(m_callback_custom_apply_sample_map_mtx); - for (const auto& iter : m_callback_custom_apply_sample_map) - { - iter.second(sample_); - } - } + // add registration sample to registration loop + AddSingleSample(sample_); - // update sample list - AddSample2SampleList(sample_); - - // if registration is forced - if (force_) - { - SendSampleList(); - - // send single registration sample over udp - //SendSample2UDP(sample_); - -#if ECAL_CORE_REGISTRATION_SHM - // broadcast (updated) sample list over shm - //SendSampleList2SHM(); -#endif - } + // wake up registration thread + m_reg_sample_snd_thread->trigger(); return(true); } - void CRegistrationProvider::SetCustomApplySampleCallback(const std::string& customer_, const ApplySampleCallbackT& callback_) + // unregister single sample + bool CRegistrationProvider::UnregisterSample(const Registration::Sample& sample_) { - const std::lock_guard lock(m_callback_custom_apply_sample_map_mtx); - m_callback_custom_apply_sample_map[customer_] = callback_; - } - - void CRegistrationProvider::RemCustomApplySampleCallback(const std::string& customer_) - { - const std::lock_guard lock(m_callback_custom_apply_sample_map_mtx); - auto iter = m_callback_custom_apply_sample_map.find(customer_); - if (iter != m_callback_custom_apply_sample_map.end()) - { - m_callback_custom_apply_sample_map.erase(iter); - } - } + if (!m_created) return(false); - void CRegistrationProvider::AddSample2SampleList(const Registration::Sample& sample_) - { - const std::lock_guard lock(m_sample_list_mtx); - m_sample_list.samples.push_back(sample_); - } + // add registration sample to registration loop, no need to force registration thread to send + AddSingleSample(sample_); - void CRegistrationProvider::ClearSampleList() - { - // lock sample list - const std::lock_guard lock(m_sample_list_mtx); - // clear sample list - m_sample_list.samples.clear(); + return(true); } - void CRegistrationProvider::SendSampleList() + void CRegistrationProvider::AddSingleSample(const Registration::Sample& sample_) { - std::lock_guard lock(m_sample_list_mtx); - m_reg_sender->SendSampleList(m_sample_list); + const std::lock_guard lock(m_applied_sample_list_mtx); + m_applied_sample_list.samples.push_back(sample_); } void CRegistrationProvider::RegisterSendThread() { + // collect all registrations and send them out cyclic + { + // create sample list + Registration::SampleList sample_list; + + // and add process registration sample + sample_list.samples.push_back(Registration::GetProcessRegisterSample()); + #if ECAL_CORE_SUBSCRIBER - // refresh subscriber registration - if (g_subgate() != nullptr) g_subgate()->RefreshRegistrations(); + // add subscriber registrations + if (g_subgate() != nullptr) g_subgate()->GetRegistrations(sample_list); #endif #if ECAL_CORE_PUBLISHER - // refresh publisher registration - if (g_pubgate() != nullptr) g_pubgate()->RefreshRegistrations(); + // add publisher registrations + if (g_pubgate() != nullptr) g_pubgate()->GetRegistrations(sample_list); #endif #if ECAL_CORE_SERVICE - // refresh server registration - if (g_servicegate() != nullptr) g_servicegate()->RefreshRegistrations(); + // add server registrations + if (g_servicegate() != nullptr) g_servicegate()->GetRegistrations(sample_list); - // refresh client registration - if (g_clientgate() != nullptr) g_clientgate()->RefreshRegistrations(); + // add client registrations + if (g_clientgate() != nullptr) g_clientgate()->GetRegistrations(sample_list); #endif - SendSampleList(); + // send collected registration sample list + m_reg_sender->SendSampleList(sample_list); - // clear registration sample list - ClearSampleList(); - - // add process registration sample to internal sample list as first sample (for next registration loop) - AddSample2SampleList(Registration::GetProcessRegisterSample()); + // send asynchronously applied samples at the end of the registration loop + { + const std::lock_guard lock(m_applied_sample_list_mtx); + m_reg_sender->SendSampleList(m_applied_sample_list); + m_applied_sample_list.samples.clear(); + } + } } } diff --git a/ecal/core/src/registration/ecal_registration_provider.h b/ecal/core/src/registration/ecal_registration_provider.h index 422e6527..5fe66527 100644 --- a/ecal/core/src/registration/ecal_registration_provider.h +++ b/ecal/core/src/registration/ecal_registration_provider.h @@ -28,16 +28,12 @@ #pragma once -#include "io/udp/ecal_udp_sample_sender.h" -#include +#include "registration/ecal_registration_sender.h" +#include "util/ecal_thread.h" + #include #include -#include -#include - -#include -#include "util/ecal_thread.h" namespace eCAL { @@ -50,32 +46,22 @@ namespace eCAL void Start(); void Stop(); - bool ApplySample(const Registration::Sample& sample_, bool force_); - - using ApplySampleCallbackT = std::function; - void SetCustomApplySampleCallback(const std::string& customer_, const ApplySampleCallbackT& callback_); - void RemCustomApplySampleCallback(const std::string& customer_); + bool RegisterSample(const Registration::Sample& sample_); + bool UnregisterSample(const Registration::Sample& sample_); protected: - void AddSample2SampleList(const Registration::Sample& sample_); - void ClearSampleList(); - void SendSampleList(); - + void AddSingleSample(const Registration::Sample& sample_); void RegisterSendThread(); static std::atomic m_created; std::unique_ptr m_reg_sender; - std::shared_ptr m_reg_sample_snd_thread; - std::mutex m_sample_list_mtx; - Registration::SampleList m_sample_list; - + std::mutex m_applied_sample_list_mtx; + Registration::SampleList m_applied_sample_list; + bool m_use_registration_udp; bool m_use_registration_shm; - - std::mutex m_callback_custom_apply_sample_map_mtx; - std::map m_callback_custom_apply_sample_map; }; } diff --git a/ecal/core/src/registration/ecal_registration_receiver.cpp b/ecal/core/src/registration/ecal_registration_receiver.cpp index 8cd919a4..ed092060 100644 --- a/ecal/core/src/registration/ecal_registration_receiver.cpp +++ b/ecal/core/src/registration/ecal_registration_receiver.cpp @@ -31,11 +31,6 @@ #if ECAL_CORE_REGISTRATION_SHM #include "registration/shm/ecal_registration_receiver_shm.h" #endif -#include "ecal_global_accessors.h" - -#include "pubsub/ecal_subgate.h" -#include "pubsub/ecal_pubgate.h" -#include "service/ecal_clientgate.h" #include "io/udp/ecal_udp_configurations.h" #include @@ -51,23 +46,29 @@ namespace eCAL ////////////////////////////////////////////////////////////////// std::atomic CRegistrationReceiver::m_created; - CRegistrationReceiver::CRegistrationReceiver() : - m_network(Config::IsNetworkEnabled()), - m_loopback(false), - m_callback_pub(nullptr), - m_callback_sub(nullptr), - m_callback_service(nullptr), - m_callback_client(nullptr), - m_callback_process(nullptr), - m_use_registration_udp(false), - m_use_registration_shm(false), - m_host_group_name(Process::GetHostGroupName()) + CRegistrationReceiver::CRegistrationReceiver() + : m_use_registration_udp(false) + , m_use_registration_shm(false) + , m_sample_applier(Config::IsNetworkEnabled(), false, Process::GetHostGroupName(), Process::GetProcessID()) { + // Connect User registration callback and gates callback with the sample applier + m_sample_applier.SetCustomApplySampleCallback("gates", [](const eCAL::Registration::Sample& sample_) + { + Registration::CSampleApplierGates::ApplySample(sample_); + }); + m_sample_applier.SetCustomApplySampleCallback("custom_registration", [this](const eCAL::Registration::Sample& sample_) + { + m_user_applier.ApplySample(sample_); + }); + } CRegistrationReceiver::~CRegistrationReceiver() { Stop(); + + m_sample_applier.RemCustomApplySampleCallback("custom_registration"); + m_sample_applier.RemCustomApplySampleCallback("gates"); } void CRegistrationReceiver::Start() @@ -80,13 +81,13 @@ namespace eCAL if (m_use_registration_udp) { - m_registration_receiver_udp = std::make_unique([this](const Registration::Sample& sample_) {return this->ApplySample(sample_); }); + m_registration_receiver_udp = std::make_unique([this](const Registration::Sample& sample_) {return m_sample_applier.ApplySample(sample_); }); } #if ECAL_CORE_REGISTRATION_SHM if (m_use_registration_shm) { - m_registration_receiver_shm = std::make_unique([this](const Registration::Sample& sample_) {return this->ApplySample(sample_); }); + m_registration_receiver_shm = std::make_unique([this](const Registration::Sample& sample_) {return m_sample_applier.ApplySample(sample_); }); } #endif @@ -110,254 +111,32 @@ namespace eCAL } #endif - // reset callbacks - m_callback_pub = nullptr; - m_callback_sub = nullptr; - m_callback_service = nullptr; - m_callback_client = nullptr; - m_callback_process = nullptr; - - // finished m_created = false; } void CRegistrationReceiver::EnableLoopback(bool state_) { - m_loopback = state_; - } - - bool CRegistrationReceiver::ApplySample(const Registration::Sample& sample_) - { - if (!m_created) return false; - - // forward all registration samples to outside "customer" (e.g. monitoring, descgate) - { - const std::lock_guard lock(m_callback_custom_apply_sample_map_mtx); - for (const auto& iter : m_callback_custom_apply_sample_map) - { - iter.second(sample_); - } - } - - std::string reg_sample; - if (m_callback_pub - || m_callback_sub - || m_callback_service - || m_callback_client - || m_callback_process - ) - { - SerializeToBuffer(sample_, reg_sample); - } - - switch (sample_.cmd_type) - { - case bct_none: - case bct_set_sample: - break; - case bct_reg_process: - case bct_unreg_process: - // unregistration event not implemented currently - if (m_callback_process) m_callback_process(reg_sample.c_str(), static_cast(reg_sample.size())); - break; -#if ECAL_CORE_SERVICE - case bct_reg_service: - if (g_clientgate() != nullptr) g_clientgate()->ApplyServiceRegistration(sample_); - if (m_callback_service) m_callback_service(reg_sample.c_str(), static_cast(reg_sample.size())); - break; - case bct_unreg_service: - // current client implementation doesn't need that information - if (m_callback_service) m_callback_service(reg_sample.c_str(), static_cast(reg_sample.size())); - break; -#endif - case bct_reg_client: - case bct_unreg_client: - // current service implementation doesn't need that information - if (m_callback_client) m_callback_client(reg_sample.c_str(), static_cast(reg_sample.size())); - break; - case bct_reg_subscriber: - case bct_unreg_subscriber: - ApplySubscriberRegistration(sample_); - if (m_callback_sub) m_callback_sub(reg_sample.c_str(), static_cast(reg_sample.size())); - break; - case bct_reg_publisher: - case bct_unreg_publisher: - ApplyPublisherRegistration(sample_); - if (m_callback_pub) m_callback_pub(reg_sample.c_str(), static_cast(reg_sample.size())); - break; - default: - Logging::Log(log_level_debug1, "CRegistrationReceiver::ApplySample : unknown sample type"); - break; - } - - return true; + m_sample_applier.EnableLoopback(state_); } bool CRegistrationReceiver::AddRegistrationCallback(enum eCAL_Registration_Event event_, const RegistrationCallbackT& callback_) { - if (!m_created) return false; - switch (event_) - { - case reg_event_publisher: - m_callback_pub = callback_; - return true; - case reg_event_subscriber: - m_callback_sub = callback_; - return true; - case reg_event_service: - m_callback_service = callback_; - return true; - case reg_event_client: - m_callback_client = callback_; - return true; - case reg_event_process: - m_callback_process = callback_; - return true; - default: - return false; - } + return m_user_applier.AddRegistrationCallback(event_, callback_); } bool CRegistrationReceiver::RemRegistrationCallback(enum eCAL_Registration_Event event_) { - if (!m_created) return false; - switch (event_) - { - case reg_event_publisher: - m_callback_pub = nullptr; - return true; - case reg_event_subscriber: - m_callback_sub = nullptr; - return true; - case reg_event_service: - m_callback_service = nullptr; - return true; - case reg_event_client: - m_callback_client = nullptr; - return true; - case reg_event_process: - m_callback_process = nullptr; - return true; - default: - return false; - } - } - - void CRegistrationReceiver::ApplySubscriberRegistration(const Registration::Sample& sample_) - { -#if ECAL_CORE_PUBLISHER - if (g_pubgate() == nullptr) return; - - // process registrations from same host group - if (IsHostGroupMember(sample_)) - { - // do not register local entities, only if loop back flag is set true - if (m_loopback || (sample_.topic.pid != Process::GetProcessID())) - { - switch (sample_.cmd_type) - { - case bct_reg_subscriber: - g_pubgate()->ApplySubRegistration(sample_); - break; - case bct_unreg_subscriber: - g_pubgate()->ApplySubUnregistration(sample_); - break; - default: - break; - } - } - } - // process external registrations - else - { - if (m_network) - { - switch (sample_.cmd_type) - { - case bct_reg_subscriber: - g_pubgate()->ApplySubRegistration(sample_); - break; - case bct_unreg_subscriber: - g_pubgate()->ApplySubUnregistration(sample_); - break; - default: - break; - } - } - } -#endif - } - - void CRegistrationReceiver::ApplyPublisherRegistration(const Registration::Sample& sample_) - { -#if ECAL_CORE_SUBSCRIBER - if (g_subgate() == nullptr) return; - - // process registrations from same host group - if (IsHostGroupMember(sample_)) - { - // do not register local entities, only if loop back flag is set true - if (m_loopback || (sample_.topic.pid != Process::GetProcessID())) - { - switch (sample_.cmd_type) - { - case bct_reg_publisher: - g_subgate()->ApplyPubRegistration(sample_); - break; - case bct_unreg_publisher: - g_subgate()->ApplyPubUnregistration(sample_); - break; - default: - break; - } - } - } - // process external registrations - else - { - if (m_network) - { - switch (sample_.cmd_type) - { - case bct_reg_publisher: - g_subgate()->ApplyPubRegistration(sample_); - break; - case bct_unreg_publisher: - g_subgate()->ApplyPubUnregistration(sample_); - break; - default: - break; - } - } - } -#endif - } - - bool CRegistrationReceiver::IsHostGroupMember(const Registration::Sample& sample_) - { - const std::string& sample_host_group_name = sample_.topic.hgname.empty() ? sample_.topic.hname : sample_.topic.hgname; - - if (sample_host_group_name.empty() || m_host_group_name.empty()) - return false; - if (sample_host_group_name != m_host_group_name) - return false; - - return true; + return m_user_applier.RemRegistrationCallback(event_); } void CRegistrationReceiver::SetCustomApplySampleCallback(const std::string& customer_, const ApplySampleCallbackT& callback_) { - const std::lock_guard lock(m_callback_custom_apply_sample_map_mtx); - m_callback_custom_apply_sample_map[customer_] = callback_; + m_sample_applier.SetCustomApplySampleCallback(customer_, callback_); } void CRegistrationReceiver::RemCustomApplySampleCallback(const std::string& customer_) { - const std::lock_guard lock(m_callback_custom_apply_sample_map_mtx); - auto iter = m_callback_custom_apply_sample_map.find(customer_); - if(iter != m_callback_custom_apply_sample_map.end()) - { - m_callback_custom_apply_sample_map.erase(iter); - } + m_sample_applier.RemCustomApplySampleCallback(customer_); } + } diff --git a/ecal/core/src/registration/ecal_registration_receiver.h b/ecal/core/src/registration/ecal_registration_receiver.h index c00931df..2a6d1c61 100644 --- a/ecal/core/src/registration/ecal_registration_receiver.h +++ b/ecal/core/src/registration/ecal_registration_receiver.h @@ -31,6 +31,9 @@ #include #include "serialization/ecal_struct_sample_registration.h" +#include "registration/ecal_registration_sample_applier.h" +#include "registration/ecal_registration_sample_applier_gates.h" +#include "registration/ecal_registration_sample_applier_user.h" #include #include @@ -51,13 +54,13 @@ namespace eCAL CRegistrationReceiver(); ~CRegistrationReceiver(); + //what about the rest of the rule of 5? + void Start(); void Stop(); void EnableLoopback(bool state_); - bool ApplySample(const Registration::Sample& sample_); - bool AddRegistrationCallback(enum eCAL_Registration_Event event_, const RegistrationCallbackT& callback_); bool RemRegistrationCallback(enum eCAL_Registration_Event event_); @@ -65,21 +68,9 @@ namespace eCAL void SetCustomApplySampleCallback(const std::string& customer_, const ApplySampleCallbackT& callback_); void RemCustomApplySampleCallback(const std::string& customer_); - protected: - void ApplySubscriberRegistration(const eCAL::Registration::Sample& sample_); - void ApplyPublisherRegistration(const eCAL::Registration::Sample& sample_); - - bool IsHostGroupMember(const eCAL::Registration::Sample& sample_); - + private: + // why is this a static variable? can someone explain? static std::atomic m_created; - bool m_network; - bool m_loopback; - - RegistrationCallbackT m_callback_pub; - RegistrationCallbackT m_callback_sub; - RegistrationCallbackT m_callback_service; - RegistrationCallbackT m_callback_client; - RegistrationCallbackT m_callback_process; std::unique_ptr m_registration_receiver_udp; #if ECAL_CORE_REGISTRATION_SHM @@ -89,9 +80,12 @@ namespace eCAL bool m_use_registration_udp; bool m_use_registration_shm; - std::mutex m_callback_custom_apply_sample_map_mtx; - std::map m_callback_custom_apply_sample_map; + // This class distributes samples to all everyone who is interested in being notified about samples + Registration::CSampleApplier m_sample_applier; - std::string m_host_group_name; + // These classes are interested in being notified about samples + // Possibly remove these from this class + // The custom user callbacks (who receive serialized samples), e.g. registration events. + Registration::CSampleApplierUser m_user_applier; }; } diff --git a/ecal/core/src/registration/ecal_registration_sample_applier.cpp b/ecal/core/src/registration/ecal_registration_sample_applier.cpp new file mode 100644 index 00000000..5dba33db --- /dev/null +++ b/ecal/core/src/registration/ecal_registration_sample_applier.cpp @@ -0,0 +1,161 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * 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. + * + * ========================= eCAL LICENSE ================================= +*/ + +#include "registration/ecal_registration_sample_applier.h" + +namespace eCAL +{ + namespace Registration + { + ////////////////////////////////////////////////////////////////// + // CSampleApplier + ////////////////////////////////////////////////////////////////// + CSampleApplier::CSampleApplier(bool network, bool loopback, const std::string& host_group_name, uint32_t pid) + : + m_network(network), + m_loopback(loopback), + m_host_group_name(host_group_name), + m_pid(pid) + { + } + + void CSampleApplier::EnableLoopback(bool state_) + { + m_loopback = state_; + } + + bool CSampleApplier::ApplySample(const Registration::Sample& sample_) + { + if (!AcceptRegistrationSample(sample_)) + { + Logging::Log(log_level_debug1, "CSampleApplier::ApplySample : Incoming sample discarded"); + return false; + } + + // forward all registration samples to outside "customer" (e.g. monitoring, descgate, pub/subgate/client/service gates) + { + const std::lock_guard lock(m_callback_custom_apply_sample_map_mtx); + for (const auto& iter : m_callback_custom_apply_sample_map) + { + iter.second(sample_); + } + } + return true; + } + + bool CSampleApplier::IsHostGroupMember(const Registration::Sample& sample_) const + { + std::string host_group_name; + std::string host_name; + switch (sample_.cmd_type) + { + case bct_reg_publisher: + case bct_unreg_publisher: + case bct_reg_subscriber: + case bct_unreg_subscriber: + host_group_name = sample_.topic.hgname; + host_name = sample_.topic.hname; + break; + case bct_reg_service: + case bct_unreg_service: + //host_group_name = sample_.service.hgname; // TODO: we need to add hgname attribute to services + host_name = sample_.service.hname; + break; + case bct_reg_client: + case bct_unreg_client: + //host_group_name = sample_.client.hgname; // TODO: we need to add hgname attribute to clients + host_name = sample_.client.hname; + break; + default: + break; + } + + const std::string& sample_host_group_name = host_group_name.empty() ? host_name : host_group_name; + + if (sample_host_group_name.empty() || m_host_group_name.empty()) + return false; + if (sample_host_group_name != m_host_group_name) + return false; + + return true; + } + + bool CSampleApplier::IsSameProcess(const Registration::Sample& sample_) const + { + int32_t pid(0); + switch (sample_.cmd_type) + { + case bct_reg_process: + case bct_unreg_process: + pid = sample_.process.pid; + break; + case bct_reg_publisher: + case bct_unreg_publisher: + case bct_reg_subscriber: + case bct_unreg_subscriber: + pid = sample_.topic.pid; + break; + case bct_reg_service: + case bct_unreg_service: + pid = sample_.service.pid; + break; + case bct_reg_client: + case bct_unreg_client: + pid = sample_.client.pid; + break; + default: + break; + } + + return pid == m_pid; + } + + bool CSampleApplier::AcceptRegistrationSample(const Registration::Sample& sample_) + { + // check if the sample is from the same host group + if (IsHostGroupMember(sample_)) + { + // register if the sample is from another process + // or if loopback mode is enabled + return !IsSameProcess(sample_) || m_loopback; + } + else + { + // if the sample is from an external host, register only if network mode is enabled + return m_network; + } + } + + void CSampleApplier::SetCustomApplySampleCallback(const std::string& customer_, const ApplySampleCallbackT& callback_) + { + const std::lock_guard lock(m_callback_custom_apply_sample_map_mtx); + m_callback_custom_apply_sample_map[customer_] = callback_; + } + + void CSampleApplier::RemCustomApplySampleCallback(const std::string& customer_) + { + const std::lock_guard lock(m_callback_custom_apply_sample_map_mtx); + auto iter = m_callback_custom_apply_sample_map.find(customer_); + if (iter != m_callback_custom_apply_sample_map.end()) + { + m_callback_custom_apply_sample_map.erase(iter); + } + } + } +} \ No newline at end of file diff --git a/ecal/core/src/registration/ecal_registration_sample_applier.h b/ecal/core/src/registration/ecal_registration_sample_applier.h new file mode 100644 index 00000000..bd2fcf88 --- /dev/null +++ b/ecal/core/src/registration/ecal_registration_sample_applier.h @@ -0,0 +1,72 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * 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. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @brief eCAL Sample Applier + * + * This class applies incoming samples to everyone who is interested. +**/ + +#pragma once + +#include +#include + +#include "serialization/ecal_struct_sample_registration.h" + +#include +#include +#include +#include + +namespace eCAL +{ + namespace Registration + { + class CSampleApplier + { + public: + // to be replaced by config version soon! + CSampleApplier(bool network, bool loopback, const std::string& host_group_name, uint32_t pid); + + // to be removed for eCAL 6, but keep until eCAL 5.14 + void EnableLoopback(bool state_); + bool ApplySample(const Registration::Sample& sample_); + + using ApplySampleCallbackT = std::function; + void SetCustomApplySampleCallback(const std::string& customer_, const ApplySampleCallbackT& callback_); + void RemCustomApplySampleCallback(const std::string& customer_); + + private: + bool IsSameProcess(const Registration::Sample& sample_) const; + bool IsHostGroupMember(const eCAL::Registration::Sample& sample_) const; + + bool AcceptRegistrationSample(const Registration::Sample& sample_); + + bool m_network; + bool m_loopback; + std::string m_host_group_name; + int32_t m_pid; + + std::mutex m_callback_custom_apply_sample_map_mtx; + // We need to check the performance now. Unlike before the pub / subgates also go through the map + std::map m_callback_custom_apply_sample_map; + }; + } +} diff --git a/ecal/core/src/registration/ecal_registration_sample_applier_gates.cpp b/ecal/core/src/registration/ecal_registration_sample_applier_gates.cpp new file mode 100644 index 00000000..e7614096 --- /dev/null +++ b/ecal/core/src/registration/ecal_registration_sample_applier_gates.cpp @@ -0,0 +1,74 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * 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. + * + * ========================= eCAL LICENSE ================================= +*/ + +#include "registration/ecal_registration_sample_applier_gates.h" +#include "ecal_global_accessors.h" +#include "pubsub/ecal_subgate.h" +#include "pubsub/ecal_pubgate.h" +#include "service/ecal_clientgate.h" + +#include + +namespace eCAL +{ + namespace Registration + { + void CSampleApplierGates::ApplySample(const eCAL::Registration::Sample& sample_) + { + switch (sample_.cmd_type) + { + case bct_none: + case bct_set_sample: + case bct_reg_process: + case bct_unreg_process: + break; +#if ECAL_CORE_SERVICE + case bct_reg_service: + if (g_clientgate() != nullptr) g_clientgate()->ApplyServiceRegistration(sample_); + break; +#endif + case bct_unreg_service: + break; + case bct_reg_client: + case bct_unreg_client: + // current client implementation doesn't need that information + break; +#if ECAL_CORE_PUBLISHER + case bct_reg_subscriber: + if (g_pubgate() != nullptr) g_pubgate()->ApplySubRegistration(sample_); + break; + case bct_unreg_subscriber: + if (g_pubgate() != nullptr) g_pubgate()->ApplySubUnregistration(sample_); + break; +#endif +#if ECAL_CORE_SUBSCRIBER + case bct_reg_publisher: + if (g_subgate() != nullptr) g_subgate()->ApplyPubRegistration(sample_); + break; + case bct_unreg_publisher: + if (g_subgate() != nullptr) g_subgate()->ApplyPubUnregistration(sample_); + break; +#endif + default: + Logging::Log(log_level_debug1, "CGatesApplier::ApplySample : unknown sample type"); + break; + } + } + } +} \ No newline at end of file diff --git a/ecal/core/src/pubsub/ecal_publisher_config.cpp b/ecal/core/src/registration/ecal_registration_sample_applier_gates.h similarity index 71% rename from ecal/core/src/pubsub/ecal_publisher_config.cpp rename to ecal/core/src/registration/ecal_registration_sample_applier_gates.h index ede5dddd..c2bf8bf7 100644 --- a/ecal/core/src/pubsub/ecal_publisher_config.cpp +++ b/ecal/core/src/registration/ecal_registration_sample_applier_gates.h @@ -18,19 +18,23 @@ */ /** - * @brief eCAL publisher configuration + * @brief eCAL Sample Applier Gates + * + * This class applies incoming samples to the registration gates **/ -#include -#include +#pragma once + +#include "serialization/ecal_struct_sample_registration.h" namespace eCAL { - namespace Publisher + namespace Registration { - Configuration::Configuration() + class CSampleApplierGates { - *this = GetConfiguration().publisher; - } + public: + static void ApplySample(const eCAL::Registration::Sample& sample_); + }; } } diff --git a/ecal/core/src/registration/ecal_registration_sample_applier_user.cpp b/ecal/core/src/registration/ecal_registration_sample_applier_user.cpp new file mode 100644 index 00000000..0edae0f7 --- /dev/null +++ b/ecal/core/src/registration/ecal_registration_sample_applier_user.cpp @@ -0,0 +1,120 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * 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. + * + * ========================= eCAL LICENSE ================================= +*/ + +#include "registration/ecal_registration_sample_applier_user.h" +#include "serialization/ecal_serialize_sample_registration.h" + +namespace eCAL +{ + namespace Registration + { + bool CSampleApplierUser::AddRegistrationCallback(eCAL_Registration_Event event_, const RegistrationCallbackT& callback_) + { + switch (event_) + { + case reg_event_publisher: + m_callback_pub = callback_; + return true; + case reg_event_subscriber: + m_callback_sub = callback_; + return true; + case reg_event_service: + m_callback_service = callback_; + return true; + case reg_event_client: + m_callback_client = callback_; + return true; + case reg_event_process: + m_callback_process = callback_; + return true; + default: + return false; + } + } + + bool CSampleApplierUser::RemRegistrationCallback(eCAL_Registration_Event event_) + { + switch (event_) + { + case reg_event_publisher: + m_callback_pub = nullptr; + return true; + case reg_event_subscriber: + m_callback_sub = nullptr; + return true; + case reg_event_service: + m_callback_service = nullptr; + return true; + case reg_event_client: + m_callback_client = nullptr; + return true; + case reg_event_process: + m_callback_process = nullptr; + return true; + default: + return false; + } + } + + void CSampleApplierUser::ApplySample(const eCAL::Registration::Sample& sample_) + { + RegistrationCallbackT reg_callback(nullptr); + switch (sample_.cmd_type) + { + case bct_none: + case bct_set_sample: + break; + case bct_reg_process: + case bct_unreg_process: + // unregistration event not implemented currently + reg_callback = m_callback_process; + break; + case bct_reg_service: + case bct_unreg_service: + reg_callback = m_callback_service; + break; + case bct_reg_client: + case bct_unreg_client: + // current client implementation doesn't need that information + reg_callback = m_callback_client; + break; + case bct_reg_subscriber: + case bct_unreg_subscriber: + reg_callback = m_callback_sub; + break; + case bct_reg_publisher: + case bct_unreg_publisher: + reg_callback = m_callback_pub; + break; + default: + break; + } + + // call user registration callback + if (reg_callback) + { + std::string reg_sample; + if (SerializeToBuffer(sample_, reg_sample)) + { + reg_callback(reg_sample.c_str(), static_cast(reg_sample.size())); + } + } + } + } +} \ No newline at end of file diff --git a/ecal/core/src/registration/ecal_registration_sample_applier_user.h b/ecal/core/src/registration/ecal_registration_sample_applier_user.h new file mode 100644 index 00000000..f6fcd1f0 --- /dev/null +++ b/ecal/core/src/registration/ecal_registration_sample_applier_user.h @@ -0,0 +1,57 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * 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. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @brief eCAL registration receiver + * + * Receives registration information from the sample applier and forwards them to + * user defined callbacks. +**/ + +#pragma once + +#include +#include + +#include "serialization/ecal_struct_sample_registration.h" + +namespace eCAL +{ + namespace Registration + { + class CSampleApplierUser + { + public: + bool AddRegistrationCallback(enum eCAL_Registration_Event event_, const RegistrationCallbackT& callback_); + bool RemRegistrationCallback(enum eCAL_Registration_Event event_); + + void ApplySample(const eCAL::Registration::Sample& sample_); + + private: + // in the future this may be stored in a map? or somehow differently + RegistrationCallbackT m_callback_pub = nullptr; + RegistrationCallbackT m_callback_sub = nullptr; + RegistrationCallbackT m_callback_service = nullptr; + RegistrationCallbackT m_callback_client = nullptr; + RegistrationCallbackT m_callback_process = nullptr; + + // protect by mutexes? very likeley need to! + }; + } +} diff --git a/ecal/core/src/registration/shm/ecal_registration_sender_shm.cpp b/ecal/core/src/registration/shm/ecal_registration_sender_shm.cpp index c040037d..c8fed5d3 100644 --- a/ecal/core/src/registration/shm/ecal_registration_sender_shm.cpp +++ b/ecal/core/src/registration/shm/ecal_registration_sender_shm.cpp @@ -54,12 +54,13 @@ bool eCAL::CRegistrationSenderSHM::SendSampleList(const Registration::SampleList { bool return_value{true}; // serialize whole sample list - if (SerializeToBuffer(sample_list, m_sample_list_buffer)) + std::vector sample_list_buffer; + if (SerializeToBuffer(sample_list, sample_list_buffer)) { - if (!m_sample_list_buffer.empty()) + if (!sample_list_buffer.empty()) { // broadcast sample list over shm - return_value &= m_memfile_broadcast_writer.Write(m_sample_list_buffer.data(), m_sample_list_buffer.size()); + return_value &= m_memfile_broadcast_writer.Write(sample_list_buffer.data(), sample_list_buffer.size()); } } return return_value; diff --git a/ecal/core/src/registration/shm/ecal_registration_sender_shm.h b/ecal/core/src/registration/shm/ecal_registration_sender_shm.h index 7f449e4b..67f4638b 100644 --- a/ecal/core/src/registration/shm/ecal_registration_sender_shm.h +++ b/ecal/core/src/registration/shm/ecal_registration_sender_shm.h @@ -51,7 +51,6 @@ namespace eCAL bool SendSampleList(const Registration::SampleList& sample_list) override; private: - std::vector m_sample_list_buffer; CMemoryFileBroadcast m_memfile_broadcast; CMemoryFileBroadcastWriter m_memfile_broadcast_writer; }; diff --git a/ecal/core/src/registration/udp/ecal_registration_receiver_udp.cpp b/ecal/core/src/registration/udp/ecal_registration_receiver_udp.cpp index 55ce9c72..0ec879a0 100644 --- a/ecal/core/src/registration/udp/ecal_registration_receiver_udp.cpp +++ b/ecal/core/src/registration/udp/ecal_registration_receiver_udp.cpp @@ -36,7 +36,7 @@ namespace attr.port = UDP::GetRegistrationPort(); attr.broadcast = UDP::IsBroadcast(); attr.loopback = true; - attr.rcvbuf = Config::GetUdpMulticastRcvBufSizeBytes(); + attr.rcvbuf = UDP::GetReceiveBufferSize(); return attr; } diff --git a/ecal/core/src/registration/udp/ecal_registration_sender_udp.cpp b/ecal/core/src/registration/udp/ecal_registration_sender_udp.cpp index e1ce8182..ab8d5fed 100644 --- a/ecal/core/src/registration/udp/ecal_registration_sender_udp.cpp +++ b/ecal/core/src/registration/udp/ecal_registration_sender_udp.cpp @@ -43,7 +43,7 @@ namespace attr.ttl = UDP::GetMulticastTtl(); attr.broadcast = UDP::IsBroadcast(); attr.loopback = true; - attr.sndbuf = Config::GetUdpMulticastSndBufSizeBytes(); + attr.sndbuf = UDP::GetSendBufferSize(); return attr; } @@ -61,10 +61,11 @@ namespace eCAL bool CRegistrationSenderUDP::SendSample(const Registration::Sample& sample_) { // serialize single sample - if (SerializeToBuffer(sample_, m_sample_buffer)) + std::vector sample_buffer; + if (SerializeToBuffer(sample_, sample_buffer)) { // send single sample over udp - return m_reg_sample_snd.Send("reg_sample", m_sample_buffer) != 0; + return m_reg_sample_snd.Send("reg_sample", sample_buffer) != 0; } return false; } diff --git a/ecal/core/src/registration/udp/ecal_registration_sender_udp.h b/ecal/core/src/registration/udp/ecal_registration_sender_udp.h index 65967cd1..ad49e8ed 100644 --- a/ecal/core/src/registration/udp/ecal_registration_sender_udp.h +++ b/ecal/core/src/registration/udp/ecal_registration_sender_udp.h @@ -50,6 +50,5 @@ namespace eCAL bool SendSample(const Registration::Sample& sample_); UDP::CSampleSender m_reg_sample_snd; - std::vector m_sample_buffer; }; } \ No newline at end of file diff --git a/ecal/core/src/serialization/ecal_serialize_logging.cpp b/ecal/core/src/serialization/ecal_serialize_logging.cpp index 8cc69fdf..ef679925 100644 --- a/ecal/core/src/serialization/ecal_serialize_logging.cpp +++ b/ecal/core/src/serialization/ecal_serialize_logging.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -157,6 +157,7 @@ namespace if (!pb_decode(&pb_istream, eCAL_pb_LogMessage_fields, &pb_log_message)) { std::cerr << "NanoPb eCAL::Logging::LogMessage decode failed: " << pb_istream.errmsg << '\n'; + return false; } /////////////////////////////////////////////// @@ -293,6 +294,7 @@ namespace if (!pb_decode(&pb_istream, eCAL_pb_LogMessageList_fields, &pb_log_message_list)) { std::cerr << "NanoPb eCAL::Logging::LogMessageList decode failed: " << pb_istream.errmsg << '\n'; + return false; } return true; diff --git a/ecal/core/src/serialization/ecal_serialize_monitoring.cpp b/ecal/core/src/serialization/ecal_serialize_monitoring.cpp index bdfacd13..5e0bd04a 100644 --- a/ecal/core/src/serialization/ecal_serialize_monitoring.cpp +++ b/ecal/core/src/serialization/ecal_serialize_monitoring.cpp @@ -894,6 +894,7 @@ namespace if (!pb_decode(&pb_istream, eCAL_pb_Monitoring_fields, &pb_mon_message)) { std::cerr << "NanoPb eCAL::Monitoring::SMonitoring decode failed: " << pb_istream.errmsg << '\n'; + return false; } return true; diff --git a/ecal/core/src/serialization/ecal_serialize_sample_payload.cpp b/ecal/core/src/serialization/ecal_serialize_sample_payload.cpp index 1f8caf41..45e2b920 100644 --- a/ecal/core/src/serialization/ecal_serialize_sample_payload.cpp +++ b/ecal/core/src/serialization/ecal_serialize_sample_payload.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -168,6 +168,7 @@ namespace if (!pb_decode(&pb_istream, eCAL_pb_Sample_fields, &pb_sample)) { std::cerr << "NanoPb eCAL::Payload::Sample decode failed: " << pb_istream.errmsg << '\n'; + return false; } /////////////////////////////////////////////// diff --git a/ecal/core/src/serialization/ecal_serialize_sample_registration.cpp b/ecal/core/src/serialization/ecal_serialize_sample_registration.cpp index d758f79e..c4bfffd9 100644 --- a/ecal/core/src/serialization/ecal_serialize_sample_registration.cpp +++ b/ecal/core/src/serialization/ecal_serialize_sample_registration.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -430,6 +430,7 @@ namespace if (!pb_decode(&pb_istream, eCAL_pb_Sample_fields, &pb_sample)) { std::cerr << "NanoPb eCAL::Registration::Sample decode failed: " << pb_istream.errmsg << '\n'; + return false; } /////////////////////////////////////////////// @@ -568,6 +569,7 @@ namespace if (!pb_decode(&pb_istream, eCAL_pb_SampleList_fields, &pb_sample_list)) { std::cerr << "NanoPb eCAL::Registration::Sample decode failed: " << pb_istream.errmsg << '\n'; + return false; } return true; diff --git a/ecal/core/src/serialization/ecal_serialize_service.cpp b/ecal/core/src/serialization/ecal_serialize_service.cpp index 0a9bb723..9bf6260d 100644 --- a/ecal/core/src/serialization/ecal_serialize_service.cpp +++ b/ecal/core/src/serialization/ecal_serialize_service.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -144,6 +144,7 @@ namespace if (!pb_decode(&pb_istream, eCAL_pb_Request_fields, &pb_request)) { std::cerr << "NanoPb eCAL::Service::Request decode failed: " << pb_istream.errmsg << '\n'; + return false; } /////////////////////////////////////////////// @@ -270,6 +271,7 @@ namespace if (!pb_decode(&pb_istream, eCAL_pb_Response_fields, &pb_response)) { std::cerr << "NanoPb eCAL::Service::Response decode failed: " << pb_istream.errmsg << '\n'; + return false; } /////////////////////////////////////////////// diff --git a/ecal/core/src/service/ecal_clientgate.cpp b/ecal/core/src/service/ecal_clientgate.cpp index 47f7402f..698d96d4 100644 --- a/ecal/core/src/service/ecal_clientgate.cpp +++ b/ecal/core/src/service/ecal_clientgate.cpp @@ -156,16 +156,15 @@ namespace eCAL return(ret_vec); } - void CClientGate::RefreshRegistrations() + void CClientGate::GetRegistrations(Registration::SampleList& reg_sample_list_) { if (!m_created) return; - // refresh client registrations - const std::shared_lock lock(m_client_set_sync); - for (auto *iter : m_client_set) + // read service registrations + std::shared_lock const lock(m_client_set_sync); + for (const auto& service_client_impl : m_client_set) { - // force client to (re)register itself on registration provider - iter->RefreshRegistration(); + reg_sample_list_.samples.emplace_back(service_client_impl->GetRegistration()); } } } diff --git a/ecal/core/src/service/ecal_clientgate.h b/ecal/core/src/service/ecal_clientgate.h index d3930051..910c0c0b 100644 --- a/ecal/core/src/service/ecal_clientgate.h +++ b/ecal/core/src/service/ecal_clientgate.h @@ -55,7 +55,7 @@ namespace eCAL std::vector GetServiceAttr(const std::string& service_name_); - void RefreshRegistrations(); + void GetRegistrations(Registration::SampleList& reg_sample_list_); protected: static std::atomic m_created; diff --git a/ecal/core/src/service/ecal_service_client_impl.cpp b/ecal/core/src/service/ecal_service_client_impl.cpp index 90e2c375..abce7327 100644 --- a/ecal/core/src/service/ecal_service_client_impl.cpp +++ b/ecal/core/src/service/ecal_service_client_impl.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -89,7 +89,7 @@ namespace eCAL m_created = true; // register this client - Register(true); + Register(); return(true); } @@ -427,10 +427,15 @@ namespace eCAL } // called by eCAL:CClientGate every second to update registration layer - void CServiceClientImpl::RefreshRegistration() + Registration::Sample CServiceClientImpl::GetRegistration() { - if (!m_created) return; - Register(false); + // refresh connected services map + CheckForNewServices(); + + // check for disconnected services + CheckForDisconnectedServices(); + + return GetRegistrationSample(); } std::shared_ptr>> @@ -629,14 +634,12 @@ namespace eCAL response_.response = std::string(response_struct_.response.data(), response_struct_.response.size()); } - void CServiceClientImpl::Register(const bool force_) + Registration::Sample CServiceClientImpl::GetRegistrationSample() { - if (!m_created) return; - if (m_service_name.empty()) return; + Registration::Sample ecal_reg_sample; + ecal_reg_sample.cmd_type = bct_reg_client; - Registration::Sample sample; - sample.cmd_type = bct_reg_client; - auto& service_client = sample.client; + auto& service_client = ecal_reg_sample.client; service_client.version = m_client_version; service_client.hname = Process::GetHostName(); service_client.pname = Process::GetProcessName(); @@ -645,7 +648,6 @@ namespace eCAL service_client.sname = m_service_name; service_client.sid = m_service_id; - { const std::lock_guard lock(m_method_sync); @@ -655,61 +657,25 @@ namespace eCAL const auto& method_information = method_information_pair.second; Service::Method method; - method.mname = method_name; - method.req_type = method_information.request_type.name; - method.req_desc = method_information.request_type.descriptor; - method.resp_type = method_information.response_type.name; - method.resp_desc = method_information.response_type.descriptor; + method.mname = method_name; + method.req_type = method_information.request_type.name; + method.req_desc = method_information.request_type.descriptor; + method.resp_type = method_information.response_type.name; + method.resp_desc = method_information.response_type.descriptor; method.call_count = m_method_call_count_map.at(method_name); service_client.methods.push_back(method); } } - // register entity - if (g_registration_provider() != nullptr) g_registration_provider()->ApplySample(sample, force_); - - // refresh connected services map - CheckForNewServices(); - - // check for disconnected services - { - std::lock_guard const lock(m_client_map_sync); - for (auto& client : m_client_map) - { - if (client.second->get_state() == eCAL::service::State::FAILED) - { - std::string const service_key = client.first; - - // is the service still in the connecting map ? - auto iter = m_connected_services_map.find(service_key); - if (iter != m_connected_services_map.end()) - { - // call disconnect event - std::lock_guard const lock_cb(m_event_callback_map_sync); - auto e_iter = m_event_callback_map.find(client_event_disconnected); - if (e_iter != m_event_callback_map.end()) - { - SClientEventCallbackData sdata; - sdata.type = client_event_disconnected; - sdata.time = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); - sdata.attr = iter->second; - (e_iter->second)(m_service_name.c_str(), &sdata); - } - // remove service - m_connected_services_map.erase(iter); - } - } - } - } + return ecal_reg_sample; } - void CServiceClientImpl::Unregister() + Registration::Sample CServiceClientImpl::GetUnregistrationSample() { - if (m_service_name.empty()) return; + Registration::Sample ecal_reg_sample; + ecal_reg_sample.cmd_type = bct_unreg_client; - Registration::Sample sample; - sample.cmd_type = bct_unreg_client; - auto& service_client = sample.client; + auto& service_client = ecal_reg_sample.client; service_client.hname = Process::GetHostName(); service_client.pname = Process::GetProcessName(); service_client.uname = Process::GetUnitName(); @@ -718,9 +684,24 @@ namespace eCAL service_client.sid = m_service_id; service_client.version = m_client_version; + return ecal_reg_sample; + } + + void CServiceClientImpl::Register() + { + if (!m_created) return; + if (m_service_name.empty()) return; + + // register entity + if (g_registration_provider() != nullptr) g_registration_provider()->RegisterSample(GetRegistrationSample()); + } + + void CServiceClientImpl::Unregister() + { + if (m_service_name.empty()) return; // unregister entity - if (g_registration_provider() != nullptr) g_registration_provider()->ApplySample(sample, false); + if (g_registration_provider() != nullptr) g_registration_provider()->UnregisterSample(GetUnregistrationSample()); } void CServiceClientImpl::CheckForNewServices() @@ -754,7 +735,7 @@ namespace eCAL const std::vector> endpoint_list { {iter.hname, port_to_use}, - {iter.hname + ".local", port_to_use}, // TODO: Make this configurable from the ecal.ini + {iter.hname + ".local", port_to_use}, // TODO: Make this configurable from the ecal.yaml }; const auto new_client_session = client_manager->create_client(static_cast(protocol_version), endpoint_list, event_callback); if (new_client_session) @@ -763,6 +744,37 @@ namespace eCAL } } + void CServiceClientImpl::CheckForDisconnectedServices() + { + std::lock_guard const lock(m_client_map_sync); + for (auto& client : m_client_map) + { + if (client.second->get_state() == eCAL::service::State::FAILED) + { + std::string const service_key = client.first; + + // is the service still in the connecting map ? + auto iter = m_connected_services_map.find(service_key); + if (iter != m_connected_services_map.end()) + { + // call disconnect event + std::lock_guard const lock_cb(m_event_callback_map_sync); + auto e_iter = m_event_callback_map.find(client_event_disconnected); + if (e_iter != m_event_callback_map.end()) + { + SClientEventCallbackData sdata; + sdata.type = client_event_disconnected; + sdata.time = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); + sdata.attr = iter->second; + (e_iter->second)(m_service_name.c_str(), &sdata); + } + // remove service + m_connected_services_map.erase(iter); + } + } + } + } + void CServiceClientImpl::ErrorCallback(const std::string& method_name_, const std::string& error_message_) { std::lock_guard const lock(m_response_callback_sync); diff --git a/ecal/core/src/service/ecal_service_client_impl.h b/ecal/core/src/service/ecal_service_client_impl.h index c1368c10..cb9059d1 100644 --- a/ecal/core/src/service/ecal_service_client_impl.h +++ b/ecal/core/src/service/ecal_service_client_impl.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,9 +25,11 @@ #include #include #include - #include +#include "serialization/ecal_serialize_sample_registration.h" +#include "serialization/ecal_struct_service.h" + #include #include #include @@ -78,7 +80,7 @@ namespace eCAL void RegisterService(const std::string& key_, const SServiceAttr& service_); // called by eCAL:CClientGate every second to update registration layer - void RefreshRegistration(); + Registration::Sample GetRegistration(); std::string GetServiceName() { return m_service_name; }; @@ -94,10 +96,14 @@ namespace eCAL static void fromSerializedProtobuf(const std::string& response_pb_, eCAL::SServiceResponse& response_); static void fromStruct(const Service::Response& response_struct_, eCAL::SServiceResponse& response_); - void Register(bool force_); + Registration::Sample GetRegistrationSample(); + Registration::Sample GetUnregistrationSample(); + + void Register(); void Unregister(); void CheckForNewServices(); + void CheckForDisconnectedServices(); void ErrorCallback(const std::string &method_name_, const std::string &error_message_); @@ -128,7 +134,7 @@ namespace eCAL ServiceMethodInformationMapT m_method_information_map; using MethodCallCountMapT = std::map; - MethodCallCountMapT m_method_call_count_map; + MethodCallCountMapT m_method_call_count_map; std::atomic m_created; }; diff --git a/ecal/core/src/service/ecal_service_server_impl.cpp b/ecal/core/src/service/ecal_service_server_impl.cpp index bc356179..10d2ff64 100644 --- a/ecal/core/src/service/ecal_service_server_impl.cpp +++ b/ecal/core/src/service/ecal_service_server_impl.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -128,9 +128,6 @@ namespace eCAL // mark as created m_created = true; - // register this service - Register(false); - return(true); } @@ -200,9 +197,6 @@ namespace eCAL } } - // register this service - Register(false); - return true; } @@ -238,9 +232,6 @@ namespace eCAL } } - // register this service - Register(false); - return true; } @@ -304,33 +295,32 @@ namespace eCAL } // called by the eCAL::CServiceGate to register a client - void CServiceServerImpl::RegisterClient(const std::string& /*key_*/, const SClientAttr& /*client_*/) // TODO: This function is empty, why does it exist???? + void CServiceServerImpl::RegisterClient(const std::string& /*key_*/, const SClientAttr& /*client_*/) { + // this function is just a placeholder to implement logic if a new client connects + // currently there is no need to do so } // called by eCAL:CServiceGate every second to update registration layer - void CServiceServerImpl::RefreshRegistration() + Registration::Sample CServiceServerImpl::GetRegistration() { - if (!m_created) return; - Register(false); + return GetRegistrationSample(); } - void CServiceServerImpl::Register(const bool force_) + Registration::Sample CServiceServerImpl::GetRegistrationSample() { - if (!m_created) return; - if (m_service_name.empty()) return; + // create registration sample + Registration::Sample ecal_reg_sample; + ecal_reg_sample.cmd_type = bct_reg_service; // might be zero in contruction phase unsigned short const server_tcp_port_v0(m_tcp_server_v0 ? m_tcp_server_v0->get_port() : 0); - if ((Config::IsServiceProtocolV0Enabled()) && (server_tcp_port_v0 == 0)) return; + if ((Config::IsServiceProtocolV0Enabled()) && (server_tcp_port_v0 == 0)) return ecal_reg_sample; unsigned short const server_tcp_port_v1(m_tcp_server_v1 ? m_tcp_server_v1->get_port() : 0); - if ((Config::IsServiceProtocolV1Enabled()) && (server_tcp_port_v1 == 0)) return; + if ((Config::IsServiceProtocolV1Enabled()) && (server_tcp_port_v1 == 0)) return ecal_reg_sample; - // create service registration sample - Registration::Sample sample; - sample.cmd_type = bct_reg_service; - auto& service = sample.service; + auto& service = ecal_reg_sample.service; service.version = m_server_version; service.hname = Process::GetHostName(); service.pname = Process::GetProcessName(); @@ -357,28 +347,49 @@ namespace eCAL } } - // register entity - if (g_registration_provider() != nullptr) g_registration_provider()->ApplySample(sample, force_); + return ecal_reg_sample; } - void CServiceServerImpl::Unregister() + Registration::Sample CServiceServerImpl::GetUnregistrationSample() { - if (m_service_name.empty()) return; + // create registration sample + Registration::Sample ecal_reg_sample; + ecal_reg_sample.cmd_type = bct_unreg_service; + + auto& service = ecal_reg_sample.service; + service.version = m_server_version; + service.hname = Process::GetHostName(); + service.pname = Process::GetProcessName(); + service.uname = Process::GetUnitName(); + service.pid = Process::GetProcessID(); + service.sname = m_service_name; + service.sid = m_service_id; + + return ecal_reg_sample; + } - // create service registration sample - Registration::Sample sample; - sample.cmd_type = bct_unreg_service; - auto& service = sample.service; - service.version = m_server_version; - service.hname = Process::GetHostName(); - service.pname = Process::GetProcessName(); - service.uname = Process::GetUnitName(); - service.pid = Process::GetProcessID(); - service.sname = m_service_name; - service.sid = m_service_id; + void CServiceServerImpl::Register() + { +#if ECAL_CORE_REGISTRATION + if (g_registration_provider() != nullptr) g_registration_provider()->RegisterSample(GetRegistrationSample()); + +#ifndef NDEBUG + // log it + Logging::Log(log_level_debug4, m_service_name + "::CServiceServerImpl::Register"); +#endif +#endif // ECAL_CORE_REGISTRATION + } - // unregister entity - if (g_registration_provider() != nullptr) g_registration_provider()->ApplySample(sample, false); + void CServiceServerImpl::Unregister() + { +#if ECAL_CORE_REGISTRATION + if (g_registration_provider() != nullptr) g_registration_provider()->UnregisterSample(GetUnregistrationSample()); + +#ifndef NDEBUG + // log it + Logging::Log(log_level_debug4, m_service_name + "::CServiceServerImpl::Unregister"); +#endif +#endif // ECAL_CORE_REGISTRATION } int CServiceServerImpl::RequestCallback(const std::string& request_pb_, std::string& response_pb_) diff --git a/ecal/core/src/service/ecal_service_server_impl.h b/ecal/core/src/service/ecal_service_server_impl.h index fec56d90..ccf741be 100644 --- a/ecal/core/src/service/ecal_service_server_impl.h +++ b/ecal/core/src/service/ecal_service_server_impl.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,17 +26,17 @@ #include #include #include +#include + +#include "serialization/ecal_serialize_sample_registration.h" +#include "serialization/ecal_struct_service.h" #include #include #include #include - -#include #include -#include "serialization/ecal_struct_service.h" - namespace eCAL { /** @@ -80,14 +80,17 @@ namespace eCAL void RegisterClient(const std::string& key_, const SClientAttr& client_); // called by eCAL:CServiceGate every second to update registration layer - void RefreshRegistration(); + Registration::Sample GetRegistration(); std::string GetServiceName() { return m_service_name; }; protected: - void Register(bool force_); + void Register(); void Unregister(); + Registration::Sample GetRegistrationSample(); + Registration::Sample GetUnregistrationSample(); + /** * @brief Calls the request callback based on the request and fills the response * diff --git a/ecal/core/src/service/ecal_servicegate.cpp b/ecal/core/src/service/ecal_servicegate.cpp index fe587ea9..1b275a5d 100644 --- a/ecal/core/src/service/ecal_servicegate.cpp +++ b/ecal/core/src/service/ecal_servicegate.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -94,15 +94,15 @@ namespace eCAL return(ret_state); } - void CServiceGate::RefreshRegistrations() + void CServiceGate::GetRegistrations(Registration::SampleList& reg_sample_list_) { if (!m_created) return; - // refresh service registrations + // read service registrations std::shared_lock const lock(m_service_set_sync); for (const auto& service_server_impl : m_service_set) { - service_server_impl->RefreshRegistration(); + reg_sample_list_.samples.emplace_back(service_server_impl->GetRegistration()); } } } diff --git a/ecal/core/src/service/ecal_servicegate.h b/ecal/core/src/service/ecal_servicegate.h index da3047f6..687c527e 100644 --- a/ecal/core/src/service/ecal_servicegate.h +++ b/ecal/core/src/service/ecal_servicegate.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ #pragma once #include "ecal_def.h" +#include "serialization/ecal_struct_sample_registration.h" #include #include @@ -45,7 +46,7 @@ namespace eCAL bool Register (CServiceServerImpl* service_); bool Unregister(CServiceServerImpl* service_); - void RefreshRegistrations(); + void GetRegistrations(Registration::SampleList& reg_sample_list_); protected: static std::atomic m_created; diff --git a/ecal/core/src/time/ecal_timegate.cpp b/ecal/core/src/time/ecal_timegate.cpp index bfca24c0..6e2b528a 100644 --- a/ecal/core/src/time/ecal_timegate.cpp +++ b/ecal/core/src/time/ecal_timegate.cpp @@ -26,7 +26,6 @@ #include -#include "config/ecal_config_reader_hlp.h" #include "ecal_def.h" #include "ecal_timegate.h" #include "util/getenvvar.h" diff --git a/ecal/core/src/types/ecal_custom_data_types.cpp b/ecal/core/src/types/ecal_custom_data_types.cpp index 5fbf5615..ac2c8819 100644 --- a/ecal/core/src/types/ecal_custom_data_types.cpp +++ b/ecal/core/src/types/ecal_custom_data_types.cpp @@ -22,6 +22,7 @@ **/ #include "ecal/types/ecal_custom_data_types.h" + #include #include #include @@ -42,10 +43,6 @@ namespace eCAL { namespace Types { - - // IpAddressV4 definitions - IpAddressV4::IpAddressV4() : IpAddressV4(NET_UDP_MULTICAST_GROUP) {}; - IpAddressV4::IpAddressV4(const std::string& ip_address_) { validateIpString(ip_address_); @@ -79,10 +76,17 @@ namespace eCAL throw std::invalid_argument("[IpAddressV4] No valid IP address: " + ip_address_); } - std::string IpAddressV4::Get() const { return m_ip_address; }; - IpAddressV4& IpAddressV4::operator=(const std::string& ip_string) { this->validateIpString(ip_string); return *this; }; - IpAddressV4::operator std::string() { return m_ip_address; }; + std::string IpAddressV4::Get() const { return m_ip_address; }; + IpAddressV4& IpAddressV4::operator=(const std::string& ip_string_) { this->validateIpString(ip_string_); return *this; }; + IpAddressV4& IpAddressV4::operator=(const char* ip_string_) { this->validateIpString(ip_string_); return *this; }; + IpAddressV4::operator std::string() { return m_ip_address; }; std::ostream& operator<<(std::ostream& os, const IpAddressV4& ipv4) { os << ipv4.Get(); return os; }; - } + + bool IpAddressV4::operator==(const eCAL::Types::IpAddressV4& rhs) const { return m_ip_address == rhs.Get(); }; + bool operator==(eCAL::Types::IpAddressV4 lhs, const char* ip_string_) { return lhs.Get() == std::string(ip_string_); }; + bool operator==(const char* ip_string_, eCAL::Types::IpAddressV4 rhs) { return rhs == ip_string_; }; + bool operator==(eCAL::Types::IpAddressV4 lhs, const std::string& ip_string_) { return lhs.Get() == ip_string_; }; + bool operator==(const std::string& ip_string_, eCAL::Types::IpAddressV4 rhs) { return rhs == ip_string_; }; + } } diff --git a/ecal/core/src/types/ecal_registration_options.cpp b/ecal/core/src/types/ecal_registration_options.cpp deleted file mode 100644 index ae4051fb..00000000 --- a/ecal/core/src/types/ecal_registration_options.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* ========================= eCAL LICENSE ================================= - * - * Copyright (C) 2016 - 2024 Continental Corporation - * - * 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. - * - * ========================= eCAL LICENSE ================================= -*/ - -/** - * @brief Definition of custom data types. -**/ - -#include -#include "ecal_def.h" - -namespace eCAL -{ - namespace Registration - { - Configuration::Configuration() - : network_enabled(NET_ENABLED) - , shm_registration_enabled(SHM_REGISTRATION_ENABLED) - , share_ttype(PUB_SHARE_TTYPE) - , share_tdesc(PUB_SHARE_TDESC) - , m_registration_timeout(CMN_REGISTRATION_TO) - , m_registration_refresh(CMN_REGISTRATION_REFRESH) - {} - - Configuration::Configuration(unsigned int reg_timeout_, unsigned int reg_refresh_) - : network_enabled(NET_ENABLED) - , shm_registration_enabled(SHM_REGISTRATION_ENABLED) - , share_ttype(PUB_SHARE_TTYPE) - , share_tdesc(PUB_SHARE_TDESC) - { - if (reg_refresh_ < reg_timeout_) - { - m_registration_timeout = reg_timeout_; - m_registration_refresh = reg_refresh_; - } - else - { - throw std::invalid_argument("[RegistrationOptions] Refresh(" + std::to_string(reg_refresh_) + ") >= registration timeout (" + std::to_string(reg_timeout_) + ")."); - } - } - - unsigned int Configuration::getTimeoutMS() const { return m_registration_timeout; } - unsigned int Configuration::getRefreshMS() const { return m_registration_refresh; } - } -} \ No newline at end of file diff --git a/ecal/core/src/util/ecal_thread.h b/ecal/core/src/util/ecal_thread.h index 49aec754..7aa1d13f 100644 --- a/ecal/core/src/util/ecal_thread.h +++ b/ecal/core/src/util/ecal_thread.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -84,12 +84,28 @@ namespace eCAL } } + /** + * @brief Trigger the callback thread to interrupt the current sleep without stopping it. + * The callback function will be executed immediately. + */ + void trigger() + { + { + const std::unique_lock lock(mtx_); + // Set the flag to signal the callback thread to trigger + triggerThread_ = true; + // Notify the callback thread to wake up and check the flag + cv_.notify_one(); + } + } + private: std::thread callbackThread_; /**< The callback thread object. */ std::function callback_; /**< The callback function to be executed in the callback thread. */ std::mutex mtx_; /**< Mutex for thread synchronization. */ std::condition_variable cv_; /**< Condition variable for signaling between threads. */ - bool stopThread_{false}; /**< Flag to indicate whether the callback thread should stop. */ + bool stopThread_{ false }; /**< Flag to indicate whether the callback thread should stop. */ + bool triggerThread_{ false }; /**< Flag to indicate whether the callback thread should be triggered. */ /** * @brief Callback function that runs in the callback thread. @@ -105,10 +121,17 @@ namespace eCAL { std::unique_lock lock(mtx_); // Wait for a signal or a timeout - if (cv_.wait_for(lock, timeout, [this] { return stopThread_; })) + if (cv_.wait_for(lock, timeout, [this] { return stopThread_ || triggerThread_; })) { - // If the stopThread flag is true, break out of the loop - break; + if (stopThread_) { + // If the stopThread flag is true, break out of the loop + break; + } + + if (triggerThread_) { + // If the triggerThread flag is true, reset it and proceed + triggerThread_ = false; + } } } diff --git a/ecal/ecal-core-options.cmake b/ecal/ecal-core-options.cmake index 60d20fdc..7a1903de 100644 --- a/ecal/ecal-core-options.cmake +++ b/ecal/ecal-core-options.cmake @@ -12,7 +12,7 @@ option(ECAL_CORE_BUILD_TESTS "Build the eCAL google # ------------------------------------------------------------------------------------------------------------------------------------------------------------------ # core internal feature configuration (adapt to your needs) # ------------------------------------------------------------------------------------------------------------------------------------------------------------------ -option(ECAL_CORE_CONFIG_INIFILE "Enables to configure eCAL via ecal.ini file" ON) +option(ECAL_CORE_CONFIGURATION "Enables to configure eCAL at runtime via ecal.yaml file" ON) option(ECAL_CORE_COMMAND_LINE "Enables eCAL application cmd line interfaces" ON) option(ECAL_CORE_REGISTRATION "Enables the eCAL registration layer" ON) option(ECAL_CORE_MONITORING "Enables the eCAL monitoring functionality" ON) diff --git a/ecal/samples/cpp/benchmarks/datarate_snd/src/datarate_snd.cpp b/ecal/samples/cpp/benchmarks/datarate_snd/src/datarate_snd.cpp index 6349ee7a..90e491ac 100644 --- a/ecal/samples/cpp/benchmarks/datarate_snd/src/datarate_snd.cpp +++ b/ecal/samples/cpp/benchmarks/datarate_snd/src/datarate_snd.cpp @@ -67,11 +67,11 @@ int main(int argc, char **argv) // create publisher config eCAL::Publisher::Configuration pub_config; // set zero copy - pub_config.shm.zero_copy_mode = zero_copy; + pub_config.layer.shm.zero_copy_mode = zero_copy; // set buffering - pub_config.shm.memfile_buffer_count = buffer_count; + pub_config.layer.shm.memfile_buffer_count = buffer_count; // set handshake acknowledgement timeout [ms] - pub_config.shm.acknowledge_timeout_ms = acknowledge_time; + pub_config.layer.shm.acknowledge_timeout_ms = acknowledge_time; // new publisher eCAL::CPublisher pub(topic_name, pub_config); diff --git a/ecal/samples/cpp/benchmarks/latency_snd/src/latency_snd.cpp b/ecal/samples/cpp/benchmarks/latency_snd/src/latency_snd.cpp index bddb0e29..d4822471 100644 --- a/ecal/samples/cpp/benchmarks/latency_snd/src/latency_snd.cpp +++ b/ecal/samples/cpp/benchmarks/latency_snd/src/latency_snd.cpp @@ -52,11 +52,11 @@ void do_run(const int runs, int snd_size /*kB*/, int mem_buffer, bool zero_copy) // create publisher config eCAL::Publisher::Configuration pub_config; // set number of publisher memory buffers - pub_config.shm.memfile_buffer_count = mem_buffer; + pub_config.layer.shm.memfile_buffer_count = mem_buffer; // enable zero copy mode - pub_config.shm.zero_copy_mode = zero_copy; + pub_config.layer.shm.zero_copy_mode = zero_copy; // set acknowledgement timeout to 100ms - pub_config.shm.acknowledge_timeout_ms = 100; + pub_config.layer.shm.acknowledge_timeout_ms = 100; // create publisher eCAL::CPublisher pub("ping", pub_config); diff --git a/ecal/samples/cpp/benchmarks/performance_snd/src/performance_snd.cpp b/ecal/samples/cpp/benchmarks/performance_snd/src/performance_snd.cpp index 0e994853..38894427 100644 --- a/ecal/samples/cpp/benchmarks/performance_snd/src/performance_snd.cpp +++ b/ecal/samples/cpp/benchmarks/performance_snd/src/performance_snd.cpp @@ -50,15 +50,15 @@ int main(int argc, char **argv) // enable zero copy mode std::cout << "Zero copy mode: " << zero_copy << std::endl; - pub_config.shm.zero_copy_mode = zero_copy; + pub_config.layer.shm.zero_copy_mode = zero_copy; // set write buffer count std::cout << "Number of write buffers: " << buffer_count << std::endl; - pub_config.shm.memfile_buffer_count = buffer_count; + pub_config.layer.shm.memfile_buffer_count = buffer_count; // enable handshake mode std::cout << "Acknowledge timeout: " << acknowledge_timeout_ms << " ms" << std::endl; - pub_config.shm.acknowledge_timeout_ms = acknowledge_timeout_ms; + pub_config.layer.shm.acknowledge_timeout_ms = acknowledge_timeout_ms; std::cout << std::endl; // create publisher diff --git a/ecal/samples/cpp/benchmarks/pubsub_throughput/src/pubsub_throughput.cpp b/ecal/samples/cpp/benchmarks/pubsub_throughput/src/pubsub_throughput.cpp index f306a9f8..734b9ba0 100644 --- a/ecal/samples/cpp/benchmarks/pubsub_throughput/src/pubsub_throughput.cpp +++ b/ecal/samples/cpp/benchmarks/pubsub_throughput/src/pubsub_throughput.cpp @@ -37,27 +37,27 @@ void throughput_test(int snd_size, int snd_loops, eCAL::TLayer::eTransportLayer eCAL::Publisher::Configuration pub_config; // set transport layer - pub_config.shm.enable = false; - pub_config.udp.enable = false; - pub_config.tcp.enable = false; + pub_config.layer.shm.enable = false; + pub_config.layer.udp.enable = false; + pub_config.layer.tcp.enable = false; switch (layer) { case eCAL::TLayer::tlayer_shm: - pub_config.shm.enable = true; + pub_config.layer.shm.enable = true; break; case eCAL::TLayer::tlayer_udp_mc: - pub_config.udp.enable = true; + pub_config.layer.udp.enable = true; break; case eCAL::TLayer::tlayer_tcp: - pub_config.tcp.enable = true; + pub_config.layer.tcp.enable = true; break; } // enable zero copy mode - pub_config.shm.zero_copy_mode = zero_copy; + pub_config.layer.shm.zero_copy_mode = zero_copy; // enable handshake mode - pub_config.shm.acknowledge_timeout_ms = 100; + pub_config.layer.shm.acknowledge_timeout_ms = 100; // create publisher eCAL::CPublisher pub("throughput", pub_config); diff --git a/ecal/samples/cpp/pubsub/binary/binary_zero_copy_snd/src/binary_zero_copy_snd.cpp b/ecal/samples/cpp/pubsub/binary/binary_zero_copy_snd/src/binary_zero_copy_snd.cpp index 4524357b..065353cd 100644 --- a/ecal/samples/cpp/pubsub/binary/binary_zero_copy_snd/src/binary_zero_copy_snd.cpp +++ b/ecal/samples/cpp/pubsub/binary/binary_zero_copy_snd/src/binary_zero_copy_snd.cpp @@ -127,7 +127,7 @@ int main(int argc, char** argv) eCAL::Publisher::Configuration pub_config; // turn zero copy mode on - pub_config.shm.zero_copy_mode = true; + pub_config.layer.shm.zero_copy_mode = true; // create the publisher eCAL::CPublisher pub(topicName, { "custom", structTypeName, "" }, pub_config); diff --git a/ecal/samples/cpp/pubsub/protobuf/person_rec/src/person_rec.cpp b/ecal/samples/cpp/pubsub/protobuf/person_rec/src/person_rec.cpp index 1d423205..63a80c26 100644 --- a/ecal/samples/cpp/pubsub/protobuf/person_rec/src/person_rec.cpp +++ b/ecal/samples/cpp/pubsub/protobuf/person_rec/src/person_rec.cpp @@ -57,9 +57,9 @@ int main(int argc, char **argv) eCAL::Subscriber::Configuration sub_config; // activate transport layer - sub_config.shm.enable = true; - sub_config.udp.enable = true; - sub_config.tcp.enable = true; + sub_config.layer.shm.enable = true; + sub_config.layer.udp.enable = true; + sub_config.layer.tcp.enable = true; // create a subscriber (topic name "person") eCAL::protobuf::CSubscriber sub("person", sub_config); diff --git a/ecal/samples/cpp/pubsub/protobuf/person_snd_tcp/src/person_snd_tcp.cpp b/ecal/samples/cpp/pubsub/protobuf/person_snd_tcp/src/person_snd_tcp.cpp index 69432a49..b7feae04 100644 --- a/ecal/samples/cpp/pubsub/protobuf/person_snd_tcp/src/person_snd_tcp.cpp +++ b/ecal/samples/cpp/pubsub/protobuf/person_snd_tcp/src/person_snd_tcp.cpp @@ -36,9 +36,9 @@ int main(int argc, char **argv) eCAL::Publisher::Configuration pub_config; // switch shm and udp layer off, tcp layer on - pub_config.shm.enable = false; - pub_config.udp.enable = false; - pub_config.tcp.enable = true; + pub_config.layer.shm.enable = false; + pub_config.layer.udp.enable = false; + pub_config.layer.tcp.enable = true; // create a publisher (topic name "person") eCAL::protobuf::CPublisher pub("person", pub_config); diff --git a/ecal/samples/cpp/pubsub/protobuf/person_snd_udp/src/person_snd_udp.cpp b/ecal/samples/cpp/pubsub/protobuf/person_snd_udp/src/person_snd_udp.cpp index 65590939..e5a8d1f7 100644 --- a/ecal/samples/cpp/pubsub/protobuf/person_snd_udp/src/person_snd_udp.cpp +++ b/ecal/samples/cpp/pubsub/protobuf/person_snd_udp/src/person_snd_udp.cpp @@ -36,9 +36,9 @@ int main(int argc, char **argv) eCAL::Publisher::Configuration pub_config; // switch shm and tcp layer off, udp layer on - pub_config.shm.enable = false; - pub_config.udp.enable = true; - pub_config.tcp.enable = false; + pub_config.layer.shm.enable = false; + pub_config.layer.udp.enable = true; + pub_config.layer.tcp.enable = false; // create a publisher (topic name "person") eCAL::protobuf::CPublisher pub("person", pub_config); diff --git a/ecal/tests/cpp/clientserver_proto_test/src/clientserver_test_proto.cpp b/ecal/tests/cpp/clientserver_proto_test/src/clientserver_test_proto.cpp index 83a9f5ad..d6c70241 100644 --- a/ecal/tests/cpp/clientserver_proto_test/src/clientserver_test_proto.cpp +++ b/ecal/tests/cpp/clientserver_proto_test/src/clientserver_test_proto.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -71,6 +71,9 @@ TEST(core_cpp_clientserver_proto, ProtoCallback) // initialize eCAL API eCAL::Initialize(0, nullptr, "clientserver proto callback test"); + // enable loop back communication in the same thread + eCAL::Util::EnableLoopback(true); + // create MathService server std::shared_ptr math_service_impl = std::make_shared(); eCAL::protobuf::CServiceServer math_server(math_service_impl); @@ -160,6 +163,9 @@ TEST(core_cpp_clientserver_proto, ProtoBlocking) // initialize eCAL API eCAL::Initialize(0, nullptr, "clientserver proto blocking test"); + // enable loop back communication in the same thread + eCAL::Util::EnableLoopback(true); + // create PingService server std::shared_ptr ping_service_impl = std::make_shared(); eCAL::protobuf::CServiceServer ping_server(ping_service_impl); diff --git a/ecal/tests/cpp/clientserver_test/src/clientserver_test.cpp b/ecal/tests/cpp/clientserver_test/src/clientserver_test.cpp index 049995cb..e9302336 100644 --- a/ecal/tests/cpp/clientserver_test/src/clientserver_test.cpp +++ b/ecal/tests/cpp/clientserver_test/src/clientserver_test.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -89,6 +89,9 @@ TEST(core_cpp_clientserver, ClientConnectEvent) // initialize eCAL API eCAL::Initialize(0, nullptr, "clientserver base connect event callback"); + // enable loop back communication in the same thread + eCAL::Util::EnableLoopback(true); + // create client eCAL::CServiceClient client("service"); @@ -158,6 +161,9 @@ TEST(core_cpp_clientserver, ServerConnectEvent) // initialize eCAL API eCAL::Initialize(0, nullptr, "clientserver base connect event callback"); + // enable loop back communication in the same thread + eCAL::Util::EnableLoopback(true); + // create server eCAL::CServiceServer server("service"); @@ -231,6 +237,9 @@ TEST(core_cpp_clientserver, BaseCallback) // initialize eCAL API eCAL::Initialize(0, nullptr, "clientserver base callback test"); + // enable loop back communication in the same thread + eCAL::Util::EnableLoopback(true); + // create service servers ServiceVecT service_vec; for (auto s = 0; s < num_services; ++s) @@ -345,6 +354,9 @@ TEST(core_cpp_clientserver, BaseCallbackTimeout) // initialize eCAL API eCAL::Initialize(0, nullptr, "clientserver base callback test with timeout"); + // enable loop back communication in the same thread + eCAL::Util::EnableLoopback(true); + // create service servers ServiceVecT service_vec; for (auto s = 0; s < num_services; ++s) @@ -513,6 +525,9 @@ TEST(core_cpp_clientserver, BaseAsyncCallback) // initialize eCAL API eCAL::Initialize(0, nullptr, "clientserver base async callback test"); + // enable loop back communication in the same thread + eCAL::Util::EnableLoopback(true); + // create service server eCAL::CServiceServer server("service"); @@ -586,6 +601,9 @@ TEST(core_cpp_clientserver, BaseAsync) // initialize eCAL API eCAL::Initialize(0, nullptr, "clientserver base async callback test with timeout"); + // enable loop back communication in the same thread + eCAL::Util::EnableLoopback(true); + // create service server eCAL::CServiceServer server("service"); @@ -696,6 +714,9 @@ TEST(core_cpp_clientserver, BaseBlocking) // initialize eCAL API eCAL::Initialize(0, nullptr, "clientserver base blocking test"); + // enable loop back communication in the same thread + eCAL::Util::EnableLoopback(true); + // create service servers ServiceVecT service_vec; for (auto s = 0; s < num_services; ++s) @@ -797,6 +818,9 @@ TEST(core_cpp_clientserver, NestedRPCCall) // initialize eCAL API eCAL::Initialize(0, nullptr, "nested rpc call test"); + // enable loop back communication in the same thread + eCAL::Util::EnableLoopback(true); + // create service server eCAL::CServiceServer server("service"); diff --git a/ecal/tests/cpp/config_test/CMakeLists.txt b/ecal/tests/cpp/config_test/CMakeLists.txt index 9a8fc3cb..f6fa9b49 100644 --- a/ecal/tests/cpp/config_test/CMakeLists.txt +++ b/ecal/tests/cpp/config_test/CMakeLists.txt @@ -22,9 +22,15 @@ find_package(Threads REQUIRED) find_package(GTest REQUIRED) find_package(tclap REQUIRED) +if(ECAL_CORE_CONFIGURATION) + find_package(yaml-cpp REQUIRED) + include(${ECAL_PROJECT_ROOT}/thirdparty/yaml-cpp/compatibility-yaml-cpp.cmake) + yaml_cpp_create_compatibility_targets() +endif() + set(cmd_parser_src ${ECAL_CORE_PROJECT_ROOT}/core/src/config/ecal_cmd_parser.cpp - ${ECAL_CORE_PROJECT_ROOT}/core/src/util/advanced_tclap_output.cpp + ${ECAL_CORE_PROJECT_ROOT}/core/src/util/advanced_tclap_output.cpp ${ECAL_PROJECT_ROOT}/lib/ecal_utils/src/filesystem.cpp ${ECAL_PROJECT_ROOT}/lib/ecal_utils/src/str_convert.cpp ) @@ -32,8 +38,16 @@ set(cmd_parser_src set(config_test_src src/config_test.cpp ${cmd_parser_src} + ${ECAL_CORE_PROJECT_ROOT}/core/src/config/default_configuration.cpp ) +if(ECAL_CORE_CONFIGURATION) + list(APPEND config_test_src + ${ECAL_CORE_PROJECT_ROOT}/core/src/config/configuration_reader.cpp + ${ECAL_CORE_PROJECT_ROOT}/core/src/config/configuration_to_yaml.cpp + ) +endif() + ecal_add_gtest(${PROJECT_NAME} ${config_test_src}) target_include_directories(${PROJECT_NAME} PRIVATE @@ -49,6 +63,11 @@ target_link_libraries(${PROJECT_NAME} tclap::tclap ) +if(ECAL_CORE_CONFIGURATION) + target_link_libraries(${PROJECT_NAME} PRIVATE yaml-cpp) + target_compile_definitions(${PROJECT_NAME} PRIVATE ECAL_CORE_CONFIGURATION) +endif() + target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_14) target_compile_definitions(${PROJECT_NAME} PRIVATE ECAL_CORE_COMMAND_LINE) diff --git a/ecal/tests/cpp/config_test/src/config_test.cpp b/ecal/tests/cpp/config_test/src/config_test.cpp index 93c2c75b..920d122b 100644 --- a/ecal/tests/cpp/config_test/src/config_test.cpp +++ b/ecal/tests/cpp/config_test/src/config_test.cpp @@ -29,6 +29,11 @@ #include #include "ecal_cmd_parser.h" +#ifdef ECAL_CORE_CONFIGURATION + #include "configuration_reader.h" +#endif +#include "default_configuration.h" +#include "ecal_def.h" template void SetValue(MEMBER& member, VALUE value) @@ -36,7 +41,7 @@ void SetValue(MEMBER& member, VALUE value) member = value; } -TEST(core_cpp_config, user_config_passing) +TEST(core_cpp_config /*unused*/, user_config_passing /*unused*/) { // Registration options const unsigned int registration_timeout = 80000U; @@ -53,235 +58,278 @@ TEST(core_cpp_config, user_config_passing) const eCAL_Logging_Filter mon_log_filter_con = log_level_warning; // Publisher options - const bool pub_use_shm = true; + const bool pub_use_shm = false; eCAL::Configuration custom_config(0, nullptr); try { - const eCAL::Registration::Configuration registration = eCAL::Registration::Configuration(registration_timeout, registration_refresh); - - custom_config.transport_layer.drop_out_of_order_messages = drop_out_of_order_messages; - custom_config.transport_layer.mc_options.group = ip_address; - custom_config.transport_layer.mc_options.sndbuf = upd_snd_buff; + custom_config.subscriber.drop_out_of_order_messages = drop_out_of_order_messages; + custom_config.transport_layer.udp.network.group = ip_address; + custom_config.transport_layer.udp.send_buffer = upd_snd_buff; - custom_config.monitoring.monitoring_timeout = mon_timeout; + custom_config.monitoring.timeout = mon_timeout; custom_config.monitoring.filter_excl = mon_filter_excl; - custom_config.logging.filter_log_con = mon_log_filter_con; + custom_config.logging.sinks.console.filter_log_con = mon_log_filter_con; - custom_config.publisher.shm.enable = pub_use_shm; + custom_config.publisher.layer.shm.enable = pub_use_shm; - custom_config.registration = registration; + custom_config.registration.registration_refresh = registration_refresh; + custom_config.registration.registration_timeout = registration_timeout; } catch (std::invalid_argument& e) { - throw std::runtime_error("Error while configuring Configuration: " + std::string(e.what())); + FAIL() << "Error while configuring Configuration: " << std::string(e.what()); + return; } // Initialize ecal api with custom config EXPECT_EQ(0, eCAL::Initialize(custom_config, "User Config Passing Test", eCAL::Init::Default)); // Test boolean assignment, default is false - EXPECT_EQ(drop_out_of_order_messages, eCAL::GetConfiguration().transport_layer.drop_out_of_order_messages); + EXPECT_EQ(drop_out_of_order_messages, eCAL::GetConfiguration().subscriber.drop_out_of_order_messages); // Test IP address assignment, default is 239.0.0.1 - EXPECT_EQ(ip_address, static_cast(eCAL::GetConfiguration().transport_layer.mc_options.group)); + EXPECT_EQ(ip_address, eCAL::GetConfiguration().transport_layer.udp.network.group); // Test UDP send buffer assignment, default is 5242880 - EXPECT_EQ(upd_snd_buff, static_cast(eCAL::GetConfiguration().transport_layer.mc_options.sndbuf)); + EXPECT_EQ(upd_snd_buff, eCAL::GetConfiguration().transport_layer.udp.send_buffer); // Test monitoring timeout assignment, default is 5000U - EXPECT_EQ(mon_timeout, eCAL::GetConfiguration().monitoring.monitoring_timeout); + EXPECT_EQ(mon_timeout, eCAL::GetConfiguration().monitoring.timeout); // Test monitoring filter exclude assignment, default is "_.*" EXPECT_EQ(mon_filter_excl, eCAL::GetConfiguration().monitoring.filter_excl); // Test monitoring console log assignment, default is (log_level_info | log_level_warning | log_level_error | log_level_fatal) - EXPECT_EQ(mon_log_filter_con, eCAL::GetConfiguration().logging.filter_log_con); + EXPECT_EQ(mon_log_filter_con, eCAL::GetConfiguration().logging.sinks.console.filter_log_con); // Test publisher sendmode assignment, default is eCAL::TLayer::eSendMode::smode_auto - EXPECT_EQ(pub_use_shm, eCAL::GetConfiguration().publisher.shm.enable); + EXPECT_EQ(pub_use_shm, eCAL::GetConfiguration().publisher.layer.shm.enable); // Test registration option assignment, default timeout is 60000U and default refresh is 1000U - EXPECT_EQ(registration_timeout, eCAL::GetConfiguration().registration.getTimeoutMS()); - EXPECT_EQ(registration_refresh, eCAL::GetConfiguration().registration.getRefreshMS()); + EXPECT_EQ(registration_timeout, eCAL::GetConfiguration().registration.registration_timeout); + EXPECT_EQ(registration_refresh, eCAL::GetConfiguration().registration.registration_refresh); // Finalize eCAL API EXPECT_EQ(0, eCAL::Finalize()); } -TEST(ConfigDeathTest, user_config_death_test) +TEST(ConfigDeathTest /*unused*/, user_config_death_test /*unused*/) { eCAL::Configuration custom_config(0, nullptr); // Test the IpAddressV4 class with wrong values ASSERT_THROW( - SetValue(custom_config.transport_layer.mc_options.group, std::string("42")), + SetValue(custom_config.transport_layer.udp.network.group, "42"), std::invalid_argument); // Test the IpAddressV4 class with invalid addresses ASSERT_THROW( - SetValue(custom_config.transport_layer.mc_options.group, std::string("256.0.0.0")), + SetValue(custom_config.transport_layer.udp.network.group, "256.0.0.0"), std::invalid_argument); ASSERT_THROW( - SetValue(custom_config.transport_layer.mc_options.group, std::string("127.0.0.1")), + SetValue(custom_config.transport_layer.udp.network.group, "127.0.0.1"), std::invalid_argument); ASSERT_THROW( - SetValue(custom_config.transport_layer.mc_options.group, std::string("255.255.255.255")), + SetValue(custom_config.transport_layer.udp.network.group, "255.255.255.255"), std::invalid_argument); ASSERT_THROW( - SetValue(custom_config.transport_layer.mc_options.group, std::string("FFF.FF.FF.FF")), + SetValue(custom_config.transport_layer.udp.network.group, "FFF.FF.FF.FF"), std::invalid_argument); ASSERT_THROW( - SetValue(custom_config.transport_layer.mc_options.group, std::string("FF.FF.FF.FF")), + SetValue(custom_config.transport_layer.udp.network.group, "FF.FF.FF.FF"), std::invalid_argument); ASSERT_THROW( - SetValue(custom_config.transport_layer.mc_options.group, std::string("Ff.fF.ff.Ff")), + SetValue(custom_config.transport_layer.udp.network.group, "Ff.fF.ff.Ff"), std::invalid_argument); ASSERT_THROW( - SetValue(custom_config.transport_layer.mc_options.group, std::string("7f.0.0.1")), + SetValue(custom_config.transport_layer.udp.network.group, "7f.0.0.1"), std::invalid_argument); ASSERT_THROW( - SetValue(custom_config.transport_layer.mc_options.group, std::string("0.0.0.0")), + SetValue(custom_config.transport_layer.udp.network.group, "0.0.0.0"), std::invalid_argument); ASSERT_THROW( - SetValue(custom_config.transport_layer.mc_options.group, std::string("00.00.00.00")), + SetValue(custom_config.transport_layer.udp.network.group, "00.00.00.00"), std::invalid_argument); ASSERT_THROW( - SetValue(custom_config.transport_layer.mc_options.group, std::string("000.000.000.000")), + SetValue(custom_config.transport_layer.udp.network.group, "000.000.000.000"), std::invalid_argument); ASSERT_THROW( - SetValue(custom_config.transport_layer.mc_options.group, std::string("0.00.000.0")), + SetValue(custom_config.transport_layer.udp.network.group, "0.00.000.0"), std::invalid_argument); // Test the ConstrainedInteger class with wrong values. Default are MIN = 5242880, STEP = 1024 // Value below MIN ASSERT_THROW( - SetValue(custom_config.transport_layer.mc_options.sndbuf, 42), + SetValue(custom_config.transport_layer.udp.send_buffer, 42), std::invalid_argument); // Wrong step. Default STEP = 1024 ASSERT_THROW( - SetValue(custom_config.transport_layer.mc_options.sndbuf, (5242880 + 512)), + SetValue(custom_config.transport_layer.udp.send_buffer, (5242880 + 512)), std::invalid_argument); - // Test the registration option limits - // Refresh timeout > registration timeout - ASSERT_THROW( - eCAL::Registration::Configuration(2000U, 3000U), std::invalid_argument); - - // Refresh timeout = registration timeout - ASSERT_THROW( - eCAL::Registration::Configuration(2000U, 2000U), std::invalid_argument); } -TEST(core_cpp_config, config_custom_datatypes_tests) +TEST(core_cpp_config /*unused*/, config_custom_datatypes_tests /*unused*/) { // test custom datatype assignment operators - eCAL::Types::IpAddressV4 ip1; - eCAL::Types::IpAddressV4 ip2; - EXPECT_EQ(static_cast(ip1), static_cast(ip2)); + eCAL::Types::IpAddressV4 ip1 { "192.168.0.1" }; + eCAL::Types::IpAddressV4 ip2 { "192.168.0.1" }; + EXPECT_EQ(ip1, ip2); ip1 = "192.168.0.2"; ip2 = ip1; - EXPECT_EQ(static_cast(ip1), static_cast(ip2)); + EXPECT_EQ(ip1, ip2); eCAL::Types::ConstrainedInteger<0,1,10> s1; eCAL::Types::ConstrainedInteger<0,1,10> s2; - EXPECT_EQ(static_cast(s1), static_cast(s2)); + EXPECT_EQ(s1, s2); s1 = 5; s2 = s1; - EXPECT_EQ(static_cast(s1), static_cast(s2)); + EXPECT_EQ(s1, s2); // test copy method for config structure eCAL::Configuration config1(0, nullptr); eCAL::Configuration config2(0, nullptr); - std::string testValue = std::string("234.0.3.2"); - config2.transport_layer.mc_options.group = testValue; + std::string testValue = "234.0.3.2"; + config2.transport_layer.udp.network.group = testValue; auto& config2ref = config2; config1 = config2ref; - EXPECT_EQ(static_cast(config1.transport_layer.mc_options.group), testValue); + EXPECT_EQ(config1.transport_layer.udp.network.group, testValue); } -TEST(core_cpp_config, config_cmd_parser) +TEST(CmdParserTest /*unused*/, config_cmd_parser_test /*unused*/) +{ + const std::string some_file_name = "someFileName.yml"; + + eCAL::Config::CmdParser parser{}; + + EXPECT_EQ(parser.getUserIni(), ""); + EXPECT_EQ(parser.getDumpConfig(), false); + + std::vector arguments{}; + + arguments.push_back("test_config_cmd_parser_test"); + // set a file name as ini file + arguments.push_back("--ecal-config-file " + some_file_name); + // set the dump config flag + arguments.push_back("--ecal-dump-config"); + + parser.parseArguments(arguments); + + EXPECT_EQ(parser.getUserIni(), some_file_name); + EXPECT_EQ(parser.getDumpConfig(), true); +} + +#ifdef ECAL_CORE_CONFIGURATION +TEST(YamlConfigReaderTest /*unused*/, read_write_file_test /*unused*/) { // create a custom ini file - std::string ini_file_name = "customIni.ini"; + std::string ini_file_name = "customIni.yml"; std::ofstream custom_ini_file(ini_file_name); if (custom_ini_file.is_open()) { - custom_ini_file << ini_file_as_string; + custom_ini_file << ini_file_as_string_yaml; custom_ini_file.close(); } else { std::cerr << "Error opening file for ini writing" << "\n"; + FAIL() << "Error opening file for ini writing"; return; } - eCAL::Config::CmdParser parser; + eCAL::Configuration config{}; + EXPECT_NO_THROW(eCAL::Config::YamlFileToConfig(ini_file_name, config)); + + EXPECT_EQ(true, eCAL::Config::ConfigToYamlFile("myTest.yml", config)); + + remove(ini_file_name.data()); + remove("myTest.yml"); +} + +TEST(YamlConfigReaderTest /*unused*/, parse_values_test /*unused*/) +{ + eCAL::Configuration config{}; + EXPECT_NO_THROW(eCAL::Config::YamlStringToConfig(ini_file_as_string_yaml, config)); + + // Check string + EXPECT_EQ(config.application.startup.terminal_emulator, "myTestTerminal"); + + // Check equality of IpAddressV4 + EXPECT_EQ(config.transport_layer.udp.network.group, "239.5.0.1"); - std::vector arguments; + // Check constrained Integer + EXPECT_EQ(config.transport_layer.udp.port, 14010); - const std::string set_config_key = "--ecal-set-config-key "; - const std::string sep_slash = "/"; - const std::string sep_col = ":"; + // Check boolean + EXPECT_EQ(config.transport_layer.udp.npcap_enabled, true); - const std::string network = "network"; - const std::string host_group_name = "host_group_name"; - const std::string config_test_machine = "ConfigTestMachine"; - const std::string network_enabled = "network_enabled"; - const std::string is_network_enabled = "true"; + // Check unsigned size_t + EXPECT_EQ(config.transport_layer.tcp.max_reconnections, 7); + + // Check unsigned int + EXPECT_EQ(config.publisher.layer.shm.acknowledge_timeout_ms, 346U); +} + +TEST(YamlConfigReaderTest /*unused*/, yaml_node_merger /*unused*/) +{ + YAML::Node node_1{}; + YAML::Node node_2{}; + + node_1["test"] = 1; + node_2["test"] = 2; + node_2[3] = "I have an int key!"; + + node_1["test2"] = 3; - const std::string common = "common"; - const std::string registration_timeout = "registration_timeout"; - const std::string registration_refresh = "registration_refresh"; - const std::string reg_to_value = "6000"; - const std::string reg_rf_value = "1000"; - - arguments.push_back("test_config_cmd_parser"); - arguments.push_back("--ecal-ini-file customIni.ini"); - arguments.push_back(set_config_key + network + sep_slash + host_group_name + sep_col + config_test_machine); - arguments.push_back(set_config_key + network + sep_slash + network_enabled + sep_col + is_network_enabled); - arguments.push_back(set_config_key + common + sep_slash + registration_timeout + sep_col + reg_to_value); - arguments.push_back(set_config_key + common + sep_slash + registration_refresh + sep_col + reg_rf_value); + node_1["firstLayer1"]["secondLayer1"] = "192.168.0.2"; + node_2["firstLayer1"]["secondLayer1"] = "192.168.0.5"; - try + // try also with a sequence + node_2["firstLayer2"]["secondLayer2"] = YAML::Load("[1, 2, 3]"); + + eCAL::Config::MergeYamlNodes(node_1, node_2); + + EXPECT_EQ(node_1["test"], node_2["test"]); + EXPECT_EQ(node_1[3], node_2[3]); + EXPECT_EQ(node_1["3"], node_2["3"]); + EXPECT_EQ(node_1["firstLayer1"]["secondLayer1"], node_2["firstLayer1"]["secondLayer1"]); + EXPECT_EQ(node_1["firstLayer2"]["secondLayer2"], node_2["firstLayer2"]["secondLayer2"]); +} + +TEST(YamlConfigReaderTest /*unused*/, yaml_to_config_merger /*unused*/) +{ + // create a custom ini file + std::string ini_file_name = "customIni.yml"; + std::ofstream custom_ini_file(ini_file_name); + + if (custom_ini_file.is_open()) { - parser.parseArguments(arguments); + custom_ini_file << ini_file_as_string_yaml; + custom_ini_file.close(); } - catch(const std::runtime_error& e) + else { - std::cerr << e.what() << '\n'; + std::cerr << "Error opening file for ini writing" << "\n"; + FAIL() << "Error opening file for ini writing"; + return; } - - // Expect a valid ini file - EXPECT_NE(parser.getUserIni(), std::string("")); - - // Expect a proper key-value map in the config key map - EXPECT_EQ(parser.getConfigKeysMap()[network][host_group_name], config_test_machine); - EXPECT_EQ(parser.getConfigKeysMap()[network][network_enabled], is_network_enabled); - EXPECT_EQ(parser.getConfigKeysMap()[common][registration_timeout], reg_to_value); - EXPECT_EQ(parser.getConfigKeysMap()[common][registration_refresh], reg_rf_value); - remove(ini_file_name.data()); -} + eCAL::Configuration config{}; -TEST(CmdParserDeathTest, config_cmd_parser_death_test) -{ - eCAL::Config::CmdParser parser; + EXPECT_TRUE(config.publisher.layer.shm.enable); - std::vector arguments; + eCAL::Config::MergeYamlIntoConfiguration(ini_file_name, config); - arguments.push_back("test_config_cmd_parser_death_test"); - arguments.push_back("--ecal-ini-file someNotValidFileName.ini"); + EXPECT_FALSE(config.publisher.layer.shm.enable); - ASSERT_THROW( - parser.parseArguments(arguments), - std::runtime_error - ); -} \ No newline at end of file + remove(ini_file_name.data()); +} +#endif \ No newline at end of file diff --git a/ecal/tests/cpp/config_test/src/ini_file.h b/ecal/tests/cpp/config_test/src/ini_file.h index fafd498d..bb3f27a7 100644 --- a/ecal/tests/cpp/config_test/src/ini_file.h +++ b/ecal/tests/cpp/config_test/src/ini_file.h @@ -1,194 +1,228 @@ #include -static const std::string ini_file_as_string = -"; --------------------------------------------------\n" -"; NETWORK SETTINGS\n" -"; --------------------------------------------------\n" -"; network_enabled = true / false true = all eCAL components communicate over network boundaries\n" -"; false = local host only communication\n" -";\n" -"; multicast_config_version = v1 / v2 UDP configuration version (Since eCAL 5.12.)\n" -"; v1: default behavior\n" -"; v2: new behavior, comes with a bit more intuitive handling regarding masking of the groups\n" -"; multicast_group = 239.0.0.1 UDP multicast group base\n" -"; All registration and logging is sent on this address\n" -"; multicast_mask = 0.0.0.1-0.0.0.255 v1: Mask maximum number of dynamic multicast group\n" -"; 255.0.0.0-255.255.255.255 v2: masks are now considered like routes masking\n" -";\n" -"; multicast_port = 14000 + x UDP multicast port number (eCAL will use at least the 2 following port\n" -"; numbers too, so please modify in steps of 10 (e.g. 1010, 1020 ...)\n" -";\n" -"; multicast_ttl = 0 + x UDP ttl value, also known as hop limit, is used in determining \n" -"; the intermediate routers being traversed towards the destination\n" -";\n" -"; multicast_sndbuf = 1024 * x UDP send buffer in bytes\n" -"; \n" -"; multicast_rcvbuf = 1024 * x UDP receive buffer in bytes\n" -";\n" -"; multicast_join_all_if = false Linux specific setting to enable joining multicast groups on all network interfacs\n" -"; independent of their link state. Enabling this makes sure that eCAL processes\n" -"; receive data if they are started before network devices are up and running.\n" -"; \n" -"; shm_rec_enabled = true Enable to receive on eCAL shared memory layer\n" -"; tcp_rec_enabled = true Enable to receive on eCAL tcp layer\n" -"; udp_mc_rec_enabled = true Enable to receive on eCAL udp multicast layer\n" -";\n" -"; npcap_enabled = false Enable to receive UDP traffic with the Npcap based receiver\n" -";\n" -"; tcp_pubsub_num_executor_reader = 4 Tcp_pubsub reader amount of threads that shall execute workload\n" -"; tcp_pubsub_num_executor_writer = 4 Tcp_pubsub writer amount of threads that shall execute workload\n" -"; tcp_pubsub_max_reconnections = 5 Tcp_pubsub reconnection attemps the session will try to reconnect in \n" -"; case of an issue (a negative value means infinite reconnection attemps)\n" -";\n" -"; host_group_name = Common host group name that enables interprocess mechanisms across \n" -"; (virtual) host borders (e.g, Docker); by default equivalent to local host name\n" -"; --------------------------------------------------\n" -"\n" -"[network]\n" -"network_enabled = false\n" -"multicast_config_version = v1\n" -"multicast_group = 239.0.0.1\n" -"multicast_mask = 0.0.0.15\n" -"multicast_port = 14000\n" -"multicast_ttl = 2\n" -"multicast_sndbuf = 5242880\n" -"multicast_rcvbuf = 5242880\n" -"\n" -"multicast_join_all_if = false\n" -"\n" -"shm_rec_enabled = true\n" -"tcp_rec_enabled = true\n" -"udp_mc_rec_enabled = true\n" -"\n" -"npcap_enabled = false\n" -"\n" -"tcp_pubsub_num_executor_reader = 4\n" -"tcp_pubsub_num_executor_writer = 4\n" -"tcp_pubsub_max_reconnections = 5\n" -"\n" -"host_group_name =\n" -"\n" -"; --------------------------------------------------\n" -"; COMMON SETTINGS\n" -"; --------------------------------------------------\n" -"; registration_timeout = 60000 Timeout for topic registration in ms (internal)\n" -"; registration_refresh = 1000 Topic registration refresh cylce (has to be smaller then registration timeout !)\n" -"\n" -"; --------------------------------------------------\n" -"[common]\n" -"registration_timeout = 60000\n" -"registration_refresh = 1000\n" -"\n" -"; --------------------------------------------------\n" -"; TIME SETTINGS\n" -"; --------------------------------------------------\n" -"; timesync_module_rt = ecaltime-localtime Time synchronisation interface name (dynamic library)\n" -"; The name will be extended with platform suffix (32|64), debug suffix (d) and platform extension (.dll|.so)\n" -";\n" -"; Available modules are:\n" -"; - ecaltime-localtime local system time without synchronization \n" -"; - ecaltime-linuxptp For PTP / gPTP synchronization over ethernet on Linux\n" -"; (device configuration in ecaltime.ini)\n" -"; --------------------------------------------------\n" -"[time]\n" -"timesync_module_rt = ecaltime-localtime\n" -"\n" -"; ---------------------------------------------\n" -"; PROCESS SETTINGS\n" -"; ---------------------------------------------\n" -";\n" -"; terminal_emulator = /usr/bin/x-terminal-emulator -e command for starting applications with an external terminal emulator. If empty, the command will be ignored. Ignored on Windows.\n" -"; e.g. /usr/bin/x-terminal-emulator -e\n" -"; /usr/bin/gnome-terminal -x\n" -"; /usr/bin/xterm -e\n" -";\n" -"; ---------------------------------------------\n" -"[process]\n" -"terminal_emulator = \n" -"\n" -"; --------------------------------------------------\n" -"; PUBLISHER SETTINGS\n" -"; --------------------------------------------------\n" -"; use_shm = 0, 1, 2 Use shared memory transport layer (0 = off, 1 = on, 2 = auto, default = 2)\n" -"; use_tcp = 0, 1, 2 Use tcp transport layer (0 = off, 1 = on, 2 = auto, default = 0)\n" -"; use_udp_mc = 0, 1, 2 Use udp multicast transport layer (0 = off, 1 = on, 2 = auto, default = 2)\n" -";\n" -"; memfile_minsize = x * 4096 kB Default memory file size for new publisher\n" -";\n" -"; memfile_reserve = 50 .. x % Dynamic file size reserve before recreating memory file if topic size changes\n" -";\n" -"; memfile_ack_timeout = 0 .. x ms Publisher timeout for ack event from subscriber that memory file content is processed\n" -";\n" -"; memfile_buffer_count = 1 .. x Number of parallel used memory file buffers for 1:n publish/subscribe ipc connections (default = 1)\n" -"; memfile_zero_copy = 0, 1 Allow matching subscriber to access memory file without copying its content in advance (blocking mode)\n" -";\n" -"; share_ttype = 0, 1 Share topic type via registration layer\n" -"; share_tdesc = 0, 1 Share topic description via registration layer (switch off to disable reflection)\n" -"; --------------------------------------------------\n" -"[publisher]\n" -"use_shm = 2\n" -"use_tcp = 0\n" -"use_udp_mc = 2\n" -"\n" -"memfile_minsize = 4096\n" -"memfile_reserve = 50\n" -"memfile_ack_timeout = 0\n" -"memfile_buffer_count = 1\n" -"memfile_zero_copy = 0\n" -"\n" -"share_ttype = 1\n" -"share_tdesc = 1\n" -"\n" -"; --------------------------------------------------\n" -"; SERVICE SETTINGS\n" -"; --------------------------------------------------\n" -"; protocol_v0 = 0, 1 Support service protocol v0, eCAL 5.11 and older (0 = off, 1 = on)\n" -"; protocol_v1 = 0, 1 Support service protocol v1, eCAL 5.12 and newer (0 = off, 1 = on)\n" -"; --------------------------------------------------\n" -"[service]\n" -"protocol_v0 = 1\n" -"protocol_v1 = 1\n" -"\n" -"; --------------------------------------------------\n" -"; MONITORING SETTINGS\n" -"; --------------------------------------------------\n" -"; timeout = 1000 + (x * 1000) Timeout for topic monitoring in ms\n" -"; filter_excl = __.* Topics blacklist as regular expression (will not be monitored)\n" -"; filter_incl = Topics whitelist as regular expression (will be monitored only)\n" -"; filter_log_con = info, warning, error, fatal Log messages logged to console (all, info, warning, error, fatal, debug1, debug2, debug3, debug4)\n" -"; filter_log_file = Log messages to logged into file system\n" -"; filter_log_udp = info, warning, error, fatal Log messages logged via udp network\n" -"; --------------------------------------------------\n" -"[monitoring]\n" -"timeout = 5000\n" -"filter_excl = __.*\n" -"filter_incl =\n" -"filter_log_con = info, warning, error, fatal\n" -"filter_log_file =\n" -"filter_log_udp = info, warning, error, fatal\n" -"\n" -"; --------------------------------------------------\n" -"; SYS SETTINGS\n" -"; --------------------------------------------------\n" -"; filter_excl = App1,App2 Apps blacklist to be excluded when importing tasks from cloud\n" -"; --------------------------------------------------\n" -"[sys]\n" -"filter_excl = ^eCALSysClient$|^eCALSysGUI$|^eCALSys$\n" -"\n" -"; --------------------------------------------------\n" -"; EXPERIMENTAL SETTINGS\n" -"; --------------------------------------------------\n" -"; shm_monitoring_enabled = false Enable distribution of monitoring/registration information via shared memory\n" -"; shm_monitoring_domain = ecal_monitoring Domain name for shared memory based monitoring/registration\n" -"; shm_monitoring_queue_size = 1024 Queue size of monitoring/registration events\n" -"; network_monitoring_enabled = true Enable distribution of monitoring/registration information via network\n" -";\n" -"; drop_out_of_order_messages = false Enable dropping of payload messages that arrive out of order\n" -"; --------------------------------------------------\n" -"[experimental]\n" -"shm_monitoring_enabled = false\n" -"shm_monitoring_domain = ecal_mon\n" -"shm_monitoring_queue_size = 1024\n" -"network_monitoring_enabled = true\n" -"drop_out_of_order_messages = false\n" -; \ No newline at end of file +const std::string ini_file_as_string_yaml = R"(# _____ _ _ ____ _ _ +# | ____|___| (_)_ __ ___ ___ ___ / ___| / \ | | +# | _| / __| | | '_ \/ __|/ _ \ _____ / _ \ | / _ \ | | +# | |__| (__| | | |_) \__ \ __/ |_____| | __/ |___ / ___ \| |___ +# |_____\___|_|_| .__/|___/\___| \___|\____/_/ \_\_____| +# |_| +# _ _ _ __ _ _ _ +# __ _| | ___ | |__ __ _| | ___ ___ _ __ / _(_) __ _ _ _ _ __ __ _| |_(_) ___ _ __ +# / _` | |/ _ \| '_ \ / _` | | / __/ _ \| '_ \| |_| |/ _` | | | | '__/ _` | __| |/ _ \| '_ \ +# | (_| | | (_) | |_) | (_| | | | (_| (_) | | | | _| | (_| | |_| | | | (_| | |_| | (_) | | | | +# \__, |_|\___/|_.__/ \__,_|_| \___\___/|_| |_|_| |_|\__, |\__,_|_| \__,_|\__|_|\___/|_| |_| +# |___/ |___/ + + +# Registration layer configuration +registration: + # Topic registration refresh cylce (has to be smaller then registration timeout! Default: 1000) + registration_refresh: 1000 + # Timeout for topic registration in ms (internal, Default: 60000) + registration_timeout: 60000 + # Enable to receive registration information on the same local machine + loopback: true + # Host group name that enables interprocess mechanisms across (virtual) + # host borders (e.g, Docker); by default equivalent to local host name + host_group_name: "" + # true = all eCAL components communicate over network boundaries + # false = local host only communication (Default: false) + network_enabled: false + + layer: + shm: + enable: false + # Domain name for shared memory based registration + domain: "ecal_mon" + # Queue size of registration events + queue_size: 1024 + + udp: + enable: true + port: 14000 + + +# Monitoring configuration +monitoring: + # Timeout for topic monitoring in ms (Default: 1000), increase in 1000er steps + timeout: 1000 + # Topics blacklist as regular expression (will not be monitored) + filter_excl: "^__.*$" + # Topics whitelist as regular expression (will be monitored only) (Default: "") + filter_incl: "" + + +# Transport layer configuration +transport_layer: + udp: + # UDP configuration version (Since eCAL 5.12.) + # v1: default behavior + # v2: new behavior, comes with a bit more intuitive handling regarding masking of the groups + config_version: "v2" + # Valid modes: local, network (Default: local) + mode: "local" + # Multicast port number + port: 14010 + # v1: Mask maximum number of dynamic multicast group (range 0.0.0.1-0.0.0.255) + # v2: Masks are now considered like routes masking (range 255.0.0.0-255.255.255.255) + mask: "255.255.255.240" + # Send buffer in bytes + send_buffer: 5242880 + # Receive buffer in bytes + receive_buffer: 5242880 + # Linux specific setting to join all network interfaces independend of their link state. + # Enabling ensures that eCAL processes receive data when they are started before the + # network devices are up and running. + join_all_interfaces: false + # Windows specific setting to enable receiving UDP traffic with the Npcap based receiver + npcap_enabled: true + + # In local mode multicast group and ttl are set by default and are not adjustable + local: + # Multicast group base. All registration and logging is sent on this address + # group: "127.0.0.1" + # TTL (hop limit) is used to determine the amount of routers being traversed towards the destination + # ttl: 0 + + network: + # Multicast group base. All registration and logging is sent on this address + group: "239.5.0.1" + # TTL (hop limit) is used to determine the amount of routers being traversed towards the destination + ttl: 3 + + tcp: + # Reader amount of threads that shall execute workload + number_executor_reader: 4 + # Writer amount of threads that shall execute workload + number_executor_writer: 4 + # Reconnection attemps the session will try to reconnect in case of an issue + max_reconnections: 7 + + shm: + # Default memory file size for new publisher + memfile_min_size_bytes: 4096 + # Dynamic file size reserve before recreating memory file if topic size changes + memfile_reserve_percent: 50 + + +# Publisher specific base settings +publisher: + layer: + # Base configuration for shared memory publisher + shm: + # Enable layer + enable: false + # Enable zero copy shared memory transport mode + zero_copy_mode: false + # Force connected subscribers to send acknowledge event after processing the message. + # The publisher send call is blocked on this event with this timeout (0 == no handshake). + acknowledge_timeout_ms: 346 + # Maximum number of used buffers (needs to be greater than 1, default = 1) + memfile_buffer_count: 1 + + # Base configuration for UDP publisher + udp: + # Enable layer + enable: true + + # Base configuration for TCP publisher + tcp: + # Enable layer + enable: true + + # Share topic type via registration + share_topic_type: true + # Share topic description via registration + share_topic_description: true + # Priority list for layer usage in local mode (Default: SHM > UDP > TCP) + priority_local: ["shm", "udp", "tcp"] + # Priority list for layer usage in cloud mode (Default: UDP > TCP) + priority_network: ["udp", "tcp"] + + +# Subscriber specific base configuration +subscriber: + layer: + # Base configuration for shared memory subscriber + shm: + # Enable layer + enable: false + + # Base configuration for UDP subscriber + udp: + # Enabler layer + enable: true + + # Base configuration for TCP subscriber + tcp: + # Enable layer + enable: false + + # Enable dropping of payload messages that arrive out of order + drop_out_of_order_messages: true + + +# Time configuration +time: + # Time synchronisation interface name (dynamic library) + # The name will be extended with platform suffix (32|64), debug suffix (d) and platform extension (.dll|.so) + # Available modules are: + # - ecaltime-localtime local system time without synchronization + # - ecaltime-linuxptp For PTP / gPTP synchronization over ethernet on Linux + # (device configuration in ecaltime.ini) + rt: "ecaltime-localtime" + # Specify the module name for replaying + replay: "" + + +# Service configuration +service: + # Support service protocol v0, eCAL 5.11 and older (0 = off, 1 = on) + protocol_v0: true + # Support service protocol v1, eCAL 5.12 and newer (0 = off, 1 = on) + protocol_v1: false + + +# eCAL Application Configuration +application: + # Configuration for eCAL Sys + sys: + # Apps blacklist to be excluded when importing tasks from cloud + filter_excl: "^eCALSysClient$|^eCALSysGUI$|^eCALSys$*" + # Process specific configuration + terminal: + # Linux only command for starting applications with an external terminal emulator. + # e.g. /usr/bin/x-terminal-emulator -e + # /usr/bin/gnome-terminal -x + # /usr/bin/xterm -e + # If empty, the command will be ignored. + emulator: "myTestTerminal" + + +# Logging configuration +logging: + sinks: + # Console logging configuration + console: + # Enable console logging + enable: false + # Log level for console output + level: ["info", "warning", "error", "fatal"] + # File logging configuration + file: + # Enable file logging + enable: false + # Log level for file output + level: [] + # Log file path + path: "ecal.log" + # UDP logging configuration + udp: + # Enable UDP logging + enable: true + # Log level for UDP output + level: ["info", "warning", "error", "fatal"] + # UDP + port: 14001 + +)"; \ No newline at end of file diff --git a/ecal/tests/cpp/pubsub_proto_test/src/proto_subscriber_test.cpp b/ecal/tests/cpp/pubsub_proto_test/src/proto_subscriber_test.cpp index a6600461..6d198b1e 100644 --- a/ecal/tests/cpp/pubsub_proto_test/src/proto_subscriber_test.cpp +++ b/ecal/tests/cpp/pubsub_proto_test/src/proto_subscriber_test.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,12 +46,20 @@ class ProtoSubscriberTest : public ::testing::Test { eCAL::Finalize(); } - void SendPerson(eCAL::protobuf::CPublisher& pub) + size_t SendPerson(eCAL::protobuf::CPublisher& pub) { - pb::People::Person p; p.set_id(1); p.set_name("Max"); - pub.Send(p); + return pub.Send(p); + } + + size_t GetPersonSize() + { +#if GOOGLE_PROTOBUF_VERSION >= 3001000 + return static_cast(p.ByteSizeLong()); +#else + return static_cast(p.ByteSize()); +#endif } void OnPerson(const char*, const pb::People::Person&, long long, long long) @@ -60,6 +68,9 @@ class ProtoSubscriberTest : public ::testing::Test { } std::atomic received_callbacks; + +private: + pb::People::Person p; }; using core_cpp_pubsub_proto_sub = ProtoSubscriberTest; @@ -75,11 +86,11 @@ TEST_F(core_cpp_pubsub_proto_sub, ProtoSubscriberTest_SendReceive) std::this_thread::sleep_for(std::chrono::milliseconds(2000)); - SendPerson(person_pub); + auto bytes_send = SendPerson(person_pub); std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // assert that the OnPerson callback has been called once. ASSERT_EQ(1, received_callbacks); - + ASSERT_EQ(bytes_send, GetPersonSize()); } TEST_F(core_cpp_pubsub_proto_sub, ProtoSubscriberTest_MoveAssignment) diff --git a/ecal/tests/cpp/pubsub_test/src/pubsub_acknowledge.cpp b/ecal/tests/cpp/pubsub_test/src/pubsub_acknowledge.cpp index 1530f66e..e564457d 100644 --- a/ecal/tests/cpp/pubsub_test/src/pubsub_acknowledge.cpp +++ b/ecal/tests/cpp/pubsub_test/src/pubsub_acknowledge.cpp @@ -55,7 +55,7 @@ TEST(core_cpp_pubsub, TimeoutAcknowledgment) // create publisher config eCAL::Publisher::Configuration pub_config; - pub_config.shm.acknowledge_timeout_ms = 500; + pub_config.layer.shm.acknowledge_timeout_ms = 500; // create publisher eCAL::string::CPublisher pub("topic", pub_config); diff --git a/ecal/tests/cpp/pubsub_test/src/pubsub_multibuffer.cpp b/ecal/tests/cpp/pubsub_test/src/pubsub_multibuffer.cpp index 31acdb61..569736ef 100644 --- a/ecal/tests/cpp/pubsub_test/src/pubsub_multibuffer.cpp +++ b/ecal/tests/cpp/pubsub_test/src/pubsub_multibuffer.cpp @@ -78,13 +78,13 @@ std::vector multibuffer_pub_sub_test(int buffer_count, bool zero_copy, int // create publisher config eCAL::Publisher::Configuration pub_config; // set transport layer - pub_config.shm.enable = true; - pub_config.udp.enable = false; - pub_config.tcp.enable = false; + pub_config.layer.shm.enable = true; + pub_config.layer.udp.enable = false; + pub_config.layer.tcp.enable = false; // set zero copy mode - pub_config.shm.zero_copy_mode = zero_copy; + pub_config.layer.shm.zero_copy_mode = zero_copy; // set number of memory buffer - pub_config.shm.memfile_buffer_count = buffer_count; + pub_config.layer.shm.memfile_buffer_count = buffer_count; // create publisher for topic "A" eCAL::CPublisher pub("A", pub_config); diff --git a/ecal/tests/cpp/pubsub_test/src/pubsub_receive_test.cpp b/ecal/tests/cpp/pubsub_test/src/pubsub_receive_test.cpp index e61dc53b..25a8bc70 100644 --- a/ecal/tests/cpp/pubsub_test/src/pubsub_receive_test.cpp +++ b/ecal/tests/cpp/pubsub_test/src/pubsub_receive_test.cpp @@ -234,7 +234,7 @@ TEST(PubSub, TestSubscriberSeen) // publishing thread auto publisher_thread = [&]() { eCAL::Publisher::Configuration pub_config; - pub_config.shm.acknowledge_timeout_ms = 500; + pub_config.layer.shm.acknowledge_timeout_ms = 500; eCAL::CPublisher pub("blob", pub_config); int cnt(0); diff --git a/ecal/tests/cpp/pubsub_test/src/pubsub_test_shm.cpp b/ecal/tests/cpp/pubsub_test/src/pubsub_test_shm.cpp index fe40695b..d326c181 100644 --- a/ecal/tests/cpp/pubsub_test/src/pubsub_test_shm.cpp +++ b/ecal/tests/cpp/pubsub_test/src/pubsub_test_shm.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -60,12 +60,17 @@ TEST(core_cpp_pubsub, ZeroPayloadMessageSHM) // create publisher config eCAL::Publisher::Configuration pub_config; // set transport layer - pub_config.shm.enable = true; - pub_config.udp.enable = false; - pub_config.tcp.enable = false; + pub_config.layer.shm.enable = true; + pub_config.layer.udp.enable = false; + pub_config.layer.tcp.enable = false; + + // create publisher for topic "A" (no zero copy) + eCAL::CPublisher pub1("A", pub_config); + + // switch on zero copy + pub_config.layer.shm.zero_copy_mode = true; + eCAL::CPublisher pub2("A", pub_config); - // create publisher for topic "A" - eCAL::CPublisher pub("A", pub_config); // add callback EXPECT_EQ(true, sub.AddReceiveCallback(std::bind(OnReceive, std::placeholders::_1, std::placeholders::_2))); @@ -76,21 +81,30 @@ TEST(core_cpp_pubsub, ZeroPayloadMessageSHM) g_callback_received_bytes = 0; g_callback_received_count = 0; - EXPECT_EQ(send_s.size(), pub.Send(send_s)); + // send without zero copy + EXPECT_EQ(send_s.size(), pub1.Send(send_s)); + eCAL::Process::SleepMS(DATA_FLOW_TIME_MS); + + EXPECT_EQ(send_s.size(), pub1.Send(nullptr, 0)); + eCAL::Process::SleepMS(DATA_FLOW_TIME_MS); + + // send with zero copy + EXPECT_EQ(send_s.size(), pub2.Send(send_s)); eCAL::Process::SleepMS(DATA_FLOW_TIME_MS); - EXPECT_EQ(send_s.size(), pub.Send(nullptr, 0)); + EXPECT_EQ(send_s.size(), pub2.Send(nullptr, 0)); eCAL::Process::SleepMS(DATA_FLOW_TIME_MS); // check callback receive EXPECT_EQ(send_s.size(), g_callback_received_bytes); - EXPECT_EQ(2, g_callback_received_count); + EXPECT_EQ(4, g_callback_received_count); // destroy subscriber sub.Destroy(); // destroy publisher - pub.Destroy(); + pub1.Destroy(); + pub2.Destroy(); // finalize eCAL API eCAL::Finalize(); @@ -115,9 +129,9 @@ TEST(core_cpp_pubsub, MultipleSendsSHM) // create publisher config eCAL::Publisher::Configuration pub_config; // set transport layer - pub_config.shm.enable = true; - pub_config.udp.enable = false; - pub_config.tcp.enable = false; + pub_config.layer.shm.enable = true; + pub_config.layer.udp.enable = false; + pub_config.layer.tcp.enable = false; // create publisher for topic "A" eCAL::string::CPublisher pub("A", pub_config); diff --git a/ecal/tests/cpp/pubsub_test/src/pubsub_test_udp.cpp b/ecal/tests/cpp/pubsub_test/src/pubsub_test_udp.cpp index 0776132e..cfdf27b5 100644 --- a/ecal/tests/cpp/pubsub_test/src/pubsub_test_udp.cpp +++ b/ecal/tests/cpp/pubsub_test/src/pubsub_test_udp.cpp @@ -60,9 +60,9 @@ TEST(core_cpp_pubsub, ZeroPayloadMessageUDP) // create publisher config eCAL::Publisher::Configuration pub_config; // set transport layer - pub_config.shm.enable = false; - pub_config.udp.enable = true; - pub_config.tcp.enable = false; + pub_config.layer.shm.enable = false; + pub_config.layer.udp.enable = true; + pub_config.layer.tcp.enable = false; // create publisher for topic "A" eCAL::CPublisher pub("A", pub_config); @@ -115,9 +115,9 @@ TEST(core_cpp_pubsub, MultipleSendsUDP) // create publisher config eCAL::Publisher::Configuration pub_config; // set transport layer - pub_config.shm.enable = false; - pub_config.udp.enable = true; - pub_config.tcp.enable = false; + pub_config.layer.shm.enable = false; + pub_config.layer.udp.enable = true; + pub_config.layer.tcp.enable = false; // create publisher for topic "A" eCAL::string::CPublisher pub("A", pub_config); diff --git a/ecal/tests/cpp/util_test/src/util_getclients.cpp b/ecal/tests/cpp/util_test/src/util_getclients.cpp index bd70c9db..ee93e2ef 100644 --- a/ecal/tests/cpp/util_test/src/util_getclients.cpp +++ b/ecal/tests/cpp/util_test/src/util_getclients.cpp @@ -22,8 +22,8 @@ #include enum { - CMN_MONITORING_TIMEOUT_MS = (5000), - CMN_REGISTRATION_REFRESH_MS = (1000 * 2) + CMN_MONITORING_TIMEOUT_MS = (5000 + 100), + CMN_REGISTRATION_REFRESH_MS = (1000) }; TEST(core_cpp_util, ClientExpiration) @@ -31,6 +31,9 @@ TEST(core_cpp_util, ClientExpiration) // initialize eCAL API eCAL::Initialize(0, nullptr, "core_cpp_util"); + // enable loop back communication in the same process + eCAL::Util::EnableLoopback(true); + std::map client_info_map; // create simple client and let it expire @@ -43,6 +46,9 @@ TEST(core_cpp_util, ClientExpiration) service_method_info.response_type.descriptor = "foo::resp_desc"; const eCAL::CServiceClient client("foo::service", { {"foo::method", service_method_info} }); + // let's register + eCAL::Process::SleepMS(2 * CMN_REGISTRATION_REFRESH_MS); + // get all clients eCAL::Util::GetClients(client_info_map); @@ -70,7 +76,7 @@ TEST(core_cpp_util, ClientExpiration) } // let's unregister - eCAL::Process::SleepMS(CMN_REGISTRATION_REFRESH_MS); + eCAL::Process::SleepMS(2 * CMN_REGISTRATION_REFRESH_MS); // get all clients again, all clients // should be removed from the map @@ -88,6 +94,9 @@ TEST(core_cpp_util, ClientEqualQualities) // initialize eCAL API eCAL::Initialize(0, nullptr, "core_cpp_util"); + // enable loop back communication in the same process + eCAL::Util::EnableLoopback(true); + std::map client_info_map; // create 2 clients with the same quality of data type information @@ -100,6 +109,9 @@ TEST(core_cpp_util, ClientEqualQualities) service_method_info1.response_type.descriptor = "foo::resp_desc1"; eCAL::CServiceClient client1("foo::service", { {"foo::method", service_method_info1} }); + // let's register + eCAL::Process::SleepMS(2 * CMN_REGISTRATION_REFRESH_MS); + // get all clients eCAL::Util::GetClients(client_info_map); @@ -149,6 +161,9 @@ TEST(core_cpp_util, ClientEqualQualities) // destroy client 1 client1.Destroy(); + // let's register + eCAL::Process::SleepMS(2 * CMN_REGISTRATION_REFRESH_MS); + // check attributes, client 1 attributes should be replaced by client 2 attributes now eCAL::Util::GetClientTypeNames("foo::service", "foo::method", req_type, resp_type); EXPECT_EQ(req_type, "foo::req_type2"); @@ -159,7 +174,7 @@ TEST(core_cpp_util, ClientEqualQualities) } // let's unregister - eCAL::Process::SleepMS(CMN_REGISTRATION_REFRESH_MS); + eCAL::Process::SleepMS(2 * CMN_REGISTRATION_REFRESH_MS); // get all clients again, all clients // should be removed from the map @@ -177,6 +192,9 @@ TEST(core_cpp_util, ClientDifferentQualities) // initialize eCAL API eCAL::Initialize(0, nullptr, "core_cpp_util"); + // enable loop back communication in the same process + eCAL::Util::EnableLoopback(true); + std::map client_info_map; // create 2 clients with different qualities of data type information @@ -189,6 +207,9 @@ TEST(core_cpp_util, ClientDifferentQualities) service_method_info1.response_type.descriptor = ""; eCAL::CServiceClient client1("foo::service", { {"foo::method", service_method_info1} }); + // let's register + eCAL::Process::SleepMS(2 * CMN_REGISTRATION_REFRESH_MS); + // get all clients eCAL::Util::GetClients(client_info_map); @@ -214,6 +235,9 @@ TEST(core_cpp_util, ClientDifferentQualities) service_method_info2.response_type.descriptor = "foo::resp_desc2"; eCAL::CServiceClient client2("foo::service", { {"foo::method", service_method_info2} }); + // let's register + eCAL::Process::SleepMS(2 * CMN_REGISTRATION_REFRESH_MS); + // check attributes, we expect attributes from client 2 here eCAL::Util::GetClientTypeNames("foo::service", "foo::method", req_type, resp_type); EXPECT_EQ(req_type, "foo::req_type2"); @@ -227,7 +251,7 @@ TEST(core_cpp_util, ClientDifferentQualities) } // let's unregister - eCAL::Process::SleepMS(CMN_REGISTRATION_REFRESH_MS); + eCAL::Process::SleepMS(2 * CMN_REGISTRATION_REFRESH_MS); // get all clients again, all clients // should be removed from the map diff --git a/ecal/tests/cpp/util_test/src/util_getservices.cpp b/ecal/tests/cpp/util_test/src/util_getservices.cpp index fbf2239d..2e1aef8c 100644 --- a/ecal/tests/cpp/util_test/src/util_getservices.cpp +++ b/ecal/tests/cpp/util_test/src/util_getservices.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ enum { CMN_MONITORING_TIMEOUT_MS = (5000 + 100), - CMN_REGISTRATION_REFRESH_MS = (1000 + 100) + CMN_REGISTRATION_REFRESH_MS = (1000) }; TEST(core_cpp_util, ServiceExpiration) @@ -31,6 +31,9 @@ TEST(core_cpp_util, ServiceExpiration) // initialize eCAL API eCAL::Initialize(0, nullptr, "core_cpp_util"); + // enable loop back communication in the same process + eCAL::Util::EnableLoopback(true); + std::map service_info_map; // create simple service and let it expire @@ -39,6 +42,9 @@ TEST(core_cpp_util, ServiceExpiration) eCAL::CServiceServer service("foo::service"); service.AddDescription("foo::method", "foo::req_type", "foo::req_desc", "foo::resp_type", "foo::resp_desc"); + // let's register + eCAL::Process::SleepMS(2 * CMN_REGISTRATION_REFRESH_MS); + // get all services eCAL::Util::GetServices(service_info_map); @@ -66,7 +72,7 @@ TEST(core_cpp_util, ServiceExpiration) } // let's unregister - eCAL::Process::SleepMS(CMN_REGISTRATION_REFRESH_MS); + eCAL::Process::SleepMS(2 * CMN_REGISTRATION_REFRESH_MS); // get all services again, all services // should be removed from the map @@ -84,6 +90,9 @@ TEST(core_cpp_util, ServiceEqualQualities) // initialize eCAL API eCAL::Initialize(0, nullptr, "core_cpp_util"); + // enable loop back communication in the same process + eCAL::Util::EnableLoopback(true); + std::map service_info_map; // create 2 services with the same quality of data type information @@ -92,6 +101,9 @@ TEST(core_cpp_util, ServiceEqualQualities) eCAL::CServiceServer service1("foo::service"); service1.AddDescription("foo::method", "foo::req_type1", "foo::req_desc1", "foo::resp_type1", "foo::resp_desc1"); + // let's register + eCAL::Process::SleepMS(2 * CMN_REGISTRATION_REFRESH_MS); + // get all services eCAL::Util::GetServices(service_info_map); @@ -137,6 +149,9 @@ TEST(core_cpp_util, ServiceEqualQualities) // destroy service 1 service1.Destroy(); + // let's register + eCAL::Process::SleepMS(2 * CMN_REGISTRATION_REFRESH_MS); + // check attributes, service 1 attributes should be replaced by service 2 attributes now eCAL::Util::GetServiceTypeNames("foo::service", "foo::method", req_type, resp_type); EXPECT_EQ(req_type, "foo::req_type2"); @@ -147,7 +162,7 @@ TEST(core_cpp_util, ServiceEqualQualities) } // let's unregister - eCAL::Process::SleepMS(CMN_REGISTRATION_REFRESH_MS); + eCAL::Process::SleepMS(2 * CMN_REGISTRATION_REFRESH_MS); // get all services again, all services // should be removed from the map @@ -165,6 +180,9 @@ TEST(core_cpp_util, ServiceDifferentQualities) // initialize eCAL API eCAL::Initialize(0, nullptr, "core_cpp_util"); + // enable loop back communication in the same process + eCAL::Util::EnableLoopback(true); + std::map service_info_map; // create 2 services with different qualities of data type information @@ -173,6 +191,9 @@ TEST(core_cpp_util, ServiceDifferentQualities) eCAL::CServiceServer service1("foo::service"); service1.AddDescription("foo::method", "foo::req_type1", "foo::req_desc1", "", ""); + // let's register + eCAL::Process::SleepMS(2 * CMN_REGISTRATION_REFRESH_MS); + // get all services eCAL::Util::GetServices(service_info_map); @@ -194,6 +215,9 @@ TEST(core_cpp_util, ServiceDifferentQualities) eCAL::CServiceServer service2("foo::service"); service2.AddDescription("foo::method", "foo::req_type2", "foo::req_desc2", "foo::resp_type2", "foo::resp_desc2"); + // let's register + eCAL::Process::SleepMS(2 * CMN_REGISTRATION_REFRESH_MS); + // check attributes, we expect attributes from service 2 here eCAL::Util::GetServiceTypeNames("foo::service", "foo::method", req_type, resp_type); EXPECT_EQ(req_type, "foo::req_type2"); @@ -207,7 +231,7 @@ TEST(core_cpp_util, ServiceDifferentQualities) } // let's unregister - eCAL::Process::SleepMS(CMN_REGISTRATION_REFRESH_MS); + eCAL::Process::SleepMS(2 * CMN_REGISTRATION_REFRESH_MS); // get all services again, all services // should be removed from the map diff --git a/ecal/tests/cpp/util_test/src/util_gettopics.cpp b/ecal/tests/cpp/util_test/src/util_gettopics.cpp index 3b3199e9..3d4466a3 100644 --- a/ecal/tests/cpp/util_test/src/util_gettopics.cpp +++ b/ecal/tests/cpp/util_test/src/util_gettopics.cpp @@ -27,8 +27,8 @@ #include enum { - CMN_MONITORING_TIMEOUT_MS = (5000), - CMN_REGISTRATION_REFRESH_MS = (1000 * 2) + CMN_MONITORING_TIMEOUT_MS = (5000 + 100), + CMN_REGISTRATION_REFRESH_MS = (1000) }; TEST(core_cpp_util, GetTopics) @@ -36,6 +36,9 @@ TEST(core_cpp_util, GetTopics) // initialize eCAL API eCAL::Initialize(0, nullptr, "core_cpp_util"); + // enable loop back communication in the same process + eCAL::Util::EnableLoopback(true); + std::map topic_info_map; // create and check a few pub/sub entities @@ -66,6 +69,9 @@ TEST(core_cpp_util, GetTopics) // this should trigger a warning but not increase map size eCAL::CSubscriber sub12("B1", info_B1_2); + // let's register + eCAL::Process::SleepMS(2 * CMN_REGISTRATION_REFRESH_MS); + // get all topics eCAL::Util::GetTopics(topic_info_map); @@ -96,6 +102,9 @@ TEST(core_cpp_util, GetTopics) pub1.Destroy(); sub1.Destroy(); + // let's register + eCAL::Process::SleepMS(2 * CMN_REGISTRATION_REFRESH_MS); + // size should be 5 again (because of pub12 and sub12 should have replaced pub1 and sub1 attributes now) EXPECT_EQ(topic_info_map.size(), 5); @@ -113,7 +122,7 @@ TEST(core_cpp_util, GetTopics) } // let's unregister - eCAL::Process::SleepMS(CMN_REGISTRATION_REFRESH_MS); + eCAL::Process::SleepMS(2 * CMN_REGISTRATION_REFRESH_MS); // get all topics again, now all topics // should be removed from the map @@ -129,12 +138,15 @@ TEST(core_cpp_util, GetTopics) TEST(core_cpp_util, GetTopicsParallel) { constexpr const int max_publisher_count(2000); - constexpr const int waiting_time_thread(1000); + constexpr const int waiting_time_thread(4000); constexpr const int parallel_threads(1); // initialize eCAL API eCAL::Initialize(0, nullptr, "core_cpp_util"); + // enable loop back communication in the same process + eCAL::Util::EnableLoopback(true); + auto create_publishers = [&]() { std::string topic_name = "Test.ParallelUtilFunctions"; std::atomic call_back_count{ 0 }; diff --git a/submodule_dependencies.cmake b/submodule_dependencies.cmake index da902e96..4ae35dd2 100644 --- a/submodule_dependencies.cmake +++ b/submodule_dependencies.cmake @@ -14,6 +14,7 @@ set(ecal_submodule_dependencies tcp_pubsub udpcap ecaludp + yaml-cpp ) set(ecal_inproject_dependencies diff --git a/thirdparty/simpleini/CMakeLists.txt b/thirdparty/simpleini/CMakeLists.txt deleted file mode 100644 index 3a912b72..00000000 --- a/thirdparty/simpleini/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -add_library(simpleini INTERFACE) -target_include_directories(simpleini INTERFACE ${CMAKE_CURRENT_LIST_DIR}/simpleini) -add_library(simpleini::simpleini ALIAS simpleini) \ No newline at end of file diff --git a/thirdparty/simpleini/build-simpleini.cmake b/thirdparty/simpleini/build-simpleini.cmake deleted file mode 100644 index b4ab0259..00000000 --- a/thirdparty/simpleini/build-simpleini.cmake +++ /dev/null @@ -1,3 +0,0 @@ -include_guard(GLOBAL) - -add_subdirectory(${CMAKE_CURRENT_LIST_DIR} thirdparty/simpleini SYSTEM) \ No newline at end of file diff --git a/thirdparty/simpleini/simpleini b/thirdparty/simpleini/simpleini deleted file mode 160000 index 382ddbb4..00000000 --- a/thirdparty/simpleini/simpleini +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 382ddbb4b92c0b26aa1b32cefba2002119a5b1f2 diff --git a/thirdparty/yaml-cpp/yaml-cpp b/thirdparty/yaml-cpp/yaml-cpp index 9f7babc3..f7320141 160000 --- a/thirdparty/yaml-cpp/yaml-cpp +++ b/thirdparty/yaml-cpp/yaml-cpp @@ -1 +1 @@ -Subproject commit 9f7babc3ff000d1a8a567479c1b5d309658d8b7f +Subproject commit f7320141120f720aecc4c32be25586e7da9eb978