diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4a1fac1..0840379 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -160,6 +160,8 @@ jobs: shell: bash run: | tar xvfJ ${{ env.MATRIX_MD5 }}.tar.xz + cd OpenDDS + git submodule init && git submodule update - name: 'Configure & Build OpenDDS (Linux / macOS)' if: steps.cache-build.outputs.cache-hit != 'true' && (runner.os == 'Linux' || runner.os == 'macOS') shell: bash diff --git a/src/topic_monitor.cpp b/src/topic_monitor.cpp index 4c95d21..0152993 100644 --- a/src/topic_monitor.cpp +++ b/src/topic_monitor.cpp @@ -15,9 +15,9 @@ TopicMonitor::TopicMonitor(const QString& topicName) : m_topicName(topicName), m_filter(""), m_typeCode(nullptr), - m_listener(OpenDDS::DCPS::make_rch(OpenDDS::DCPS::ref(*this))), + m_recorder_listener(OpenDDS::DCPS::make_rch(OpenDDS::DCPS::ref(*this))), m_recorder(nullptr), - m_dr_listener(*this), + m_dr_listener(new DataReaderListenerImpl(*this)), m_topic(nullptr), m_paused(false) { @@ -36,12 +36,12 @@ TopicMonitor::TopicMonitor(const QString& topicName) : OpenDDS::DCPS::Service_Participant* service = TheServiceParticipant; DDS::DomainParticipant_var participant; if (CommonData::m_ddsManager) { - participant = CommonData::m_ddsManager->getDomainParticipant(); + participant = CommonData::m_ddsManager->getDomainParticipant(); } if (!participant) { - std::cerr << "No domain participant" << std::endl; - return; + std::cerr << "No domain participant" << std::endl; + return; } if (topicInfo->typeCode) { @@ -64,7 +64,7 @@ TopicMonitor::TopicMonitor(const QString& topicName) : m_topic, topicInfo->subQos, topicInfo->readerQos, - m_listener); + m_recorder_listener); if (!m_recorder) { std::cerr << "Failed to created recorder for topic " << topicInfo->name << std::endl; return; @@ -94,7 +94,7 @@ TopicMonitor::TopicMonitor(const QString& topicName) : m_dr = subscriber->create_datareader(m_topic, topicInfo->readerQos, - &m_dr_listener, + m_dr_listener, OpenDDS::DCPS::DEFAULT_STATUS_MASK); if (!m_dr) { std::cerr << "Failed to create data reader for topic " << topicInfo->name << std::endl; @@ -251,8 +251,8 @@ void TopicMonitor::on_sample_data_received(OpenDDS::DCPS::Recorder*, QDateTime dataTime = QDateTime::fromMSecsSinceEpoch( - (static_cast(rawSample.source_timestamp_.sec) * 1000) + - (static_cast(rawSample.source_timestamp_.nanosec) * 1e-6)); + (static_cast(rawSample.source_timestamp_.sec) * 1000) + + (static_cast(rawSample.source_timestamp_.nanosec) * 1e-6)); QString sampleName = dataTime.toString("HH:mm:ss.zzz"); CommonData::storeSample(m_topicName, sampleName, sample); @@ -280,8 +280,8 @@ void TopicMonitor::on_data_available(DDS::DataReader_ptr dr) if (infos[i].valid_data) { // TODO: Apply content filtering when it's supported. QDateTime dataTime = QDateTime::fromMSecsSinceEpoch( - (static_cast(infos[i].source_timestamp.sec) * 1000) + - (static_cast(infos[i].source_timestamp.nanosec) * 1e-6)); + (static_cast(infos[i].source_timestamp.sec) * 1000) + + (static_cast(infos[i].source_timestamp.nanosec) * 1e-6)); QString sampleName = dataTime.toString("HH:mm:ss.zzz"); CommonData::storeDynamicSample(m_topicName, sampleName, DDS::DynamicData::_duplicate(messages[i].in())); diff --git a/src/topic_monitor.h b/src/topic_monitor.h index f913820..0dd4f36 100644 --- a/src/topic_monitor.h +++ b/src/topic_monitor.h @@ -135,13 +135,13 @@ class TopicMonitor const CORBA::TypeCode* m_typeCode; /// Listener for the recorder, calls back into this object - OpenDDS::DCPS::RcHandle m_listener; + OpenDDS::DCPS::RcHandle m_recorder_listener; /// Stores the recorder object for this monitor. OpenDDS::DCPS::Recorder* m_recorder; /// Listener for a dynamic reader - DataReaderListenerImpl m_dr_listener; + DDS::DataReaderListener_var m_dr_listener; /// A dynamic data reader for this topic DDS::DataReader_var m_dr; diff --git a/src/topic_table_model.cpp b/src/topic_table_model.cpp index 0072274..8bb8c75 100644 --- a/src/topic_table_model.cpp +++ b/src/topic_table_model.cpp @@ -662,43 +662,43 @@ void TopicTableModel::setDataRow(DataRow* const data_row, // When @bit_bound is supported, update this to call the right interface. CORBA::Long value; if (check_rc(data->get_int32_value(value, id), "get enum value failed")) { - DDS::DynamicType_var type = data->type(); - const OpenDDS::XTypes::TypeKind tk = type->get_kind(); - DDS::DynamicType_var enum_dt; - if (tk == OpenDDS::XTypes::TK_STRUCTURE || tk == OpenDDS::XTypes::TK_UNION) { - DDS::DynamicTypeMember_var enum_dtm; - if (type->get_member(enum_dtm, id) != DDS::RETCODE_OK) { - std::cerr << "get_member failed for enum member with Id " - << id << std::endl; - break; - } - DDS::MemberDescriptor_var enum_md; - if (enum_dtm->get_descriptor(enum_md) != DDS::RETCODE_OK) { - std::cerr << "get_descriptor failed for enum member with Id " - << id << std::endl; - break; - } - enum_dt = DDS::DynamicType::_duplicate(enum_md->type()); - } else if (tk == OpenDDS::XTypes::TK_SEQUENCE || tk == OpenDDS::XTypes::TK_ARRAY) { - DDS::TypeDescriptor_var td; - if (type->get_descriptor(td) != DDS::RETCODE_OK) { - std::cerr << "get_descriptor failed" << std::endl; - break; - } - enum_dt = OpenDDS::XTypes::get_base_type(td->element_type()); - } - - DDS::DynamicTypeMember_var enum_lit_dtm; - if (enum_dt->get_member(enum_lit_dtm, value) != DDS::RETCODE_OK) { - std::cerr << "get_member failed for enum literal with value " << value << std::endl; - break; - } - DDS::MemberDescriptor_var enum_lit_md; - if (enum_lit_dtm->get_descriptor(enum_lit_md) != DDS::RETCODE_OK) { - std::cerr << "get_descriptor failed for enum literal with value " << value << std::endl; - break; - } - data_row->value = enum_lit_md->name(); + DDS::DynamicType_var type = data->type(); + const OpenDDS::XTypes::TypeKind tk = type->get_kind(); + DDS::DynamicType_var enum_dt; + if (tk == OpenDDS::XTypes::TK_STRUCTURE || tk == OpenDDS::XTypes::TK_UNION) { + DDS::DynamicTypeMember_var enum_dtm; + if (type->get_member(enum_dtm, id) != DDS::RETCODE_OK) { + std::cerr << "get_member failed for enum member with Id " + << id << std::endl; + break; + } + DDS::MemberDescriptor_var enum_md; + if (enum_dtm->get_descriptor(enum_md) != DDS::RETCODE_OK) { + std::cerr << "get_descriptor failed for enum member with Id " + << id << std::endl; + break; + } + enum_dt = DDS::DynamicType::_duplicate(enum_md->type()); + } else if (tk == OpenDDS::XTypes::TK_SEQUENCE || tk == OpenDDS::XTypes::TK_ARRAY) { + DDS::TypeDescriptor_var td; + if (type->get_descriptor(td) != DDS::RETCODE_OK) { + std::cerr << "get_descriptor failed" << std::endl; + break; + } + enum_dt = OpenDDS::XTypes::get_base_type(td->element_type()); + } + + DDS::DynamicTypeMember_var enum_lit_dtm; + if (enum_dt->get_member(enum_lit_dtm, value) != DDS::RETCODE_OK) { + std::cerr << "get_member failed for enum literal with value " << value << std::endl; + break; + } + DDS::MemberDescriptor_var enum_lit_md; + if (enum_lit_dtm->get_descriptor(enum_lit_md) != DDS::RETCODE_OK) { + std::cerr << "get_descriptor failed for enum literal with value " << value << std::endl; + break; + } + data_row->value = enum_lit_md->name(); } break; } @@ -740,8 +740,8 @@ void TopicTableModel::parseCollection(const DDS::DynamicData_var& data, const st if (ret != DDS::RETCODE_OK) { std::cerr << "get_complex_value for element at index " << i << " failed" << std::endl; } else { - std::string scoped_elem_name = namePrefix + "[" + std::to_string(i) + "]"; - parseData(nested_data, scoped_elem_name); + std::string scoped_elem_name = namePrefix + "[" + std::to_string(i) + "]"; + parseData(nested_data, scoped_elem_name); } continue; } @@ -751,8 +751,8 @@ void TopicTableModel::parseCollection(const DDS::DynamicData_var& data, const st DataRow* data_row = new DataRow; data_row->type = typekind_to_tckind(elem_tk); data_row->isOptional = false; // TODO: Get the right value from the containing type - std::string scoped_elem_name = namePrefix + "[" + std::to_string(i) + "]"; - data_row->name = scoped_elem_name.c_str(); + std::string scoped_elem_name = namePrefix + "[" + std::to_string(i) + "]"; + data_row->name = scoped_elem_name.c_str(); data_row->isKey = false; // TODO: Get the right value from the containing type // Update the current editor delegate @@ -793,8 +793,9 @@ void TopicTableModel::parseAggregated(const DDS::DynamicData_var& data, const st continue; } - std::string scoped_member_name = namePrefix.empty() ? md->name() : namePrefix + "." + md->name(); - const OpenDDS::XTypes::TypeKind member_tk = OpenDDS::XTypes::get_base_type(md->type())->get_kind(); + std::string scoped_member_name = namePrefix.empty() ? md->name() : namePrefix + "." + md->name(); + const DDS::DynamicType_var base_type = OpenDDS::XTypes::get_base_type(md->type()); + const OpenDDS::XTypes::TypeKind member_tk = base_type->get_kind(); switch (member_tk) { case OpenDDS::XTypes::TK_SEQUENCE: case OpenDDS::XTypes::TK_ARRAY: @@ -805,7 +806,7 @@ void TopicTableModel::parseAggregated(const DDS::DynamicData_var& data, const st if (ret != DDS::RETCODE_OK) { std::cerr << "get_complex_value for member Id " << id << " failed" << std::endl; } else { - parseData(nested_data, scoped_member_name); + parseData(nested_data, scoped_member_name); } continue; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 69b54d4..982aefa 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -2,47 +2,22 @@ cmake_minimum_required(VERSION 3.20) project(opendds-monitor-tests VERSION 0.0.1 LANGUAGES CXX) -add_executable(managed_testapp - managed.cpp -) - +add_library(test_common INTERFACE) +target_compile_options(test_common INTERFACE $<$,$,$>: -Wall -Wpedantic -Wno-unused -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-include-dirs -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wstrict-overflow=5 -Wundef -Werror> $<$: /W4>) if (MSVC) - target_compile_definitions(managed_testapp PRIVATE _CRT_SECURE_NO_WARNINGS) + target_compile_definitions(test_common INTERFACE _CRT_SECURE_NO_WARNINGS) else() - target_compile_features(managed_testapp PRIVATE cxx_std_17) + target_compile_features(test_common INTERFACE cxx_std_17) endif() - -target_compile_options(managed_testapp PRIVATE $<$,$,$>: -Wall -Wpedantic -Wno-unused -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-include-dirs -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wstrict-overflow=5 -Wundef -Werror> $<$: /W4>) - -OPENDDS_TARGET_SOURCES(managed_testapp test.idl OPENDDS_IDL_OPTIONS "-Gxtypes-complete" SUPPRESS_ANYS OFF) - -target_link_libraries(managed_testapp - OpenDDW -) - -target_include_directories(managed_testapp PRIVATE +target_include_directories(test_common INTERFACE ../src ) -add_executable(unmanaged_testapp - unmanaged.cpp -) -if (MSVC) - target_compile_definitions(unmanaged_testapp PRIVATE _CRT_SECURE_NO_WARNINGS) -else () - target_compile_features(unmanaged_testapp PRIVATE cxx_std_17) -endif() +add_executable(managed_testapp managed.cpp) +OPENDDS_TARGET_SOURCES(managed_testapp test.idl OPENDDS_IDL_OPTIONS "-Gxtypes-complete" SUPPRESS_ANYS OFF) +target_link_libraries(managed_testapp OpenDDW test_common) +add_executable(unmanaged_testapp unmanaged.cpp) OPENDDS_TARGET_SOURCES(unmanaged_testapp test.idl OPENDDS_IDL_OPTIONS "-Gxtypes-complete" SUPPRESS_ANYS OFF) - -target_compile_options(unmanaged_testapp PRIVATE $<$,$,$>: -Wall -Wpedantic -Wno-unused -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-include-dirs -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wstrict-overflow=5 -Wundef -Werror> $<$: /W4>) - -target_link_libraries(unmanaged_testapp - OpenDDS::Dcps - ${OPENDDS_TARGETS} -) - -target_include_directories(unmanaged_testapp PRIVATE - ../src -) +target_link_libraries(unmanaged_testapp OpenDDS::Dcps test_common) diff --git a/test/common.h b/test/common.h index 22cf620..120f398 100644 --- a/test/common.h +++ b/test/common.h @@ -13,7 +13,7 @@ std::string to_str(const T& t) return oss.str(); } -void generate_bt(std::mt19937& mt, test::BasicTypes& bt) +void generate_bt(std::mt19937& mt, std::mt19937::result_type /*recursion_limit*/, test::BasicTypes& bt) { const std::string str = std::string("A basic string ") + to_str(mt()); @@ -34,23 +34,29 @@ void generate_bt(std::mt19937& mt, test::BasicTypes& bt) bt.str = str.c_str(); } -void generate_bts(std::mt19937& mt, test::BasicTypesSeq& bts) +void generate_bts(std::mt19937& mt, std::mt19937::result_type recursion_limit, test::BasicTypesSeq& bts) { - bts.length((mt() % 3)); - for (CORBA::ULong i = 0; i < bts.length(); ++i) { - generate_bt(mt, bts[i]); + const CORBA::ULong len = mt() % recursion_limit; + if (len) { + bts.length(len); + } + for (CORBA::ULong i = 0; i < len; ++i) { + generate_bt(mt, recursion_limit - 1, bts[i]); } } -void generate_btss(std::mt19937& mt, test::BasicTypesSeqSeq& btss) +void generate_btss(std::mt19937& mt, std::mt19937::result_type recursion_limit, test::BasicTypesSeqSeq& btss) { - btss.length((mt() % 3)); - for (CORBA::ULong i = 0; i < btss.length(); ++i) { - generate_bts(mt, btss[i]); + const CORBA::ULong len = mt() % recursion_limit; + if (len) { + btss.length(len); + } + for (CORBA::ULong i = 0; i < len; ++i) { + generate_bts(mt, recursion_limit - 1, btss[i]); } } -void generate_ut(std::mt19937& mt, test::UnionType& ut) +void generate_ut(std::mt19937& mt, std::mt19937::result_type recursion_limit, test::UnionType& ut) { std::mt19937::result_type res = 1 + mt() % 4; switch (res) { @@ -62,27 +68,27 @@ void generate_ut(std::mt19937& mt, test::UnionType& ut) case 2: { test::BasicTypes bt; ut.bt(bt); - generate_bt(mt, ut.bt()); + generate_bt(mt, recursion_limit, ut.bt()); break; } case 3: { test::BasicTypesSeq bts; ut.bts(bts); - generate_bts(mt, ut.bts()); + generate_bts(mt, recursion_limit, ut.bts()); break; } case 4: { test::BasicTypesSeqSeq btss; ut.btss(btss); - generate_btss(mt, ut.btss()); + generate_btss(mt, recursion_limit, ut.btss()); break; } } } -void generate_tns(std::mt19937& mt, test::TreeNodeSeq& tns); +void generate_tns(std::mt19937& mt, std::mt19937::result_type recursion_limit, test::TreeNodeSeq& tns); -void generate_tn(std::mt19937& mt, test::TreeNode& tn) +void generate_tn(std::mt19937& mt, std::mt19937::result_type recursion_limit, test::TreeNode& tn) { switch (1 + mt() % 4) { case 1: tn.et = test::one; break; @@ -90,19 +96,22 @@ void generate_tn(std::mt19937& mt, test::TreeNode& tn) case 3: tn.et = test::three; break; case 4: tn.et = test::four; break; } - generate_ut(mt, tn.ut); - generate_tns(mt, tn.tns); + generate_ut(mt, recursion_limit, tn.ut); + generate_tns(mt, recursion_limit, tn.tns); } -void generate_tns(std::mt19937& mt, test::TreeNodeSeq& tns) +void generate_tns(std::mt19937& mt, std::mt19937::result_type recursion_limit, test::TreeNodeSeq& tns) { - tns.length((mt() % 3)); - for (CORBA::ULong i = 0; i < tns.length(); ++i) { - generate_tn(mt, tns[i]); + const CORBA::ULong len = mt() % recursion_limit; + if (len) { + tns.length(len); + } + for (CORBA::ULong i = 0; i < len; ++i) { + generate_tn(mt, recursion_limit - 1, tns[i]); } } -void generate_cut(std::mt19937& mt, test::ComplexUnionType& cut) +void generate_cut(std::mt19937& mt, std::mt19937::result_type recursion_limit, test::ComplexUnionType& cut) { std::mt19937::result_type res = 1 + mt() % 4; switch (res) { @@ -114,33 +123,36 @@ void generate_cut(std::mt19937& mt, test::ComplexUnionType& cut) case 2: { test::UnionType ut; cut.ut(ut); - generate_ut(mt, cut.ut()); + generate_ut(mt, recursion_limit, cut.ut()); break; } case 3: { test::TreeNode tn; cut.tn(tn); - generate_tn(mt, cut.tn()); + generate_tn(mt, recursion_limit, cut.tn()); break; } case 4: { test::TreeNodeSeq tns; cut.tns(tns); - generate_tns(mt, cut.tns()); + generate_tns(mt, recursion_limit, cut.tns()); break; } } } -void generate_cuts(std::mt19937& mt, test::ComplexUnionTypeSeq& cuts) +void generate_cuts(std::mt19937& mt, std::mt19937::result_type recursion_limit, test::ComplexUnionTypeSeq& cuts) { - cuts.length((mt() % 3)); - for (CORBA::ULong i = 0; i < cuts.length(); ++i) { - generate_cut(mt, cuts[i]); + const CORBA::ULong len = mt() % recursion_limit; + if (len) { + cuts.length(len); + } + for (CORBA::ULong i = 0; i < len; ++i) { + generate_cut(mt, recursion_limit - 1, cuts[i]); } } -void generate_samples(std::mt19937& mt, CORBA::ULongLong count, test::BasicMessage& bm, test::ComplexMessage& cm) +void generate_samples(std::mt19937& mt, std::mt19937::result_type recursion_limit, CORBA::ULongLong count, test::BasicMessage& bm, test::ComplexMessage& cm) { const std::string count_str = std::string("The current count is ") + to_str(count); @@ -178,6 +190,6 @@ void generate_samples(std::mt19937& mt, CORBA::ULongLong count, test::BasicMessa cm.ct.bt.wc = 'Z' - (count % 26); bm.bt.str = count_str.c_str(); - generate_cuts(mt, cm.ct.cuts); + generate_cuts(mt, recursion_limit, cm.ct.cuts); } diff --git a/test/json_conversion.h b/test/json_conversion.h new file mode 100644 index 0000000..74c1943 --- /dev/null +++ b/test/json_conversion.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#ifndef OPENDDS_RAPIDJSON +# define OPENDDS_RAPIDJSON +#endif +#include +#include + +#include + +template > +bool idl_2_json(const IDL_Type& idl_value, std::ostream& os, + int max_decimal_places = Writer_Type::kDefaultMaxDecimalPlaces) +{ + rapidjson::OStreamWrapper osw(os); + Writer_Type writer(osw); + OpenDDS::DCPS::JsonValueWriter jvw(writer); + if (max_decimal_places != Writer_Type::kDefaultMaxDecimalPlaces) { + writer.SetMaxDecimalPlaces(max_decimal_places); + } + vwrite(jvw, idl_value); + osw.Flush(); + os << std::endl; + return true; +} diff --git a/test/managed.cpp b/test/managed.cpp index dcffafa..3053b49 100644 --- a/test/managed.cpp +++ b/test/managed.cpp @@ -1,4 +1,5 @@ #include "common.h" +#include "json_conversion.h" #include "testTypeSupportImpl.h" #include "std_qosC.h" @@ -57,27 +58,45 @@ int main(int argc, char* argv[]) const std::string id = ex.substr(ex.find_last_of("/\\") + 1) + '-' + OpenDDS::DCPS::get_fully_qualified_hostname() + "-" + to_str(ACE_OS::getpid()); CORBA::ULongLong count = 0; + std::cout << "Creating write thread." << std::endl; + std::thread thread([&](){ + + std::cout << "Write thread started." << std::endl << std::endl; + + const std::mt19937::result_type seed = static_cast(time(0)); std::mt19937 mt; - mt.seed(static_cast(time(0))); + mt.seed(seed); + + std::cout << "reproducible seed = " << seed; while (run) { + + // Start with sleep to give monitor time to connect and open topic window + std::this_thread::sleep_for(std::chrono::seconds(10)); + test::BasicMessage basic_message{}; basic_message.origin = id.c_str(); test::ComplexMessage complex_message{}; complex_message.origin = id.c_str(); - generate_samples(mt, count, basic_message, complex_message); + generate_samples(mt, 3, count, basic_message, complex_message); + + std::stringstream ss; + if (idl_2_json(complex_message, ss)) { + std::cout << std::endl << "Writing complex sample: " << ss.str() << std::endl; + } else { + std::cerr << "Error: failure to convert complex sample to json" << std::endl; + } dds_manager->writeSample(basic_message, basic_topic_name); dds_manager->writeSample(complex_message, complex_topic_name); ++count; - - std::this_thread::sleep_for(std::chrono::seconds(5)); } + std::cout << "Write thread stopped." << std::endl; }); std::string line; @@ -85,6 +104,8 @@ int main(int argc, char* argv[]) run = false; + std::cout << "Joining write thread." << std::endl; + thread.join(); return 0; diff --git a/test/unmanaged.cpp b/test/unmanaged.cpp index 8a35211..fdfdd34 100644 --- a/test/unmanaged.cpp +++ b/test/unmanaged.cpp @@ -1,4 +1,5 @@ #include "common.h" +#include "json_conversion.h" #include "testTypeSupportImpl.h" @@ -141,27 +142,45 @@ int main(int argc, char* argv[]) const std::string id = ex.substr(ex.find_last_of("/\\") + 1) + '-' + OpenDDS::DCPS::get_fully_qualified_hostname() + "-" + to_str(ACE_OS::getpid()); CORBA::ULongLong count = 0; + std::cout << "Creating write thread." << std::endl; + std::thread thread([&](){ + + std::cout << "Write thread started." << std::endl << std::endl; + + const std::mt19937::result_type seed = static_cast(time(0)); std::mt19937 mt; - mt.seed(static_cast(time(0))); + mt.seed(seed); + + std::cout << "reproducible seed = " << seed; while (run) { + + // Start with sleep to give monitor time to connect and open topic window + std::this_thread::sleep_for(std::chrono::seconds(10)); + test::BasicMessage basic_message{}; basic_message.origin = id.c_str(); test::ComplexMessage complex_message{}; complex_message.origin = id.c_str(); - generate_samples(mt, count, basic_message, complex_message); + generate_samples(mt, 3, count, basic_message, complex_message); + + std::stringstream ss; + if (idl_2_json(complex_message, ss)) { + std::cout << std::endl << "Writing complex sample: " << ss.str() << std::endl; + } else { + std::cerr << "Error: failure to convert complex sample to json" << std::endl; + } basic_message_dw->write(basic_message, DDS::HANDLE_NIL); complex_message_dw->write(complex_message, DDS::HANDLE_NIL); ++count; - - std::this_thread::sleep_for(std::chrono::seconds(5)); } + std::cout << "Write thread stopped." << std::endl; }); std::string line; @@ -169,6 +188,8 @@ int main(int argc, char* argv[]) run = false; + std::cout << "Joining write thread." << std::endl; + thread.join(); participant->delete_contained_entities();