Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic data support for plotting, recording, and replaying/publishing #47

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 188 additions & 1 deletion src/dds_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,61 @@ std::shared_ptr<TopicInfo> CommonData::getTopicInfo(const QString& topicName)
return topicInfo;
}

//------------------------------------------------------------------------------
OpenDDS::XTypes::TypeKind CommonData::getMemberTypeKindById(const DDS::DynamicData_var& currentData,
const DDS::MemberId memberId)
{
DDS::ReturnCode_t rc = DDS::RETCODE_OK;
DDS::DynamicType_var memberType = currentData->type();
DDS::DynamicTypeMember_var dtm;
rc = memberType->get_member(dtm, memberId);
if (rc != DDS::RETCODE_OK) {
std::cerr << "Failed to get DynamicTypeMember for member Id " << memberId << std::endl;
}
DDS::MemberDescriptor_var md;
rc = dtm->get_descriptor(md);
if (rc != DDS::RETCODE_OK) {
std::cerr << "Failed to get MemberDescriptor for member Id " << memberId << std::endl;
}
const DDS::DynamicType_var base_type = OpenDDS::XTypes::get_base_type(md->type());
return base_type->get_kind();
}

//------------------------------------------------------------------------------
DDS::MemberId CommonData::getNestedMemberAndIdByName(DDS::DynamicData_var& currentData,
const QString& memberName)
{
// Split memberName by '.'
QStringList memberPath = memberName.split('.');
DDS::ReturnCode_t rc = DDS::RETCODE_OK;
DDS::MemberId memberId = currentData->get_member_id_by_name(memberName.toUtf8().data());

// Traverse through the structure according to the member path
for (int i = 0; i < memberPath.size(); ++i) {
const QString& currentMemberName = memberPath.at(i);

// Find the target member within this sample
memberId = currentData->get_member_id_by_name(currentMemberName.toUtf8().data());
if (memberId == OpenDDS::XTypes::MEMBER_ID_INVALID) {
std::cerr << "Invalid member ID for: " << currentMemberName.toStdString() << std::endl;
}

// If it's the last part of the member path, retrieve the value
if (i == memberPath.size() - 1) {
break;
} else {
// If it's not the last part, treat it as a nested structure (complex type) and keep going
DDS::DynamicData_var nextData;
rc = currentData->get_complex_value(nextData, memberId);
if (rc != DDS::RETCODE_OK) {
std::cerr << "Failed to get complex value for: " << currentMemberName.toStdString() << std::endl;
}
currentData = nextData; // Move to the next level of the nested structure
}
}
return memberId;
}

