From 1b9dee5b980591e3d4db6b208ac572021b518154 Mon Sep 17 00:00:00 2001 From: tftzee <49162693+rex-schilasky@users.noreply.github.com> Date: Wed, 17 Jul 2024 11:03:28 +0200 Subject: [PATCH] sync-with-eclipse-ecal-2024-07-17 --- CMakeLists.txt | 2 +- ecal/CMakeLists.txt | 4 +- ecal/core/CMakeLists.txt | 17 +- ecal/core/cfg/ecal.ini | 9 +- ecal/core/include/ecal/config/application.h | 57 ++++ ecal/core/include/ecal/config/configuration.h | 80 +++++ ecal/core/include/ecal/config/logging.h | 41 +++ ecal/core/include/ecal/config/monitoring.h | 59 ++++ .../publisher.h} | 42 +-- ecal/core/include/ecal/config/registration.h | 68 +++++ ecal/core/include/ecal/config/service.h | 39 +++ .../subscriber.h} | 21 +- ecal/core/include/ecal/config/time.h | 47 +++ .../include/ecal/config/transport_layer.h | 74 +++++ .../core/include/ecal/config/user_arguments.h | 45 +++ ecal/core/include/ecal/ecal.h | 3 +- ecal/core/include/ecal/ecal_config.h | 106 +++---- ecal/core/include/ecal/ecal_core.h | 14 +- ecal/core/include/ecal/ecal_publisher.h | 11 +- ecal/core/include/ecal/ecal_subscriber.h | 9 +- .../include/ecal/msg/capnproto/publisher.h | 2 +- .../include/ecal/msg/flatbuffers/publisher.h | 2 +- .../include/ecal/msg/messagepack/publisher.h | 2 +- .../msg/protobuf/dynamic_json_subscriber.h | 288 ++++++------------ .../ecal/msg/protobuf/dynamic_publisher.h | 2 +- .../include/ecal/msg/protobuf/publisher.h | 2 +- ecal/core/include/ecal/msg/publisher.h | 2 +- ecal/core/include/ecal/msg/string/publisher.h | 2 +- .../ecal/types/ecal_custom_data_types.h | 104 +++++++ ecal/core/src/config/ecal_cmd_parser.cpp | 254 +++++++++++++++ ecal/core/src/config/ecal_cmd_parser.h | 66 ++++ ecal/core/src/config/ecal_config.cpp | 106 +++---- .../src/config/ecal_config_initializer.cpp | 262 ++++++++++++++++ ecal/core/src/config/ecal_config_reader.cpp | 72 ++--- ecal/core/src/config/ecal_config_reader.h | 9 +- ecal/core/src/ecal.cpp | 144 +++------ ecal/core/src/ecal_def.h | 55 ++-- ecal/core/src/ecal_descgate.cpp | 14 +- ecal/core/src/ecal_descgate.h | 6 +- ecal/core/src/ecal_global_accessors.cpp | 49 ++- ecal/core/src/ecal_global_accessors.h | 15 +- ecal/core/src/ecal_globals.cpp | 32 -- ecal/core/src/ecal_globals.h | 9 +- ecal/core/src/ecal_process.cpp | 2 +- .../src/io/udp/ecal_udp_configurations.cpp | 4 +- .../src/monitoring/ecal_monitoring_impl.cpp | 20 +- .../src/monitoring/ecal_monitoring_impl.h | 10 +- ecal/core/src/pubsub/ecal_publisher.cpp | 6 +- .../core/src/pubsub/ecal_publisher_config.cpp | 25 +- ecal/core/src/pubsub/ecal_subgate.cpp | 14 +- ecal/core/src/pubsub/ecal_subscriber.cpp | 6 + .../src/pubsub/ecal_subscriber_config.cpp | 11 +- ecal/core/src/readwrite/ecal_reader.cpp | 4 +- ecal/core/src/readwrite/ecal_reader.h | 4 +- ecal/core/src/readwrite/ecal_writer.cpp | 2 +- ecal/core/src/readwrite/ecal_writer.h | 7 +- ecal/core/src/readwrite/shm/ecal_writer_shm.h | 4 +- ecal/core/src/readwrite/tcp/ecal_writer_tcp.h | 4 +- ecal/core/src/readwrite/udp/ecal_writer_udp.h | 4 +- .../ecal_process_registration.cpp | 104 +++++++ .../registration/ecal_process_registration.h | 37 +++ .../ecal_registration_provider.cpp | 236 +++----------- .../registration/ecal_registration_provider.h | 46 +-- .../ecal_registration_receiver.cpp | 6 +- .../registration/ecal_registration_sender.h | 57 ++++ .../ecal_registration_sender_shm.cpp | 66 ++++ .../ecal_registration_sender_shm.h | 58 ++++ .../ecal_registration_sender_udp.cpp | 81 +++++ .../ecal_registration_sender_udp.h | 55 ++++ ecal/core/src/service/ecal_clientgate.cpp | 4 +- ecal/core/src/service/ecal_clientgate.h | 4 +- ecal/core/src/time/ecal_timegate.cpp | 2 +- .../core/src/types/ecal_custom_data_types.cpp | 88 ++++++ .../src/types/ecal_registration_options.cpp | 60 ++++ ecal/core/src/util/ecal_expmap.h | 200 +++++++----- ecal/core/src/util/frequency_calculator.h | 46 ++- ecal/samples/CMakeLists.txt | 4 +- .../counter_rec/src/counter_rec.cpp | 6 +- .../dynsize_snd/src/dynsize_snd.cpp | 4 +- .../benchmarks/massive_pub_sub/CMakeLists.txt | 41 +++ .../massive_pub_sub/src/massive_pub_sub.cpp | 128 ++++++++ ecal/samples/cpp/misc/config/CMakeLists.txt | 44 +++ .../cpp/misc/config/src/config_sample.cpp | 54 ++++ .../src/monitoring_get_topics.cpp | 8 +- .../proto_dyn_json_rec/CMakeLists.txt | 4 +- .../src/proto_dyn_json_rec.cpp | 7 +- .../latency_client/src/latency_client.cpp | 4 +- .../services/math_client/src/math_client.cpp | 4 +- .../services/ping_client/src/ping_client.cpp | 4 +- .../ping_client_dyn/src/ping_client_dyn.cpp | 4 +- ecal/tests/CMakeLists.txt | 2 + ecal/tests/cpp/config_test/CMakeLists.txt | 62 ++++ .../tests/cpp/config_test/src/config_test.cpp | 287 +++++++++++++++++ ecal/tests/cpp/config_test/src/ini_file.h | 194 ++++++++++++ ecal/tests/cpp/descgate_test/CMakeLists.txt | 4 +- ecal/tests/cpp/event_test/CMakeLists.txt | 4 +- .../tests/cpp/expmap_test/src/expmap_test.cpp | 102 +++++-- ecal/tests/cpp/io_memfile_test/CMakeLists.txt | 18 +- .../pubsub_test/src/pubsub_acknowledge.cpp | 2 +- .../pubsub_test/src/pubsub_receive_test.cpp | 96 +++++- .../cpp/serialization_test/CMakeLists.txt | 84 +++-- .../cpp/util_test/src/util_getclients.cpp | 6 +- .../cpp/util_test/src/util_gettopics.cpp | 6 +- ecal/tests/cpp/util_test/src/util_test.cpp | 55 +++- lib/{ecalutils => ecal_utils}/CMakeLists.txt | 0 .../include/ecal_utils/command_line.h | 0 .../include/ecal_utils/ecal_utils.h | 0 .../include/ecal_utils/filesystem.h | 0 .../include/ecal_utils/portable_endian.h | 0 .../include/ecal_utils/str_convert.h | 0 .../include/ecal_utils/string.h | 0 .../src/command_line.cpp | 0 .../src/filesystem.cpp | 0 .../src/str_convert.cpp | 0 114 files changed, 3647 insertions(+), 1115 deletions(-) create mode 100644 ecal/core/include/ecal/config/application.h create mode 100644 ecal/core/include/ecal/config/configuration.h create mode 100644 ecal/core/include/ecal/config/logging.h create mode 100644 ecal/core/include/ecal/config/monitoring.h rename ecal/core/include/ecal/{ecal_publisher_config.h => config/publisher.h} (73%) create mode 100644 ecal/core/include/ecal/config/registration.h create mode 100644 ecal/core/include/ecal/config/service.h rename ecal/core/include/ecal/{ecal_subscriber_config.h => config/subscriber.h} (59%) create mode 100644 ecal/core/include/ecal/config/time.h create mode 100644 ecal/core/include/ecal/config/transport_layer.h create mode 100644 ecal/core/include/ecal/config/user_arguments.h create mode 100644 ecal/core/include/ecal/types/ecal_custom_data_types.h create mode 100644 ecal/core/src/config/ecal_cmd_parser.cpp create mode 100644 ecal/core/src/config/ecal_cmd_parser.h create mode 100644 ecal/core/src/config/ecal_config_initializer.cpp create mode 100644 ecal/core/src/registration/ecal_process_registration.cpp create mode 100644 ecal/core/src/registration/ecal_process_registration.h create mode 100644 ecal/core/src/registration/ecal_registration_sender.h create mode 100644 ecal/core/src/registration/ecal_registration_sender_shm.cpp create mode 100644 ecal/core/src/registration/ecal_registration_sender_shm.h create mode 100644 ecal/core/src/registration/ecal_registration_sender_udp.cpp create mode 100644 ecal/core/src/registration/ecal_registration_sender_udp.h create mode 100644 ecal/core/src/types/ecal_custom_data_types.cpp create mode 100644 ecal/core/src/types/ecal_registration_options.cpp create mode 100644 ecal/samples/cpp/benchmarks/massive_pub_sub/CMakeLists.txt create mode 100644 ecal/samples/cpp/benchmarks/massive_pub_sub/src/massive_pub_sub.cpp create mode 100644 ecal/samples/cpp/misc/config/CMakeLists.txt create mode 100644 ecal/samples/cpp/misc/config/src/config_sample.cpp create mode 100644 ecal/tests/cpp/config_test/CMakeLists.txt create mode 100644 ecal/tests/cpp/config_test/src/config_test.cpp create mode 100644 ecal/tests/cpp/config_test/src/ini_file.h rename lib/{ecalutils => ecal_utils}/CMakeLists.txt (100%) rename lib/{ecalutils => ecal_utils}/include/ecal_utils/command_line.h (100%) rename lib/{ecalutils => ecal_utils}/include/ecal_utils/ecal_utils.h (100%) rename lib/{ecalutils => ecal_utils}/include/ecal_utils/filesystem.h (100%) rename lib/{ecalutils => ecal_utils}/include/ecal_utils/portable_endian.h (100%) rename lib/{ecalutils => ecal_utils}/include/ecal_utils/str_convert.h (100%) rename lib/{ecalutils => ecal_utils}/include/ecal_utils/string.h (100%) rename lib/{ecalutils => ecal_utils}/src/command_line.cpp (100%) rename lib/{ecalutils => ecal_utils}/src/filesystem.cpp (100%) rename lib/{ecalutils => ecal_utils}/src/str_convert.cpp (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8aca51cf..f02ccc3e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -203,7 +203,7 @@ endif() # -------------------------------------------------------- # utils (needs to get a thirdparty) # -------------------------------------------------------- -add_subdirectory(lib/ecalutils) +add_subdirectory(lib/ecal_utils) # -------------------------------------------------------- # debscripts diff --git a/ecal/CMakeLists.txt b/ecal/CMakeLists.txt index dc36fe1e..8463fa41 100644 --- a/ecal/CMakeLists.txt +++ b/ecal/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. @@ -18,6 +18,8 @@ cmake_minimum_required(VERSION 3.13) +set(ECAL_CORE_PROJECT_ROOT ${CMAKE_CURRENT_LIST_DIR}) + # -------------------------------------------------------- # core # -------------------------------------------------------- diff --git a/ecal/core/CMakeLists.txt b/ecal/core/CMakeLists.txt index 33caca1d..558419d6 100644 --- a/ecal/core/CMakeLists.txt +++ b/ecal/core/CMakeLists.txt @@ -63,10 +63,14 @@ endif() # config ###################################### set(ecal_config_src + 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/types/ecal_custom_data_types.cpp + src/types/ecal_registration_options.cpp ) ###################################### @@ -274,15 +278,22 @@ endif() ###################################### if (ECAL_CORE_REGISTRATION) set(ecal_registration_src + src/registration/ecal_process_registration.cpp + src/registration/ecal_process_registration.h src/registration/ecal_registration_provider.cpp src/registration/ecal_registration_provider.h src/registration/ecal_registration_receiver.cpp src/registration/ecal_registration_receiver.h + src/registration/ecal_registration_sender.h + src/registration/ecal_registration_sender_udp.cpp + src/registration/ecal_registration_sender_udp.h ) if(ECAL_CORE_REGISTRATION_SHM) list(APPEND ecal_registration_src src/registration/ecal_registration_receiver_shm.cpp src/registration/ecal_registration_receiver_shm.h + src/registration/ecal_registration_sender_shm.cpp + src/registration/ecal_registration_sender_shm.h src/registration/shm/ecal_memfile_broadcast.cpp src/registration/shm/ecal_memfile_broadcast.h src/registration/shm/ecal_memfile_broadcast_reader.cpp @@ -450,10 +461,11 @@ endif() set(ecal_header_cmn include/ecal/types/logging.h include/ecal/types/monitoring.h + include/ecal/config/publisher.h + include/ecal/config/subscriber.h include/ecal/ecal.h include/ecal/ecal_callback.h include/ecal/ecal_client.h - include/ecal/ecal_config.h include/ecal/ecal_core.h include/ecal/ecal_deprecate.h include/ecal/ecal_init.h @@ -465,16 +477,15 @@ set(ecal_header_cmn include/ecal/ecal_process.h include/ecal/ecal_process_severity.h include/ecal/ecal_publisher.h - include/ecal/ecal_publisher_config.h include/ecal/ecal_server.h include/ecal/ecal_service_info.h include/ecal/ecal_subscriber.h - include/ecal/ecal_subscriber_config.h include/ecal/ecal_time.h include/ecal/ecal_timer.h include/ecal/ecal_tlayer.h include/ecal/ecal_types.h include/ecal/ecal_util.h + include/ecal/config/configuration.h ) set(ecal_header_cimpl diff --git a/ecal/core/cfg/ecal.ini b/ecal/core/cfg/ecal.ini index f4745795..5bad09ad 100644 --- a/ecal/core/cfg/ecal.ini +++ b/ecal/core/cfg/ecal.ini @@ -1,8 +1,8 @@ ; -------------------------------------------------- ; NETWORK SETTINGS ; -------------------------------------------------- -; network_enabled = true / false true = all eCAL components communicate over network boundaries -; false = local host only communication +; 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 @@ -43,6 +43,7 @@ [network] network_enabled = false +shm_registration_enabled = false multicast_config_version = v1 multicast_group = 239.0.0.1 multicast_mask = 0.0.0.15 @@ -175,16 +176,12 @@ filter_excl = ^eCALSysClient$|^eCALSysGUI$|^eCALSys$ ; -------------------------------------------------- ; EXPERIMENTAL SETTINGS ; -------------------------------------------------- -; shm_monitoring_enabled = false Enable distribution of monitoring/registration information via shared memory ; shm_monitoring_domain = ecal_monitoring Domain name for shared memory based monitoring/registration ; shm_monitoring_queue_size = 1024 Queue size of monitoring/registration events -; network_monitoring_disabled = false Disable distribution of monitoring/registration information via network ; ; drop_out_of_order_messages = false Enable dropping of payload messages that arrive out of order ; -------------------------------------------------- [experimental] -shm_monitoring_enabled = false shm_monitoring_domain = ecal_mon shm_monitoring_queue_size = 1024 -network_monitoring_disabled = false drop_out_of_order_messages = false diff --git a/ecal/core/include/ecal/config/application.h b/ecal/core/include/ecal/config/application.h new file mode 100644 index 00000000..e08367a2 --- /dev/null +++ b/ecal/core/include/ecal/config/application.h @@ -0,0 +1,57 @@ +/* =========================== 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. + * + * =========================== LICENSE ================================= + */ + +/** + * @file ecal_application_config.h + * @brief eCAL configuration for applications +**/ + +#pragma once + +#include +#include +#include + +namespace eCAL +{ + namespace Application + { + namespace Sys + { + struct Configuration + { + std::string filter_excl; //!< + }; + } + + namespace Startup + { + struct Configuration + { + std::string terminal_emulator; //!< + }; + } + + struct Configuration + { + 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 new file mode 100644 index 00000000..e016d897 --- /dev/null +++ b/ecal/core/include/ecal/config/configuration.h @@ -0,0 +1,80 @@ +/* =========================== 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. + * + * =========================== LICENSE ================================= + */ + +/** + * @file configuration.h + * @brief eCAL configuration interface +**/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "ecal/ecal_os.h" +#include "ecal/ecal_log_level.h" + +#include +#include +#include +#include + +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{}; + + ECAL_API Configuration(); + ECAL_API Configuration(int argc_, char** argv_); + ECAL_API Configuration(std::vector& args_); + + ECAL_API void InitConfigWithDefaultIni(); + ECAL_API void InitConfig(std::string ini_path_ = std::string("")); + + ECAL_API std::string GetIniFilePath(); + + friend class CmdParser; + + protected: + std::string ecal_ini_file_path{}; + + private: + ECAL_API void Init(std::vector& args_); + }; +} diff --git a/ecal/core/include/ecal/config/logging.h b/ecal/core/include/ecal/config/logging.h new file mode 100644 index 00000000..bb1ae9ef --- /dev/null +++ b/ecal/core/include/ecal/config/logging.h @@ -0,0 +1,41 @@ +/* =========================== 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. + * + * =========================== LICENSE ================================= + */ + +/** + * @file ecal_logging_config.h + * @brief eCAL configuration for logging +**/ + +#pragma once + +#include + +namespace eCAL +{ + namespace Logging + { + 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) + }; + } +} \ No newline at end of file diff --git a/ecal/core/include/ecal/config/monitoring.h b/ecal/core/include/ecal/config/monitoring.h new file mode 100644 index 00000000..bf67687b --- /dev/null +++ b/ecal/core/include/ecal/config/monitoring.h @@ -0,0 +1,59 @@ +/* =========================== 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. + * + * =========================== LICENSE ================================= + */ + +/** + * @file ecal_monitoring_config.h + * @brief eCAL configuration for monitoring +**/ + +#pragma once + +#include + +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: "") + }; + } +} \ No newline at end of file diff --git a/ecal/core/include/ecal/ecal_publisher_config.h b/ecal/core/include/ecal/config/publisher.h similarity index 73% rename from ecal/core/include/ecal/ecal_publisher_config.h rename to ecal/core/include/ecal/config/publisher.h index a54cf62a..63e45d14 100644 --- a/ecal/core/include/ecal/ecal_publisher_config.h +++ b/ecal/core/include/ecal/config/publisher.h @@ -18,7 +18,7 @@ */ /** - * @file ecal_publisher_config.h + * @file publisher.h * @brief eCAL publisher configuration * * This publisher configuration struct can be used to define the behavior of an eCAL publisher. Additional information on @@ -89,6 +89,7 @@ #pragma once #include +#include #include @@ -98,46 +99,49 @@ namespace eCAL { namespace SHM { - struct ECAL_API Configuration + struct Configuration { - bool enable = false; //!< enable layer - bool zero_copy_mode = false; //!< enable zero copy shared memory transport mode - int acknowledge_timeout_ms = 0; /*!< 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) */ - size_t memfile_min_size_bytes = 4096; //!< default memory file size for new publisher - size_t memfile_reserve_percent = 50; //!< dynamic file size reserve before recreating memory file if topic size changes - size_t memfile_buffer_count = 1; //!< maximum number of used buffers (needs to be greater than 1, default = 1) + 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) }; } namespace UDP { - struct ECAL_API Configuration + struct Configuration { - bool enable = false; //!< enable layer - bool loopback = false; //!< enable to receive udp messages on the same local machine - int sndbuf_size_bytes = (5*1024*1024); //!< udp send buffer size in bytes (default 5MB) + 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) }; } namespace TCP { - struct ECAL_API Configuration + struct Configuration { - bool enable = false; //!< enable layer + bool enable; //!< 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 ECAL_API Configuration + struct Configuration { - Configuration(); + ECAL_API Configuration(); SHM::Configuration shm; UDP::Configuration udp; TCP::Configuration tcp; - bool share_topic_type = true; //!< share topic type via registration - bool share_topic_description = true; //!< share topic description via registration + bool share_topic_type; //!< share topic type via registration + bool share_topic_description; //!< share topic description via registration }; } } diff --git a/ecal/core/include/ecal/config/registration.h b/ecal/core/include/ecal/config/registration.h new file mode 100644 index 00000000..a521501f --- /dev/null +++ b/ecal/core/include/ecal/config/registration.h @@ -0,0 +1,68 @@ +/* =========================== 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. + * + * =========================== LICENSE ================================= + */ + +/** + * @file ecal_registration_config.h + * @brief eCAL configuration for the registration layer +**/ + +#pragma once + +#include "ecal/ecal_os.h" + +#include +#include + +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 + { + public: + ECAL_API Configuration(); + ECAL_API Configuration(unsigned int reg_timeout_, unsigned int reg_refresh_); + + 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) + + 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) + + private: + unsigned int m_registration_timeout; + unsigned int m_registration_refresh; + }; + } +} \ No newline at end of file diff --git a/ecal/core/include/ecal/config/service.h b/ecal/core/include/ecal/config/service.h new file mode 100644 index 00000000..74f4b542 --- /dev/null +++ b/ecal/core/include/ecal/config/service.h @@ -0,0 +1,39 @@ +/* =========================== 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. + * + * =========================== LICENSE ================================= + */ + +/** + * @file ecal_service_config.h + * @brief eCAL configuration for services +**/ + +#pragma once + +#include + +namespace eCAL +{ + namespace Service + { + 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) + }; + } +} \ No newline at end of file diff --git a/ecal/core/include/ecal/ecal_subscriber_config.h b/ecal/core/include/ecal/config/subscriber.h similarity index 59% rename from ecal/core/include/ecal/ecal_subscriber_config.h rename to ecal/core/include/ecal/config/subscriber.h index 5e2221c8..9b283a4b 100644 --- a/ecal/core/include/ecal/ecal_subscriber_config.h +++ b/ecal/core/include/ecal/config/subscriber.h @@ -34,31 +34,36 @@ namespace eCAL { namespace SHM { - struct ECAL_API Configuration + struct Configuration { - bool enable = false; //!< enable layer + bool enable; //!< enable layer }; } namespace UDP { - struct ECAL_API Configuration + struct Configuration { - bool enable = false; //!< enable layer + bool enable; //!< enable layer }; } namespace TCP { - struct ECAL_API Configuration + struct Configuration { - bool enable = false; //!< enable layer + bool enable; //!< 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) + + size_t max_reconnections{}; //!< reconnection attemps the session will try to reconnect in (Default: 5) }; } - struct ECAL_API Configuration + struct Configuration { - Configuration(); + ECAL_API Configuration(); SHM::Configuration shm; UDP::Configuration udp; diff --git a/ecal/core/include/ecal/config/time.h b/ecal/core/include/ecal/config/time.h new file mode 100644 index 00000000..dbe62028 --- /dev/null +++ b/ecal/core/include/ecal/config/time.h @@ -0,0 +1,47 @@ +/* ========================= 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 ================================= +*/ + +/** + * @file time.h + * @brief eCAL time configuration +**/ + +#pragma once + +#include + +namespace eCAL +{ + namespace Time + { + 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: "") + }; + } +} + + diff --git a/ecal/core/include/ecal/config/transport_layer.h b/ecal/core/include/ecal/config/transport_layer.h new file mode 100644 index 00000000..fac354b5 --- /dev/null +++ b/ecal/core/include/ecal/config/transport_layer.h @@ -0,0 +1,74 @@ +/* =========================== 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. + * + * =========================== LICENSE ================================= + */ + +/** + * @file transport_layer.h + * @brief eCAL configuration for the transport layer +**/ + +// TODO PG: Deprecated when configuration is implemented in all modules? +#pragma once + +#include + +namespace eCAL +{ + namespace TransportLayer + { + namespace SHM + { + 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: "")*/ }; + } + + namespace UDPMC + { + 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)*/ + + bool npcap_enabled{}; //!< Enable to receive UDP traffic with the Npcap based receiver (Default: false) + }; + } + + 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{}; + }; + } +} \ 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 new file mode 100644 index 00000000..6f64cdf1 --- /dev/null +++ b/ecal/core/include/ecal/config/user_arguments.h @@ -0,0 +1,45 @@ +/* =========================== 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. + * + * =========================== LICENSE ================================= + */ + +/** + * @file user_arguments.h + * @brief Arguments given by the user via command line +**/ + +#pragma once + +#include +#include +#include + +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) + }; + } +} \ No newline at end of file diff --git a/ecal/core/include/ecal/ecal.h b/ecal/core/include/ecal/ecal.h index 43669cb8..0bfbc138 100644 --- a/ecal/core/include/ecal/ecal.h +++ b/ecal/core/include/ecal/ecal.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. @@ -42,3 +42,4 @@ #include #include #include +#include diff --git a/ecal/core/include/ecal/ecal_config.h b/ecal/core/include/ecal/ecal_config.h index 78ea92e5..7d0cc9cc 100644 --- a/ecal/core/include/ecal/ecal_config.h +++ b/ecal/core/include/ecal/ecal_config.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. @@ -23,117 +23,111 @@ #include #include #include +#include "ecal/config/configuration.h" #include //@{ namespace eCAL { + ECAL_API Configuration& GetConfiguration(); + namespace Config { - enum class UdpConfigVersion - { - V1 = 1, // Legacy - V2 = 2 - }; - ///////////////////////////////////// // common ///////////////////////////////////// - ECAL_API std::string GetLoadedEcalIniPath (); - ECAL_API int GetRegistrationTimeoutMs (); - ECAL_API int GetRegistrationRefreshMs (); + ECAL_API std::string GetLoadedEcalIniPath (); + ECAL_API int GetRegistrationTimeoutMs (); + ECAL_API int GetRegistrationRefreshMs (); ///////////////////////////////////// // network ///////////////////////////////////// - ECAL_API bool IsNetworkEnabled (); - ECAL_API UdpConfigVersion GetUdpMulticastConfigVersion (); - ECAL_API std::string GetUdpMulticastGroup (); - ECAL_API std::string GetUdpMulticastMask (); - ECAL_API int GetUdpMulticastPort (); - ECAL_API int GetUdpMulticastTtl (); + ECAL_API bool IsNetworkEnabled (); + ECAL_API bool IsShmRegistrationEnabled (); + ECAL_API Types::UdpConfigVersion GetUdpMulticastConfigVersion (); + ECAL_API std::string GetUdpMulticastGroup (); + ECAL_API std::string GetUdpMulticastMask (); + ECAL_API int GetUdpMulticastPort (); + ECAL_API int GetUdpMulticastTtl (); + + ECAL_API int GetUdpMulticastSndBufSizeBytes (); + ECAL_API int GetUdpMulticastRcvBufSizeBytes (); + + ECAL_API bool IsUdpMulticastJoinAllIfEnabled (); - ECAL_API int GetUdpMulticastSndBufSizeBytes (); - ECAL_API int GetUdpMulticastRcvBufSizeBytes (); + ECAL_API bool IsUdpMulticastRecEnabled (); + ECAL_API bool IsShmRecEnabled (); + ECAL_API bool IsTcpRecEnabled (); - ECAL_API bool IsUdpMulticastJoinAllIfEnabled (); + ECAL_API bool IsNpcapEnabled (); - ECAL_API bool IsUdpMulticastRecEnabled (); - ECAL_API bool IsShmRecEnabled (); - ECAL_API bool IsTcpRecEnabled (); + ECAL_API int GetTcpPubsubReaderThreadpoolSize (); + ECAL_API int GetTcpPubsubWriterThreadpoolSize (); + ECAL_API int GetTcpPubsubMaxReconnectionAttemps (); - ECAL_API bool IsNpcapEnabled (); + ECAL_API int GetTcpPubReaderThreadpoolSize (); + ECAL_API int GetTcpPubWriterThreadpoolSize (); - ECAL_API int GetTcpPubsubReaderThreadpoolSize (); - ECAL_API int GetTcpPubsubWriterThreadpoolSize (); - ECAL_API int GetTcpPubsubMaxReconnectionAttemps (); + ECAL_API int GetTcpSubReaderThreadpoolSize (); + ECAL_API int GetTcpSubWriterThreadpoolSize (); + ECAL_API int GetTcpSubMaxReconnectionAttemps (); - ECAL_API std::string GetHostGroupName (); + ECAL_API std::string GetHostGroupName (); ///////////////////////////////////// // time ///////////////////////////////////// - ECAL_API std::string GetTimesyncModuleName (); - + ECAL_API std::string GetTimesyncModuleName (); + ECAL_API std::string GetTimesyncModuleReplay (); + ///////////////////////////////////// // process ///////////////////////////////////// - ECAL_API std::string GetTerminalEmulatorCommand (); + ECAL_API std::string GetTerminalEmulatorCommand (); ///////////////////////////////////// // monitoring ///////////////////////////////////// - ECAL_API int GetMonitoringTimeoutMs (); - ECAL_API std::string GetMonitoringFilterExcludeList (); - ECAL_API std::string GetMonitoringFilterIncludeList (); - ECAL_API eCAL_Logging_Filter GetConsoleLogFilter (); - ECAL_API eCAL_Logging_Filter GetFileLogFilter (); - ECAL_API eCAL_Logging_Filter GetUdpLogFilter (); + ECAL_API int GetMonitoringTimeoutMs (); + ECAL_API std::string GetMonitoringFilterExcludeList (); + ECAL_API std::string GetMonitoringFilterIncludeList (); + ECAL_API eCAL_Logging_Filter GetConsoleLogFilter (); + ECAL_API eCAL_Logging_Filter GetFileLogFilter (); + ECAL_API eCAL_Logging_Filter GetUdpLogFilter (); ///////////////////////////////////// // sys ///////////////////////////////////// - ECAL_API std::string GetEcalSysFilterExcludeList (); + ECAL_API std::string GetEcalSysFilterExcludeList (); ///////////////////////////////////// // publisher ///////////////////////////////////// - ECAL_API TLayer::eSendMode GetPublisherShmMode (); - ECAL_API TLayer::eSendMode GetPublisherTcpMode (); - ECAL_API TLayer::eSendMode GetPublisherUdpMulticastMode (); - - ECAL_API size_t GetMemfileMinsizeBytes (); - ECAL_API size_t GetMemfileOverprovisioningPercentage (); - ECAL_API int GetMemfileAckTimeoutMs (); - ECAL_API bool IsMemfileZerocopyEnabled (); - ECAL_API size_t GetMemfileBufferCount (); - - ECAL_API bool IsTopicTypeSharingEnabled (); - ECAL_API bool IsTopicDescriptionSharingEnabled (); + ECAL_API bool IsTopicTypeSharingEnabled (); + ECAL_API bool IsTopicDescriptionSharingEnabled (); ///////////////////////////////////// // service ///////////////////////////////////// - ECAL_API bool IsServiceProtocolV0Enabled (); - ECAL_API bool IsServiceProtocolV1Enabled (); + ECAL_API bool IsServiceProtocolV0Enabled (); + ECAL_API bool IsServiceProtocolV1Enabled (); ///////////////////////////////////// // experimental ///////////////////////////////////// namespace Experimental { - ECAL_API bool IsShmMonitoringEnabled (); - ECAL_API bool IsNetworkMonitoringDisabled (); - ECAL_API size_t GetShmMonitoringQueueSize (); - ECAL_API std::string GetShmMonitoringDomain (); - ECAL_API bool GetDropOutOfOrderMessages (); + ECAL_API size_t GetShmMonitoringQueueSize (); + ECAL_API std::string GetShmMonitoringDomain (); + ECAL_API bool GetDropOutOfOrderMessages (); } } } diff --git a/ecal/core/include/ecal/ecal_core.h b/ecal/core/include/ecal/ecal_core.h index ce8aa1ed..a725191b 100644 --- a/ecal/core/include/ecal/ecal_core.h +++ b/ecal/core/include/ecal/ecal_core.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. @@ -31,6 +31,7 @@ #include #include +#include namespace eCAL { @@ -82,6 +83,17 @@ namespace eCAL **/ ECAL_API int Initialize(std::vector args_, const char *unit_name_ = nullptr, unsigned int components_ = Init::Default); + /** + * @brief Initialize eCAL API. + * + * @param config_ User defined configuration object. + * @param unit_name_ Defines the name of the eCAL unit. + * @param components_ Defines which component to initialize. + * + * @return Zero if succeeded, 1 if already initialized, -1 if failed. + **/ + ECAL_API int Initialize(eCAL::Configuration& config_, const char *unit_name_ = nullptr, unsigned int components_ = Init::Default); + /** * @brief Finalize eCAL API. * diff --git a/ecal/core/include/ecal/ecal_publisher.h b/ecal/core/include/ecal/ecal_publisher.h index 80c65143..c79f134b 100644 --- a/ecal/core/include/ecal/ecal_publisher.h +++ b/ecal/core/include/ecal/ecal_publisher.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. @@ -29,7 +29,8 @@ #include #include #include -#include +#include +#include #include #include @@ -193,7 +194,7 @@ namespace eCAL * * @return Number of bytes sent. **/ - ECAL_API size_t Send(const void* buf_, size_t len_, long long time_ = DEFAULT_TIME_ARGUMENT) const; + ECAL_API size_t Send(const void* buf_, size_t len_, long long time_ = DEFAULT_TIME_ARGUMENT); /** * @brief Send a message to all subscribers. @@ -203,7 +204,7 @@ namespace eCAL * * @return Number of bytes sent. **/ - ECAL_API size_t Send(CPayloadWriter& payload_, long long time_ = DEFAULT_TIME_ARGUMENT) const; + ECAL_API size_t Send(CPayloadWriter& payload_, long long time_ = DEFAULT_TIME_ARGUMENT); /** * @brief Send a message to all subscribers. @@ -213,7 +214,7 @@ namespace eCAL * * @return Number of bytes sent. **/ - ECAL_API size_t Send(const std::string& s_, long long time_ = DEFAULT_TIME_ARGUMENT) const; + ECAL_API size_t Send(const std::string& s_, long long time_ = DEFAULT_TIME_ARGUMENT); /** * @brief Add callback function for publisher events. diff --git a/ecal/core/include/ecal/ecal_subscriber.h b/ecal/core/include/ecal/ecal_subscriber.h index 0ed5ea9f..71b78e92 100644 --- a/ecal/core/include/ecal/ecal_subscriber.h +++ b/ecal/core/include/ecal/ecal_subscriber.h @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include @@ -241,6 +241,13 @@ namespace eCAL **/ ECAL_API bool IsCreated() const {return(m_created);} + /** + * @brief Query if the subscriber is published. + * + * @return true if published, false if not. + **/ + ECAL_API bool IsPublished() const; + /** * @brief Query the number of publishers. * diff --git a/ecal/core/include/ecal/msg/capnproto/publisher.h b/ecal/core/include/ecal/msg/capnproto/publisher.h index bf6b3d6e..60192fd4 100644 --- a/ecal/core/include/ecal/msg/capnproto/publisher.h +++ b/ecal/core/include/ecal/msg/capnproto/publisher.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. diff --git a/ecal/core/include/ecal/msg/flatbuffers/publisher.h b/ecal/core/include/ecal/msg/flatbuffers/publisher.h index 6e9e8367..8e6cf3a3 100644 --- a/ecal/core/include/ecal/msg/flatbuffers/publisher.h +++ b/ecal/core/include/ecal/msg/flatbuffers/publisher.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. diff --git a/ecal/core/include/ecal/msg/messagepack/publisher.h b/ecal/core/include/ecal/msg/messagepack/publisher.h index 70a7298a..5d7904c4 100644 --- a/ecal/core/include/ecal/msg/messagepack/publisher.h +++ b/ecal/core/include/ecal/msg/messagepack/publisher.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. diff --git a/ecal/core/include/ecal/msg/protobuf/dynamic_json_subscriber.h b/ecal/core/include/ecal/msg/protobuf/dynamic_json_subscriber.h index bf6a5305..aa0d2369 100644 --- a/ecal/core/include/ecal/msg/protobuf/dynamic_json_subscriber.h +++ b/ecal/core/include/ecal/msg/protobuf/dynamic_json_subscriber.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,6 +26,7 @@ #include #include +#include #include #include @@ -33,6 +34,7 @@ #include #include #include +#include #ifdef _MSC_VER #pragma warning(push, 0) // disable proto warnings @@ -54,216 +56,106 @@ namespace eCAL { - namespace protobuf - { - /** - * @brief eCAL dynamic protobuf to json subscriber. - **/ - class CDynamicJSONSubscriber + namespace internal { - public: - /** - * @brief Constructor. - **/ - CDynamicJSONSubscriber(); - - /** - * @brief Constructor. - * - * @param topic_name_ Unique topic name. - **/ - explicit CDynamicJSONSubscriber(const std::string& topic_name_); - - /** - * @brief Destructor. - **/ - ~CDynamicJSONSubscriber(); - - CDynamicJSONSubscriber(const CDynamicJSONSubscriber&) = delete; - CDynamicJSONSubscriber& operator=(const CDynamicJSONSubscriber&) = delete; - CDynamicJSONSubscriber(CDynamicJSONSubscriber&& rhs) = delete; - CDynamicJSONSubscriber& operator=(CDynamicJSONSubscriber&& rhs) = delete; - - /** - * @brief Creates this object. - * - * @param topic_name_ Unique topic name. - * - * @return true if it succeeds, false if it fails. - **/ - void Create(const std::string& topic_name_); - - /** - * @brief Destroys this object. - * - * @return true if it succeeds, false if it fails. - **/ - void Destroy(); - - /** - * @brief Query if this object is created. - * - * @return true if created, false if not. - **/ - bool IsCreated() const { return(m_created); } - - /** - * @brief Add callback function for incoming receives. - * - * @param callback_ The callback function to add. - * - * @return True if succeeded, false if not. - **/ - bool AddReceiveCallback(ReceiveCallbackT callback_); - - /** - * @brief Remove callback function for incoming receives. - * - * @return True if succeeded, false if not. - **/ - bool RemReceiveCallback(); - - protected: - void OnReceive(const char* topic_name_, const struct eCAL::SReceiveCallbackData* data_); - - bool m_created; - std::unique_ptr m_msg_decoder; - std::string m_msg_string; - eCAL::CSubscriber m_msg_sub; - ReceiveCallbackT m_msg_callback; - - std::string m_topic_type; - std::string m_topic_type_full; - - std::string m_topic_desc; - std::shared_ptr m_resolver; - google::protobuf::DescriptorPool m_descriptor_pool; - }; - /** @example proto_dyn_json.cpp - * This is an example how to use CDynamicJSONSubscriber to receive dynamic google::protobuf data as a JSON string with eCAL. - */ - - inline CDynamicJSONSubscriber::CDynamicJSONSubscriber() : - m_created(false), - m_msg_decoder(nullptr) - {} - - inline CDynamicJSONSubscriber::CDynamicJSONSubscriber(const std::string& topic_name_) : - m_created(false), - m_msg_decoder(nullptr) - { - Create(topic_name_); - } - - inline CDynamicJSONSubscriber::~CDynamicJSONSubscriber() - { - Destroy(); - } - - inline void CDynamicJSONSubscriber::Create(const std::string& topic_name_) - { - if (m_created) return; - - // create message decoder - m_msg_decoder = std::make_unique(); - - // create subscriber - m_msg_sub.Create(topic_name_); - - // add callback - m_msg_sub.AddReceiveCallback(std::bind(&CDynamicJSONSubscriber::OnReceive, this, std::placeholders::_1, std::placeholders::_2)); - - m_created = true; - } - - inline void CDynamicJSONSubscriber::Destroy() - { - if (!m_created) return; - - // remove callback - m_msg_sub.RemReceiveCallback(); - - // destroy subscriber - m_msg_sub.Destroy(); - - // delete message decoder - m_msg_decoder.reset(); - - m_created = false; - } + class ProtobufDynamicJSONDeserializer + { + public: + std::string Deserialize(const void* buffer_, size_t size_, const SDataTypeInformation& datatype_info_) + { + google::protobuf::util::JsonOptions options; +#if GOOGLE_PROTOBUF_VERSION >= 5026000 + options.always_print_fields_with_no_presence = true; +#else + options.always_print_primitive_fields = true; +#endif - inline bool CDynamicJSONSubscriber::AddReceiveCallback(ReceiveCallbackT callback_) - { - if (!m_created) return false; - m_msg_callback = callback_; - return true; - } + std::string binary_input; + binary_input.assign(static_cast(buffer_), static_cast(size_)); + std::string json_output; + auto status = google::protobuf::util::BinaryToJsonString(GetTypeResolver(datatype_info_).get(), GetQualifiedTopicType(datatype_info_), binary_input, &json_output, options); + if (status.ok()) + { + return json_output; + } + else + { + throw new DynamicReflectionException("Error deserializing Protobuf data to json object."); + } + } - inline bool CDynamicJSONSubscriber::RemReceiveCallback() - { - if (!m_created) return false; - m_msg_callback = nullptr; - return true; - } + private: + std::shared_ptr GetTypeResolver(const SDataTypeInformation& datatype_info_) + { + auto schema = m_type_resolver_map.find(datatype_info_); + if (schema == m_type_resolver_map.end()) + { + m_type_resolver_map[datatype_info_] = CreateTypeResolver(datatype_info_); + } + return m_type_resolver_map[datatype_info_]; + } - inline void CDynamicJSONSubscriber::OnReceive(const char* topic_name_, const struct eCAL::SReceiveCallbackData* data_) - { - if (m_msg_string.empty()) - { - // get topic type - SDataTypeInformation topic_info; - //nodiscard??? - eCAL::Util::GetTopicDataTypeInformation(topic_name_, topic_info); - m_topic_type_full = topic_info.name; - m_topic_type = m_topic_type_full.substr(m_topic_type_full.find_last_of('.') + 1, m_topic_type_full.size()); - m_topic_type_full = "/" + m_topic_type_full; + std::shared_ptr CreateTypeResolver(const SDataTypeInformation& datatype_info_) + { + std::string unqualified_topic_type = GetUnqualifiedTopicType(datatype_info_); + + if (StrEmptyOrNull(unqualified_topic_type)) + { + throw DynamicReflectionException("ProtobufDynamicJSONDeserializer: Could not get type"); + } + + std::string topic_desc = datatype_info_.descriptor; + if (StrEmptyOrNull(topic_desc)) + { + throw DynamicReflectionException("ProtobufDynamicJSONDeserializer: Could not get description for type" + std::string(unqualified_topic_type)); + } + + google::protobuf::FileDescriptorSet proto_desc; + proto_desc.ParseFromString(topic_desc); + std::string error_s; + const std::shared_ptr msg(m_dynamic_decoder.GetProtoMessageFromDescriptorSet(proto_desc, unqualified_topic_type, error_s)); + std::shared_ptr resolver{ google::protobuf::util::NewTypeResolverForDescriptorPool("", m_dynamic_decoder.GetDescriptorPool()) }; + + if (resolver == nullptr) + { + std::stringstream s; + s << "ProtobufDynamicJSONDeserializer: Message of type " + unqualified_topic_type << " could not be decoded" << std::endl; + s << error_s; + throw DynamicReflectionException(s.str()); + } + + return resolver; + } - if (m_topic_type.empty()) + std::string GetQualifiedTopicType(const SDataTypeInformation& data_type_info_) { - std::cout << "could not get type for topic " << topic_name_ << std::endl; - return; + return "/" + data_type_info_.name; } - // get topic description - m_topic_desc = topic_info.descriptor; - if (m_topic_desc.empty()) + std::string GetUnqualifiedTopicType(const SDataTypeInformation& data_type_info_) { - std::cout << "could not get description for topic " << topic_name_ << std::endl; - return; + const auto& type_name = data_type_info_.name; + return type_name.substr(type_name.find_last_of('.') + 1, type_name.size()); } - std::string error_s; - google::protobuf::FileDescriptorSet proto_desc; - proto_desc.ParseFromString(m_topic_desc); - const std::shared_ptr msg(m_msg_decoder->GetProtoMessageFromDescriptorSet(proto_desc, m_topic_type, error_s)); - m_resolver.reset(google::protobuf::util::NewTypeResolverForDescriptorPool("", m_msg_decoder->GetDescriptorPool())); - } - // decode message and execute callback - //if(msg_callback && msg_ptr && msg_ptr->ParseFromArray(data_->buf, data_->size)) - if (m_msg_callback) - { + eCAL::protobuf::CProtoDynDecoder m_dynamic_decoder; + std::map> m_type_resolver_map; + }; + } - google::protobuf::util::JsonOptions options; -#if GOOGLE_PROTOBUF_VERSION >= 5026000 - options.always_print_fields_with_no_presence = true; -#else - options.always_print_primitive_fields = true; -#endif + namespace protobuf + { + /** + * @brief eCAL protobuf dynamic subscriber class. + * + * Dynamic subscriber class for protobuf messages. For details see documentation of CDynamicMessageSubscriber class. + * + **/ + using CDynamicJSONSubscriber = CDynamicMessageSubscriber; - std::string binary_input; - binary_input.assign(static_cast(data_->buf), static_cast(data_->size)); - m_msg_string.clear(); - auto status = google::protobuf::util::BinaryToJsonString(m_resolver.get(), m_topic_type_full, binary_input, &m_msg_string, options); - if (status.ok()) - { - SReceiveCallbackData cb_data; - cb_data.buf = (void*)m_msg_string.c_str(); - cb_data.size = (long)m_msg_string.size(); - cb_data.time = data_->time; - m_msg_callback(topic_name_, &cb_data); - } - } + /** @example proto_dyn_rec.cpp + * This is an example how to use eCAL::protobuf::CDynamicSubscriber to receive dynamic protobuf data with eCAL. To receive the data, see @ref proto_dyn_rec.cpp . + */ } - } } diff --git a/ecal/core/include/ecal/msg/protobuf/dynamic_publisher.h b/ecal/core/include/ecal/msg/protobuf/dynamic_publisher.h index 1a7ca4f2..717ab81f 100644 --- a/ecal/core/include/ecal/msg/protobuf/dynamic_publisher.h +++ b/ecal/core/include/ecal/msg/protobuf/dynamic_publisher.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. diff --git a/ecal/core/include/ecal/msg/protobuf/publisher.h b/ecal/core/include/ecal/msg/protobuf/publisher.h index e5832928..b6b79bd8 100644 --- a/ecal/core/include/ecal/msg/protobuf/publisher.h +++ b/ecal/core/include/ecal/msg/protobuf/publisher.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. diff --git a/ecal/core/include/ecal/msg/publisher.h b/ecal/core/include/ecal/msg/publisher.h index 5f3b0625..74e993c6 100644 --- a/ecal/core/include/ecal/msg/publisher.h +++ b/ecal/core/include/ecal/msg/publisher.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. diff --git a/ecal/core/include/ecal/msg/string/publisher.h b/ecal/core/include/ecal/msg/string/publisher.h index f1d45d58..03cbf886 100644 --- a/ecal/core/include/ecal/msg/string/publisher.h +++ b/ecal/core/include/ecal/msg/string/publisher.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. diff --git a/ecal/core/include/ecal/types/ecal_custom_data_types.h b/ecal/core/include/ecal/types/ecal_custom_data_types.h new file mode 100644 index 00000000..8162c099 --- /dev/null +++ b/ecal/core/include/ecal/types/ecal_custom_data_types.h @@ -0,0 +1,104 @@ +/* =========================== 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. + * + * =========================== LICENSE ================================= + */ + +/** + * @file ecal_custom_types.h + * @brief eCAL custom types for configuration declarations +**/ + +#pragma once + +#include "ecal/ecal_os.h" + +#include +#include +#include +#include + +namespace eCAL +{ + namespace Types + { + /** + * @brief Class for evaluation and storing an IPv4/IPv6 address. + * Invalid addresses: 255.255.255.255, 127.0.0.1, 0.0.0.0 + * + * @param ip_address_ The IP address as std::string. + * + * @throws std::invalid_argument exception. + **/ + class IpAddressV4 + { + public: + ECAL_API IpAddressV4(); + ECAL_API IpAddressV4(const std::string& ip_address_); + + std::string Get() const; + + ECAL_API IpAddressV4& operator=(const std::string& ip_string); + ECAL_API operator std::string(); + + private: + ECAL_API void validateIpString(const std::string& ip_address_); + ECAL_API static void throwException(const std::string& ip_address_ = std::string("")); + + std::string m_ip_address{}; + }; + + /** + * @brief Template class to specify sizes with a concrete minimum, maximum and step size definition. + * + * @tparam MIN Optional minimum possible size. Default: 0 + * @tparam STEP Optional step size. Default: 1 + * @tparam MAX Optional maximum possible size. Default: std::numeric_limits::max() + * + * @param size_ Optional size value. If not set, ConstrainedInteger will return the MIN value. + * + * @throws std::invalid_argument exception. + **/ + template::max()> + class ConstrainedInteger + { + public: + ConstrainedInteger(int size_ = MIN) + { + if (size_ >= MIN && size_ <= MAX && size_ % STEP == 0 && MAX >= MIN) + { + m_size = size_; + } + else + { + throw std::invalid_argument("[ConstrainedInteger] Faulty size configuration or assignment. MIN: " + std::to_string(MIN) + " MAX: " + std::to_string(MAX) + " STEP: " + std::to_string(STEP) + " VALUE:" + std::to_string(size_)); + } + }; + + operator int() const { return m_size; }; + bool operator==(const ConstrainedInteger& other) const { return this->m_size == other; }; + + private: + int m_size{}; + }; + + enum class UdpConfigVersion + { + V1 = 1, + V2 = 2 + }; + } +} \ 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 new file mode 100644 index 00000000..b2567657 --- /dev/null +++ b/ecal/core/src/config/ecal_cmd_parser.cpp @@ -0,0 +1,254 @@ +#include "config/ecal_cmd_parser.h" + +#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" +#endif + +#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 +{ + namespace Config + { + CmdParser::CmdParser() + : m_dump_config{false} + {} + + CmdParser::CmdParser(std::vector& arguments_) + : CmdParser() + { + parseArguments(arguments_); + } + + void CmdParser::parseArguments(std::vector& arguments_) + { +#if ECAL_CORE_COMMAND_LINE + if (!arguments_.empty()) + { + // define command line object + TCLAP::CmdLine cmd("", ' ', ECAL_VERSION); + + // 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::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); + + // parse command line + cmd.parse(arguments_); + + // set globals + if (dump_config_arg.isSet()) + { + m_dump_config = true; + } + 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); + } + } +#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 new file mode 100644 index 00000000..dd1ed957 --- /dev/null +++ b/ecal/core/src/config/ecal_cmd_parser.h @@ -0,0 +1,66 @@ +/* ========================= 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. +**/ + +#pragma once + +#include + +#include +#include +#include + +namespace eCAL +{ + namespace Config + { + /** + * @brief Class for parsing and storing command line arguments and their values. + * Defaults as empty strings, vectors and false booleans. + * + * @param argc_ Number of arguments + * @param argv_ Array of arguments + * + **/ + class CmdParser + { + public: + CmdParser(std::vector& arguments_); + CmdParser(); + + void parseArguments(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; + }; + } +} \ No newline at end of file diff --git a/ecal/core/src/config/ecal_config.cpp b/ecal/core/src/config/ecal_config.cpp index ffb4543d..61a28ae3 100644 --- a/ecal/core/src/config/ecal_config.cpp +++ b/ecal/core/src/config/ecal_config.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,99 +89,89 @@ namespace eCAL // common ///////////////////////////////////// - ECAL_API std::string GetLoadedEcalIniPath () { return g_default_ini_file; } - ECAL_API int GetRegistrationTimeoutMs () { return eCALPAR(CMN, REGISTRATION_TO); } - ECAL_API int GetRegistrationRefreshMs () { return eCALPAR(CMN, REGISTRATION_REFRESH); } + ECAL_API std::string GetLoadedEcalIniPath () { return GetConfiguration().GetIniFilePath(); } + ECAL_API int GetRegistrationTimeoutMs () { return GetConfiguration().registration.getTimeoutMS(); } + ECAL_API int GetRegistrationRefreshMs () { return GetConfiguration().registration.getRefreshMS(); } ///////////////////////////////////// // network ///////////////////////////////////// - ECAL_API bool IsNetworkEnabled () { return eCALPAR(NET, ENABLED); } + ECAL_API bool IsNetworkEnabled () { return GetConfiguration().registration.network_enabled; } + ECAL_API bool IsShmRegistrationEnabled () { return GetConfiguration().registration.shm_registration_enabled; } - ECAL_API UdpConfigVersion GetUdpMulticastConfigVersion() - { - const std::string udp_config_version_string = eCALPAR(NET, UDP_MULTICAST_CONFIG_VERSION); - if (udp_config_version_string == "v1") - return UdpConfigVersion::V1; - if (udp_config_version_string == "v2") - return UdpConfigVersion::V2; - // TODO: Log error. However not sure if logging is initialized at this place. - return UdpConfigVersion::V1; - } + 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 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 std::string GetUdpMulticastGroup () { return eCALPAR(NET, UDP_MULTICAST_GROUP); } - ECAL_API std::string GetUdpMulticastMask () { return eCALPAR(NET, UDP_MULTICAST_MASK); } - ECAL_API int GetUdpMulticastPort () { return eCALPAR(NET, UDP_MULTICAST_PORT); } - ECAL_API int GetUdpMulticastTtl () { return eCALPAR(NET, UDP_MULTICAST_TTL); } + 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 int GetUdpMulticastSndBufSizeBytes () { return eCALPAR(NET, UDP_MULTICAST_SNDBUF); } - ECAL_API int GetUdpMulticastRcvBufSizeBytes () { return eCALPAR(NET, UDP_MULTICAST_RCVBUF); } - ECAL_API bool IsUdpMulticastJoinAllIfEnabled () { return eCALPAR(NET, UDP_MULTICAST_JOIN_ALL_IF_ENABLED); } + ECAL_API bool IsNpcapEnabled () { return GetConfiguration().transport_layer.mc_options.npcap_enabled; } - ECAL_API bool IsUdpMulticastRecEnabled () { return eCALPAR(NET, UDP_MC_REC_ENABLED); } - ECAL_API bool IsShmRecEnabled () { return eCALPAR(NET, SHM_REC_ENABLED); } - ECAL_API bool IsTcpRecEnabled () { return eCALPAR(NET, TCP_REC_ENABLED); } + 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 IsNpcapEnabled () { return eCALPAR(NET, NPCAP_ENABLED); } + 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 int GetTcpPubsubReaderThreadpoolSize () { return eCALPAR(NET, TCP_PUBSUB_NUM_EXECUTOR_READER); } - ECAL_API int GetTcpPubsubWriterThreadpoolSize () { return eCALPAR(NET, TCP_PUBSUB_NUM_EXECUTOR_WRITER); } - ECAL_API int GetTcpPubsubMaxReconnectionAttemps () { return eCALPAR(NET, TCP_PUBSUB_MAX_RECONNECTIONS); } + // 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 std::string GetHostGroupName () { return eCALPAR(NET, HOST_GROUP_NAME); } + ECAL_API std::string GetHostGroupName () { return GetConfiguration().transport_layer.shm_options.host_group_name; } ///////////////////////////////////// // time ///////////////////////////////////// - ECAL_API std::string GetTimesyncModuleName () { return eCALPAR(TIME, SYNC_MOD_RT); } + ECAL_API std::string GetTimesyncModuleName () { return GetConfiguration().timesync.timesync_module_rt; } + ECAL_API std::string GetTimesyncModuleReplay () { return GetConfiguration().timesync.timesync_module_replay; } ///////////////////////////////////// // process ///////////////////////////////////// - ECAL_API std::string GetTerminalEmulatorCommand () { return eCALPAR(PROCESS, TERMINAL_EMULATOR); } + ECAL_API std::string GetTerminalEmulatorCommand () { return GetConfiguration().application.startup.terminal_emulator; } ///////////////////////////////////// // monitoring ///////////////////////////////////// - ECAL_API int GetMonitoringTimeoutMs () { return eCALPAR(MON, TIMEOUT); } - ECAL_API std::string GetMonitoringFilterExcludeList () { return eCALPAR(MON, FILTER_EXCL); } - ECAL_API std::string GetMonitoringFilterIncludeList () { return eCALPAR(MON, FILTER_INCL); } - ECAL_API eCAL_Logging_Filter GetConsoleLogFilter () { return ParseLogLevel(eCALPAR(MON, LOG_FILTER_CON)); } - ECAL_API eCAL_Logging_Filter GetFileLogFilter () { return ParseLogLevel(eCALPAR(MON, LOG_FILTER_FILE)); } - ECAL_API eCAL_Logging_Filter GetUdpLogFilter () { return ParseLogLevel(eCALPAR(MON, LOG_FILTER_UDP)); } + ECAL_API int GetMonitoringTimeoutMs () { return GetConfiguration().monitoring.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; } ///////////////////////////////////// // sys ///////////////////////////////////// - ECAL_API std::string GetEcalSysFilterExcludeList () { return eCALPAR(SYS, FILTER_EXCL); } + ECAL_API std::string GetEcalSysFilterExcludeList () { return GetConfiguration().application.sys.filter_excl; } ///////////////////////////////////// // publisher ///////////////////////////////////// - - ECAL_API TLayer::eSendMode GetPublisherUdpMulticastMode () { return TLayer::eSendMode(eCALPAR(PUB, USE_UDP_MC)); } - ECAL_API TLayer::eSendMode GetPublisherShmMode () { return TLayer::eSendMode(eCALPAR(PUB, USE_SHM)); } - ECAL_API TLayer::eSendMode GetPublisherTcpMode () { return TLayer::eSendMode(eCALPAR(PUB, USE_TCP)); } - - ECAL_API size_t GetMemfileMinsizeBytes () { return static_cast(eCALPAR(PUB, MEMFILE_MINSIZE)); } - ECAL_API size_t GetMemfileOverprovisioningPercentage () { return static_cast(eCALPAR(PUB, MEMFILE_RESERVE)); } - ECAL_API int GetMemfileAckTimeoutMs () { return eCALPAR(PUB, MEMFILE_ACK_TO); } - ECAL_API bool IsMemfileZerocopyEnabled () { return (eCALPAR(PUB, MEMFILE_ZERO_COPY) != 0); } - ECAL_API size_t GetMemfileBufferCount () { return static_cast(eCALPAR(PUB, MEMFILE_BUF_COUNT)); } - - ECAL_API bool IsTopicTypeSharingEnabled () { return (eCALPAR(PUB, SHARE_TTYPE) != 0); } - ECAL_API bool IsTopicDescriptionSharingEnabled () { return (eCALPAR(PUB, SHARE_TDESC) != 0); } + ECAL_API bool IsTopicTypeSharingEnabled () { return GetConfiguration().registration.share_ttype; } + ECAL_API bool IsTopicDescriptionSharingEnabled () { return GetConfiguration().registration.share_tdesc; } ///////////////////////////////////// // service ///////////////////////////////////// - ECAL_API bool IsServiceProtocolV0Enabled () { return (eCALPAR(SERVICE, PROTOCOL_V0) != 0); } - ECAL_API bool IsServiceProtocolV1Enabled () { return (eCALPAR(SERVICE, PROTOCOL_V1) != 0); } + ECAL_API bool IsServiceProtocolV0Enabled () { return GetConfiguration().service.protocol_v0; } + ECAL_API bool IsServiceProtocolV1Enabled () { return GetConfiguration().service.protocol_v1; } ///////////////////////////////////// // experimemtal @@ -189,11 +179,9 @@ namespace eCAL namespace Experimental { - ECAL_API bool IsShmMonitoringEnabled () { return eCALPAR(EXP, SHM_MONITORING_ENABLED); } - ECAL_API bool IsNetworkMonitoringDisabled () { return eCALPAR(EXP, NETWORK_MONITORING_DISABLED); } - ECAL_API size_t GetShmMonitoringQueueSize () { return static_cast(eCALPAR(EXP, SHM_MONITORING_QUEUE_SIZE)); } - ECAL_API std::string GetShmMonitoringDomain () { return eCALPAR(EXP, SHM_MONITORING_DOMAIN);} - ECAL_API bool GetDropOutOfOrderMessages () { return eCALPAR(EXP, DROP_OUT_OF_ORDER_MESSAGES); } + 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; } } } } diff --git a/ecal/core/src/config/ecal_config_initializer.cpp b/ecal/core/src/config/ecal_config_initializer.cpp new file mode 100644 index 00000000..6c838620 --- /dev/null +++ b/ecal/core/src/config/ecal_config_initializer.cpp @@ -0,0 +1,262 @@ +/* ========================= 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 Function definitions for setting default config values +**/ + +#include "ecal/ecal_config.h" + +#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" + +#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) + { + std::string::size_type pos = 0; + std::string::size_type 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(str.data() + lastPos, pos - lastPos); + } + break; + } + else + { + if (pos != lastPos || !trimEmpty) + { + tokens.emplace_back(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 +{ + void Configuration::InitConfig(std::string ini_path_ /*= std::string("")*/) + { + CConfig iniConfig; + if (!command_line_arguments.config_keys.empty()) + iniConfig.OverwriteKeys(command_line_arguments.config_keys); + + if (!ini_path_.empty()) + { + iniConfig.AddFile(ini_path_); + ecal_ini_file_path = ini_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); + + 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; + + // 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); + + 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")); + }; + + Configuration::Configuration(int argc_ , char **argv_) + { + std::vector arguments; + if (argc_ > 0 && argv_ != nullptr) + { + for (size_t i = 0; i < static_cast(argc_); ++i) + if (argv_[i] != nullptr) + arguments.emplace_back(argv_[i]); + } + Init(arguments); + } + + Configuration::Configuration(std::vector& args_) + { + Init(args_); + } + + void Configuration::Init(std::vector& arguments_) + { + Config::CmdParser parser(arguments_); + + 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(); + + InitConfig(command_line_arguments.specified_config); + } + + void Configuration::InitConfigWithDefaultIni() + { + InitConfig(g_default_ini_file); + } + + Configuration::Configuration() + : Configuration(0, nullptr) + { + InitConfig(); + } + + std::string Configuration::GetIniFilePath() + { + return ecal_ini_file_path; + } + + Configuration& GetConfiguration() + { + return g_ecal_configuration; + }; +} \ 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 index cefe2296..7b4be4de 100644 --- a/ecal/core/src/config/ecal_config_reader.cpp +++ b/ecal/core/src/config/ecal_config_reader.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. @@ -292,9 +292,33 @@ namespace eCAL void OverwriteKeys(const std::vector& key_vec_) { m_overwrite_keys = key_vec_; + OverwriteKeysNow(); } - void AddFile(std::string& file_name_) + 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)) @@ -321,25 +345,9 @@ namespace eCAL file_name_ = cfg_fname; } - // 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); + OverwriteKeysNow(); - 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 << "."; - } - } + return loaded; } protected: std::vector m_overwrite_keys; @@ -379,9 +387,9 @@ namespace eCAL m_impl->OverwriteKeys(key_vec_); } - void CConfig::AddFile(std::string& ini_file_) + bool CConfig::AddFile(std::string& ini_file_) { - m_impl->AddFile(ini_file_); + return m_impl->AddFile(ini_file_); } bool CConfig::Validate() @@ -444,24 +452,4 @@ namespace eCAL { return m_impl->GetValue(section_.c_str(), key_.c_str(), default_); } - - bool CfgGetBool(const std::string& section_, const std::string& key_, bool default_ /*= false*/) - { - return g_config()->get(section_, key_, default_); - } - - int CfgGetInt(const std::string& section_, const std::string& key_, int default_ /*= 0*/) - { - return g_config()->get(section_, key_, default_); - } - - double CfgGetDouble(const std::string& section_, const std::string& key_, double default_ /*= 0.0*/) - { - return g_config()->get(section_, key_, default_); - } - - std::string CfgGetString(const std::string& section_, const std::string& key_, const char* default_ /*= ""*/) - { - return g_config()->get(section_, key_, default_); - } } diff --git a/ecal/core/src/config/ecal_config_reader.h b/ecal/core/src/config/ecal_config_reader.h index d1bbca0a..a08fbea3 100644 --- a/ecal/core/src/config/ecal_config_reader.h +++ b/ecal/core/src/config/ecal_config_reader.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. @@ -39,7 +39,7 @@ namespace eCAL virtual ~CConfig(); void OverwriteKeys(const std::vector& key_vec_); - void AddFile(std::string& ini_file_); + bool AddFile(std::string& ini_file_); bool Validate(); @@ -54,9 +54,4 @@ namespace eCAL private: std::unique_ptr m_impl; }; - - ECAL_API bool CfgGetBool (const std::string& section_, const std::string& key_, bool default_ = false); - ECAL_API int CfgGetInt (const std::string& section_, const std::string& key_, int default_ = 0); - ECAL_API double CfgGetDouble(const std::string& section_, const std::string& key_, double default_ = 0.0); - ECAL_API std::string CfgGetString(const std::string& section_, const std::string& key_, const char* default_ = ""); } diff --git a/ecal/core/src/ecal.cpp b/ecal/core/src/ecal.cpp index 7fa088e7..03c2e1a4 100644 --- a/ecal/core/src/ecal.cpp +++ b/ecal/core/src/ecal.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. @@ -24,6 +24,7 @@ #include "ecal_def.h" #include "ecal_event.h" #include "ecal_globals.h" +#include "config/ecal_cmd_parser.h" #include #include @@ -99,116 +100,71 @@ namespace eCAL **/ int Initialize(int argc_ , char **argv_, const char *unit_name_, unsigned int components_) { - bool dump_config(false); - std::vector config_keys; - -#if ECAL_CORE_COMMAND_LINE - if ((argc_ > 0) && (argv_ != nullptr)) - { - // define command line object - TCLAP::CmdLine cmd("", ' ', ECAL_VERSION); - - // 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::UnlabeledMultiArg dummy_arg("__dummy__", "Dummy", false, ""); // Dummy arg to eat all unrecognized arguments + eCAL::Configuration config(argc_, argv_); + + // Default behaviour: If not specified, try to use the default ini file + if (config.GetIniFilePath().empty()) + config.InitConfigWithDefaultIni(); - cmd.add(dump_config_arg); - cmd.add(default_ini_file_arg); - cmd.add(set_config_key_arg); - cmd.add(dummy_arg); + return Initialize(config, unit_name_, components_); + } - CustomTclap::AdvancedTclapOutput advanced_tclap_output(&std::cout, 75); - advanced_tclap_output.setArgumentHidden(&dummy_arg, true); - cmd.setOutput(&advanced_tclap_output); + /** + * @brief Initialize eCAL API. + * + * @param args_ Vector of config arguments to overwrite (["arg1", "value1", "arg2", "arg3", "value3" ..]). + * @param unit_name_ Defines the name of the eCAL unit. + * @param components_ Defines which component to initialize. + * + * @return Zero if succeeded, 1 if already initialized, -1 if failed. + **/ + 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(); - // parse command line - cmd.parse(argc_, argv_); + return Initialize(config, unit_name_, components_); + } - // set globals - if (dump_config_arg.isSet()) - { - dump_config = true; - } - if (default_ini_file_arg.isSet()) - { - g_default_ini_file = default_ini_file_arg.getValue(); - } - if (set_config_key_arg.isSet()) - { - config_keys = set_config_key_arg.getValue(); - } + /** + * @brief Initialize eCAL API. + * + * @param config_ User defined configuration object. + * @param unit_name_ Defines the name of the eCAL unit. + * @param components_ Defines which component to initialize. + * + * @return Zero if succeeded, 1 if already initialized, -1 if failed. + **/ + int Initialize(eCAL::Configuration& config_, const char *unit_name_ /*= nullptr*/, unsigned int components_ /*= Init::Default*/) + { + if (g_globals() == nullptr) + { + InitGlobals(); } -#endif + + g_ecal_configuration = config_; - // first call - if (g_globals_ctx == nullptr) + if (unit_name_ != nullptr) { - g_globals_ctx = new CGlobals; - - if(unit_name_ != nullptr) g_unit_name = unit_name_; - if (g_unit_name.empty()) - { - g_unit_name = Process::GetProcessName(); -#ifdef ECAL_OS_WINDOWS - size_t p = g_unit_name.rfind('\\'); - if (p != std::string::npos) - { - g_unit_name = g_unit_name.substr(p+1); - } - p = g_unit_name.rfind('.'); - if (p != std::string::npos) - { - g_unit_name = g_unit_name.substr(0, p); - } -#endif -#ifdef ECAL_OS_LINUX - size_t p = g_unit_name.rfind('/'); - if (p != std::string::npos) - { - g_unit_name = g_unit_name.substr(p + 1); - } -#endif - } - - if (argv_ != nullptr) - { - for (size_t i = 0; i < static_cast(argc_); ++i) if (argv_[i] != nullptr) g_task_parameter.emplace_back(argv_[i]); - } + SetGlobalUnitName(unit_name_); } + g_globals_ctx_ref_cnt++; - // (post)initialize single components - const int success = g_globals()->Initialize(components_, &config_keys); + // (post)initialize single components + const int success = g_globals()->Initialize(components_, &GetConfiguration().command_line_arguments.config_keys); - // print out configuration - if (dump_config) + if (config_.command_line_arguments.dump_config) { Process::DumpConfig(); } - + return success; } - /** - * @brief Initialize eCAL API. - * - * @param args_ Vector of config arguments to overwrite (["arg1", "value1", "arg2", "arg3", "value3" ..]). - * @param unit_name_ Defines the name of the eCAL unit. - * @param components_ Defines which component to initialize. - * - * @return Zero if succeeded, 1 if already initialized, -1 if failed. - **/ - int Initialize(std::vector args_, const char *unit_name_, unsigned int components_) //-V826 - { - args_.emplace(args_.begin(), eCAL::Process::GetProcessName()); - std::vector argv(args_.size()); - std::transform(args_.begin(), args_.end(), argv.begin(), [](std::string& s) {return s.c_str();}); - return Initialize(static_cast(argv.size()), const_cast(argv.data()), unit_name_, components_); - } - /** * @brief Check eCAL initialize state. * diff --git a/ecal/core/src/ecal_def.h b/ecal/core/src/ecal_def.h index ada5beb8..fcfb23a3 100644 --- a/ecal/core/src/ecal_def.h +++ b/ecal/core/src/ecal_def.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. @@ -23,6 +23,9 @@ #pragma once +#include +#include +#include #include /**********************************************************************************************/ @@ -48,9 +51,9 @@ constexpr const char* MON_FILTER_EXCL = "^__.*$"; constexpr const char* MON_FILTER_INCL = ""; /* logging filter settings */ -constexpr const char* MON_LOG_FILTER_CON = "info,warning,error,fatal"; -constexpr const char* MON_LOG_FILTER_FILE = ""; -constexpr const char* MON_LOG_FILTER_UDP = "info,warning,error,fatal"; +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); /**********************************************************************************************/ @@ -64,19 +67,20 @@ constexpr const char* SYS_FILTER_EXCL = "^eCALSysClient$|^eCALSysGUI$|^eCALS /**********************************************************************************************/ /* network switch */ constexpr bool NET_ENABLED = false; +constexpr bool SHM_REGISTRATION_ENABLED = false; /* eCAL udp multicast defines */ -constexpr const char* NET_UDP_MULTICAST_CONFIG_VERSION = "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 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 */ @@ -102,16 +106,16 @@ constexpr const char* NET_HOST_GROUP_NAME = ""; /* publisher settings */ /**********************************************************************************************/ /* use shared memory transport layer [auto = 2, on = 1, off = 0] */ -constexpr unsigned int PUB_USE_SHM = 2U; +constexpr eCAL::TLayer::eSendMode PUB_USE_SHM = eCAL::TLayer::eSendMode::smode_auto; /* use tcp transport layer [auto = 2, on = 1, off = 0] */ -constexpr unsigned int PUB_USE_TCP = 0U; +constexpr eCAL::TLayer::eSendMode PUB_USE_TCP = eCAL::TLayer::eSendMode::smode_off; /* use udp multicast transport layer [auto = 2, on = 1, off = 0] */ -constexpr unsigned int PUB_USE_UDP_MC = 2U; +constexpr eCAL::TLayer::eSendMode PUB_USE_UDP_MC = eCAL::TLayer::eSendMode::smode_auto; /* share topic type [ on = 1, off = 0] */ -constexpr unsigned int PUB_SHARE_TTYPE = 1U; +constexpr bool PUB_SHARE_TTYPE = true; /* share topic description [ on = 1, off = 0] */ -constexpr unsigned int PUB_SHARE_TDESC = 1U; +constexpr bool PUB_SHARE_TDESC = true; /* minimum size for created shared memory files */ constexpr unsigned int PUB_MEMFILE_MINSIZE = (4U*1024U); @@ -137,22 +141,23 @@ constexpr unsigned int PUB_MEMFILE_BUF_COUNT = 1U; 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 unsigned int PUB_MEMFILE_ZERO_COPY = 0U; +constexpr bool PUB_MEMFILE_ZERO_COPY = false; /**********************************************************************************************/ /* service settings */ /**********************************************************************************************/ /* support service protocol v0, eCAL 5.11 and older (0 = off, 1 = on) */ -constexpr unsigned int SERVICE_PROTOCOL_V0 = 1U; +constexpr bool SERVICE_PROTOCOL_V0 = true; /* support service protocol v1, eCAL 5.12 and newer (0 = off, 1 = on) */ -constexpr unsigned int SERVICE_PROTOCOL_V1 = 1U; +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 */ @@ -183,10 +188,6 @@ constexpr const char* EVENT_SHUTDOWN_PROC = "ecal_shutdown_pro /**********************************************************************************************/ /* experimental */ /**********************************************************************************************/ -/* enable distribution of monitoring/registration information via shared memory */ -constexpr bool EXP_SHM_MONITORING_ENABLED = false; -/* disable distribution of monitoring/registration information via network (default) */ -constexpr bool EXP_NETWORK_MONITORING_DISABLED = false; /* queue size of monitoring/registration events */ constexpr unsigned int EXP_SHM_MONITORING_QUEUE_SIZE = 1024U; /* domain name for shared memory based monitoring/registration */ diff --git a/ecal/core/src/ecal_descgate.cpp b/ecal/core/src/ecal_descgate.cpp index ea80fd0d..40d69e85 100644 --- a/ecal/core/src/ecal_descgate.cpp +++ b/ecal/core/src/ecal_descgate.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. @@ -77,7 +77,7 @@ namespace eCAL Util::QualityTopicInfoMultiMap multi_map; const std::lock_guard lock(topic_info_map_.mtx); - topic_info_map_.map.remove_deprecated(); + topic_info_map_.map.erase_expired(); for (const auto& topic_map_it : topic_info_map_.map) { @@ -92,7 +92,7 @@ namespace eCAL Util::QualityServiceInfoMultimap multi_map; const std::lock_guard lock(service_method_info_map_.mtx); - service_method_info_map_.map.remove_deprecated(); + service_method_info_map_.map.erase_expired(); for (const auto& service_method_info_map_it : service_method_info_map_.map) { @@ -183,14 +183,14 @@ namespace eCAL topic_quality_info.quality = topic_quality_; const std::unique_lock lock(topic_info_map_.mtx); - topic_info_map_.map.remove_deprecated(); + topic_info_map_.map.erase_expired(); topic_info_map_.map[topic_info_key] = topic_quality_info; } void CDescGate::RemTopicDescription(SQualityTopicIdMap& topic_info_map_, const std::string& topic_name_, const Util::TopicId& topic_id_) { const std::unique_lock lock(topic_info_map_.mtx); - topic_info_map_.map.remove_deprecated(); + topic_info_map_.map.erase_expired(); topic_info_map_.map.erase(STopicIdKey{ topic_name_, topic_id_ }); } @@ -213,7 +213,7 @@ namespace eCAL service_quality_info.response_quality = response_type_quality_; const std::lock_guard lock(service_method_info_map_.mtx); - service_method_info_map_.map.remove_deprecated(); + service_method_info_map_.map.erase_expired(); service_method_info_map_.map[service_method_info_key] = service_quality_info; } @@ -222,7 +222,7 @@ namespace eCAL std::list service_method_infos_to_remove; const std::lock_guard lock(service_method_info_map_.mtx); - service_method_info_map_.map.remove_deprecated(); + service_method_info_map_.map.erase_expired(); for (auto&& service_it : service_method_info_map_.map) { diff --git a/ecal/core/src/ecal_descgate.h b/ecal/core/src/ecal_descgate.h index c91b854b..fbc10653 100644 --- a/ecal/core/src/ecal_descgate.h +++ b/ecal/core/src/ecal_descgate.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. @@ -89,7 +89,7 @@ namespace eCAL CDescGate& operator=(CDescGate&&) = delete; protected: - using QualityTopicIdExpMap = eCAL::Util::CExpMap; + using QualityTopicIdExpMap = eCAL::Util::CExpirationMap; struct SQualityTopicIdMap { explicit SQualityTopicIdMap(const std::chrono::milliseconds& timeout_) : map(timeout_) {}; @@ -97,7 +97,7 @@ namespace eCAL QualityTopicIdExpMap map; }; - using QualityServiceIdExpMap = eCAL::Util::CExpMap; + using QualityServiceIdExpMap = eCAL::Util::CExpirationMap; struct SQualityServiceIdMap { explicit SQualityServiceIdMap(const std::chrono::milliseconds& timeout_) : map(timeout_) {}; diff --git a/ecal/core/src/ecal_global_accessors.cpp b/ecal/core/src/ecal_global_accessors.cpp index 2f402cb9..eea54871 100644 --- a/ecal/core/src/ecal_global_accessors.cpp +++ b/ecal/core/src/ecal_global_accessors.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. @@ -24,6 +24,7 @@ #include "ecal_global_accessors.h" #include "ecal_def.h" #include "ecal_globals.h" +#include "ecal/config/configuration.h" #include #include @@ -33,6 +34,7 @@ namespace eCAL std::atomic g_globals_ctx_ref_cnt; std::string g_default_ini_file(ECAL_DEFAULT_CFG); + Configuration g_ecal_configuration{}; std::string g_host_name; std::string g_unit_name; @@ -47,15 +49,45 @@ namespace eCAL eCAL_Process_eSeverity g_process_severity(eCAL_Process_eSeverity::proc_sev_unknown); eCAL_Process_eSeverity_Level g_process_severity_level(eCAL_Process_eSeverity_Level::proc_sev_level1); - CGlobals* g_globals() + void InitGlobals() { - return g_globals_ctx; + g_globals_ctx = new CGlobals; } - CConfig* g_config() + void SetGlobalUnitName(const char *unit_name_) { - if (g_globals() == nullptr) return(nullptr); - return(g_globals()->config().get()); + // There is a function already "SetUnitName" which sets the g_unit_name just as string. + // Used in global API. It does not have the following logic -> should that be added/removed/combined? + // For previous consistency this function is added here for the time being. + if(unit_name_ != nullptr) g_unit_name = unit_name_; + if (g_unit_name.empty()) + { + g_unit_name = Process::GetProcessName(); +#ifdef ECAL_OS_WINDOWS + size_t p = g_unit_name.rfind('\\'); + if (p != std::string::npos) + { + g_unit_name = g_unit_name.substr(p+1); + } + p = g_unit_name.rfind('.'); + if (p != std::string::npos) + { + g_unit_name = g_unit_name.substr(0, p); + } +#endif +#ifdef ECAL_OS_LINUX + const size_t p = g_unit_name.rfind('/'); + if (p != std::string::npos) + { + g_unit_name = g_unit_name.substr(p + 1); + } +#endif + } + }; + + CGlobals* g_globals() + { + return g_globals_ctx; } CLog* g_log() @@ -64,6 +96,11 @@ namespace eCAL return(g_globals()->log().get()); } + Configuration& g_ecal_config() + { + return(g_ecal_configuration); + } + #if ECAL_CORE_MONITORING CMonitoring* g_monitoring() { diff --git a/ecal/core/src/ecal_global_accessors.h b/ecal/core/src/ecal_global_accessors.h index 3ae00eda..a0d3516e 100644 --- a/ecal/core/src/ecal_global_accessors.h +++ b/ecal/core/src/ecal_global_accessors.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. @@ -31,9 +31,10 @@ // Forward declaration of global accessible classes namespace eCAL { - class CGlobals; - class CConfig; - class CLog; + class CGlobals; + class CLog; + struct Configuration; + #if ECAL_CORE_MONITORING class CMonitoring; #endif @@ -60,9 +61,11 @@ namespace eCAL class CMemFileMap; #endif + void SetGlobalUnitName(const char *unit_name_); + void InitGlobals(); + // Declaration of getter functions for globally accessible variable instances CGlobals* g_globals(); - CConfig* g_config(); CLog* g_log(); #if ECAL_CORE_MONITORING CMonitoring* g_monitoring(); @@ -88,6 +91,7 @@ namespace eCAL #if defined(ECAL_CORE_REGISTRATION_SHM) || defined(ECAL_CORE_TRANSPORT_SHM) CMemFileThreadPool* g_memfile_pool(); CMemFileMap* g_memfile_map(); + #endif // declaration of globally accessible variables @@ -95,6 +99,7 @@ namespace eCAL extern std::atomic g_globals_ctx_ref_cnt; extern std::string g_default_ini_file; + extern Configuration g_ecal_configuration; extern std::string g_host_name; extern std::string g_unit_name; diff --git a/ecal/core/src/ecal_globals.cpp b/ecal/core/src/ecal_globals.cpp index 778005b8..088bfc60 100644 --- a/ecal/core/src/ecal_globals.cpp +++ b/ecal/core/src/ecal_globals.cpp @@ -50,36 +50,6 @@ namespace eCAL // will be set if any new module was initialized bool new_initialization(false); - ///////////////////// - // CONFIG - ///////////////////// - if (config_instance == nullptr) - { - config_instance = std::make_unique(); - if (config_keys_ != nullptr) - { - config_instance->OverwriteKeys(*config_keys_); - } - config_instance->AddFile(g_default_ini_file); - - if (!config_instance->Validate()) - { - const std::string emsg("Core initialization failed cause by a configuration error."); - - std::cerr << '\n'; - std::cerr << "----------------------------------------------------------" << '\n'; - std::cerr << "eCAL CORE PANIC :-(" << '\n'; - std::cerr << '\n'; - std::cerr << emsg << '\n'; - std::cerr << "----------------------------------------------------------" << '\n'; - std::cerr << '\n'; - - throw std::runtime_error(emsg.c_str()); - } - - new_initialization = true; - } - #if ECAL_CORE_REGISTRATION ///////////////////// // REGISTRATION PROVIDER @@ -377,8 +347,6 @@ namespace eCAL memfile_map_instance = nullptr; #endif log_instance = nullptr; - config_instance = nullptr; - initialized = false; return(0); diff --git a/ecal/core/src/ecal_globals.h b/ecal/core/src/ecal_globals.h index 6feda75a..dc5eaed7 100644 --- a/ecal/core/src/ecal_globals.h +++ b/ecal/core/src/ecal_globals.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. @@ -63,13 +63,13 @@ namespace eCAL int Initialize ( unsigned int components_, std::vector* config_keys_ = nullptr); bool IsInitialized ( unsigned int component_ ); - + unsigned int GetComponents() const { return(components); }; int Finalize(); - const std::unique_ptr& config() { return config_instance; }; const std::unique_ptr& log() { return log_instance; }; + #if ECAL_CORE_MONITORING const std::unique_ptr& monitoring() { return monitoring_instance; }; #endif @@ -93,13 +93,13 @@ namespace eCAL #if defined(ECAL_CORE_REGISTRATION_SHM) || defined(ECAL_CORE_TRANSPORT_SHM) const std::unique_ptr& memfile_pool() { return memfile_pool_instance; }; const std::unique_ptr& memfile_map() { return memfile_map_instance; }; + #endif const std::unique_ptr& descgate() { return descgate_instance; }; private: bool initialized; unsigned int components; - std::unique_ptr config_instance; std::unique_ptr log_instance; #if ECAL_CORE_MONITORING std::unique_ptr monitoring_instance; @@ -124,6 +124,7 @@ namespace eCAL #if defined(ECAL_CORE_REGISTRATION_SHM) || defined(ECAL_CORE_TRANSPORT_SHM) std::unique_ptr memfile_pool_instance; std::unique_ptr memfile_map_instance; + #endif std::unique_ptr descgate_instance; }; diff --git a/ecal/core/src/ecal_process.cpp b/ecal/core/src/ecal_process.cpp index fab2a446..20c26b45 100644 --- a/ecal/core/src/ecal_process.cpp +++ b/ecal/core/src/ecal_process.cpp @@ -193,7 +193,7 @@ namespace eCAL #if ECAL_CORE_TIMEPLUGIN sstream << "------------------------- TIME -----------------------------------" << '\n'; sstream << "Synchronization realtime : " << Config::GetTimesyncModuleName() << '\n'; - sstream << "Synchronization replay : " << eCALPAR(TIME, SYNC_MOD_REPLAY) << '\n'; + sstream << "Synchronization replay : " << Config::GetTimesyncModuleReplay() << '\n'; sstream << "State : "; if (g_timegate()->IsSynchronized()) sstream << " synchronized " << '\n'; else sstream << " not synchronized " << '\n'; diff --git a/ecal/core/src/io/udp/ecal_udp_configurations.cpp b/ecal/core/src/io/udp/ecal_udp_configurations.cpp index 589da387..d3e81cf4 100644 --- a/ecal/core/src/io/udp/ecal_udp_configurations.cpp +++ b/ecal/core/src/io/udp/ecal_udp_configurations.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. @@ -140,7 +140,7 @@ namespace eCAL } // determine the UDP multicast configuration version - if (Config::GetUdpMulticastConfigVersion() == Config::UdpConfigVersion::V1) + if (Config::GetUdpMulticastConfigVersion() == Types::UdpConfigVersion::V1) { // retrieve the corresponding multicast address based on the topic name using v1 implementation return UDP::V1::topic2mcast(topic_name, Config::GetUdpMulticastGroup(), Config::GetUdpMulticastMask()); diff --git a/ecal/core/src/monitoring/ecal_monitoring_impl.cpp b/ecal/core/src/monitoring/ecal_monitoring_impl.cpp index 73fac8cc..59595dff 100644 --- a/ecal/core/src/monitoring/ecal_monitoring_impl.cpp +++ b/ecal/core/src/monitoring/ecal_monitoring_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. @@ -619,7 +619,7 @@ namespace eCAL monitoring_.processes.reserve(m_process_map.map->size()); // iterate map - m_process_map.map->remove_deprecated(); + m_process_map.map->erase_expired(); for (const auto& process : (*m_process_map.map)) { monitoring_.processes.emplace_back(process.second); @@ -637,7 +637,7 @@ namespace eCAL monitoring_.publisher.reserve(m_publisher_map.map->size()); // iterate map - m_publisher_map.map->remove_deprecated(); + m_publisher_map.map->erase_expired(); for (const auto& publisher : (*m_publisher_map.map)) { monitoring_.publisher.emplace_back(publisher.second); @@ -655,7 +655,7 @@ namespace eCAL monitoring_.subscriber.reserve(m_subscriber_map.map->size()); // iterate map - m_subscriber_map.map->remove_deprecated(); + m_subscriber_map.map->erase_expired(); for (const auto& subscriber : (*m_subscriber_map.map)) { monitoring_.subscriber.emplace_back(subscriber.second); @@ -673,7 +673,7 @@ namespace eCAL monitoring_.server.reserve(m_server_map.map->size()); // iterate map - m_server_map.map->remove_deprecated(); + m_server_map.map->erase_expired(); for (const auto& server : (*m_server_map.map)) { monitoring_.server.emplace_back(server.second); @@ -691,7 +691,7 @@ namespace eCAL monitoring_.clients.reserve(m_clients_map.map->size()); // iterate map - m_clients_map.map->remove_deprecated(); + m_clients_map.map->erase_expired(); for (const auto& client : (*m_clients_map.map)) { monitoring_.clients.emplace_back(client.second); @@ -705,7 +705,7 @@ namespace eCAL const std::lock_guard lock(m_process_map.sync); // iterate map - m_process_map.map->remove_deprecated(); + m_process_map.map->erase_expired(); for (const auto& process : (*m_process_map.map)) { // add process @@ -719,7 +719,7 @@ namespace eCAL const std::lock_guard lock(m_server_map.sync); // iterate map - m_server_map.map->remove_deprecated(); + m_server_map.map->erase_expired(); for (const auto& server : (*m_server_map.map)) { // add service @@ -733,7 +733,7 @@ namespace eCAL const std::lock_guard lock(m_clients_map.sync); // iterate map - m_clients_map.map->remove_deprecated(); + m_clients_map.map->erase_expired(); for (const auto& client : (*m_clients_map.map)) { // add client @@ -747,7 +747,7 @@ namespace eCAL const std::lock_guard lock(map_.sync); // iterate map - map_.map->remove_deprecated(); + map_.map->erase_expired(); for (const auto& topic : (*map_.map)) { if (direction_ == "publisher") diff --git a/ecal/core/src/monitoring/ecal_monitoring_impl.h b/ecal/core/src/monitoring/ecal_monitoring_impl.h index bfce0290..703bda85 100644 --- a/ecal/core/src/monitoring/ecal_monitoring_impl.h +++ b/ecal/core/src/monitoring/ecal_monitoring_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. @@ -81,7 +81,7 @@ namespace eCAL bool RegisterTopic(const Registration::Sample& sample_, enum ePubSub pubsub_type_); bool UnregisterTopic(const Registration::Sample& sample_, enum ePubSub pubsub_type_); - using TopicMonMapT = Util::CExpMap; + using TopicMonMapT = Util::CExpirationMap; struct STopicMonMap { explicit STopicMonMap(const std::chrono::milliseconds& timeout_) : @@ -92,7 +92,7 @@ namespace eCAL std::unique_ptr map; }; - using ProcessMonMapT = Util::CExpMap; + using ProcessMonMapT = Util::CExpirationMap; struct SProcessMonMap { explicit SProcessMonMap(const std::chrono::milliseconds& timeout_) : @@ -103,7 +103,7 @@ namespace eCAL std::unique_ptr map; }; - using ServerMonMapT = Util::CExpMap; + using ServerMonMapT = Util::CExpirationMap; struct SServerMonMap { explicit SServerMonMap(const std::chrono::milliseconds& timeout_) : @@ -114,7 +114,7 @@ namespace eCAL std::unique_ptr map; }; - using ClientMonMapT = Util::CExpMap; + using ClientMonMapT = Util::CExpirationMap; struct SClientMonMap { explicit SClientMonMap(const std::chrono::milliseconds& timeout_) : diff --git a/ecal/core/src/pubsub/ecal_publisher.cpp b/ecal/core/src/pubsub/ecal_publisher.cpp index 3369d43b..ef04c32c 100644 --- a/ecal/core/src/pubsub/ecal_publisher.cpp +++ b/ecal/core/src/pubsub/ecal_publisher.cpp @@ -151,13 +151,13 @@ namespace eCAL return(true); } - size_t CPublisher::Send(const void* const buf_, const size_t len_, const long long time_ /* = DEFAULT_TIME_ARGUMENT */) const + size_t CPublisher::Send(const void* const buf_, const size_t len_, const long long time_ /* = DEFAULT_TIME_ARGUMENT */) { CBufferPayloadWriter payload{ buf_, len_ }; return Send(payload, time_); } - size_t CPublisher::Send(CPayloadWriter& payload_, long long time_) const + size_t CPublisher::Send(CPayloadWriter& payload_, long long time_) { if (!m_created) return(0); @@ -180,7 +180,7 @@ namespace eCAL return written_bytes; } - size_t CPublisher::Send(const std::string& s_, long long time_) const + size_t CPublisher::Send(const std::string& s_, long long time_) { return(Send(s_.data(), s_.size(), time_)); } diff --git a/ecal/core/src/pubsub/ecal_publisher_config.cpp b/ecal/core/src/pubsub/ecal_publisher_config.cpp index 949980e6..ede5dddd 100644 --- a/ecal/core/src/pubsub/ecal_publisher_config.cpp +++ b/ecal/core/src/pubsub/ecal_publisher_config.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. @@ -22,32 +22,15 @@ **/ #include -#include +#include namespace eCAL { namespace Publisher { - Configuration::Configuration() : - share_topic_type(eCAL::Config::IsTopicTypeSharingEnabled()), - share_topic_description(eCAL::Config::IsTopicDescriptionSharingEnabled()) + Configuration::Configuration() { - // shm config - shm.enable = eCAL::Config::GetPublisherShmMode() != TLayer::eSendMode::smode_off; - shm.zero_copy_mode = eCAL::Config::IsMemfileZerocopyEnabled(); - shm.acknowledge_timeout_ms = eCAL::Config::GetMemfileAckTimeoutMs(); - - shm.memfile_min_size_bytes = eCAL::Config::GetMemfileMinsizeBytes(); - shm.memfile_reserve_percent = eCAL::Config::GetMemfileOverprovisioningPercentage(); - shm.memfile_buffer_count = eCAL::Config::GetMemfileBufferCount(); - - // udp config - udp.enable = eCAL::Config::GetPublisherUdpMulticastMode() != TLayer::eSendMode::smode_off; - udp.loopback = false; // TODO: make this configurable - udp.sndbuf_size_bytes = eCAL::Config::GetUdpMulticastSndBufSizeBytes(); - - // tcp config - tcp.enable = eCAL::Config::GetPublisherTcpMode() != TLayer::eSendMode::smode_off; + *this = GetConfiguration().publisher; } } } diff --git a/ecal/core/src/pubsub/ecal_subgate.cpp b/ecal/core/src/pubsub/ecal_subgate.cpp index 44261b5e..a303dd08 100644 --- a/ecal/core/src/pubsub/ecal_subgate.cpp +++ b/ecal/core/src/pubsub/ecal_subgate.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. @@ -261,8 +261,16 @@ namespace eCAL { iter->second->ApplyLayerParameter(publication_info, tlayer.type, tlayer.par_layer); } - // inform for publisher connection - iter->second->ApplyPublication(publication_info, topic_information, layer_states); + // we only inform the subscriber when the publisher has already recognized at least one subscriber + // this should avoid to set the "IsPublished" state before the publisher is able to send data + const bool local_publication = publication_info.host_name == Process::GetHostName(); + const bool external_publication = !local_publication; + const bool local_confirmed = local_publication && (ecal_sample_.topic.connections_loc > 0); + const bool external_confirmed = external_publication && (ecal_sample_.topic.connections_ext > 0); + if(local_confirmed || external_confirmed) + { + iter->second->ApplyPublication(publication_info, topic_information, layer_states); + } } } diff --git a/ecal/core/src/pubsub/ecal_subscriber.cpp b/ecal/core/src/pubsub/ecal_subscriber.cpp index 0086f32a..c5aaeea3 100644 --- a/ecal/core/src/pubsub/ecal_subscriber.cpp +++ b/ecal/core/src/pubsub/ecal_subscriber.cpp @@ -172,6 +172,12 @@ namespace eCAL return(m_datareader->RemEventCallback(type_)); } + bool CSubscriber::IsPublished() const + { + if (m_datareader == nullptr) return(false); + return(m_datareader->IsPublished()); + } + size_t CSubscriber::GetPublisherCount() const { if (m_datareader == nullptr) return(0); diff --git a/ecal/core/src/pubsub/ecal_subscriber_config.cpp b/ecal/core/src/pubsub/ecal_subscriber_config.cpp index 45a7becd..1ecdea26 100644 --- a/ecal/core/src/pubsub/ecal_subscriber_config.cpp +++ b/ecal/core/src/pubsub/ecal_subscriber_config.cpp @@ -22,7 +22,7 @@ **/ #include -#include +#include namespace eCAL { @@ -30,14 +30,7 @@ namespace eCAL { Configuration::Configuration() { - // shm config - shm.enable = eCAL::Config::IsShmRecEnabled(); - - // udp config - udp.enable = eCAL::Config::IsUdpMulticastRecEnabled(); - - // tcp config - tcp.enable = eCAL::Config::IsTcpRecEnabled(); + *this = GetConfiguration().subscriber; } } } diff --git a/ecal/core/src/readwrite/ecal_reader.cpp b/ecal/core/src/readwrite/ecal_reader.cpp index 9fedd736..160071e5 100644 --- a/ecal/core/src/readwrite/ecal_reader.cpp +++ b/ecal/core/src/readwrite/ecal_reader.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. @@ -818,7 +818,7 @@ namespace eCAL // check connection timeouts { const std::lock_guard lock(m_pub_map_mtx); - m_pub_map.remove_deprecated(); + m_pub_map.erase_expired(); if (m_pub_map.empty()) { diff --git a/ecal/core/src/readwrite/ecal_reader.h b/ecal/core/src/readwrite/ecal_reader.h index 5d48a3c1..fbe0213e 100644 --- a/ecal/core/src/readwrite/ecal_reader.h +++ b/ecal/core/src/readwrite/ecal_reader.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. @@ -143,7 +143,7 @@ namespace eCAL std::atomic m_topic_size; std::atomic m_connected; - using PublicationMapT = Util::CExpMap>; + using PublicationMapT = Util::CExpirationMap>; mutable std::mutex m_pub_map_mtx; PublicationMapT m_pub_map; diff --git a/ecal/core/src/readwrite/ecal_writer.cpp b/ecal/core/src/readwrite/ecal_writer.cpp index 6f4548e5..bc754e8f 100644 --- a/ecal/core/src/readwrite/ecal_writer.cpp +++ b/ecal/core/src/readwrite/ecal_writer.cpp @@ -488,7 +488,7 @@ namespace eCAL // check connection timeouts { const std::lock_guard lock(m_sub_map_mtx); - m_sub_map.remove_deprecated(); + m_sub_map.erase_expired(); if (m_sub_map.empty()) { diff --git a/ecal/core/src/readwrite/ecal_writer.h b/ecal/core/src/readwrite/ecal_writer.h index 019c06fd..d7738f82 100644 --- a/ecal/core/src/readwrite/ecal_writer.h +++ b/ecal/core/src/readwrite/ecal_writer.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,7 +25,8 @@ #include #include -#include +#include +#include #include #include "util/ecal_expmap.h" @@ -152,7 +153,7 @@ namespace eCAL std::atomic m_connected; - using SSubscriptionMapT = Util::CExpMap>; + using SSubscriptionMapT = Util::CExpirationMap>; mutable std::mutex m_sub_map_mtx; SSubscriptionMapT m_sub_map; diff --git a/ecal/core/src/readwrite/shm/ecal_writer_shm.h b/ecal/core/src/readwrite/shm/ecal_writer_shm.h index 01517db7..fd6dff0d 100644 --- a/ecal/core/src/readwrite/shm/ecal_writer_shm.h +++ b/ecal/core/src/readwrite/shm/ecal_writer_shm.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. @@ -23,7 +23,7 @@ #pragma once -#include +#include #include "readwrite/ecal_writer_base.h" #include "io/shm/ecal_memfile_sync.h" diff --git a/ecal/core/src/readwrite/tcp/ecal_writer_tcp.h b/ecal/core/src/readwrite/tcp/ecal_writer_tcp.h index 6258ae28..94a3e96f 100644 --- a/ecal/core/src/readwrite/tcp/ecal_writer_tcp.h +++ b/ecal/core/src/readwrite/tcp/ecal_writer_tcp.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. @@ -23,7 +23,7 @@ #pragma once -#include +#include #include "readwrite/ecal_writer_base.h" diff --git a/ecal/core/src/readwrite/udp/ecal_writer_udp.h b/ecal/core/src/readwrite/udp/ecal_writer_udp.h index a9b2d4ea..32a7ef78 100644 --- a/ecal/core/src/readwrite/udp/ecal_writer_udp.h +++ b/ecal/core/src/readwrite/udp/ecal_writer_udp.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. @@ -23,7 +23,7 @@ #pragma once -#include +#include #include "io/udp/ecal_udp_sample_sender.h" #include "readwrite/ecal_writer_base.h" diff --git a/ecal/core/src/registration/ecal_process_registration.cpp b/ecal/core/src/registration/ecal_process_registration.cpp new file mode 100644 index 00000000..18ca56aa --- /dev/null +++ b/ecal/core/src/registration/ecal_process_registration.cpp @@ -0,0 +1,104 @@ +/* ========================= 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 Functions to generate Process Registration / Unregistration samples. + * +**/ + +#include "ecal_process_registration.h" + +#include +#include +#include "ecal_global_accessors.h" +#include "ecal_globals.h" +#include "time/ecal_timegate.h" + +eCAL::Registration::Sample eCAL::Registration::GetProcessRegisterSample() +{ + Registration::Sample process_sample; + process_sample.cmd_type = bct_reg_process; + auto& process_sample_process = process_sample.process; + process_sample_process.hname = eCAL::Process::GetHostName(); + process_sample_process.hgname = eCAL::Process::GetHostGroupName(); + process_sample_process.pid = eCAL::Process::GetProcessID(); + process_sample_process.pname = eCAL::Process::GetProcessName(); + process_sample_process.uname = eCAL::Process::GetUnitName(); + process_sample_process.pparam = eCAL::Process::GetProcessParameter(); + process_sample_process.state.severity = static_cast(g_process_severity); + process_sample_process.state.severity_level = static_cast(g_process_severity_level); + process_sample_process.state.info = g_process_info; +#if ECAL_CORE_TIMEPLUGIN + if (g_timegate() == nullptr) + { + process_sample_process.tsync_state = Registration::eTSyncState::tsync_none; + } + else + { + if (!g_timegate()->IsSynchronized()) + { + process_sample_process.tsync_state = Registration::eTSyncState::tsync_none; + } + else + { + switch (g_timegate()->GetSyncMode()) + { + case CTimeGate::eTimeSyncMode::realtime: + process_sample_process.tsync_state = Registration::eTSyncState::tsync_realtime; + break; + case CTimeGate::eTimeSyncMode::replay: + process_sample_process.tsync_state = Registration::eTSyncState::tsync_replay; + break; + default: + process_sample_process.tsync_state = Registration::eTSyncState::tsync_none; + break; + } + } + process_sample_process.tsync_mod_name = g_timegate()->GetName(); + } +#endif + + // eCAL initialization state + const unsigned int comp_state(g_globals()->GetComponents()); + process_sample_process.component_init_state = static_cast(comp_state); + std::string component_info; + if ((comp_state & eCAL::Init::Publisher) != 0u) component_info += "|pub"; + if ((comp_state & eCAL::Init::Subscriber) != 0u) component_info += "|sub"; + if ((comp_state & eCAL::Init::Logging) != 0u) component_info += "|log"; + if ((comp_state & eCAL::Init::TimeSync) != 0u) component_info += "|time"; + if (!component_info.empty()) component_info = component_info.substr(1); + process_sample_process.component_init_info = component_info; + + process_sample_process.ecal_runtime_version = eCAL::GetVersionString(); + + return process_sample; +} + +eCAL::Registration::Sample eCAL::Registration::GetProcessUnregisterSample() +{ + Registration::Sample process_sample; + process_sample.cmd_type = bct_unreg_process; + auto& process_sample_process = process_sample.process; + process_sample_process.hname = eCAL::Process::GetHostName(); + process_sample_process.pid = eCAL::Process::GetProcessID(); + process_sample_process.pname = eCAL::Process::GetProcessName(); + process_sample_process.uname = eCAL::Process::GetUnitName(); + + return process_sample; +} diff --git a/ecal/core/src/registration/ecal_process_registration.h b/ecal/core/src/registration/ecal_process_registration.h new file mode 100644 index 00000000..e5961f5f --- /dev/null +++ b/ecal/core/src/registration/ecal_process_registration.h @@ -0,0 +1,37 @@ +/* ========================= 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 Functions to generate Process Registration / Unregistration samples. + * +**/ + +#pragma once + +#include "serialization/ecal_struct_sample_registration.h" + +namespace eCAL +{ + namespace Registration + { + Sample GetProcessRegisterSample(); + + Sample GetProcessUnregisterSample(); + } +} \ No newline at end of file diff --git a/ecal/core/src/registration/ecal_registration_provider.cpp b/ecal/core/src/registration/ecal_registration_provider.cpp index 90cf7148..363ede8f 100644 --- a/ecal/core/src/registration/ecal_registration_provider.cpp +++ b/ecal/core/src/registration/ecal_registration_provider.cpp @@ -25,17 +25,9 @@ * These information will be send cyclic (registration refresh) via UDP to external eCAL processes. * **/ - -#include -#include - -#include "ecal_def.h" -#include "ecal_globals.h" #include "ecal_registration_provider.h" -#include "io/udp/ecal_udp_configurations.h" -#include "io/udp/ecal_udp_sample_sender.h" - +#include #include #include #include @@ -43,6 +35,16 @@ #include #include +#include +#include +#include "ecal_def.h" + +#include +#include +#if ECAL_CORE_REGISTRATION_SHM +#include +#endif + namespace eCAL { std::atomic CRegistrationProvider::m_created; @@ -62,31 +64,21 @@ namespace eCAL { if(m_created) return; - // send registration to shared memory and to udp - m_use_registration_udp = !Config::Experimental::IsNetworkMonitoringDisabled(); - m_use_registration_shm = Config::Experimental::IsShmMonitoringEnabled(); - - if (m_use_registration_udp) - { - // set network attributes - eCAL::UDP::SSenderAttr attr; - attr.address = UDP::GetRegistrationAddress(); - attr.port = UDP::GetRegistrationPort(); - attr.ttl = UDP::GetMulticastTtl(); - attr.broadcast = UDP::IsBroadcast(); - attr.loopback = true; - attr.sndbuf = Config::GetUdpMulticastSndBufSizeBytes(); - - // create udp registration sender - m_reg_sample_snd = std::make_shared(attr); - } + // send registration over udp or shared memory + m_use_registration_shm = Config::IsShmRegistrationEnabled(); + m_use_registration_udp = !m_use_registration_shm; + // TODO Create the registration sender #if ECAL_CORE_REGISTRATION_SHM if (m_use_registration_shm) { - std::cout << "Shared memory monitoring is enabled (domain: " << Config::Experimental::GetShmMonitoringDomain() << " - queue size: " << Config::Experimental::GetShmMonitoringQueueSize() << ")" << '\n'; - m_memfile_broadcast.Create(Config::Experimental::GetShmMonitoringDomain(), Config::Experimental::GetShmMonitoringQueueSize()); - m_memfile_broadcast_writer.Bind(&m_memfile_broadcast); + m_reg_sender = std::make_unique(); + } + else + { +#endif + m_reg_sender = std::make_unique(); +#if ECAL_CORE_REGISTRATION_SHM } #endif @@ -105,28 +97,11 @@ namespace eCAL m_reg_sample_snd_thread->stop(); // add process unregistration sample - AddSample2SampleList(GetProcessUnregisterSample()); + AddSample2SampleList(Registration::GetProcessUnregisterSample()); - if (m_use_registration_udp) - { - // send process unregistration sample over udp - SendSampleList2UDP(); + SendSampleList(); - // destroy udp registration sample sender - m_reg_sample_snd.reset(); - } - -#if ECAL_CORE_REGISTRATION_SHM - if (m_use_registration_shm) - { - // broadcast process unregistration sample over shm - SendSampleList2SHM(); - - // destroy shm registration sample writer - m_memfile_broadcast_writer.Unbind(); - m_memfile_broadcast.Destroy(); - } -#endif + m_reg_sender.reset(); m_created = false; } @@ -150,12 +125,14 @@ namespace eCAL // if registration is forced if (force_) { + SendSampleList(); + // send single registration sample over udp - SendSample2UDP(sample_); + //SendSample2UDP(sample_); #if ECAL_CORE_REGISTRATION_SHM // broadcast (updated) sample list over shm - SendSampleList2SHM(); + //SendSampleList2SHM(); #endif } @@ -184,72 +161,6 @@ namespace eCAL m_sample_list.samples.push_back(sample_); } - bool CRegistrationProvider::SendSample2UDP(const Registration::Sample& sample_) - { - if (!m_created) return(false); - - if (m_use_registration_udp && m_reg_sample_snd) - { - // lock sample buffer - const std::lock_guard lock(m_sample_buffer_mtx); - - // serialize single sample - if (SerializeToBuffer(sample_, m_sample_buffer)) - { - // send single sample over udp - return m_reg_sample_snd->Send("reg_sample", m_sample_buffer) != 0; - } - } - return(false); - } - - bool CRegistrationProvider::SendSampleList2UDP() - { - if (!m_created) return(false); - bool return_value{ true }; - - // lock sample list - const std::lock_guard lock(m_sample_list_mtx); - - // send all (single) samples over udp - if (m_use_registration_udp && m_reg_sample_snd) - { - for (const auto& sample : m_sample_list.samples) - { - return_value &= SendSample2UDP(sample); - } - } - - return return_value; - } - -#if ECAL_CORE_REGISTRATION_SHM - bool CRegistrationProvider::SendSampleList2SHM() - { - if (!m_created) return(false); - - bool return_value{ true }; - - // send sample list over shm - if (m_use_registration_shm) - { - // lock sample list - const std::lock_guard lock(m_sample_list_mtx); - - // serialize whole sample list - if (SerializeToBuffer(m_sample_list, m_sample_list_buffer)) - { - if (!m_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 return_value; - } -#endif - void CRegistrationProvider::ClearSampleList() { // lock sample list @@ -258,6 +169,12 @@ namespace eCAL m_sample_list.samples.clear(); } + void CRegistrationProvider::SendSampleList() + { + std::lock_guard lock(m_sample_list_mtx); + m_reg_sender->SendSampleList(m_sample_list); + } + void CRegistrationProvider::RegisterSendThread() { #if ECAL_CORE_SUBSCRIBER @@ -278,91 +195,12 @@ namespace eCAL if (g_clientgate() != nullptr) g_clientgate()->RefreshRegistrations(); #endif - // send out sample list over udp - SendSampleList2UDP(); - -#if ECAL_CORE_REGISTRATION_SHM - // broadcast sample list over shm - SendSampleList2SHM(); -#endif + SendSampleList(); // clear registration sample list ClearSampleList(); // add process registration sample to internal sample list as first sample (for next registration loop) - AddSample2SampleList(GetProcessRegisterSample()); - } - - Registration::Sample CRegistrationProvider::GetProcessRegisterSample() - { - Registration::Sample process_sample; - process_sample.cmd_type = bct_reg_process; - auto& process_sample_process = process_sample.process; - process_sample_process.hname = Process::GetHostName(); - process_sample_process.hgname = Process::GetHostGroupName(); - process_sample_process.pid = Process::GetProcessID(); - process_sample_process.pname = Process::GetProcessName(); - process_sample_process.uname = Process::GetUnitName(); - process_sample_process.pparam = Process::GetProcessParameter(); - process_sample_process.state.severity = static_cast(g_process_severity); - process_sample_process.state.severity_level = static_cast(g_process_severity_level); - process_sample_process.state.info = g_process_info; -#if ECAL_CORE_TIMEPLUGIN - if (g_timegate() == nullptr) - { - process_sample_process.tsync_state = Registration::eTSyncState::tsync_none; - } - else - { - if (!g_timegate()->IsSynchronized()) - { - process_sample_process.tsync_state = Registration::eTSyncState::tsync_none; - } - else - { - switch (g_timegate()->GetSyncMode()) - { - case CTimeGate::eTimeSyncMode::realtime: - process_sample_process.tsync_state = Registration::eTSyncState::tsync_realtime; - break; - case CTimeGate::eTimeSyncMode::replay: - process_sample_process.tsync_state = Registration::eTSyncState::tsync_replay; - break; - default: - process_sample_process.tsync_state = Registration::eTSyncState::tsync_none; - break; - } - } - process_sample_process.tsync_mod_name = g_timegate()->GetName(); - } -#endif - - // eCAL initialization state - const unsigned int comp_state(g_globals()->GetComponents()); - process_sample_process.component_init_state = static_cast(comp_state); - std::string component_info; - if ((comp_state & Init::Publisher) != 0u) component_info += "|pub"; - if ((comp_state & Init::Subscriber) != 0u) component_info += "|sub"; - if ((comp_state & Init::Logging) != 0u) component_info += "|log"; - if ((comp_state & Init::TimeSync) != 0u) component_info += "|time"; - if (!component_info.empty()) component_info = component_info.substr(1); - process_sample_process.component_init_info = component_info; - - process_sample_process.ecal_runtime_version = GetVersionString(); - - return process_sample; - } - - Registration::Sample CRegistrationProvider::GetProcessUnregisterSample() - { - Registration::Sample process_sample; - process_sample.cmd_type = bct_unreg_process; - auto& process_sample_process = process_sample.process; - process_sample_process.hname = Process::GetHostName(); - process_sample_process.pid = Process::GetProcessID(); - process_sample_process.pname = Process::GetProcessName(); - process_sample_process.uname = Process::GetUnitName(); - - return process_sample; + AddSample2SampleList(Registration::GetProcessRegisterSample()); } } diff --git a/ecal/core/src/registration/ecal_registration_provider.h b/ecal/core/src/registration/ecal_registration_provider.h index 098a9ef2..422e6527 100644 --- a/ecal/core/src/registration/ecal_registration_provider.h +++ b/ecal/core/src/registration/ecal_registration_provider.h @@ -30,21 +30,15 @@ #include "io/udp/ecal_udp_sample_sender.h" -#include "util/ecal_thread.h" - -#if ECAL_CORE_REGISTRATION_SHM -#include "shm/ecal_memfile_broadcast.h" -#include "shm/ecal_memfile_broadcast_writer.h" -#endif - -#include "serialization/ecal_serialize_sample_registration.h" - #include #include #include #include #include +#include +#include "util/ecal_thread.h" + namespace eCAL { class CRegistrationProvider @@ -64,40 +58,24 @@ namespace eCAL protected: void AddSample2SampleList(const Registration::Sample& sample_); - bool SendSample2UDP(const Registration::Sample& sample_); - - bool SendSampleList2UDP(); -#if ECAL_CORE_REGISTRATION_SHM - bool SendSampleList2SHM(); -#endif void ClearSampleList(); + void SendSampleList(); void RegisterSendThread(); - Registration::Sample GetProcessRegisterSample(); - Registration::Sample GetProcessUnregisterSample(); - - static std::atomic m_created; - - std::shared_ptr m_reg_sample_snd; - std::shared_ptr m_reg_sample_snd_thread; + static std::atomic m_created; - std::mutex m_sample_buffer_mtx; - std::vector m_sample_buffer; + std::unique_ptr m_reg_sender; - std::mutex m_sample_list_mtx; - Registration::SampleList m_sample_list; + std::shared_ptr m_reg_sample_snd_thread; -#if ECAL_CORE_REGISTRATION_SHM - std::vector m_sample_list_buffer; - CMemoryFileBroadcast m_memfile_broadcast; - CMemoryFileBroadcastWriter m_memfile_broadcast_writer; -#endif + std::mutex m_sample_list_mtx; + Registration::SampleList m_sample_list; - bool m_use_registration_udp; - bool m_use_registration_shm; + bool m_use_registration_udp; + bool m_use_registration_shm; - std::mutex m_callback_custom_apply_sample_map_mtx; + 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 1ef8bfbf..b587fa58 100644 --- a/ecal/core/src/registration/ecal_registration_receiver.cpp +++ b/ecal/core/src/registration/ecal_registration_receiver.cpp @@ -69,9 +69,9 @@ namespace eCAL { if(m_created) return; - // receive registration from shared memory and or udp - m_use_registration_udp = !Config::Experimental::IsNetworkMonitoringDisabled(); - m_use_registration_shm = Config::Experimental::IsShmMonitoringEnabled(); + // receive registration via udp or shared memory + m_use_registration_shm = Config::IsShmRegistrationEnabled(); + m_use_registration_udp = !m_use_registration_shm; if (m_use_registration_udp) { diff --git a/ecal/core/src/registration/ecal_registration_sender.h b/ecal/core/src/registration/ecal_registration_sender.h new file mode 100644 index 00000000..4f9d6e50 --- /dev/null +++ b/ecal/core/src/registration/ecal_registration_sender.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 provider + * + * 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. + * +**/ + +#pragma once + +#include "serialization/ecal_struct_sample_registration.h" + + +namespace eCAL +{ + class CRegistrationSender + { + public: + CRegistrationSender() = default; + virtual ~CRegistrationSender() = default; + + // Copy constructor + CRegistrationSender(const CRegistrationSender& other) = delete; + + // Copy assignment operator + CRegistrationSender& operator=(const CRegistrationSender & other) = delete; + + // Move constructor + CRegistrationSender(CRegistrationSender && other) noexcept = delete; + + // Move assignment operator + CRegistrationSender& operator=(CRegistrationSender && other) noexcept = delete; + + //virtual bool SendSample(const Registration::Sample& sample_) = 0; + virtual bool SendSampleList(const Registration::SampleList& sample_list) = 0; + }; +} diff --git a/ecal/core/src/registration/ecal_registration_sender_shm.cpp b/ecal/core/src/registration/ecal_registration_sender_shm.cpp new file mode 100644 index 00000000..ddde350b --- /dev/null +++ b/ecal/core/src/registration/ecal_registration_sender_shm.cpp @@ -0,0 +1,66 @@ +/* ========================= 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 provider + * + * 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. + * +**/ + +#include "registration/ecal_registration_sender_shm.h" +#include "serialization/ecal_serialize_sample_registration.h" + + +eCAL::CRegistrationSenderSHM::CRegistrationSenderSHM() +{ + std::cout << "Shared memory monitoring is enabled (domain: " << Config::Experimental::GetShmMonitoringDomain() << " - queue size: " << Config::Experimental::GetShmMonitoringQueueSize() << ")" << '\n'; + m_memfile_broadcast.Create(Config::Experimental::GetShmMonitoringDomain(), Config::Experimental::GetShmMonitoringQueueSize()); + m_memfile_broadcast_writer.Bind(&m_memfile_broadcast); +} + +eCAL::CRegistrationSenderSHM::~CRegistrationSenderSHM() +{ + m_memfile_broadcast_writer.Unbind(); + m_memfile_broadcast.Destroy(); +} + +/* +bool eCAL::CRegistrationSenderSHM::SendSample(const Registration::Sample& sample_) +{ + return false; +} +*/ + +bool eCAL::CRegistrationSenderSHM::SendSampleList(const Registration::SampleList& sample_list) +{ + bool return_value{true}; + // serialize whole sample list + if (SerializeToBuffer(sample_list, m_sample_list_buffer)) + { + if (!m_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 return_value; +} diff --git a/ecal/core/src/registration/ecal_registration_sender_shm.h b/ecal/core/src/registration/ecal_registration_sender_shm.h new file mode 100644 index 00000000..266e644c --- /dev/null +++ b/ecal/core/src/registration/ecal_registration_sender_shm.h @@ -0,0 +1,58 @@ +/* ========================= 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 provider + * + * 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. + * +**/ + +#pragma once + +#include "registration/ecal_registration_sender.h" + +#include "shm/ecal_memfile_broadcast.h" +#include "shm/ecal_memfile_broadcast_writer.h" + +namespace eCAL +{ + class CRegistrationSenderSHM : public CRegistrationSender + { + public: + CRegistrationSenderSHM(); + ~CRegistrationSenderSHM() override; + + // Special member functionss + CRegistrationSenderSHM(const CRegistrationSenderSHM& other) = delete; + CRegistrationSenderSHM& operator=(const CRegistrationSenderSHM& other) = delete; + CRegistrationSenderSHM(CRegistrationSenderSHM&& other) noexcept = delete; + CRegistrationSenderSHM& operator=(CRegistrationSenderSHM&& other) noexcept = delete; + + //bool SendSample(const Registration::Sample& sample_) override; + bool SendSampleList(const Registration::SampleList& sample_list) override; + + private: + std::vector m_sample_list_buffer; + CMemoryFileBroadcast m_memfile_broadcast; + CMemoryFileBroadcastWriter m_memfile_broadcast_writer; + }; +} \ No newline at end of file diff --git a/ecal/core/src/registration/ecal_registration_sender_udp.cpp b/ecal/core/src/registration/ecal_registration_sender_udp.cpp new file mode 100644 index 00000000..09914832 --- /dev/null +++ b/ecal/core/src/registration/ecal_registration_sender_udp.cpp @@ -0,0 +1,81 @@ +/* ========================= 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 provider + * + * 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. + * +**/ + +#include "registration/ecal_registration_sender_udp.h" + +#include "serialization/ecal_serialize_sample_registration.h" +#include "io/udp/ecal_udp_configurations.h" +#include + +namespace +{ + using namespace eCAL; + UDP::SSenderAttr CreateAttributes() + { + eCAL::UDP::SSenderAttr attr; + attr.address = UDP::GetRegistrationAddress(); + attr.port = UDP::GetRegistrationPort(); + attr.ttl = UDP::GetMulticastTtl(); + attr.broadcast = UDP::IsBroadcast(); + attr.loopback = true; + attr.sndbuf = Config::GetUdpMulticastSndBufSizeBytes(); + return attr; + } + +} + +namespace eCAL +{ + CRegistrationSenderUDP::CRegistrationSenderUDP() + : m_reg_sample_snd(CreateAttributes()) + { + } + + CRegistrationSenderUDP::~CRegistrationSenderUDP() = default; + + bool CRegistrationSenderUDP::SendSample(const Registration::Sample& sample_) + { + // serialize single sample + if (SerializeToBuffer(sample_, m_sample_buffer)) + { + // send single sample over udp + return m_reg_sample_snd.Send("reg_sample", m_sample_buffer) != 0; + } + return false; + } + + bool CRegistrationSenderUDP::SendSampleList(const Registration::SampleList& sample_list) + { + bool return_value{ true }; + for (const auto& sample : sample_list.samples) + { + return_value &= SendSample(sample); + } + return return_value; + } +} \ No newline at end of file diff --git a/ecal/core/src/registration/ecal_registration_sender_udp.h b/ecal/core/src/registration/ecal_registration_sender_udp.h new file mode 100644 index 00000000..65967cd1 --- /dev/null +++ b/ecal/core/src/registration/ecal_registration_sender_udp.h @@ -0,0 +1,55 @@ +/* ========================= 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 sender UDP + * + * A device which sends out registration information via UDP + * +**/ + +#pragma once + +#include "registration/ecal_registration_sender.h" + +#include "io/udp/ecal_udp_sample_sender.h" + +namespace eCAL +{ + class CRegistrationSenderUDP : public CRegistrationSender + { + public: + CRegistrationSenderUDP(); + ~CRegistrationSenderUDP() override; + + // Special member functionss + CRegistrationSenderUDP(const CRegistrationSenderUDP& other) = delete; + CRegistrationSenderUDP& operator=(const CRegistrationSenderUDP& other) = delete; + CRegistrationSenderUDP(CRegistrationSenderUDP&& other) noexcept = delete; + CRegistrationSenderUDP& operator=(CRegistrationSenderUDP&& other) noexcept = delete; + + bool SendSampleList(const Registration::SampleList& sample_list) override; + + private: + 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/service/ecal_clientgate.cpp b/ecal/core/src/service/ecal_clientgate.cpp index f3e49e33..47f7402f 100644 --- a/ecal/core/src/service/ecal_clientgate.cpp +++ b/ecal/core/src/service/ecal_clientgate.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. @@ -124,7 +124,7 @@ namespace eCAL m_service_register_map[service.key] = service; // remove timeouted services - m_service_register_map.remove_deprecated(); + m_service_register_map.erase_expired(); } // inform matching clients diff --git a/ecal/core/src/service/ecal_clientgate.h b/ecal/core/src/service/ecal_clientgate.h index d3a539d9..d3930051 100644 --- a/ecal/core/src/service/ecal_clientgate.h +++ b/ecal/core/src/service/ecal_clientgate.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. @@ -64,7 +64,7 @@ namespace eCAL std::shared_timed_mutex m_client_set_sync; ServiceNameServiceImplSetT m_client_set; - using ConnectedMapT = Util::CExpMap; + using ConnectedMapT = Util::CExpirationMap; std::shared_timed_mutex m_service_register_map_sync; ConnectedMapT m_service_register_map; }; diff --git a/ecal/core/src/time/ecal_timegate.cpp b/ecal/core/src/time/ecal_timegate.cpp index 1d1495ed..bfca24c0 100644 --- a/ecal/core/src/time/ecal_timegate.cpp +++ b/ecal/core/src/time/ecal_timegate.cpp @@ -89,7 +89,7 @@ namespace eCAL m_successfully_loaded_rt = LoadModule(m_time_sync_modname, m_time_sync_rt); break; case eTimeSyncMode::replay: - m_time_sync_modname = eCALPAR(TIME, SYNC_MOD_REPLAY); + m_time_sync_modname = Config::GetTimesyncModuleReplay(); m_successfully_loaded_replay = LoadModule(m_time_sync_modname, m_time_sync_replay); break; } diff --git a/ecal/core/src/types/ecal_custom_data_types.cpp b/ecal/core/src/types/ecal_custom_data_types.cpp new file mode 100644 index 00000000..5fbf5615 --- /dev/null +++ b/ecal/core/src/types/ecal_custom_data_types.cpp @@ -0,0 +1,88 @@ +/* ========================= 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 "ecal/types/ecal_custom_data_types.h" +#include +#include +#include +#include +#include + +namespace{ + const std::array INVALID_IPV4_ADDRESSES = { + std::regex("((255|[fF][fF])\\.){3}(255|[fF][fF])"), // 255.255.255.255 + std::regex("((127|7[fF]).((0|00|000)\\.){2}(1|01|001))"), // 127.0.0.1 + std::regex("((0|00|000)\\.){3}(0|00|000)") // 0.0.0.0 + }; + const std::regex IPV4_DEC_REGEX = std::regex("(([0-9]|[0-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])"); + const std::regex IPV4_HEX_REGEX = std::regex("(([0-9a-fA-F]|[0-9a-fA-F][0-9a-fA-F])\\.){3}([0-9a-fA-F]|[0-9a-fA-F][0-9a-fA-F])"); +} + +namespace eCAL +{ + namespace Types + { + + // IpAddressV4 definitions + IpAddressV4::IpAddressV4() : IpAddressV4(NET_UDP_MULTICAST_GROUP) {}; + + IpAddressV4::IpAddressV4(const std::string& ip_address_) + { + validateIpString(ip_address_); + } + + void IpAddressV4::validateIpString(const std::string& ip_address_) + { + if ( std::regex_match(ip_address_, IPV4_DEC_REGEX) + || std::regex_match(ip_address_, IPV4_HEX_REGEX) + ) + { + for (const auto& inv_ip_regex : INVALID_IPV4_ADDRESSES) + { + if (std::regex_match(ip_address_, inv_ip_regex)) + { + throwException(ip_address_); + return; + } + } + + m_ip_address = ip_address_; + } + else + { + throwException(ip_address_); + } + } + + void IpAddressV4::throwException(const std::string& ip_address_ /*std::string("")*/) + { + 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::ostream& operator<<(std::ostream& os, const IpAddressV4& ipv4) { os << ipv4.Get(); return os; }; + } +} diff --git a/ecal/core/src/types/ecal_registration_options.cpp b/ecal/core/src/types/ecal_registration_options.cpp new file mode 100644 index 00000000..ae4051fb --- /dev/null +++ b/ecal/core/src/types/ecal_registration_options.cpp @@ -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 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_expmap.h b/ecal/core/src/util/ecal_expmap.h index b9a321b2..fd71dcfc 100644 --- a/ecal/core/src/util/ecal_expmap.h +++ b/ecal/core/src/util/ecal_expmap.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. @@ -37,23 +37,35 @@ namespace eCAL namespace Util { /** - * @brief A time expiration map - **/ + * @brief A map that stores key-value pairs and the time at which they have last been updated. + * + * @tparam Key The type of the keys. + * @tparam T The type of the values. + * @tparam ClockType The type of the clock based on which the Map expires its elements + * + * This class is *not* threadsafe and needs to be protected by locks / mutexes in multithreaded environments. + * + * From the outside / for the user, this class acts as a regular std::map. + * However, it provides one additional function (erase_expired) that removes expired elements from this map. + * Elements are considered to be expired, if they have not been accessed (via `operator[]`) within a given timeout period. + * + * Internally, this is realized by storing both a map and a list. + * The map stores the regular key, and then the actual value and additional an iterator into the timestamp list. + * The timestamp list stores together a timestamp and the key which was inserted into the list at that given timestamp. + * It is always kept in a sorted order. + * + * Whenever a map element is accessed, the responding timestamp is updated and moved to the end of the list. + * This happens in constant time. + */ template, class Alloc = std::allocator > > - class CExpMap + class CExpirationMap { public: - using clock_type = std::chrono::steady_clock; - - // Key access history, most recent at back - using key_tracker_type = std::list>; - - // Key to value and key history iterator - using key_to_value_type = std::map>; - + // Type declarations necessary to be compliant to a regular map. using allocator_type = Alloc; using value_type = std::pair; using reference = typename Alloc::reference; @@ -61,6 +73,27 @@ namespace eCAL using key_type = Key; using mapped_type = T; + private: + struct AccessTimestampListEntry + { + typename ClockType::time_point timestamp; + Key corresponding_map_key; + }; + + // Key access history, most recent at back + using AccessTimestampListType = std::list; + + struct InternalMapEntry + { + T map_value; + typename AccessTimestampListType::iterator timestamp_list_iterator; + }; + + // Key to value and key history iterator + using InternalMapType = std::map; + + public: + class iterator { friend class const_iterator; @@ -72,7 +105,7 @@ namespace eCAL using pointer = std::pair*; using reference = std::pair&; - explicit iterator(const typename key_to_value_type::iterator _it) + explicit iterator(const typename InternalMapType::iterator _it) : it(_it) {} @@ -90,7 +123,7 @@ namespace eCAL std::pair operator*() const { - return std::make_pair(it->first, it->second.first); + return std::make_pair(it->first, it->second.map_value); } //friend void swap(iterator& lhs, iterator& rhs); //C++11 I think @@ -98,7 +131,7 @@ namespace eCAL bool operator!=(const iterator& rhs) const { return it != rhs.it; } private: - typename key_to_value_type::iterator it; + typename InternalMapType::iterator it; }; class const_iterator @@ -114,7 +147,7 @@ namespace eCAL : it(other.it) {} - explicit const_iterator(const typename key_to_value_type::const_iterator _it) + explicit const_iterator(const typename InternalMapType::const_iterator _it) : it(_it) {} @@ -133,7 +166,7 @@ namespace eCAL std::pair operator*() const { - return std::make_pair(it->first, it->second.first); + return std::make_pair(it->first, it->second.map_value); } //friend void swap(iterator& lhs, iterator& rhs); //C++11 I think @@ -141,74 +174,79 @@ namespace eCAL bool operator!=(const const_iterator& rhs) const { return it != rhs.it; } private: - typename key_to_value_type::const_iterator it; + typename InternalMapType::const_iterator it; }; // Constructor specifies the timeout of the map - CExpMap() : _timeout(std::chrono::milliseconds(5000)) {}; - explicit CExpMap(clock_type::duration t) : _timeout(t) {}; + CExpirationMap() : _timeout(std::chrono::milliseconds(5000)) {}; + explicit CExpirationMap(typename ClockType::duration t) : _timeout(t) {}; /** * @brief set expiration time **/ - void set_expiration(clock_type::duration t) { _timeout = t; }; + void set_expiration(typename ClockType::duration t) { _timeout = t; }; // Iterators: iterator begin() noexcept { - return iterator(_key_to_value.begin()); + return iterator(_internal_map.begin()); } iterator end() noexcept { - return iterator(_key_to_value.end()); + return iterator(_internal_map.end()); } const_iterator begin() const noexcept { - return const_iterator(_key_to_value.begin()); + return const_iterator(_internal_map.begin()); } const_iterator end() const noexcept { - return const_iterator(_key_to_value.end()); + return const_iterator(_internal_map.end()); } // Const begin and end functions const_iterator cbegin() const noexcept { - return const_iterator(_key_to_value.cbegin()); + return const_iterator(_internal_map.cbegin()); } const_iterator cend() const noexcept { - return const_iterator(_key_to_value.cend()); + return const_iterator(_internal_map.cend()); } // Capacity bool empty() const noexcept { - return _key_to_value.empty(); + return _internal_map.empty(); } size_type size() const noexcept { - return _key_to_value.size(); + return _internal_map.size(); } size_type max_size() const noexcept { - return _key_to_value.max_size(); + return _internal_map.max_size(); } - // Element access - // Obtain value of the cached function for k + /** + * @brief Accesses the value associated with the given key, resetting its expiration time. + * + * @param key The key to access the value for. + * + * @return The value associated with the key. + */ T& operator[](const Key& k) { // Attempt to find existing record - typename key_to_value_type::iterator it - = _key_to_value.find(k); + typename InternalMapType::iterator it + = _internal_map.find(k); - if (it == _key_to_value.end()) + if (it == _internal_map.end()) { // We don't have it: // Evaluate function and create new record @@ -225,17 +263,17 @@ namespace eCAL } // Return the retrieved value - return (*it).second.first; + return (*it).second.map_value; }; mapped_type& at(const key_type& k) { - return _key_to_value.at(k).first; + return _internal_map.at(k).first; } const mapped_type& at(const key_type& k) const { - return _key_to_value.at(k).first; + return _internal_map.at(k).first; } // Modifiers @@ -248,39 +286,42 @@ namespace eCAL // Operations iterator find(const key_type& k) { - return iterator(_key_to_value.find(k)); + return iterator(_internal_map.find(k)); } const_iterator find(const Key& k) const { - return const_iterator(_key_to_value.find(k)); + return const_iterator(_internal_map.find(k)); } - // Purge the timed out elements from the cache - void remove_deprecated(std::list* key_erased = nullptr) //-V826 + /** + * @brief Erase all expired key-value pairs from the map. + * + * This function erases all expired key-value pairs from the internal map / timestamp list. + * The CExpirationMap class does not call this function internally, it has to be called explicitly by the user. + */ + void erase_expired(std::list* keys_erased_from_expired_map = nullptr) //-V826 { - // Assert method is never called when cache is empty - //assert(!_key_tracker.empty()); - clock_type::time_point eviction_limit = get_curr_time() - _timeout; - - auto it(_key_tracker.begin()); - - while (it != _key_tracker.end() && it->first < eviction_limit) + // To erase timestamps from the map, the time point of the last access is calculated, all older entries will be erased. + // Since the list is sorted, we need to remove everything from the first element until the eviction limit. + typename ClockType::time_point eviction_limit = get_curr_time() - _timeout; + auto it(_access_timestamps_list.begin()); + while (it != _access_timestamps_list.end() && it->timestamp < eviction_limit) { - if (key_erased != nullptr) key_erased->push_back(it->second); - _key_to_value.erase(it->second); // erase the element from the map - it = _key_tracker.erase(it); // erase the element from the list + if (keys_erased_from_expired_map != nullptr) keys_erased_from_expired_map->push_back(it->corresponding_map_key); + _internal_map.erase(it->corresponding_map_key); // erase the element from the map + it = _access_timestamps_list.erase(it); // erase the element from the list } } // Remove specific element from the cache bool erase(const Key& k) { - auto it = _key_to_value.find(k); - if (it != _key_to_value.end()) + auto it = _internal_map.find(k); + if (it != _internal_map.end()) { - _key_tracker.erase(it->second.second); // erase the element from the list - _key_to_value.erase(k); // erase the element from the map + _access_timestamps_list.erase(it->second.timestamp_list_iterator); // erase the element from the list + _internal_map.erase(k); // erase the element from the map return true; } return false; @@ -289,15 +330,8 @@ namespace eCAL // Remove all elements from the cache void clear() { - // Assert method is never called when cache is empty - //assert(!_key_tracker.empty()); - auto it(_key_tracker.begin()); - - while (it != _key_tracker.end()) - { - _key_to_value.erase(it->second); // erase the element from the map - it = _key_tracker.erase(it); // erase the element from the list - } + _internal_map.clear(); // erase all elements from the map + _access_timestamps_list.clear(); // erase all elements from the list } private: @@ -305,41 +339,49 @@ namespace eCAL // Maybe pass the iterator instead of the key? or at least only get k once void update_timestamp(const Key& k) { - _key_tracker.erase(_key_to_value.at(k).second); - auto new_iterator = _key_tracker.emplace(_key_tracker.end(), std::make_pair(get_curr_time(), k)); - _key_to_value.at(k).second = new_iterator; - } + auto it_in_map = _internal_map.find(k); + if (it_in_map != _internal_map.end()) + { + auto& it_in_list = it_in_map->second.timestamp_list_iterator; - // Record a fresh key-value pair in the cache - std::pair insert(const Key& k, const T& v) + // move the element to the end of the list + _access_timestamps_list.splice(_access_timestamps_list.end(), _access_timestamps_list, it_in_list); + + // update the timestamp + it_in_list->timestamp = get_curr_time(); + } + } + + // Record a fresh key-value pair in the cache + std::pair insert(const Key& k, const T& v) { // sorted list, containing (pair ( timestamp, K)) - auto it = _key_tracker.emplace(_key_tracker.end(), std::make_pair(get_curr_time(), k)); + auto it = _access_timestamps_list.emplace(_access_timestamps_list.end(), AccessTimestampListEntry{ get_curr_time(), k }); // entry mapping k -> pair (T, iterator(pair(timestamp, K))) - auto ret = _key_to_value.emplace( + auto ret = _internal_map.emplace( std::make_pair( k, - std::make_pair(v, it) + InternalMapEntry{ v, it } ) ); // return iterator to newly inserted element. return ret; } - clock_type::time_point get_curr_time() + typename ClockType::time_point get_curr_time() { - return clock_type::now(); + return ClockType::now(); } // Key access history - key_tracker_type _key_tracker; + AccessTimestampListType _access_timestamps_list; // Key-to-value lookup - key_to_value_type _key_to_value; + InternalMapType _internal_map; // Timeout of map - clock_type::duration _timeout; + typename ClockType::duration _timeout; }; } } diff --git a/ecal/core/src/util/frequency_calculator.h b/ecal/core/src/util/frequency_calculator.h index 1ec85f4f..05bda24a 100644 --- a/ecal/core/src/util/frequency_calculator.h +++ b/ecal/core/src/util/frequency_calculator.h @@ -1,6 +1,6 @@ -/* ========================= eCAL LICENSE ================================= +/* ========================= 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. @@ -52,8 +52,8 @@ namespace eCAL FrequencyCalculator(const time_point& now_) : counted_elements(0) - , first_tick(now_) - , last_tick(now_) + , first_tick_time(now_) + , last_tick_time(now_) , previous_frequency(0.0) { } @@ -61,7 +61,7 @@ namespace eCAL void addTick(const time_point& now) { counted_elements++; - last_tick = now; + last_tick_time = now; } double getFrequency() @@ -71,16 +71,16 @@ namespace eCAL return previous_frequency; } - previous_frequency = calculateFrequency(first_tick, last_tick, counted_elements); - first_tick = last_tick; + previous_frequency = calculateFrequency(first_tick_time, last_tick_time, counted_elements); + first_tick_time = last_tick_time; counted_elements = 0; return previous_frequency; } private: long long counted_elements; - time_point first_tick; - time_point last_tick; + time_point first_tick_time; + time_point last_tick_time; double previous_frequency; }; @@ -105,22 +105,37 @@ namespace eCAL { calculator->addTick(now); } - last_tick = now; + last_tick_time = now; + received_tick_since_get_frequency_called = true; } double getFrequency(const time_point& now) { double frequency = calculator ? calculator->getFrequency() : 0.0; + // if the frequency is 0.0, return it right away if (frequency == 0.0) { return 0.0; } - // calculate theoretical frequency to detect timeouts; - double theoretical_frequency = calculateFrequency(last_tick, now, 1); - // If the frequency is higher than reset_factor * theoretical_frequency, we reset. - if (frequency >= theoretical_frequency * reset_factor) + // if we have received ticks, this means we don't want to reset the calculation + // so we return the frequency that the calculator has calculated + if (received_tick_since_get_frequency_called) + { + received_tick_since_get_frequency_called = false; + return frequency; + } + + // if we have not received ticks since the last call of getFrequency + // then we calculate the ΔT, e.g. the timespan in seconds between last received and next incoming element + // Based on the last time we received a tick we could calculate when we expect the next tick + // We can also calculate when we want to time out, based on the reset factor + // timeout = last_tick + ΔT * reset_factor + // If the current time is greater than the timeout time, we reset the calculator and return 0 + auto expected_time_in_seconds_between_last_and_next_tick = std::chrono::duration(1 / frequency); + time_point timeout_time = last_tick_time + std::chrono::duration_cast(expected_time_in_seconds_between_last_and_next_tick * reset_factor); + if (now > timeout_time) { calculator.reset(); return 0.0; @@ -131,7 +146,8 @@ namespace eCAL private: float reset_factor; - time_point last_tick; + time_point last_tick_time; + bool received_tick_since_get_frequency_called = false; std::unique_ptr> calculator; }; } diff --git a/ecal/samples/CMakeLists.txt b/ecal/samples/CMakeLists.txt index 14f3fed7..eb751a33 100644 --- a/ecal/samples/CMakeLists.txt +++ b/ecal/samples/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. @@ -66,11 +66,13 @@ endif() if(ECAL_CORE_PUBLISHER AND ECAL_CORE_SUBSCRIBER) add_subdirectory(cpp/benchmarks/perftool) + add_subdirectory(cpp/benchmarks/massive_pub_sub) endif() # misc add_subdirectory(cpp/misc/process) add_subdirectory(cpp/misc/time) +add_subdirectory(cpp/misc/config) if(ECAL_CORE_PUBLISHER) add_subdirectory(cpp/misc/timer) endif() diff --git a/ecal/samples/cpp/benchmarks/counter_rec/src/counter_rec.cpp b/ecal/samples/cpp/benchmarks/counter_rec/src/counter_rec.cpp index 3a323f10..986371ab 100644 --- a/ecal/samples/cpp/benchmarks/counter_rec/src/counter_rec.cpp +++ b/ecal/samples/cpp/benchmarks/counter_rec/src/counter_rec.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. @@ -27,7 +27,9 @@ int main(int argc, char **argv) eCAL::Initialize(argc, argv, "counter_rec_cb"); // create subscriber for topic "Counter" - eCAL::CSubscriber sub("Counter", { "", "long long", "" }); + eCAL::SDataTypeInformation datatype_information; + datatype_information.encoding = "long long"; + eCAL::CSubscriber sub("Counter", datatype_information); // counter long long g_clock(0); diff --git a/ecal/samples/cpp/benchmarks/dynsize_snd/src/dynsize_snd.cpp b/ecal/samples/cpp/benchmarks/dynsize_snd/src/dynsize_snd.cpp index d71378ee..46094967 100644 --- a/ecal/samples/cpp/benchmarks/dynsize_snd/src/dynsize_snd.cpp +++ b/ecal/samples/cpp/benchmarks/dynsize_snd/src/dynsize_snd.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. @@ -27,7 +27,7 @@ int main(int argc, char **argv) eCAL::Initialize(argc, argv, "dynsize_snd"); // publisher for topic "Performance" - const eCAL::CPublisher pub("Performance"); + eCAL::CPublisher pub("Performance"); // prepare snd_buf const int MAX_BUFSIZE(10*1024*1024); diff --git a/ecal/samples/cpp/benchmarks/massive_pub_sub/CMakeLists.txt b/ecal/samples/cpp/benchmarks/massive_pub_sub/CMakeLists.txt new file mode 100644 index 00000000..5c2f37e5 --- /dev/null +++ b/ecal/samples/cpp/benchmarks/massive_pub_sub/CMakeLists.txt @@ -0,0 +1,41 @@ +# ========================= 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 ================================= + +cmake_minimum_required(VERSION 3.10) + +set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON) + +project(massive_pub_sub) + +find_package(eCAL REQUIRED) + +set(massive_pub_sub_src + src/massive_pub_sub.cpp +) + +ecal_add_sample(${PROJECT_NAME} ${massive_pub_sub_src}) + +target_link_libraries(${PROJECT_NAME} + eCAL::core +) + +target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_14) + +ecal_install_sample(${PROJECT_NAME}) + +set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER samples/cpp/benchmarks/massive_pub_sub) diff --git a/ecal/samples/cpp/benchmarks/massive_pub_sub/src/massive_pub_sub.cpp b/ecal/samples/cpp/benchmarks/massive_pub_sub/src/massive_pub_sub.cpp new file mode 100644 index 00000000..7cf864a4 --- /dev/null +++ b/ecal/samples/cpp/benchmarks/massive_pub_sub/src/massive_pub_sub.cpp @@ -0,0 +1,128 @@ +/* ========================= 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 + +#include +#include +#include +#include +#include + +const int subscriber_number (5000); + +const int publisher_number (5000); +const int publisher_type_encoding_size_bytes (10*1024); +const int publisher_type_descriptor_size_bytes (10*1024); + +const int in_between_sleep_sec (5); +const int final_sleep_sec (120); + +std::string GenerateSizedString(const std::string& name, size_t totalSize) +{ + if (name.empty() || totalSize == 0) { + return ""; + } + + std::string result; + result.reserve(totalSize); + + while (result.size() + name.size() <= totalSize) { + result += name; + } + + if (result.size() < totalSize) { + result += name.substr(0, totalSize - result.size()); + } + + return result; +} + +int main(int argc, char** argv) +{ + // initialize eCAL API + eCAL::Initialize(argc, argv, "massive_pub_sub"); + + eCAL::Util::EnableLoopback(true); + + // create subscriber + std::vector vector_of_subscriber; + std::cout << "Subscriber creation started. (" << subscriber_number << ")" << std::endl; + { + // start time measurement + auto start_time = std::chrono::high_resolution_clock::now(); + + for (int i = 0; i < subscriber_number; i++) + { + // publisher topic name + std::stringstream tname; + tname << "TOPIC_" << i; + + // create subscriber + vector_of_subscriber.emplace_back(tname.str()); + } + // stop time measurement + auto end_time = std::chrono::high_resolution_clock::now(); + + // calculate the duration + auto duration = std::chrono::duration_cast(end_time - start_time).count(); + std::cout << "Time taken for subscriber creation: " << duration << " milliseconds" << std::endl; + } + + // sleep for a few seconds + std::this_thread::sleep_for(std::chrono::seconds(in_between_sleep_sec)); + + // create publisher + std::vector vector_of_publisher; + std::cout << "Publisher creation started. (" << publisher_number << ")" << std::endl; + { + // start time measurement + auto start_time = std::chrono::high_resolution_clock::now(); + + eCAL::SDataTypeInformation data_type_info; + data_type_info.name = "TOPIC_TYPE_NAME"; + data_type_info.encoding = GenerateSizedString("TOPIC_TYPE_ENCODING", publisher_type_encoding_size_bytes); + data_type_info.descriptor = GenerateSizedString("TOPIC_TYPE_DESCRIPTOR", publisher_type_descriptor_size_bytes); + + for (int i = 0; i < publisher_number; i++) + { + // publisher topic name + std::stringstream tname; + tname << "TOPIC_" << i; + + // create publisher + vector_of_publisher.emplace_back(tname.str(), data_type_info); + } + // stop time measurement + auto end_time = std::chrono::high_resolution_clock::now(); + + // calculate the duration + auto duration = std::chrono::duration_cast(end_time - start_time).count(); + std::cout << "Time taken for publisher creation: " << duration << " milliseconds" << std::endl; + } + std::cout << std::endl; + + // sleep for a few seconds + std::this_thread::sleep_for(std::chrono::seconds(final_sleep_sec)); + + // finalize eCAL API + eCAL::Finalize(); + + return(0); +} diff --git a/ecal/samples/cpp/misc/config/CMakeLists.txt b/ecal/samples/cpp/misc/config/CMakeLists.txt new file mode 100644 index 00000000..2aa52c63 --- /dev/null +++ b/ecal/samples/cpp/misc/config/CMakeLists.txt @@ -0,0 +1,44 @@ +# ========================= 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 ================================= + +cmake_minimum_required(VERSION 3.10) + +set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON) + +project(config_sample) + +find_package(eCAL REQUIRED) + +set(config_src + src/config_sample.cpp +) + +ecal_add_sample(${PROJECT_NAME} ${config_src}) + +target_include_directories(${PROJECT_NAME} PRIVATE .) + +target_link_libraries (${PROJECT_NAME} + eCAL::core +) + +target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_14) + +ecal_install_sample(${PROJECT_NAME}) + +set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER samples/cpp/misc) + diff --git a/ecal/samples/cpp/misc/config/src/config_sample.cpp b/ecal/samples/cpp/misc/config/src/config_sample.cpp new file mode 100644 index 00000000..ebe041c5 --- /dev/null +++ b/ecal/samples/cpp/misc/config/src/config_sample.cpp @@ -0,0 +1,54 @@ +/* ========================= 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 +#include + +#include + +int main(int argc, char **argv) +{ + // creating config object + eCAL::Configuration my_config(argc, argv); + + // setting a configuration + my_config.registration.network_enabled = true; + + // initialize eCAL API + eCAL::Initialize(my_config, "config sample"); + + unsigned int counter = 0; + // enter main loop + while(eCAL::Ok()) + { + // sleep 500 ms + eCAL::Process::SleepMS(500); + if (counter >= 10) + { + break; + } + + std::cout << "Finished loop " << ++counter << "\n"; + } + + // finalize eCAL API + eCAL::Finalize(); + + return(0); +} \ No newline at end of file diff --git a/ecal/samples/cpp/monitoring/monitoring_get_topics/src/monitoring_get_topics.cpp b/ecal/samples/cpp/monitoring/monitoring_get_topics/src/monitoring_get_topics.cpp index 7922c7b3..08eea271 100644 --- a/ecal/samples/cpp/monitoring/monitoring_get_topics/src/monitoring_get_topics.cpp +++ b/ecal/samples/cpp/monitoring/monitoring_get_topics/src/monitoring_get_topics.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,10 +23,11 @@ #include #include #include +#include int main(int argc, char **argv) { - int run(0), runs(1000); + int run(0), runs(10); std::chrono::steady_clock::time_point start_time; // initialize eCAL core API @@ -48,8 +49,8 @@ int main(int argc, char **argv) auto num_topics = topic_info_map.size(); auto diff_time = std::chrono::duration_cast(std::chrono::steady_clock::now() - start_time); std::cout << "GetTopics : " << static_cast(diff_time.count()) / runs << " ms" << " (" << num_topics << " topics)" << std::endl; - std::cout << std::endl; } + std::this_thread::sleep_for(std::chrono::milliseconds(500)); // GetTopicNames { @@ -66,6 +67,7 @@ int main(int argc, char **argv) std::cout << "GetTopicsNames : " << static_cast(diff_time.count()) / runs << " ms" << " (" << num_topics << " topics)" << std::endl; std::cout << std::endl; } + std::this_thread::sleep_for(std::chrono::milliseconds(500)); } // finalize eCAL API diff --git a/ecal/samples/cpp/pubsub/protobuf/proto_dyn_json_rec/CMakeLists.txt b/ecal/samples/cpp/pubsub/protobuf/proto_dyn_json_rec/CMakeLists.txt index ee46944b..2eabfa93 100644 --- a/ecal/samples/cpp/pubsub/protobuf/proto_dyn_json_rec/CMakeLists.txt +++ b/ecal/samples/cpp/pubsub/protobuf/proto_dyn_json_rec/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. @@ -36,7 +36,7 @@ target_link_libraries(${PROJECT_NAME} eCAL::core_protobuf ) -target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_14) +target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17) ecal_install_sample(${PROJECT_NAME}) diff --git a/ecal/samples/cpp/pubsub/protobuf/proto_dyn_json_rec/src/proto_dyn_json_rec.cpp b/ecal/samples/cpp/pubsub/protobuf/proto_dyn_json_rec/src/proto_dyn_json_rec.cpp index de461496..795890c0 100644 --- a/ecal/samples/cpp/pubsub/protobuf/proto_dyn_json_rec/src/proto_dyn_json_rec.cpp +++ b/ecal/samples/cpp/pubsub/protobuf/proto_dyn_json_rec/src/proto_dyn_json_rec.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. @@ -25,10 +25,9 @@ const std::string MESSAGE_NAME("person"); -void ProtoMsgCallback(const char* topic_name_, const eCAL::SReceiveCallbackData* msg_) +void ProtoMsgCallback(const char* topic_name_, const std::string& msg_, long long /*time_*/, long long /*clock_*/, long long /*id_*/) { - std::string content((char*)msg_->buf, msg_->size); - std::cout << topic_name_ << " : " << content << std::endl; + std::cout << topic_name_ << " : " << msg_ << std::endl; std::cout << std::endl; } diff --git a/ecal/samples/cpp/services/latency_client/src/latency_client.cpp b/ecal/samples/cpp/services/latency_client/src/latency_client.cpp index b5523f88..2c9a5f07 100644 --- a/ecal/samples/cpp/services/latency_client/src/latency_client.cpp +++ b/ecal/samples/cpp/services/latency_client/src/latency_client.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. @@ -36,7 +36,7 @@ int main(int argc, char** argv) eCAL::CServiceClient latency_client("latency"); // waiting for service - while (!latency_client.IsConnected()) + while (eCAL::Ok() && !latency_client.IsConnected()) { std::this_thread::sleep_for(std::chrono::milliseconds(500)); std::cout << "Waiting for the service .." << std::endl; diff --git a/ecal/samples/cpp/services/math_client/src/math_client.cpp b/ecal/samples/cpp/services/math_client/src/math_client.cpp index 2a5d93bf..e54921c4 100644 --- a/ecal/samples/cpp/services/math_client/src/math_client.cpp +++ b/ecal/samples/cpp/services/math_client/src/math_client.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. @@ -105,7 +105,7 @@ int main(int argc, char **argv) int inp2(0); // waiting for service - while (!math_client.IsConnected()) + while (eCAL::Ok() && !math_client.IsConnected()) { std::this_thread::sleep_for(std::chrono::milliseconds(500)); std::cout << "Waiting for the service .." << std::endl; diff --git a/ecal/samples/cpp/services/ping_client/src/ping_client.cpp b/ecal/samples/cpp/services/ping_client/src/ping_client.cpp index 75ab654e..e2022da6 100644 --- a/ecal/samples/cpp/services/ping_client/src/ping_client.cpp +++ b/ecal/samples/cpp/services/ping_client/src/ping_client.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. @@ -36,7 +36,7 @@ int main(int argc, char **argv) eCAL::protobuf::CServiceClient ping_client("ping service"); // waiting for service - while (!ping_client.IsConnected()) + while (eCAL::Ok() && !ping_client.IsConnected()) { std::this_thread::sleep_for(std::chrono::milliseconds(500)); std::cout << "Waiting for the service .." << std::endl; diff --git a/ecal/samples/cpp/services/ping_client_dyn/src/ping_client_dyn.cpp b/ecal/samples/cpp/services/ping_client_dyn/src/ping_client_dyn.cpp index c7b140ba..68dec7a2 100644 --- a/ecal/samples/cpp/services/ping_client_dyn/src/ping_client_dyn.cpp +++ b/ecal/samples/cpp/services/ping_client_dyn/src/ping_client_dyn.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. @@ -40,7 +40,7 @@ int main(int argc, char **argv) eCAL::CServiceClient ping_client(service_name); // waiting for service - while (!ping_client.IsConnected()) + while (eCAL::Ok() && !ping_client.IsConnected()) { std::this_thread::sleep_for(std::chrono::milliseconds(500)); std::cout << "Waiting for the service .." << '\n'; diff --git a/ecal/tests/CMakeLists.txt b/ecal/tests/CMakeLists.txt index 1fd288da..5e2fc66b 100644 --- a/ecal/tests/CMakeLists.txt +++ b/ecal/tests/CMakeLists.txt @@ -30,6 +30,8 @@ add_subdirectory(cpp/core_test) add_subdirectory(cpp/descgate_test) +add_subdirectory(cpp/config_test) + if(ECAL_CORE_REGISTRATION) add_subdirectory(cpp/util_test) endif() diff --git a/ecal/tests/cpp/config_test/CMakeLists.txt b/ecal/tests/cpp/config_test/CMakeLists.txt new file mode 100644 index 00000000..3eb4cde4 --- /dev/null +++ b/ecal/tests/cpp/config_test/CMakeLists.txt @@ -0,0 +1,62 @@ +# ========================= 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(test_config) + +find_package(Threads REQUIRED) +find_package(GTest REQUIRED) +find_package(tclap REQUIRED) + +set(cmd_parser_src + ${ECAL_CORE_PROJECT_ROOT}/core/src/config/ecal_cmd_parser.cpp + ${ECAL_PROJECT_ROOT}/lib/ecal_utils/src/filesystem.cpp # Ideally we should reference relatively to ECAL_CORE_PROJECT_ROOT + ${ECAL_PROJECT_ROOT}/lib/ecal_utils/src/str_convert.cpp +) + +set(config_test_src + src/config_test.cpp + ${cmd_parser_src} +) + +ecal_add_gtest(${PROJECT_NAME} ${config_test_src}) + +target_include_directories(${PROJECT_NAME} PRIVATE + $ + ${CMAKE_CURRENT_LIST_DIR}/src + ${ECAL_CORE_PROJECT_ROOT}/core/src/config +) + +target_link_libraries(${PROJECT_NAME} + PRIVATE + eCAL::core + Threads::Threads + tclap::tclap + CustomTclap +) + +target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_14) + +target_compile_definitions(${PROJECT_NAME} PRIVATE ECAL_CORE_COMMAND_LINE) + +ecal_install_gtest(${PROJECT_NAME}) + +set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER tests/cpp/config) + +source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES + ${${PROJECT_NAME}_src} +) diff --git a/ecal/tests/cpp/config_test/src/config_test.cpp b/ecal/tests/cpp/config_test/src/config_test.cpp new file mode 100644 index 00000000..93c2c75b --- /dev/null +++ b/ecal/tests/cpp/config_test/src/config_test.cpp @@ -0,0 +1,287 @@ +/* ========================= 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 +#include +#include "ini_file.h" + +#include + +#include +#include +#include +#include + +#include "ecal_cmd_parser.h" + +template +void SetValue(MEMBER& member, VALUE value) +{ + member = value; +} + +TEST(core_cpp_config, user_config_passing) +{ + // Registration options + const unsigned int registration_timeout = 80000U; + const unsigned int registration_refresh = 2000U; + + // Transport layer options + const bool drop_out_of_order_messages = true; + std::string ip_address = "238.200.100.2"; + const int upd_snd_buff = (5242880 + 1024); + + // Monitoring options + const unsigned int mon_timeout = 6000U; + const std::string mon_filter_excl = "_A.*"; + const eCAL_Logging_Filter mon_log_filter_con = log_level_warning; + + // Publisher options + const bool pub_use_shm = true; + + 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.monitoring.monitoring_timeout = mon_timeout; + custom_config.monitoring.filter_excl = mon_filter_excl; + custom_config.logging.filter_log_con = mon_log_filter_con; + + custom_config.publisher.shm.enable = pub_use_shm; + + custom_config.registration = registration; + } + catch (std::invalid_argument& e) + { + throw std::runtime_error("Error while configuring Configuration: " + std::string(e.what())); + } + + // 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); + + // Test IP address assignment, default is 239.0.0.1 + EXPECT_EQ(ip_address, static_cast(eCAL::GetConfiguration().transport_layer.mc_options.group)); + + // Test UDP send buffer assignment, default is 5242880 + EXPECT_EQ(upd_snd_buff, static_cast(eCAL::GetConfiguration().transport_layer.mc_options.sndbuf)); + + // Test monitoring timeout assignment, default is 5000U + EXPECT_EQ(mon_timeout, eCAL::GetConfiguration().monitoring.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); + + // Test publisher sendmode assignment, default is eCAL::TLayer::eSendMode::smode_auto + EXPECT_EQ(pub_use_shm, eCAL::GetConfiguration().publisher.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()); + + // Finalize eCAL API + EXPECT_EQ(0, eCAL::Finalize()); +} + +TEST(ConfigDeathTest, user_config_death_test) +{ + 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")), + 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")), + std::invalid_argument); + ASSERT_THROW( + SetValue(custom_config.transport_layer.mc_options.group, std::string("127.0.0.1")), + std::invalid_argument); + ASSERT_THROW( + SetValue(custom_config.transport_layer.mc_options.group, std::string("255.255.255.255")), + std::invalid_argument); + + ASSERT_THROW( + SetValue(custom_config.transport_layer.mc_options.group, std::string("FFF.FF.FF.FF")), + std::invalid_argument); + ASSERT_THROW( + SetValue(custom_config.transport_layer.mc_options.group, std::string("FF.FF.FF.FF")), + std::invalid_argument); + ASSERT_THROW( + SetValue(custom_config.transport_layer.mc_options.group, std::string("Ff.fF.ff.Ff")), + std::invalid_argument); + ASSERT_THROW( + SetValue(custom_config.transport_layer.mc_options.group, std::string("7f.0.0.1")), + std::invalid_argument); + + ASSERT_THROW( + SetValue(custom_config.transport_layer.mc_options.group, std::string("0.0.0.0")), + std::invalid_argument); + ASSERT_THROW( + SetValue(custom_config.transport_layer.mc_options.group, std::string("00.00.00.00")), + std::invalid_argument); + ASSERT_THROW( + SetValue(custom_config.transport_layer.mc_options.group, std::string("000.000.000.000")), + std::invalid_argument); + ASSERT_THROW( + SetValue(custom_config.transport_layer.mc_options.group, std::string("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), + std::invalid_argument); + + // Wrong step. Default STEP = 1024 + ASSERT_THROW( + SetValue(custom_config.transport_layer.mc_options.sndbuf, (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 custom datatype assignment operators + eCAL::Types::IpAddressV4 ip1; + eCAL::Types::IpAddressV4 ip2; + EXPECT_EQ(static_cast(ip1), static_cast(ip2)); + + ip1 = "192.168.0.2"; + ip2 = ip1; + EXPECT_EQ(static_cast(ip1), static_cast(ip2)); + + eCAL::Types::ConstrainedInteger<0,1,10> s1; + eCAL::Types::ConstrainedInteger<0,1,10> s2; + EXPECT_EQ(static_cast(s1), static_cast(s2)); + + s1 = 5; + s2 = s1; + EXPECT_EQ(static_cast(s1), static_cast(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; + auto& config2ref = config2; + config1 = config2ref; + + EXPECT_EQ(static_cast(config1.transport_layer.mc_options.group), testValue); +} + +TEST(core_cpp_config, config_cmd_parser) +{ + // create a custom ini file + std::string ini_file_name = "customIni.ini"; + std::ofstream custom_ini_file(ini_file_name); + + if (custom_ini_file.is_open()) + { + custom_ini_file << ini_file_as_string; + custom_ini_file.close(); + } + else + { + std::cerr << "Error opening file for ini writing" << "\n"; + return; + } + + eCAL::Config::CmdParser parser; + + std::vector arguments; + + const std::string set_config_key = "--ecal-set-config-key "; + const std::string sep_slash = "/"; + const std::string sep_col = ":"; + + 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"; + + 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); + + try + { + parser.parseArguments(arguments); + } + catch(const std::runtime_error& e) + { + std::cerr << e.what() << '\n'; + } + + // 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()); +} + +TEST(CmdParserDeathTest, config_cmd_parser_death_test) +{ + eCAL::Config::CmdParser parser; + + std::vector arguments; + + arguments.push_back("test_config_cmd_parser_death_test"); + arguments.push_back("--ecal-ini-file someNotValidFileName.ini"); + + ASSERT_THROW( + parser.parseArguments(arguments), + std::runtime_error + ); +} \ 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 new file mode 100644 index 00000000..fafd498d --- /dev/null +++ b/ecal/tests/cpp/config_test/src/ini_file.h @@ -0,0 +1,194 @@ +#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 diff --git a/ecal/tests/cpp/descgate_test/CMakeLists.txt b/ecal/tests/cpp/descgate_test/CMakeLists.txt index 030b0268..284c2246 100644 --- a/ecal/tests/cpp/descgate_test/CMakeLists.txt +++ b/ecal/tests/cpp/descgate_test/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. @@ -23,7 +23,7 @@ find_package(GTest REQUIRED) set(descgate_test_src src/getpublisher.cpp - ../../../core/src/ecal_descgate.cpp + ${ECAL_CORE_PROJECT_ROOT}/core/src/ecal_descgate.cpp ) ecal_add_gtest(${PROJECT_NAME} ${descgate_test_src}) diff --git a/ecal/tests/cpp/event_test/CMakeLists.txt b/ecal/tests/cpp/event_test/CMakeLists.txt index 21acb22f..aa16040c 100644 --- a/ecal/tests/cpp/event_test/CMakeLists.txt +++ b/ecal/tests/cpp/event_test/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. @@ -23,7 +23,7 @@ find_package(GTest REQUIRED) set(event_test_src src/event_test.cpp - ../../../core/src/ecal_event.cpp + ${ECAL_CORE_PROJECT_ROOT}/core/src/ecal_event.cpp ) ecal_add_gtest(${PROJECT_NAME} ${event_test_src}) diff --git a/ecal/tests/cpp/expmap_test/src/expmap_test.cpp b/ecal/tests/cpp/expmap_test/src/expmap_test.cpp index 224eae6a..3a7f57aa 100644 --- a/ecal/tests/cpp/expmap_test/src/expmap_test.cpp +++ b/ecal/tests/cpp/expmap_test/src/expmap_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. @@ -27,10 +27,41 @@ #include +class TestingClock { +public: + // Define the required types for TrivialClock + using duration = std::chrono::milliseconds; + using rep = duration::rep; + using period = duration::period; + using time_point = std::chrono::time_point; + static const bool is_steady = false; + + // Function to get the current time + static time_point now() noexcept { + return time_point(current_time); + } + + // Function to manually set the current time + static void set_time(const time_point& tp) { + current_time = tp.time_since_epoch(); + } + + // Function to manually increment the current time by a given duration + static void increment_time(const duration& d) { + current_time += d; + } + +private: + static duration current_time; +}; + +// Initialize the static member +TestingClock::duration TestingClock::current_time{ 0 }; + TEST(core_cpp_core, ExpMap_SetGet) { // create the map with 2500 ms expiration - eCAL::Util::CExpMap expmap(std::chrono::milliseconds(200)); + eCAL::Util::CExpirationMap expmap(std::chrono::milliseconds(200)); // set "A" expmap["A"] = 1; @@ -43,52 +74,59 @@ TEST(core_cpp_core, ExpMap_SetGet) EXPECT_EQ(1, expmap.size()); // sleep - std::this_thread::sleep_for(std::chrono::milliseconds(150)); + TestingClock::increment_time(std::chrono::milliseconds(150)); // access and reset timer EXPECT_EQ(1, expmap["A"]); // check size //content = expmap.clone(); - expmap.remove_deprecated(); + expmap.erase_expired(); EXPECT_EQ(1, expmap.size()); // sleep - std::this_thread::sleep_for(std::chrono::milliseconds(150)); + TestingClock::increment_time(std::chrono::milliseconds(150)); // check size //content = expmap.clone(); - expmap.remove_deprecated(); + expmap.erase_expired(); EXPECT_EQ(1, expmap.size()); // sleep - std::this_thread::sleep_for(std::chrono::milliseconds(150)); + TestingClock::increment_time(std::chrono::milliseconds(150)); // check size //content = expmap.clone(); - expmap.remove_deprecated(); + expmap.erase_expired(); EXPECT_EQ(0, expmap.size()); expmap["A"] = 1; - std::this_thread::sleep_for(std::chrono::milliseconds(150)); + TestingClock::increment_time(std::chrono::milliseconds(150)); expmap["B"] = 2; expmap["C"] = 3; - expmap.remove_deprecated(); + expmap.erase_expired(); EXPECT_EQ(3, expmap.size()); - std::this_thread::sleep_for(std::chrono::milliseconds(150)); + TestingClock::increment_time(std::chrono::milliseconds(150)); expmap["B"] = 4; - expmap.remove_deprecated(); + expmap.erase_expired(); EXPECT_EQ(2, expmap.size()); - std::this_thread::sleep_for(std::chrono::milliseconds(150)); - expmap.remove_deprecated(); + TestingClock::increment_time(std::chrono::milliseconds(150)); + expmap.erase_expired(); EXPECT_EQ(1, expmap.size()); // sleep - std::this_thread::sleep_for(std::chrono::milliseconds(150)); + TestingClock::increment_time(std::chrono::milliseconds(150)); +} + +TEST(core_cpp_core, ExpMap_EraseEmptyMap) +{ + eCAL::Util::CExpirationMap expmap(std::chrono::milliseconds(200)); + expmap.erase_expired(); + EXPECT_TRUE(expmap.empty()); } TEST(core_cpp_core, ExpMap_Insert) { - eCAL::Util::CExpMap expmap(std::chrono::milliseconds(200)); + eCAL::Util::CExpirationMap expmap(std::chrono::milliseconds(200)); auto ret = expmap.insert(std::make_pair("A", 1)); auto key = (*ret.first).first; @@ -100,15 +138,15 @@ TEST(core_cpp_core, ExpMap_Insert) EXPECT_EQ(i, 1); - std::this_thread::sleep_for(std::chrono::milliseconds(300)); - expmap.remove_deprecated(); + TestingClock::increment_time(std::chrono::milliseconds(300)); + expmap.erase_expired(); EXPECT_EQ(0, expmap.size()); } // This tests uses find to find an element TEST(core_cpp_core, ExpMap_Find) { - eCAL::Util::CExpMap expmap(std::chrono::milliseconds(200)); + eCAL::Util::CExpirationMap expmap(std::chrono::milliseconds(200)); auto it = expmap.find("A"); EXPECT_EQ(expmap.end(), it); @@ -119,15 +157,15 @@ TEST(core_cpp_core, ExpMap_Find) int i = (*it).second; EXPECT_EQ(i, 1); - std::this_thread::sleep_for(std::chrono::milliseconds(300)); - expmap.remove_deprecated(); + TestingClock::increment_time(std::chrono::milliseconds(300)); + expmap.erase_expired(); EXPECT_EQ(0, expmap.size()); } -// This test assures that find can be called on a const CExpMap and returns an CExpMap::const_iterator +// This test assures that find can be called on a const CExpirationMap and returns an CExpirationMap::const_iterator TEST(core_cpp_core, ExpMap_FindConst) { - eCAL::Util::CExpMap expmap(std::chrono::milliseconds(200)); + eCAL::Util::CExpirationMap expmap(std::chrono::milliseconds(200)); auto it = expmap.find("A"); EXPECT_EQ(expmap.end(), it); @@ -137,19 +175,19 @@ TEST(core_cpp_core, ExpMap_FindConst) const auto& const_ref_exmap = expmap; auto const_it = const_ref_exmap.find("A"); // assert that we are actually getting a const_iterator here! - static_assert(std::is_same::const_iterator>::value, "We're not being returned a const_iterator from find."); + static_assert(std::is_same::const_iterator>::value, "We're not being returned a const_iterator from find."); int i = (*const_it).second; EXPECT_EQ(i, 1); - std::this_thread::sleep_for(std::chrono::milliseconds(300)); - expmap.remove_deprecated(); + TestingClock::increment_time(std::chrono::milliseconds(300)); + expmap.erase_expired(); EXPECT_EQ(0, expmap.size()); } TEST(core_cpp_core, ExpMap_Iterate) { // create the map with 2500 ms expiration - eCAL::Util::CExpMap expmap(std::chrono::milliseconds(200)); + eCAL::Util::CExpirationMap expmap(std::chrono::milliseconds(200)); expmap["A"] = 1; std::string key; @@ -165,7 +203,7 @@ TEST(core_cpp_core, ExpMap_Iterate) EXPECT_EQ(1, value); } -void ConstRefIterate(const eCAL::Util::CExpMap& map) +void ConstRefIterate(const eCAL::Util::CExpirationMap& map) { std::string key; int value; @@ -183,7 +221,7 @@ void ConstRefIterate(const eCAL::Util::CExpMap& map) TEST(core_cpp_core, ExpMap_ConstExpMapIterate) { // create the map with 2500 ms expiration - eCAL::Util::CExpMap expmap(std::chrono::milliseconds(200)); + eCAL::Util::CExpirationMap expmap(std::chrono::milliseconds(200)); expmap["A"] = 1; ConstRefIterate(expmap); @@ -191,7 +229,7 @@ TEST(core_cpp_core, ExpMap_ConstExpMapIterate) TEST(core_cpp_core, ExpMap_Empty) { - eCAL::Util::CExpMap expmap(std::chrono::milliseconds(200)); + eCAL::Util::CExpirationMap expmap(std::chrono::milliseconds(200)); EXPECT_EQ(true, expmap.empty()); expmap["A"] = 1; EXPECT_EQ(false, expmap.empty()); @@ -199,7 +237,7 @@ TEST(core_cpp_core, ExpMap_Empty) TEST(core_cpp_core, ExpMap_Size) { - eCAL::Util::CExpMap expmap(std::chrono::milliseconds(200)); + eCAL::Util::CExpirationMap expmap(std::chrono::milliseconds(200)); EXPECT_EQ(0, expmap.size()); expmap["A"] = 1; EXPECT_EQ(1, expmap.size()); @@ -207,7 +245,7 @@ TEST(core_cpp_core, ExpMap_Size) TEST(core_cpp_core, ExpMap_Remove) { - eCAL::Util::CExpMap expmap(std::chrono::milliseconds(200)); + eCAL::Util::CExpirationMap expmap(std::chrono::milliseconds(200)); expmap["A"] = 1; EXPECT_EQ(1, expmap.size()); EXPECT_TRUE(expmap.erase("A")); diff --git a/ecal/tests/cpp/io_memfile_test/CMakeLists.txt b/ecal/tests/cpp/io_memfile_test/CMakeLists.txt index b2e7389d..9009e1a9 100644 --- a/ecal/tests/cpp/io_memfile_test/CMakeLists.txt +++ b/ecal/tests/cpp/io_memfile_test/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. @@ -24,23 +24,23 @@ find_package(GTest REQUIRED) set(memfile_test_src src/memfile_test.cpp src/memfile_naming_test.cpp - ../../../core/src/io/mtx/ecal_named_mutex.cpp - ../../../core/src/io/shm/ecal_memfile.cpp - ../../../core/src/io/shm/ecal_memfile_db.cpp - ../../../core/src/io/shm/ecal_memfile_naming.cpp + ${ECAL_CORE_PROJECT_ROOT}/core/src/io/mtx/ecal_named_mutex.cpp + ${ECAL_CORE_PROJECT_ROOT}/core/src/io/shm/ecal_memfile.cpp + ${ECAL_CORE_PROJECT_ROOT}/core/src/io/shm/ecal_memfile_db.cpp + ${ECAL_CORE_PROJECT_ROOT}/core/src/io/shm/ecal_memfile_naming.cpp ) if(UNIX) set(memfile_test_os_src - ../../../core/src/io/mtx/linux/ecal_named_mutex_impl.cpp - ../../../core/src/io/shm/linux/ecal_memfile_os.cpp + ${ECAL_CORE_PROJECT_ROOT}/core/src/io/mtx/linux/ecal_named_mutex_impl.cpp + ${ECAL_CORE_PROJECT_ROOT}/core/src/io/shm/linux/ecal_memfile_os.cpp ) endif() if(WIN32) set(memfile_test_os_src - ../../../core/src/io/mtx/win32/ecal_named_mutex_impl.cpp - ../../../core/src/io/shm/win32/ecal_memfile_os.cpp + ${ECAL_CORE_PROJECT_ROOT}/core/src/io/mtx/win32/ecal_named_mutex_impl.cpp + ${ECAL_CORE_PROJECT_ROOT}/core/src/io/shm/win32/ecal_memfile_os.cpp ) endif() diff --git a/ecal/tests/cpp/pubsub_test/src/pubsub_acknowledge.cpp b/ecal/tests/cpp/pubsub_test/src/pubsub_acknowledge.cpp index 903854a1..1530f66e 100644 --- a/ecal/tests/cpp/pubsub_test/src/pubsub_acknowledge.cpp +++ b/ecal/tests/cpp/pubsub_test/src/pubsub_acknowledge.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. 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 4e18f043..e61dc53b 100644 --- a/ecal/tests/cpp/pubsub_test/src/pubsub_receive_test.cpp +++ b/ecal/tests/cpp/pubsub_test/src/pubsub_receive_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. @@ -216,3 +216,97 @@ TEST(core_cpp_pubsub, SporadicEmptyReceives) // finalize eCAL API EXPECT_EQ(0, eCAL::Finalize()); } + +TEST(PubSub, TestSubscriberSeen) +{ + // initialize eCAL API + EXPECT_EQ(0, eCAL::Initialize(0, nullptr, "subscriber_seen")); + + // enable data loopback + eCAL::Util::EnableLoopback(true); + + std::atomic subscriber_seen_at_publication_start(false); + std::atomic subscriber_seen_at_publication_end(false); + + std::atomic do_start_publication(false); + std::atomic publication_finished(false); + + // publishing thread + auto publisher_thread = [&]() { + eCAL::Publisher::Configuration pub_config; + pub_config.shm.acknowledge_timeout_ms = 500; + eCAL::CPublisher pub("blob", pub_config); + + int cnt(0); + const auto max_runs(1000); + while (eCAL::Ok()) + { + if (do_start_publication && cnt < max_runs) + { + if (cnt == 0) + { + subscriber_seen_at_publication_start = pub.IsSubscribed(); + } + + pub.Send(std::to_string(cnt)); + cnt++; + + if (cnt == max_runs) + { + subscriber_seen_at_publication_end = pub.IsSubscribed(); + publication_finished = true; + break; + } + } + } + }; + + // subscribing thread + auto subscriber_thread = [&]() { + eCAL::CSubscriber sub("blob"); + bool received(false); + auto max_lines(10); + auto receive_lambda = [&received, &max_lines](const char* /*topic_name_*/, const struct eCAL::SReceiveCallbackData* data_) + { + if (max_lines) + { + // the final log should look like this + // ----------------------------------- + // Receiving 0 + // Receiving 1 + // Receiving 2 + // Receiving 3 + // Receiving 4 + // Receiving 5 + // Receiving 6 + // Receiving 7 + // Receiving 8 + // Receiving 9 + // ----------------------------------- + std::cout << "Receiving " << std::string(static_cast(data_->buf), data_->size) << std::endl; + max_lines--; + } + }; + sub.AddReceiveCallback(receive_lambda); + + while (eCAL::Ok() && !publication_finished) + { + if (sub.IsPublished()) do_start_publication = true; + } + }; + + // create threads for publisher and subscriber + std::thread pub_thread(publisher_thread); + std::thread sub_thread(subscriber_thread); + + // join threads to the main thread + pub_thread.join(); + sub_thread.join(); + + // finalize eCAL API + eCAL::Finalize(); + + // check if the publisher has seen the subscriber + EXPECT_TRUE(subscriber_seen_at_publication_start); + EXPECT_TRUE(subscriber_seen_at_publication_end); +} diff --git a/ecal/tests/cpp/serialization_test/CMakeLists.txt b/ecal/tests/cpp/serialization_test/CMakeLists.txt index 17e933c0..45544213 100644 --- a/ecal/tests/cpp/serialization_test/CMakeLists.txt +++ b/ecal/tests/cpp/serialization_test/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. @@ -22,51 +22,51 @@ find_package(Threads REQUIRED) find_package(GTest REQUIRED) set(nanopb_lib_src - ../../../core/src/serialization/nanopb/nanopb/pb.h - ../../../core/src/serialization/nanopb/nanopb/pb_common.c - ../../../core/src/serialization/nanopb/nanopb/pb_common.h - ../../../core/src/serialization/nanopb/nanopb/pb_decode.c - ../../../core/src/serialization/nanopb/nanopb/pb_decode.h - ../../../core/src/serialization/nanopb/nanopb/pb_encode.c - ../../../core/src/serialization/nanopb/nanopb/pb_encode.h + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/nanopb/nanopb/pb.h + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/nanopb/nanopb/pb_common.c + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/nanopb/nanopb/pb_common.h + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/nanopb/nanopb/pb_decode.c + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/nanopb/nanopb/pb_decode.h + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/nanopb/nanopb/pb_encode.c + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/nanopb/nanopb/pb_encode.h ) set(nanopb_generated_src - ../../../core/src/serialization/nanopb/ecal.pb.c - ../../../core/src/serialization/nanopb/ecal.pb.h - ../../../core/src/serialization/nanopb/host.pb.c - ../../../core/src/serialization/nanopb/host.pb.h - ../../../core/src/serialization/nanopb/layer.pb.c - ../../../core/src/serialization/nanopb/layer.pb.h - ../../../core/src/serialization/nanopb/logging.pb.c - ../../../core/src/serialization/nanopb/logging.pb.h - ../../../core/src/serialization/nanopb/monitoring.pb.c - ../../../core/src/serialization/nanopb/monitoring.pb.h - ../../../core/src/serialization/nanopb/process.pb.c - ../../../core/src/serialization/nanopb/process.pb.h - ../../../core/src/serialization/nanopb/service.pb.c - ../../../core/src/serialization/nanopb/service.pb.h - ../../../core/src/serialization/nanopb/topic.pb.c - ../../../core/src/serialization/nanopb/topic.pb.h + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/nanopb/ecal.pb.c + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/nanopb/ecal.pb.h + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/nanopb/host.pb.c + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/nanopb/host.pb.h + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/nanopb/layer.pb.c + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/nanopb/layer.pb.h + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/nanopb/logging.pb.c + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/nanopb/logging.pb.h + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/nanopb/monitoring.pb.c + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/nanopb/monitoring.pb.h + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/nanopb/process.pb.c + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/nanopb/process.pb.h + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/nanopb/service.pb.c + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/nanopb/service.pb.h + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/nanopb/topic.pb.c + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/nanopb/topic.pb.h ) set(ecal_serialize_src - ../../../core/src/serialization/ecal_serialize_common.cpp - ../../../core/src/serialization/ecal_serialize_common.h - ../../../core/src/serialization/ecal_serialize_logging.cpp - ../../../core/src/serialization/ecal_serialize_logging.h - ../../../core/src/serialization/ecal_serialize_monitoring.cpp - ../../../core/src/serialization/ecal_serialize_monitoring.h - ../../../core/src/serialization/ecal_serialize_sample_payload.cpp - ../../../core/src/serialization/ecal_serialize_sample_payload.h - ../../../core/src/serialization/ecal_serialize_sample_registration.cpp - ../../../core/src/serialization/ecal_serialize_sample_registration.h - ../../../core/src/serialization/ecal_serialize_service.cpp - ../../../core/src/serialization/ecal_serialize_service.h - ../../../core/src/serialization/ecal_struct_sample_common.h - ../../../core/src/serialization/ecal_struct_sample_payload.h - ../../../core/src/serialization/ecal_struct_sample_registration.h - ../../../core/src/serialization/ecal_struct_service.h + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/ecal_serialize_common.cpp + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/ecal_serialize_common.h + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/ecal_serialize_logging.cpp + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/ecal_serialize_logging.h + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/ecal_serialize_monitoring.cpp + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/ecal_serialize_monitoring.h + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/ecal_serialize_sample_payload.cpp + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/ecal_serialize_sample_payload.h + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/ecal_serialize_sample_registration.cpp + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/ecal_serialize_sample_registration.h + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/ecal_serialize_service.cpp + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/ecal_serialize_service.h + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/ecal_struct_sample_common.h + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/ecal_struct_sample_payload.h + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/ecal_struct_sample_registration.h + ${ECAL_CORE_PROJECT_ROOT}/core/src/serialization/ecal_struct_service.h ) set(unit_test_src @@ -96,9 +96,7 @@ ecal_add_gtest(${PROJECT_NAME} ${nanopb_lib_src} ${nanopb_generated_src} ${ecal_ target_include_directories(${PROJECT_NAME} PRIVATE - $ - $ - $ + $ ) target_link_libraries(${PROJECT_NAME} diff --git a/ecal/tests/cpp/util_test/src/util_getclients.cpp b/ecal/tests/cpp/util_test/src/util_getclients.cpp index 28eac242..bd70c9db 100644 --- a/ecal/tests/cpp/util_test/src/util_getclients.cpp +++ b/ecal/tests/cpp/util_test/src/util_getclients.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. @@ -22,8 +22,8 @@ #include enum { - CMN_MONITORING_TIMEOUT_MS = (5000 + 100), - CMN_REGISTRATION_REFRESH_MS = (1000 + 100) + CMN_MONITORING_TIMEOUT_MS = (5000), + CMN_REGISTRATION_REFRESH_MS = (1000 * 2) }; TEST(core_cpp_util, ClientExpiration) diff --git a/ecal/tests/cpp/util_test/src/util_gettopics.cpp b/ecal/tests/cpp/util_test/src/util_gettopics.cpp index 112234d0..3b3199e9 100644 --- a/ecal/tests/cpp/util_test/src/util_gettopics.cpp +++ b/ecal/tests/cpp/util_test/src/util_gettopics.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. @@ -27,8 +27,8 @@ #include enum { - CMN_MONITORING_TIMEOUT_MS = (5000 + 100), - CMN_REGISTRATION_REFRESH_MS = (1000 + 100) + CMN_MONITORING_TIMEOUT_MS = (5000), + CMN_REGISTRATION_REFRESH_MS = (1000 * 2) }; TEST(core_cpp_util, GetTopics) diff --git a/ecal/tests/cpp/util_test/src/util_test.cpp b/ecal/tests/cpp/util_test/src/util_test.cpp index abaf84d4..5936dbf4 100644 --- a/ecal/tests/cpp/util_test/src/util_test.cpp +++ b/ecal/tests/cpp/util_test/src/util_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. @@ -194,3 +194,56 @@ TEST(core_cpp_util, Freq_ResettableFrequencyCalculator) } } } + + +struct command +{ + std::string command_type; + long long time_point; +}; + +std::vector commands = +{ +command{"getting frequency", 0 }, +command{"ticking", 500 }, +command{"getting frequency", 1000 }, +command{"ticking", 1500 }, +command{"getting frequency", 2000 }, +command{"ticking", 2500 }, +command{"getting frequency", 3000 }, +command{"ticking", 3998 }, +command{"getting frequency", 4000 }, +command{"ticking", 4002 }, +command{"getting frequency", 5000 }, +command{"ticking", 5998 }, +command{"getting frequency", 6000 }, +}; + +TEST(core_cpp_util, Freq_NoZeroFrequency) +{ + eCAL::ResettableFrequencyCalculator calculator(3.0f); + int i = 0; + + for (const auto& command : commands) + { + std::chrono::steady_clock::time_point time(std::chrono::milliseconds(command.time_point)); + + if (command.command_type == "ticking") + { + calculator.addTick(time); + } + else if (command.command_type == "getting frequency") + { + auto frequency = calculator.getFrequency(time); + if (i > 1) + { + ASSERT_GT(frequency, 0.0) << "Iteration " << i; + } + + ++i; + } + else + { + } + } +} diff --git a/lib/ecalutils/CMakeLists.txt b/lib/ecal_utils/CMakeLists.txt similarity index 100% rename from lib/ecalutils/CMakeLists.txt rename to lib/ecal_utils/CMakeLists.txt diff --git a/lib/ecalutils/include/ecal_utils/command_line.h b/lib/ecal_utils/include/ecal_utils/command_line.h similarity index 100% rename from lib/ecalutils/include/ecal_utils/command_line.h rename to lib/ecal_utils/include/ecal_utils/command_line.h diff --git a/lib/ecalutils/include/ecal_utils/ecal_utils.h b/lib/ecal_utils/include/ecal_utils/ecal_utils.h similarity index 100% rename from lib/ecalutils/include/ecal_utils/ecal_utils.h rename to lib/ecal_utils/include/ecal_utils/ecal_utils.h diff --git a/lib/ecalutils/include/ecal_utils/filesystem.h b/lib/ecal_utils/include/ecal_utils/filesystem.h similarity index 100% rename from lib/ecalutils/include/ecal_utils/filesystem.h rename to lib/ecal_utils/include/ecal_utils/filesystem.h diff --git a/lib/ecalutils/include/ecal_utils/portable_endian.h b/lib/ecal_utils/include/ecal_utils/portable_endian.h similarity index 100% rename from lib/ecalutils/include/ecal_utils/portable_endian.h rename to lib/ecal_utils/include/ecal_utils/portable_endian.h diff --git a/lib/ecalutils/include/ecal_utils/str_convert.h b/lib/ecal_utils/include/ecal_utils/str_convert.h similarity index 100% rename from lib/ecalutils/include/ecal_utils/str_convert.h rename to lib/ecal_utils/include/ecal_utils/str_convert.h diff --git a/lib/ecalutils/include/ecal_utils/string.h b/lib/ecal_utils/include/ecal_utils/string.h similarity index 100% rename from lib/ecalutils/include/ecal_utils/string.h rename to lib/ecal_utils/include/ecal_utils/string.h diff --git a/lib/ecalutils/src/command_line.cpp b/lib/ecal_utils/src/command_line.cpp similarity index 100% rename from lib/ecalutils/src/command_line.cpp rename to lib/ecal_utils/src/command_line.cpp diff --git a/lib/ecalutils/src/filesystem.cpp b/lib/ecal_utils/src/filesystem.cpp similarity index 100% rename from lib/ecalutils/src/filesystem.cpp rename to lib/ecal_utils/src/filesystem.cpp diff --git a/lib/ecalutils/src/str_convert.cpp b/lib/ecal_utils/src/str_convert.cpp similarity index 100% rename from lib/ecalutils/src/str_convert.cpp rename to lib/ecal_utils/src/str_convert.cpp