OpenDDSharp: Get Started

The full code of this example can be found in the OpenDDSharp GitHub repository

Requeriments

Create the IDL project

Install the OpenDDSharp IDL Templates extension

The templates extension for the IDL project is available on the Visual Studio marketplace. You can download direclty from here or use the "Tools->Extensions and Updates" option in your Visual Studio. Once the extension is installed (remember to restart your Visual Studio after the installation) a new project and item template are added as Visual C++ project templates.

Create a new IDL project in your solution

Using the previously installed project template, create a new project in your solution and name it as you prefer (i.e. TestMessage). Even if the project is created for C++, you don't need to code any C++ here. Only the IDL file need to be modified using the IDL language and the rest of the code will be auto-generated for you and ready to use in your .NET projects. In addition, a project.json file is added to your project with the reference to the specific version of the Code Generator NuGet package. For this first example, we are going to create a simple structure that will be used to share messages between the publisher and the subscriber. Open the TestMessage.idl file and copy/paste the following code:
module HelloWorld {
    #pragma DCPS_DATA_TYPE "HelloWorld::Message"
    struct Message {
	    string Content;
    };
};
The first time the project is built the NuGet package will be downloaded and after that the code generator will create the native OpenDDS project and the C++/CLI wrapper to be used in your .NET project. If you modify the IDL file, remember to Rebuild (no only Build) the project to re-generate the code.

The HelloWorld publisher

Create the publisher project

We are going to create a simple console application for the publisher of the Hello World example. To do so, just create a new project in your solution using the "File->New->Project" and choosing the Console App (.NET Framework) template. By default, the project is created for AnyCPU platforms. As OpenDDSharp is a wrapper for C++ native code, the AnyCPU platform cannot be used and we need to create the configurations for x86 and/or x64 manually using the "Configuration Manager". After that, you need to install the OpenDDSharp library via the NuGet package. There are many ways to do so but the fastest one is to use the "Package Manager Console" with the following command:

PM > Install-Package OpenDDSharp -Version 0.3.0
Finally, we need to add a reference to the IDL project created previously. As usual, right click in the Publisher project and choose the option "Add->Reference...".

RTPS configuration file

OpenDDS uses as default discovery system the InfoRepoDiscovery that requires an external process to handle the applications discovery. In order to use the standard discovery system proposed by DDS (RTPS), we need to provide the “.ini” configuration file to the DomainParticipantFactory.
Copy the following content in a file (i.e. rtps.ini) and add it to the project. After that, select the file and in the “Properties” window change the value of “Copy to Output Directory” to “Copy if newer”.
[common]
DCPSGlobalTransportConfig=$file
DCPSDefaultDiscovery=DEFAULT_RTPS

[transport/the_rtps_transport]
transport_type=rtps_udp

Create the DDS DomainParticipant

The first entity to be created in a DDS application is the domain participant. The domain participant is created with the domain participant factory and it is the factory for the DDS topics, publishers and subscribers. The following code shows how to create a domain participant in the domain 42:
DomainParticipantFactory dpf = ParticipantService.Instance.GetDomainParticipantFactory("-DCPSConfigFile", "rtps.ini");
DomainParticipant participant = dpf.CreateParticipant(42);
if (participant == null)
{
    throw new Exception("Could not create the participant");
}

Create the DDS Topic

Before create the topic, it is mandatory to register the type that is going to be used to share the data in that topic. We are going to use the Message structure defined in the IDL project. The following code shows how to register the Message type in the previously created domain participant:
MessageTypeSupport support = new MessageTypeSupport();
ReturnCode result = support.RegisterType(participant, support.GetTypeName());
if (result != ReturnCode.Ok)
{
    throw new Exception("Could not register type: " + result.ToString());
}

Now, we can create the DDS topic entity where the messages will be shared with the subscribers:
Topic topic = participant.CreateTopic("MessageTopic", support.GetTypeName());
if (topic == null)
{
    throw new Exception("Could not create the message topic");
}

Create the DDS Publisher and the DDS DataWriter

