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 |api_ref_c|_ and |api_ref_cpp|_ documentation. Preview: Steps to Receiving Data -------------------------------- 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*. |rti_me| 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()**. |me| 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. **To prepare to receive data, create and configure the required Entities:** 1. Create a *DomainParticipant*. 2. Register user data types with the *DomainParticipant*. For example, the ‘**FooDataType**’. 3. Use the *DomainParticipant* to create a *Topic* with the registered data type. 4. 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 |me| thread when new DDS data samples arrive for the *DataReader*. 1. Create a *DDSDataReaderListener* for the *FooDataReader* or a *DDSSubscriberListener* for *Subscriber*. In C++ you must derive your own *Listener* class from those base classes. In C, you must create the individual functions and store them in a structure. 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*. 2. Install the *Listener* on either the *FooDataReader* or *Subscriber*. 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. 3. Only 1 *Listener* will be called back when new data arrives for a *DataReader*. |me| 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 |me| will not call any user functions when new data arrives for the *DataReader*. 4. In the **on_data_available()** method of the *DDSDataReaderListener*, invoke **read()** or **take()** on the *FooDataReader* to access the data. 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’s* **notify_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 *StatusCondition* 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. Create a *WaitSet*. 3. Attach the *StatusCondition* to the *WaitSet*. 4. Call the *WaitSet’s* **wait()** 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). 5. Using a **FooDataReader**, use the **read()** or **take()** operations to access the DDS data samples that have been received and stored for the *DataReader*. Subscribers ----------- An application that intends to subscribe to information needs the following *Entities*: *DomainParticipant*, *Topic*, *Subscriber*, and *DataReader*. All *Entities* have a corresponding specialized *Listener* and a set of QosPolicies. The *Listener* is how |rti_me| notifies your application of status changes relevant to the *Entity*. The QosPolicies allow your application to configure the behavior and resources of the *Entity*. - The *DomainParticipant* defines the DDS domain on which the information will be available. - The *Topic* defines the name of the data to be subscribed, as well as the type (format) of the data itself. - The *DataReader* is the *Entity* used by the application to subscribe to updated values of the data. The *DataReader* is bound at creation time to a *Topic*, thus specifying the named and typed data stream to which it is subscribed. The application uses the *DataWriter’s* **read()** or **take()** operation to access DDS data samples received for the *Topic*. - The *Subscriber* manages the activities of several *DataReader* entities. The application receives data using a *DataReader* that belongs to a *Subscriber*. However, the *Subscriber* will determine when the data received from applications is actually available for access through the *DataReader*. Depending on the settings of various QosPolicies of the *Subscriber* and *DataReader*, data may be buffered until DDS data samples for associated *DataReaders* are also received. By default, the data is available to the application as soon as it is received. For more information on creating and deleting *Subscribers*, as well as setting QosPolicies, see |rti_core_um_subscribers_verbose| in the |rti_core_um| (available |rti_core_um_subscribers|_ if you have Internet access). DataReaders ----------- To create a *DataReader*, you need a *DomainParticipant*, a *Topic*, and a *Subscriber*. You need at least one *DataReader* for each *Topic* whose DDS data samples you want to receive. For more details on all operations, see the |api_ref_c|_ and |api_ref_cpp|_ HTML documentation. Using DataReaders to Access Data (Read & Take) ---------------------------------------------- For user applications to access the data received for a *DataReader*, they must use the type-specific derived class or set of functions in the |api_ref_c|_. Thus for a user data type ‘**Foo**’, you must use methods of the **FooDataReader** class. The type-specific class or functions are automatically generated if you use *RTI Code Generator*. Subscriber QosPolicies ---------------------- Please refer to the |api_ref_c|_ and |api_ref_cpp|_ for details on supported QosPolicies. DataReader QosPolicies ---------------------- Please refer to the |api_ref_c|_ and |api_ref_cpp|_ for details on supported QosPolicies.