Maintain list of connected nodes

5 posts / 0 new
Last post
Offline
Last seen: 10 months 1 week ago
Joined: 09/17/2018
Posts: 7
Maintain list of connected nodes

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.)

Offline
Last seen: 2 months 1 week ago
Joined: 02/11/2016
Posts: 142

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.

Offline
Last seen: 10 months 1 week ago
Joined: 09/17/2018
Posts: 7

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);
            }

Gerardo Pardo's picture
Offline
Last seen: 1 day 1 hour ago
Joined: 06/02/2010
Posts: 589

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

Offline
Last seen: 10 months 1 week ago
Joined: 09/17/2018
Posts: 7

I ended up solving the problem by manually keeping track of the last time a message was received, and completely disabling DDS timeouts.