CoreDX DDS Hello World Example in C++
Here is a 'C++' CoreDX DDS version of the typical "Hello World" application.
This example consists of two applications: one application that publishes a simple string message Topic (the data contains the string "hello world!"); and one application that subscribes to this topic.
The source code presented here is the 'C++' programming language version of the 'hello world' applications. It can interoperate with 'hello world' applications written in other languages, or running on different hardware platforms.
file: hello.ddl
struct StringMsg { string msg; };
file: hello_pub.cc
/**************************************************************** * * file: hello_pub.c * desc: Provides a simple C++ 'hello world' DDS publisher. * This publishing application will send data * to the example 'hello world' subscribing * application (hello_sub). * **************************************************************** * * This file is provided by Twin Oaks Computing, Inc * as an example. It is provided in the hope that it will be * useful but WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. TOC Inc assumes no liability or responsibilty for * the use of this information for any purpose. * ****************************************************************/ #include <stdio.h> #include <string.h> #ifdef _WIN32 #include <windows.h> #else #include <unistd.h> #endif #include <dds/dds.hh> #include "hello.hh" #include "helloTypeSupport.hh" #include "helloDataWriter.hh" /**************************************************************** * main() * * Perform CoreDX DDS setup activities: * - create a Domain Participant * - create a Publisher * - register the StringMsg data type * - create a Topic * - create a DataWriter * Write data ****************************************************************/ int main(int argc, char * argv[]) { DomainParticipant * domain; Publisher * publisher; Topic * topic; DataWriter * dw; StringMsg stringMsg; ReturnCode_t retval; class DomainParticipantFactory * dpf = DomainParticipantFactory::get_instance(); /* create a DomainParticipant */ domain = dpf->create_participant( 0, PARTICIPANT_QOS_DEFAULT, NULL, 0 ); if ( domain == NULL ) { printf("ERROR creating domain participant.\n"); return -1; } /* create a Publisher */ publisher = domain->create_publisher(PUBLISHER_QOS_DEFAULT, NULL, 0 ); if ( publisher == NULL ) { printf("ERROR creating publisher.\n"); return -1; } /* Register the data type with the CoreDX middleware. * This is required before creating a Topic with * this data type. */ StringMsgTypeSupport stringMsgTS; retval = stringMsgTS.register_type( domain, NULL ); if (retval != RETCODE_OK) { printf("ERROR registering type\n"); return -1; } /* Create a DDS Topic with the StringMsg data type. */ topic = domain->create_topic("helloTopic", "StringMsg", TOPIC_QOS_DEFAULT, NULL, 0 ); if ( topic == NULL ) { printf("ERROR creating topic.\n"); return -1; } /* Create a DataWriter on the hello topic, with * default QoS settings and no listeners. */ dw = publisher->create_datawriter( topic, DATAWRITER_QOS_DEFAULT, NULL, 0 ); if (dw == NULL) { printf("ERROR creating data writer\n"); return -1; } /* Initialize the data to send. The StringMsg data type * has just one string member. * Note: Alwyas initialize a string member with * allocated memory -- the destructor will free * all string members. */ stringMsg.msg = new char[strlen("Hello WORLD from C++!")+1]; strcpy(stringMsg.msg, "Hello WORLD from C++!"); while ( 1 ) { ReturnCode_t ret = dw->write ( &stringMsg, HANDLE_NIL ); printf("wrote a sample\n"); fflush(stdout); if ( ret != RETCODE_OK) { printf("ERROR writing sample\n"); return -1; } #ifdef _WIN32 Sleep(1000); #else sleep(1); #endif } /* Cleanup */ retval = domain -> delete_contained_entities(); if ( retval != DDS_RETCODE_OK ) printf("ERROR (%s): Unable to cleanup DDS entities\n", DDS_error(retval)); return 0; }
file: hello_sub.cc
/**************************************************************** * * file: hello_sub.c * desc: Provides a simple C++ 'hello world' DDS subscriber. * This subscribing application will receive data * from the example 'hello world' publishing * application (hello_pub). * **************************************************************** * * This file is provided by Twin Oaks Computing, Inc * as an example. It is provided in the hope that it will be * useful but WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. TOC Inc assumes no liability or responsibilty for * the use of this information for any purpose. * ****************************************************************/ #include <stdio.h> #ifdef _WIN32 #include <windows.h> #else #include <unistd.h> #endif #include <dds/dds.hh> #include "hello.hh" #include "helloTypeSupport.hh" #include "helloDataReader.hh" #ifdef _WIN32 # define SLEEP(a) Sleep(a*1000) #else # define SLEEP(a) sleep(a); #endif int all_done = 0; /**************************************************************** * Construct a DataReaderListener and override the * on_data_available() method with our own. All other * listener methods will be default (no-op) functions. ****************************************************************/ class SubListener : public DataReaderListener { public: void on_data_available( DataReader * dr ); }; /**************************************************************** * DataReader Listener Method: on_data_avail() * * This listener method is called when data is available to * be read on this DataReader. ****************************************************************/ void SubListener::on_data_available( DataReader * dr) { StringMsgPtrSeq samples; SampleInfoSeq samples_info; ReturnCode_t retval; SampleStateMask ss = DDS_ANY_SAMPLE_STATE; ViewStateMask vs = DDS_ANY_VIEW_STATE; InstanceStateMask is = DDS_ANY_INSTANCE_STATE; /* Convert to our type-specific DataReader */ StringMsgDataReader * reader = StringMsgDataReader::narrow( dr ); /* Take any and all available samples. The take() operation * will remove the samples from the DataReader so they * won't be available on subsequent read() or take() calls. */ retval = reader->take( &samples, &samples_info, LENGTH_UNLIMITED, ss, vs, is ); if ( retval == RETCODE_OK ) { /* iterrate through the samples */ for ( unsigned int i = 0;i < samples.size(); i++) { /* If this sample does not contain valid data, * it is a dispose or other non-data command, * and, accessing any member from this sample * would be invalid. */ if ( samples_info[i]->valid_data) printf("Sample Received: msg %d = %s\n", i, samples[i]->msg); } fflush(stdout); /* read() and take() always "loan" the data, we need to * return it so CoreDX can release resources associated * with it. */ reader->return_loan( &samples, &samples_info ); } else { printf("ERROR (%s) taking samples from DataReader\n", DDS_error(retval)); } } /**************************************************************** * main() * * Perform CoreDX DDS setup activities: * - create a Domain Participant * - create a Subscriber * - register the StringMsg data type * - create a Topic * - create a DataReader and attach the listener created above * And wait for data ****************************************************************/ #if defined(__vxworks) && !defined(__RTP__) int hello_sub(char * args) #else int main(int argc, char * argv[]) #endif { DomainParticipant * domain; Subscriber * subscriber; Topic * topic; DataReader * dr; SubListener drListener; ReturnCode_t retval; /* Get an instance of the DDS DomainPartiticpantFactory -- * we will use this to create a DomainParticipant. */ DomainParticipantFactory * dpf = DomainParticipantFactory::get_instance(); /* create a DomainParticipant */ domain = dpf->create_participant( 0, PARTICIPANT_QOS_DEFAULT, NULL, 0 ); if ( domain == NULL ) { printf("ERROR creating domain participant.\n"); return -1; } /* create a Subscriber */ subscriber = domain->create_subscriber(SUBSCRIBER_QOS_DEFAULT, NULL, 0 ); if ( subscriber == NULL ) { printf("ERROR creating subscriber\n"); return -1; } /* Register the data type with the CoreDX middleware. * This is required before creating a Topic with * this data type. */ StringMsgTypeSupport stringMsgTS; retval = stringMsgTS.register_type( domain, NULL ); if (retval != RETCODE_OK) { printf("ERROR (%s) registering type\n", DDS_error(retval)); return -1; } /* create a DDS Topic with the StringMsg data type. */ topic = domain->create_topic( "helloTopic", "StringMsg", TOPIC_QOS_DEFAULT, NULL, 0 ); if ( ! topic ) { printf("ERROR creating topic\n"); return -1; } /* create a DDS_DataReader on the hello topic (notice * the TopicDescription is used) with default QoS settings, * and attach our listener with our on_data_available method. */ dr = subscriber->create_datareader( (TopicDescription*)topic, DATAREADER_QOS_DEFAULT, &drListener, DATA_AVAILABLE_STATUS ); if ( ! dr ) { printf("ERROR creating data reader\n"); return -1; } /* Wait forever. When data arrives at our DataReader, * our dr_on_data_avilalbe method will be invoked. */ while ( !all_done ) SLEEP(30); /* Cleanup */ retval = domain -> delete_contained_entities(); if ( retval != DDS_RETCODE_OK ) printf("ERROR (%s): Unable to cleanup DDS entities\n", DDS_error(retval)); return 0; }