38. Overview of Receiving Data

This section discusses how to create, configure, and use Subscribers and DataReaders to receive data. It describes how these objects interact, as well as the types of operations that are available for them.

The goal of this section is to help you become familiar with the Entities you need for receiving data. For up-to-date details such as formal parameters and return codes on any mentioned operations, please see the Connext API Reference HTML documentation.

There are three ways to receive data:

  • Your application can explicitly check for new data by calling a DataReader’s read() or take() operation. This method is also known as polling for data.
  • Your application can be notified asynchronously whenever new DDS data samples arrive—this is done with a Listener on either the Subscriber or the DataReader. Connext will invoke the Listener’s callback routine when there is new data. Within the callback routine, user code can access the data by calling read() or take() on the DataReader. This method is the way for your application to receive data with the least amount of latency.
  • Your application can wait for new data by using Conditions and a WaitSet, then calling wait(). Connext will block your application’s thread until the criteria (such as the arrival of DDS samples, or a specific status) set in the Condition becomes true. Then your application resumes and can access the data with read() or take().

The DataReader’s read() operation gives your application a copy of the data and leaves the data in the DataReader’s receive queue. The DataReader’s take() operation removes data from the receive queue before giving it to your application.

See 41. Using DataReaders to Access Data (Read & Take) for details on using DataReaders to access received data.

See 15.9 Conditions and WaitSets for details on using Conditions and WaitSets.

To prepare to receive data, create and configure the required Entities:

  1. Create a DomainParticipant.
  2. Register user data types1 with the DomainParticipant. For example, the ‘FooDataType’.
  3. Use the DomainParticipant to create a Topic with the registered data type.
  4. Optionally2, use the DomainParticipant to create a Subscriber.
  5. Use the Subscriber or DomainParticipant to create a DataReader for the Topic.
  6. Use a type-safe method to cast the generic DataReader created by the Subscriber to a type-specific DataReader. For example, ‘FooDataReader’.

Then use one of the following mechanisms to receive data.

  • To receive DDS data samples by polling for new data:
    • Using a FooDataReader, use the read() or take() operations to access the DDS data samples that have been received and stored for the DataReader. These operations can be invoked at any time, even if the receive queue is empty.
  • To receive DDS data samples asynchronously:
    • Install a Listener on the DataReader or Subscriber that will be called back by an internal Connext thread when new DDS data samples arrive for the DataReader.
  1. Create a DDSDataReaderListener for the FooDataReader or a DDSSubscriberListener for Subscriber. In C++ and Java, you must derive your own Listener class from those base classes. In C#, you can directly add your handlers to associated events in each entity that supports them. In C, you must create the individual functions and store them in a structure.
  2. If you created a DDSDataReaderListener with the on_data_available() callback enabled: on_data_available() will be called when new data arrives for that DataReader.

    If you created a DDSSubscriberListener with the on_data_on_readers() callback enabled: on_data_on_readers() will be called when data arrives for any DataReader created by the Subscriber.

  3. Install the Listener on either the FooDataReader or Subscriber.
  4. For the DataReader, the Listener should be installed to handle changes in the DATA_AVAILABLE status.

    For the Subscriber, the Listener should be installed to handle changes in the DATA_ON_READERS status.

  5. Only 1 Listener will be called back when new data arrives for a DataReader.
  6. Connext will call the Subscriber’s Listener if it is installed. Otherwise, the DataReader’s Listener is called if it is installed. That is, the on_data_on_readers() operation takes precedence over the on_data_available() operation.

    If neither Listeners are installed or neither Listeners are enabled to handle their respective statuses, then Connext will not call any user functions when new data arrives for the DataReader.

  7. In the on_data_available() method of the DDSDataReaderListener, invoke read() or take() on the FooDataReader to access the data.
  8. If the on_data_on_readers() method of the DDSSubscriberListener is called, the code can invoke read() or take() directly on the Subscriber’s DataReaders that have received new data. Alternatively, the code can invoke the Subscriber’snotify_datareaders() operation. This will in turn call the on_data_available() methods of the DataReaderListeners (if installed and enabled) for each of the DataReaders that have received new DDS data samples.

To wait (block) until DDS data samples arrive:

  1. Use the DataReader to create a ReadCondition that describes the DDS samples for which you want to wait. For example, you can specify that you want to wait for never-before-seen DDS samples from DataReaders that are still considered to be ‘alive.’
  2. Alternatively, you can create a StatusCondition that specifies you want to wait for the ON_DATA_AVAILABLE status.

  3. Create a WaitSet.
  4. Attach the ReadCondition or StatusCondition to the WaitSet.
  5. Call the WaitSet’swait() operation, specifying how long you are willing to wait for the desired DDS samples. When wait() returns, it will indicate that it timed out, or that the attached Condition become true (and therefore the desired DDS samples are available).
  6. Using a FooDataReader, use the read() or take() operations to access the DDS data samples that have been received and stored for the DataReader.