The publisher entity is the factory for the datawriter entities. The datawriter entity is in charge of writting the data in the related topic. You can group several datawriter entities in the same publisher entity. In this example we only need one publisher and one datawriter related with the MessageTopic created previously. The following code shows how to create the publisher entity:
Publisher publisher = participant.CreatePublisher();
if (publisher == null)
{
    throw new Exception("Could not create the publisher");
}
To create the datawriter first we need to create a generic datawriter related with the topic and after that a specific datawriter for the registered type of the topic. The following code shows how to create a datawriter for the MessageTopic:
DataWriter writer = publisher.CreateDataWriter(topic);
if (writer == null)
{
    throw new Exception("Could not create the data writer");
}
MessageDataWriter messageWriter = new MessageDataWriter(writer);

Wait for a subscription before write the message

The default QoS configuration for the datawriter use a volatile durability. Only the datareaders matched with the datawriters when the data is written will receive the message. The following code shows how to ensure that at least one datareader is present before we write the data:
Console.WriteLine("Waiting for a subscriber...");
PublicationMatchedStatus status = new PublicationMatchedStatus();
do
{
    writer.GetPublicationMatchedStatus(ref status);
    System.Threading.Thread.Sleep(500);
}
while (status.CurrentCount < 1);
Now that we are sure that at least one datareader is present in the system we can write the message to the topic:
Console.WriteLine("Subscriber found, writting data....");
messageWriter.Write(new Message
{
    Content = "Hello, I love you, won't you tell me your name?"
});

Console.WriteLine("Press a key to exit...");
Console.ReadKey();

Shutdown the application

Before exit the application you should release all the resources used by DDS. The following code shows how to release all the entities previously created:
participant.DeleteContainedEntities();
dpf.DeleteParticipant(participant);
ParticipantService.Instance.Shutdown();

The HelloWorld subscriber

Create the subscriber project

Same as the publisher project, we need to create a new console application, use a x86 or x64 platform, add the OpenDDSharp NuGet package and add a reference to the IDL project. For more details, check the section "Create the publisher project".

Create the domain participant, register the type and create the topic

You need to create the same enities as in the publisher project. Pay attention to use the same domain id (42) and the same topic name ("MessageTopic") used in the publisher application.

Create the DDS Subscriber and the DDS DataReader

The subscriber entity is the factory for the datareader entities. The datareader entity is in charge of reading the data in the related topic. You can group several datareader entities in the same subscriber entity. In this example we only need one subscriber and one datareader related with the MessageTopic created previously. The following code shows how to create the subscriber entity:
Subscriber subscriber = participant.CreateSubscriber();
if (subscriber == null)
{
    throw new Exception("Could not create the subscriber");
}
To create the datareader first we need to create a generic datareader related with the topic and after that a specific datareader for the registered type of the topic. The following code shows how to create a datareader for the MessageTopic:
DataReader reader = subscriber.CreateDataReader(topic);
if (reader == null)
{
    throw new Exception("Could not create the message data reader");
}
MessageDataReader messageReader = new MessageDataReader(reader);

Receive the message

There are different ways to read the information from the topic, listeners, waitsets or simply polling the information from the datareader. For this first application we are going to poll the information from the datareader. The following code shows how to do it:
while (true)
{
    StatusMask mask = messageReader.StatusChanges;
    if ((mask & StatusKind.DataAvailableStatus) != 0)
    {
        List<Message> receivedData = new List();
        List<SampleInfo> receivedInfo = new List();
        result = messageReader.Take(receivedData, receivedInfo);

        if (result == ReturnCode.Ok)
        {
            bool messageReceived = false;
            for (int i = 0; i < receivedData.Count; i++)
            {
                if (receivedInfo[i].ValidData)
                {
                    Console.WriteLine(receivedData[i].Content);
                    messageReceived = true;
                }
            }

            if (messageReceived)
                break;
        }
    }

    System.Threading.Thread.Sleep(100);
}

Shutdown the application

Same as with the publisher application you should release all the resources used by DDS. You can use the same code as before:
participant.DeleteContainedEntities();
dpf.DeleteParticipant(participant);
ParticipantService.Instance.Shutdown();

OpenDDSharp: WPF Shape Demo

TO BE CONTINUED!!