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. .. only:: not cert 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. .. only:: cert 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|_ 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. .. only:: not cert For more details on all operations, see the |api_ref_c|_ and |api_ref_cpp|_ HTML documentation. .. only:: cert For more details on all operations, see the |api_ref_c|_ 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 ---------------------- .. only:: not cert Please refer to the |api_ref_c|_ and |api_ref_cpp|_ for details on supported QosPolicies. .. only:: cert Please refer to the |api_ref_c|_ for details on supported QosPolicies. DataReader QosPolicies ---------------------- .. only:: not cert Please refer to the |api_ref_c|_ and |api_ref_cpp|_ for details on supported QosPolicies. .. only:: cert Please refer to the |api_ref_c|_ for details on supported QosPolicies.