//------------------------------------------------------------------------------
QVariant CommonData::readValue(const QString& topicName,
const QString& memberName,
Expand All @@ -90,9 +145,141 @@ QVariant CommonData::readValue(const QString& topicName,
QList<std::shared_ptr<OpenDynamicData>>& sampleList = m_samples[topicName];
if ((int)index >= sampleList.count())
{
value = "NULL";
// Check for dynamic data instead

locker.unlock();
QMutexLocker lockerDyn(&m_dynamicSamplesMutex);

// Make sure the index is valid
QList<DDS::DynamicData_var>& sampleListDynamic = (m_dynamicSamples[topicName]);
if ((int)index >= sampleListDynamic.count()) {
value = "NULL";
return value;
}

DDS::DynamicData_var targetSampleDynamic = sampleListDynamic.at(index);
if (!targetSampleDynamic) {
value = "NULL";
return value;
}

DDS::MemberId memberId = getNestedMemberAndIdByName(targetSampleDynamic, memberName);
OpenDDS::XTypes::TypeKind member_type_kind = getMemberTypeKindById(targetSampleDynamic, memberId);
// Check the type and get the value accordingly
switch (member_type_kind) {
case OpenDDS::XTypes::TK_INT8: {
int8_t tmpValue;
if (targetSampleDynamic->get_int8_value(tmpValue, memberId) == DDS::RETCODE_OK) {
value = tmpValue;
}
break;
}
case OpenDDS::XTypes::TK_INT16: {
int16_t tmpValue;
if (targetSampleDynamic->get_int16_value(tmpValue, memberId) == DDS::RETCODE_OK) {
value = tmpValue;
}
break;
}
case OpenDDS::XTypes::TK_INT32: {
int32_t tmpValue;
if (targetSampleDynamic->get_int32_value(tmpValue, memberId) == DDS::RETCODE_OK) {
value = tmpValue;
}
break;
}
case OpenDDS::XTypes::TK_INT64: {
int64_t tmpValue;
if (targetSampleDynamic->get_int64_value(tmpValue, memberId) == DDS::RETCODE_OK) {
value = tmpValue;
}
break;
}
case OpenDDS::XTypes::TK_UINT8: {
uint8_t tmpValue;
if (targetSampleDynamic->get_uint8_value(tmpValue, memberId) == DDS::RETCODE_OK) {
value = tmpValue;
}
break;
}
case OpenDDS::XTypes::TK_UINT16: {
uint16_t tmpValue;
if (targetSampleDynamic->get_uint16_value(tmpValue, memberId) == DDS::RETCODE_OK) {
value = tmpValue;
}
break;
}
case OpenDDS::XTypes::TK_UINT32: {
uint32_t tmpValue;
if (targetSampleDynamic->get_uint32_value(tmpValue, memberId) == DDS::RETCODE_OK) {
value = tmpValue;
}
break;
}
case OpenDDS::XTypes::TK_UINT64: {
uint64_t tmpValue;
if (targetSampleDynamic->get_uint64_value(tmpValue, memberId) == DDS::RETCODE_OK) {
value = tmpValue;
}
break;
}
case OpenDDS::XTypes::TK_FLOAT32: {
float tmpValue;
if (targetSampleDynamic->get_float32_value(tmpValue, memberId) == DDS::RETCODE_OK) {
value = tmpValue;
}
break;
}
case OpenDDS::XTypes::TK_FLOAT64: {
double tmpValue;
if (targetSampleDynamic->get_float64_value(tmpValue, memberId) == DDS::RETCODE_OK) {
value = tmpValue;
}
break;
}
case OpenDDS::XTypes::TK_BOOLEAN: {
bool tmpValue;
if (targetSampleDynamic->get_boolean_value(tmpValue, memberId) == DDS::RETCODE_OK) {
value = tmpValue;
}
break;
}
case OpenDDS::XTypes::TK_CHAR8: {
char tmpValue;
if (targetSampleDynamic->get_char8_value(tmpValue, memberId) == DDS::RETCODE_OK) {
value = tmpValue;
}
break;
}
case OpenDDS::XTypes::TK_CHAR16: {
wchar_t tmpValue;
if (targetSampleDynamic->get_char16_value(tmpValue, memberId) == DDS::RETCODE_OK) {
value = tmpValue;
}
break;
}
case OpenDDS::XTypes::TK_STRING8: {
CORBA::String_var tmpValue;
if (targetSampleDynamic->get_string_value(tmpValue.out(), memberId) == DDS::RETCODE_OK) {
value = QString::fromUtf8(tmpValue);
}
break;
}
case OpenDDS::XTypes::TK_ENUM: {
uint32_t tmpValue;
if (targetSampleDynamic->get_uint32_value(tmpValue, memberId) == DDS::RETCODE_OK) {
value = tmpValue;
}
break;
}
default:
std::cerr << "TypeKind '" << OpenDDS::XTypes::typekind_to_string(member_type_kind) << "' not handled in switch" << std::endl;
value = "NULL";
break;
}
return value;
}
// If it gets to here, it's not dynamic data

const std::shared_ptr<OpenDynamicData> targetSample = sampleList.at(index);
if (!targetSample)
Expand Down
20 changes: 19 additions & 1 deletion src/dds_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

#include <memory>
#include <string>

#include <dds/DCPS/XTypes/TypeObject.h>

class DDSManager;
class OpenDynamicData;
Expand Down Expand Up @@ -245,6 +245,24 @@ class CommonData
const QString& memberName,
const unsigned int& index = 0);

/**
* @brief Get a dynamic data member's typeKind.
* @param[in] currentData The data sample of the topic (final level if nested).
* @param[in] memberId MemberId of interest.
* @return A OpenDDS::XTypes::TypeKind containing the member's typekind.
*/
static OpenDDS::XTypes::TypeKind getMemberTypeKindById(const DDS::DynamicData_var& currentData,
const DDS::MemberId memberId);

/**
* @brief Get a dynamic data member's memberId from its full name path.
* @param[in] currentData The data sample of the topic - this will be edited to point to the final level of a nested sample.
* @param[in] memberId The member's full path/name, including parents (ie with periods).
* @return A DDS::MemberId containing the member's ID.
*/
static DDS::MemberId getNestedMemberAndIdByName(DDS::DynamicData_var& currentData,
const QString& memberName);

/**
* @brief Delete all data samples for a specified topic.
* @param[in] topicName The name of the topic.
Expand Down
11 changes: 6 additions & 5 deletions src/table_page.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,13 +291,14 @@ void TablePage::on_revertButton_clicked()
void TablePage::on_publishButton_clicked()
{
const std::shared_ptr<OpenDynamicData> sample = m_tableModel->commitSample();
if (!sample)
{
return;
}

const DDS::DynamicData_var dynamicSample = m_tableModel->commitDynamicSample();
if (dynamicSample) {
m_topicReplayer->publishSample(dynamicSample);
revertButton->setEnabled(false);
} else if (sample) {
m_topicReplayer->publishSample(sample);
revertButton->setEnabled(false);
}
}


Expand Down
56 changes: 45 additions & 11 deletions src/topic_replayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include "qos_dictionary.h"

#include <dds/DCPS/EncapsulationHeader.h>

#include <dds/DCPS/XTypes/DynamicTypeSupport.h>
#include <QDateTime>
#include <iostream>

Expand All @@ -28,23 +28,15 @@ TopicReplayer::TopicReplayer(const QString& topicName) :
return;
}

// Make sure the type code is valid
m_typeCode = topicInfo->typeCode;
if (m_typeCode == nullptr)
{
std::cerr << "Unable to find type code information for "
<< topicName.toStdString()
<< std::endl;
return;
}

//store extensibility
m_extensibility = topicInfo->extensibility;


OpenDDS::DCPS::Service_Participant* service = TheServiceParticipant;
DDS::DomainParticipant* domain = CommonData::m_ddsManager->getDomainParticipant();

if (topicInfo->typeCode) {
m_typeCode = topicInfo->typeCode;
m_topic = service->create_typeless_topic(domain,
topicInfo->name.c_str(),
topicInfo->typeName.c_str(),
Expand Down Expand Up @@ -72,6 +64,35 @@ TopicReplayer::TopicReplayer(const QString& topicName) :
std::cerr << "Failed to created replayer" << std::endl;
return;
}
} else {
// Use DynamicDataWriter instead.

m_topic = domain->create_topic(topicInfo->name.c_str(),
topicInfo->typeName.c_str(),
topicInfo->topicQos,
0,
0);
if (!m_topic) {
std::cerr << "Failed to create topic " << topicInfo->name << " in replayer" << std::endl;
return;
}

DDS::Publisher_var publisher = domain->create_publisher(topicInfo->pubQos,0,
0);
if (!publisher) {
std::cerr << "Failed to create publisher for topic " << topicInfo->name << std::endl;
return;
}

m_dw = publisher->create_datawriter(m_topic,
topicInfo->writerQos,
DDS::DataWriterListener::_nil(),
OpenDDS::DCPS::DEFAULT_STATUS_MASK);
if (!m_dw) {
std::cerr << "Failed to create data writer for topic " << topicInfo->name << std::endl;
return;
}
}
//std::cout << "DEBUG Created Replayer" << std::endl;
} // End TopicReplayer::TopicReplayer

Expand Down Expand Up @@ -174,6 +195,19 @@ void TopicReplayer::publishSample(const std::shared_ptr<OpenDynamicData> sample)

} // End TopicReplayer::publishSample

//------------------------------------------------------------------------------
void TopicReplayer::publishSample(const DDS::DynamicData_var sample) {
DDS::DynamicDataWriter_var w = DDS::DynamicDataWriter::_narrow(m_dw);
if (!w) {
std::cerr << "DataWriter narrowing failed, m_dw is invalid" << std::endl;
return;
}
DDS::ReturnCode_t response = w->write(sample, DDS::HANDLE_NIL);
if (response != DDS::RETCODE_OK) {

std::cout << "write() failed; response: " << response << std::endl;
}
}

//------------------------------------------------------------------------------
TopicReplayer::~TopicReplayer()
Expand Down
4 changes: 4 additions & 0 deletions src/topic_replayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class TopicReplayer
* @param[in] sample Publish this data sample.
*/
void publishSample(const std::shared_ptr<OpenDynamicData> sample);
void publishSample(const DDS::DynamicData_var sample);

/**
* @brief Destructor for the DDS topic replayer.
Expand All @@ -56,6 +57,9 @@ class TopicReplayer

/// The topic extensibility
OpenDDS::DCPS::Extensibility m_extensibility;

/// A dynamic data writer for this topic
DDS::DataWriter_var m_dw;
};

#endif
Expand Down
Loading