I'm in the process of porting from OpenSplice to Connext. I'm making a Qt application that controls some other nodes.
In the app I need to maintain a datamodel of all connected nodes. I do this by the nodes sending status messages with their information. This topic has a lifespan and liveliness set, so when a node stops sending status messages, it gets removed.
Note that it is important for Qt to get individual add/remove events to maintain the data model, just resetting the list will cause undesired behaviour.
In OpenSplice I used the code below. The problem is that when using RTI, the .data() call throws an exception when the node expires. This means I can't read which ID it is that expired. So either my code crashes, or nodes never get removed from the list.
void StatusInfo::checkStatus() {
dds::sub::status::DataState ds;
ds << dds::sub::status::SampleState::not_read()
<< dds::sub::status::ViewState::any()
<< dds::sub::status::InstanceState::any();
auto samples = statusReader.select().state(ds).read();
for (auto& sample: samples) {
QString key = QString::fromStdString(sample->data().id());
if(sample->info()->state().instance_state() == dds::sub::status::InstanceState::alive()) {
if (statusInfo.contains(key)) {
int row = std::distance(statusInfo.begin(), statusInfo.find(key));
statusInfo.insert(key, sample->data());
QModelIndex idx = createIndex(row, 0);
emit dataChanged(idx, idx, QVector<int>({NameRole}));
} else {
int row = std::distance(statusInfo.begin(), statusInfo.upperBound(key));
beginInsertRows(QModelIndex(), row, row);
statusInfo.insert(key, sample->data());
endInsertRows();
}
} else if (statusInfo.contains(key)) {
int row = std::distance(statusInfo.begin(), statusInfo.find(key));
beginRemoveRows(QModelIndex(), row, row);
statusInfo.remove(key);
endRemoveRows();
}
}
}
The QoS looks like this:
<qos_profile name="StatusInformation">
<topic_qos>
<reliability>
<kind>RELIABLE_RELIABILITY_QOS</kind>
</reliability>
<durability>
<kind>VOLATILE_DURABILITY_QOS</kind>
</durability>
<lifespan>
<duration>
<sec>10</sec>
<nanosec>0</nanosec>
</duration>
</lifespan>
<liveliness>
<kind>AUTOMATIC_LIVELINESS_QOS</kind>
<lease_duration>
<sec>10</sec>
<nanosec>0</nanosec>
</lease_duration>
</liveliness>
</topic_qos>
</qos_profile>
(what's up with the code tags? I think it needs a <pre> around it.)
Hey,
Not sure about the syntax to use in your language but it is my understanding that dispose / liveliness changed status is passed along the key entity (an entity which has the same key values as the data entity).
Meaning that if your status messages have the identifiers of a node set as key, you should be able to retrieve them when liveliness changed / lifespan are triggered.
Good luck,
Roy.
I'm not sure I understand what you mean. My status messages indeed have their identifier set as the key. But I can't find anything about these "key entities" you're talking about.
How can I get the key from my data reader form an expired key?
[edit] I ended up bypassing the whole lifetime thing, and do my own expiration logic based on the last time I read new data from a certain key.
if(sample->info().state().sample_state() == dds::sub::status::SampleState::not_read()) {
age.insert(key, 0);
} else {
age.insert(key, age.value(key) + 1);
}
You can get the key calling the operation key_value() on the DataReader. This takes an InstanceHandle which you can get from the SampleInfo calling sample->info()->instance_handle().
Gerardo
I ended up solving the problem by manually keeping track of the last time a message was received, and completely disabling DDS timeouts.