Initial contribution

This commit is contained in:
Michiel Beemster 2018-04-10 17:03:59 +02:00
parent 7b5cc4fa59
commit 11d9ce37aa
580 changed files with 155133 additions and 162 deletions

149
src/examples/CMakeLists.txt Normal file
View file

@ -0,0 +1,149 @@
#
# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License v. 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
# v. 1.0 which is available at
# http://www.eclipse.org/org/documents/edl-v10.php.
#
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
#
set(CMAKE_INSTALL_EXAMPLESDIR "${CMAKE_INSTALL_DATADIR}/${CMAKE_PROJECT_NAME}/examples")
add_subdirectory(helloworld)
add_subdirectory(roundtrip)
add_subdirectory(throughput)
# Examples HTML documentation
set(EXAMPLES_HTML_ARCHIVE "${CMAKE_PROJECT_NAME}ExamplesHTML.tar.gz")
set(EXAMPLES_HTML_URI "http://jenkins.prismtech.com:8080/job/BuildChameleonLinux64bit/lastSuccessfulBuild/artifact/cham/builds/examples/${EXAMPLES_HTML_ARCHIVE}")
if (BUILD_DOCS)
find_program(SPHINX_EXECUTABLE NAMES sphinx-build DOC "Sphinx documentation builder")
if (NOT SPHINX_EXECUTABLE)
message(STATUS "Unable to find sphinx-build executable, downloading examples docs...")
set(BUILD_DOCS off)
endif()
endif()
if (BUILD_DOCS)
message(STATUS "Examples html docs will be built using sphinx (${SPHINX_EXECUTABLE})")
# Process sphinx configuration file
set(sph_conf_author "ADLINK")
string(TIMESTAMP sph_conf_copyright "%Y, ADLINK")
set(sph_conf_version "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
set(sph_conf_release "${PROJECT_VERSION}")
configure_file(sphinx-conf.py.in conf.py @ONLY)
set(builder_output "examples_html_output")
set(builder_log "sphinx-examples-html.log")
add_custom_command(
OUTPUT ${builder_output}
COMMAND ${SPHINX_EXECUTABLE}
-b html
-d ${CMAKE_CURRENT_BINARY_DIR}/cache
-c ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
> ${builder_log}
COMMENT "Running Sphinx for examples html output"
VERBATIM
)
# OUTPUT is a fake target / symbolic name, not an actual file
set_property(SOURCE ${builder_output} PROPERTY SYMBOLIC 1)
add_custom_target(examples_docs ALL DEPENDS ${builder_output})
# Archive the output html files, will become a jenkins artifact for use in other jobs
# TODO this hardcoded list and archiving should be replaced by ExternalData refs
set(html_outputs
"_static"
"search.html"
"searchindex.js"
"genindex.html"
"examples.html"
"helloworld/readme.html"
"roundtrip/readme.html"
"throughput/readme.html"
)
add_custom_command(
OUTPUT ${builder_output}
COMMAND ${CMAKE_COMMAND}
-E tar "zcf"
"${EXAMPLES_HTML_ARCHIVE}"
${html_outputs}
APPEND
VERBATIM
)
# Remove generated files when cleaning the build tree
set_property(
DIRECTORY
APPEND PROPERTY
ADDITIONAL_MAKE_CLEAN_FILES
"cache"
"${builder_log}"
"objects.inv"
${html_outputs}
"_sources"
"${EXAMPLES_HTML_ARCHIVE}"
)
else()
# Download example html docs
file(DOWNLOAD "${EXAMPLES_HTML_URI}" "${CMAKE_CURRENT_BINARY_DIR}/Downloaded${EXAMPLES_HTML_ARCHIVE}"
TIMEOUT 10
STATUS status
)
list(GET status 0 status_code)
list(GET status 1 status_string)
if (NOT status_code EQUAL 0)
message(FATAL_ERROR
"Failed to download ${EXAMPLES_HTML_URI} \
(Code: ${status_code}, ${status_string})"
)
endif()
add_custom_target(examples_docs ALL)
add_custom_command(TARGET examples_docs
COMMAND ${CMAKE_COMMAND} -E tar "zxf" "Downloaded${EXAMPLES_HTML_ARCHIVE}"
VERBATIM
)
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Windows")
set(platform_exclude "examples/helloworld/Makefile")
elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
set(platform_exclude "examples/helloworld/vs|examples/helloworld/HelloWorld\.sln")
else()
set(platform_exclude "this_is_a_placeholder")
endif()
# Install example source-files
install(
DIRECTORY "${PROJECT_SOURCE_DIR}/examples/"
DESTINATION "${CMAKE_INSTALL_EXAMPLESDIR}"
COMPONENT dev
PATTERN "CMakeLists.export" EXCLUDE
PATTERN "examples/CMakeLists.txt" EXCLUDE
REGEX ${platform_exclude} EXCLUDE
REGEX "\.rst|\.py" EXCLUDE
)
# Install example html docs files
# TODO this should be replaced by install commands that use ExternalData refs (preferably in examples' CMakeLists.txt)
install(
DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
DESTINATION "${CMAKE_INSTALL_EXAMPLESDIR}"
COMPONENT dev
FILES_MATCHING
PATTERN "CMakeFiles" EXCLUDE
PATTERN "cache" EXCLUDE
PATTERN "_sources" EXCLUDE
PATTERN "*.html"
PATTERN "*.js"
PATTERN "_static/*"
)

46
src/examples/examples.rst Normal file
View file

@ -0,0 +1,46 @@
..
Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0 which is available at
http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
v. 1.0 which is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
Examples
========
.. toctree::
:maxdepth: 1
:caption: Contents:
helloworld/readme
roundtrip/readme
throughput/readme
Configuration
*************
Cyclone DDS has various configuration parameters and comes with a default built-in configuration.
To run an example, or any application that uses Cyclone DDS for its data exchange, this default
configuration is usually fine and no further action is required.
Configuration parameters for CycloneDDS are expressed in XML and grouped together in a single XML file.
To use a custom XML configuration in an application, the ``CYCLONEDDS_URI`` environment variable needs
to be set prior to starting the application and pointed to the location of the configuration file to
be used.
| *Example*
| **Windows:** ``set CYCLONEDDS_URI=file://%USERPROFILE%/CycloneDDS/my-config.xml``
| **Linux:** ``export CYCLONEDDS_URI="file://$HOME/CycloneDDS/my-config.xml"``
The CycloneDDS installation comes with a set of standard configuration files for common use cases.
You update existing configuration files or create your own by using the CycloneDDS Configurator tool,
which provides context-sensitive help on available configuration parameters and their applicability.
You can start the CycloneDDS Configuration tool through the CycloneDDS Launcher, or from your command-prompt
by entering the tools directory and running ``java -jar cycloneddsconf.jar``. The default location of the tools
directory is ``/usr/share/CycloneDDS/tools`` on Linux or ``C:\Program Files\ADLINK\Vortex DDS\share\CycloneDDS\tools``
on Windows.

View file

@ -0,0 +1,22 @@
cmake_minimum_required(VERSION 3.5)
if (NOT TARGET CycloneDDS::ddsc)
# Find the CycloneDDS package. If it is not in a default location, try
# finding it relative to the example where it most likely resides.
find_package(CycloneDDS REQUIRED PATHS "${CMAKE_SOURCE_DIR}/../../")
endif()
# This is a convenience function, provided by the CycloneDDS package,
# that will supply a library target related the the given idl file.
# In short, it takes the idl file, generates the source files with
# the proper data types and compiles them into a library.
idlc_generate(HelloWorldData_lib "HelloWorldData.idl")
# Both executables have only one related source file.
add_executable(HelloworldPublisher publisher.c)
add_executable(HelloworldSubscriber subscriber.c)
# Both executables need to be linked to the idl data type library and
# the ddsc API library.
target_link_libraries(HelloworldPublisher HelloWorldData_lib CycloneDDS::ddsc)
target_link_libraries(HelloworldSubscriber HelloWorldData_lib CycloneDDS::ddsc)

View file

@ -0,0 +1,58 @@
#
# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License v. 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
# v. 1.0 which is available at
# http://www.eclipse.org/org/documents/edl-v10.php.
#
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
#
cmake_minimum_required(VERSION 3.5)
if (NOT TARGET CycloneDDS::ddsc)
# Find the CycloneDDS package. If it is not in a default location, try
# finding it relative to the example where it most likely resides.
find_package(CycloneDDS REQUIRED PATHS ../../)
endif()
# This is a convenience function, provided by the CycloneDDS package,
# that will supply a library target related the the given idl file.
# In short, it takes the idl file, generates the source files with
# the proper data types and compiles them into a library.
idlc_generate(HelloWorldData_lib "HelloWorldData.idl")
# Both executables have only one related source file.
add_executable(HelloworldPublisher publisher.c)
add_executable(HelloworldSubscriber subscriber.c)
# Both executables need to be linked to the idl data type library and
# the ddsc API library.
target_link_libraries(HelloworldPublisher HelloWorldData_lib CycloneDDS::ddsc)
target_link_libraries(HelloworldSubscriber HelloWorldData_lib CycloneDDS::ddsc)
#
# The helloworld example is the only example to have a different CMakeLists.txt
# for building in source and install environments. This is because it has to
# do some specific installations to support the Getting Started Guide.
# The CMakelists.export will be used for the install environments.
#
install(
TARGETS HelloworldSubscriber HelloworldPublisher
DESTINATION "${CMAKE_INSTALL_EXAMPLESDIR}/helloworld/bin"
COMPONENT dev)
install(
FILES "CMakeLists.export"
DESTINATION "${CMAKE_INSTALL_EXAMPLESDIR}/helloworld"
COMPONENT dev
RENAME "CMakeLists.txt")
get_target_property(GENERATED_FILES HelloWorldData_lib INTERFACE_SOURCES)
install(
FILES ${GENERATED_FILES}
DESTINATION "${CMAKE_INSTALL_EXAMPLESDIR}/helloworld/generated"
COMPONENT dev)

View file

@ -0,0 +1,54 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25123.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HelloWorldSubscriber", "vs\HelloWorldSubscriber.vcxproj", "{D8B2F285-EB03-4657-A0DC-603172553BEA}"
ProjectSection(ProjectDependencies) = postProject
{28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D} = {28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HelloWorldPublisher", "vs\HelloWorldPublisher.vcxproj", "{D8B2F285-EB03-4657-ACDC-603172553BEA}"
ProjectSection(ProjectDependencies) = postProject
{28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D} = {28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HelloWorldType", "vs\HelloWorldType.vcxproj", "{28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D8B2F285-EB03-4657-A0DC-603172553BEA}.Debug|x64.ActiveCfg = Debug|x64
{D8B2F285-EB03-4657-A0DC-603172553BEA}.Debug|x64.Build.0 = Debug|x64
{D8B2F285-EB03-4657-A0DC-603172553BEA}.Debug|x86.ActiveCfg = Debug|Win32
{D8B2F285-EB03-4657-A0DC-603172553BEA}.Debug|x86.Build.0 = Debug|Win32
{D8B2F285-EB03-4657-A0DC-603172553BEA}.Release|x64.ActiveCfg = Release|x64
{D8B2F285-EB03-4657-A0DC-603172553BEA}.Release|x64.Build.0 = Release|x64
{D8B2F285-EB03-4657-A0DC-603172553BEA}.Release|x86.ActiveCfg = Release|Win32
{D8B2F285-EB03-4657-A0DC-603172553BEA}.Release|x86.Build.0 = Release|Win32
{D8B2F285-EB03-4657-ACDC-603172553BEA}.Debug|x64.ActiveCfg = Debug|x64
{D8B2F285-EB03-4657-ACDC-603172553BEA}.Debug|x64.Build.0 = Debug|x64
{D8B2F285-EB03-4657-ACDC-603172553BEA}.Debug|x86.ActiveCfg = Debug|Win32
{D8B2F285-EB03-4657-ACDC-603172553BEA}.Debug|x86.Build.0 = Debug|Win32
{D8B2F285-EB03-4657-ACDC-603172553BEA}.Release|x64.ActiveCfg = Release|x64
{D8B2F285-EB03-4657-ACDC-603172553BEA}.Release|x64.Build.0 = Release|x64
{D8B2F285-EB03-4657-ACDC-603172553BEA}.Release|x86.ActiveCfg = Release|Win32
{D8B2F285-EB03-4657-ACDC-603172553BEA}.Release|x86.Build.0 = Release|Win32
{28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D}.Debug|x64.ActiveCfg = Debug|x64
{28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D}.Debug|x64.Build.0 = Debug|x64
{28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D}.Debug|x86.ActiveCfg = Debug|Win32
{28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D}.Debug|x86.Build.0 = Debug|Win32
{28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D}.Release|x64.ActiveCfg = Release|x64
{28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D}.Release|x64.Build.0 = Release|x64
{28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D}.Release|x86.ActiveCfg = Release|Win32
{28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,9 @@
module HelloWorldData
{
struct Msg
{
long userID;
string message;
};
#pragma keylist Msg userID
};

View file

@ -0,0 +1,54 @@
publisher_NAME := HelloworldPublisher
publisher_SRCS := publisher.c generated/HelloWorldData.c
publisher_OBJS := ${publisher_SRCS:.c=.o}
subscriber_NAME := HelloworldSubscriber
subscriber_SRCS := subscriber.c generated/HelloWorldData.c
subscriber_OBJS := ${subscriber_SRCS:.c=.o}
# Make sure that the location where dds.h is installed is known to the
# compiler. If dds.h is not installed in a system default spot, then
# it can be introduced by adding it to the CFLAGS, like:
#CFLAGS += -I../../../../include
# Make sure that the location where libddsc.so is installed is known
# to the compiler. If the lib is not installed in a system default
# location, then it can be introduced by adding it to the LDFLAGS:
#LDFLAGS += -L../../../../lib
CFLAGS += -Igenerated
LDFLAGS += -lddsc
.PHONY: all clean distclean
all: $(publisher_NAME) $(subscriber_NAME)
$(publisher_NAME): $(publisher_OBJS)
gcc $(CFLAGS) $(publisher_OBJS) $(LDFLAGS) -o $(publisher_NAME)
$(subscriber_NAME): $(subscriber_OBJS)
gcc $(CFLAGS) $(subscriber_OBJS) $(LDFLAGS) -o $(subscriber_NAME)
clean:
@- $(RM) $(publisher_NAME)
@- $(RM) $(publisher_OBJS)
@- $(RM) $(subscriber_NAME)
@- $(RM) $(subscriber_OBJS)
distclean: clean
# Make sure that the idlc jar file is available and java can find its
# location. In this example, it is assumed that the jar is located at
# a specific relative directory. Change the classpath variable if
# this is not the case on your system.
classpath:= ../../idlc/idlc-jar-with-dependencies.jar
ifneq ($(CLASSPATH),)
classpath:= $(CLASSPATH):$(classpath)
endif
export CLASSPATH:=$(classpath)
datatype:
java org.eclipse.cyclonedds.compilers.Idlc HelloWorldData.idl

View file

@ -0,0 +1,59 @@
#include "ddsc/dds.h"
#include "HelloWorldData.h"
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char ** argv)
{
dds_entity_t participant;
dds_entity_t topic;
dds_entity_t writer;
dds_return_t ret;
HelloWorldData_Msg msg;
/* Create a Participant. */
participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
DDS_ERR_CHECK (participant, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
/* Create a Topic. */
topic = dds_create_topic (participant, &HelloWorldData_Msg_desc,
"HelloWorldData_Msg", NULL, NULL);
DDS_ERR_CHECK (topic, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
/* Create a Writer. */
writer = dds_create_writer (participant, topic, NULL, NULL);
printf("=== [Publisher] Waiting for a reader to be discovered ...\n");
ret = dds_set_enabled_status(writer, DDS_PUBLICATION_MATCHED_STATUS);
DDS_ERR_CHECK (ret, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
while(true)
{
uint32_t status;
ret = dds_get_status_changes (writer, &status);
DDS_ERR_CHECK (ret, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
if (status == DDS_PUBLICATION_MATCHED_STATUS) {
break;
}
/* Polling sleep. */
dds_sleepfor (DDS_MSECS (20));
}
/* Create a message to write. */
msg.userID = 1;
msg.message = "Hello World";
printf ("=== [Publisher] Writing : ");
printf ("Message (%d, %s)\n", msg.userID, msg.message);
ret = dds_write (writer, &msg);
DDS_ERR_CHECK (ret, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
/* Deleting the participant will delete all its children recursively as well. */
ret = dds_delete (participant);
DDS_ERR_CHECK (ret, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
return EXIT_SUCCESS;
}

View file

@ -0,0 +1,46 @@
..
Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0 which is available at
http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
v. 1.0 which is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
HelloWorld
==========
Description
***********
The basic HelloWorld example is used to illustrate the necessary steps to setup DCPS entities.
Note it is also used in the Getting Started Guide to explain the usage of CycloneDDS.
Design
******
It consists of 2 units:
- HelloworldPublisher: implements the publisher's main
- HelloworldSubscriber: implements the subscriber's main
Scenario
********
The publisher sends a single HelloWorld sample. The sample contains two fields:
- a userID field (long type)
- a message field (string type)
When it receives the sample, the subscriber displays the userID and the message field.
Running the example
*******************
It is recommended that you run the subscriber and publisher in separate terminals to avoid mixing the output.
- Open 2 terminals.
- In the first terminal start the subscriber by running HelloWorldSubscriber
- In the second terminal start the publisher by running HelloWorldPublisher

View file

@ -0,0 +1,75 @@
#include "ddsc/dds.h"
#include "HelloWorldData.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/* An array of one message (aka sample in dds terms) will be used. */
#define MAX_SAMPLES 1
int main (int argc, char ** argv)
{
dds_entity_t participant;
dds_entity_t topic;
dds_entity_t reader;
HelloWorldData_Msg *msg;
void *samples[MAX_SAMPLES];
dds_sample_info_t infos[MAX_SAMPLES];
dds_return_t ret;
dds_qos_t *qos;
/* Create a Participant. */
participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
DDS_ERR_CHECK (participant, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
/* Create a Topic. */
topic = dds_create_topic (participant, &HelloWorldData_Msg_desc,
"HelloWorldData_Msg", NULL, NULL);
DDS_ERR_CHECK (topic, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
/* Create a reliable Reader. */
qos = dds_qos_create ();
dds_qset_reliability (qos, DDS_RELIABILITY_RELIABLE, DDS_SECS (10));
reader = dds_create_reader (participant, topic, qos, NULL);
DDS_ERR_CHECK (reader, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
dds_qos_delete(qos);
printf ("\n=== [Subscriber] Waiting for a sample ...\n");
/* Initialize sample buffer, by pointing the void pointer within
* the buffer array to a valid sample memory location. */
samples[0] = HelloWorldData_Msg__alloc ();
/* Poll until data has been read. */
while (true)
{
/* Do the actual read.
* The return value contains the number of read samples. */
ret = dds_read (reader, samples, infos, MAX_SAMPLES, MAX_SAMPLES);
DDS_ERR_CHECK (ret, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
/* Check if we read some data and it is valid. */
if ((ret > 0) && (infos[0].valid_data))
{
/* Print Message. */
msg = (HelloWorldData_Msg*) samples[0];
printf ("=== [Subscriber] Received : ");
printf ("Message (%d, %s)\n", msg->userID, msg->message);
break;
}
else
{
/* Polling sleep. */
dds_sleepfor (DDS_MSECS (20));
}
}
/* Free the data location. */
HelloWorldData_Msg_free (samples[0], DDS_FREE_ALL);
/* Deleting the participant will delete all its children recursively as well. */
ret = dds_delete (participant);
DDS_ERR_CHECK (ret, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
return EXIT_SUCCESS;
}

View file

@ -0,0 +1,142 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{D8B2F285-EB03-4657-ACDC-603172553BEA}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<ProjectName>HelloWorldPublisher</ProjectName>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="directories.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="directories.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="directories.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="directories.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<IntDir>$(Platform)\$(Configuration)\Publisher\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(CycloneDDS_inc_dir);..\generated;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<SubSystem>Console</SubSystem>
<AdditionalLibraryDirectories>$(CycloneDDS_lib_dir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>ddsc.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalIncludeDirectories>$(CycloneDDS_inc_dir);..\generated;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>ddsc.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(CycloneDDS_lib_dir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<AdditionalIncludeDirectories>$(CycloneDDS_inc_dir);..\generated;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>ddsc.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(CycloneDDS_lib_dir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\generated\HelloWorldData.c" />
<ClCompile Include="..\publisher.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\generated\HelloWorldData.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
</Filter>
</ItemGroup>
</Project>

View file

@ -0,0 +1,142 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{D8B2F285-EB03-4657-A0DC-603172553BEA}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<ProjectName>HelloWorldSubscriber</ProjectName>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="directories.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="directories.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="directories.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="directories.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<IntDir>$(Platform)\$(Configuration)\Subscriber\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(CycloneDDS_inc_dir);..\generated;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<SubSystem>Console</SubSystem>
<AdditionalLibraryDirectories>$(CycloneDDS_lib_dir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>ddsc.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalIncludeDirectories>$(CycloneDDS_inc_dir);..\generated;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>ddsc.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(CycloneDDS_lib_dir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<AdditionalIncludeDirectories>$(CycloneDDS_inc_dir);..\generated;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>ddsc.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(CycloneDDS_lib_dir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\generated\HelloWorldData.c" />
<ClCompile Include="..\subscriber.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\generated\HelloWorldData.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
</Filter>
</ItemGroup>
</Project>

View file

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{28A7A97B-3CEF-4FD7-8DC5-A7586D6DAE1D}</ProjectGuid>
<RootNamespace>HelloWorldType</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="directories.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="directories.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="directories.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="directories.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemGroup>
<CustomBuild Include="..\HelloWorldData.idl">
<Command>java -classpath "$(CycloneDDS_idlc_dir)\idlc-jar-with-dependencies.jar" org.eclipse.cyclonedds.compilers.Idlc -d "$(SolutionDir)generated" "%(FullPath)"</Command>
<Message>Generating source files from IDL into "$(SolutionDir)generated"</Message>
<Outputs>HelloWorldData.h;HelloWorldData.c</Outputs>
</CustomBuild>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros">
<CycloneDDS_lib_dir>C:/Program Files/ADLINK/Cyclone DDS/lib</CycloneDDS_lib_dir>
<CycloneDDS_inc_dir>C:/Program Files/ADLINK/Cyclone DDS/include</CycloneDDS_inc_dir>
<CycloneDDS_idlc_dir>C:/Program Files/ADLINK/Cyclone DDS/share/CycloneDDS/idlc</CycloneDDS_idlc_dir>
</PropertyGroup>
<PropertyGroup />
<ItemGroup>
<BuildMacro Include="CycloneDDS_lib_dir">
<Value>$(CycloneDDS_lib_dir)</Value>
</BuildMacro>
<BuildMacro Include="CycloneDDS_inc_dir">
<Value>$(CycloneDDS_inc_dir)</Value>
</BuildMacro>
<BuildMacro Include="CycloneDDS_idlc_dir">
<Value>$(CycloneDDS_idlc_dir)</Value>
</BuildMacro>
</ItemGroup>
<PropertyGroup Label="Configuration">
<!-->
User macros are not expanded when starting the build applications in VS.
The path is extended with a possible Cyclone DLL location when they are not
installed in a system default location.
<-->
<LocalDebuggerEnvironment>PATH=../../../../../bin;%PATH%
$(LocalDebuggerEnvironment)</LocalDebuggerEnvironment>
</PropertyGroup>
</Project>

View file

@ -0,0 +1,33 @@
#
# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License v. 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
# v. 1.0 which is available at
# http://www.eclipse.org/org/documents/edl-v10.php.
#
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
#
cmake_minimum_required(VERSION 3.5)
if (NOT TARGET CycloneDDS::ddsc)
# Find the CycloneDDS package. If it is not in a default location, try
# finding it relative to the example where it most likely resides.
find_package(CycloneDDS REQUIRED PATHS "${CMAKE_SOURCE_DIR}/../../")
endif()
# This is a convenience function, provided by the CycloneDDS package,
# that will supply a library target related the the given idl file.
# In short, it takes the idl file, generates the source files with
# the proper data types and compiles them into a library.
idlc_generate(RoundTrip_lib RoundTrip.idl)
# Both executables have only one related source file.
add_executable(RoundtripPing ping.c)
add_executable(RoundtripPong pong.c)
# Both executables need to be linked to the idl data type library and
# the ddsc API library.
target_link_libraries(RoundtripPing RoundTrip_lib CycloneDDS::ddsc)
target_link_libraries(RoundtripPong RoundTrip_lib CycloneDDS::ddsc)

View file

@ -0,0 +1,8 @@
module RoundTripModule
{
struct DataType
{
sequence<octet> payload;
};
#pragma keylist DataType
};

View file

@ -0,0 +1,484 @@
#include "ddsc/dds.h"
#include "RoundTrip.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <inttypes.h>
#define TIME_STATS_SIZE_INCREMENT 50000
#define MAX_SAMPLES 100
#define US_IN_ONE_SEC 1000000LL
/* Forward declaration */
static dds_entity_t prepare_dds(dds_entity_t *writer, dds_entity_t *reader, dds_entity_t *readCond);
static void finalize_dds(dds_entity_t participant, dds_entity_t reader, dds_entity_t readCond);
typedef struct ExampleTimeStats
{
dds_time_t * values;
unsigned long valuesSize;
unsigned long valuesMax;
double average;
dds_time_t min;
dds_time_t max;
unsigned long count;
} ExampleTimeStats;
static void exampleInitTimeStats (ExampleTimeStats *stats)
{
stats->values = (dds_time_t*) malloc (TIME_STATS_SIZE_INCREMENT * sizeof (dds_time_t));
stats->valuesSize = 0;
stats->valuesMax = TIME_STATS_SIZE_INCREMENT;
stats->average = 0;
stats->min = 0;
stats->max = 0;
stats->count = 0;
}
static void exampleResetTimeStats (ExampleTimeStats *stats)
{
memset (stats->values, 0, stats->valuesMax * sizeof (dds_time_t));
stats->valuesSize = 0;
stats->average = 0;
stats->min = 0;
stats->max = 0;
stats->count = 0;
}
static void exampleDeleteTimeStats (ExampleTimeStats *stats)
{
free (stats->values);
}
static ExampleTimeStats *exampleAddTimingToTimeStats
(ExampleTimeStats *stats, dds_time_t timing)
{
if (stats->valuesSize > stats->valuesMax)
{
dds_time_t * temp = (dds_time_t*) realloc (stats->values, (stats->valuesMax + TIME_STATS_SIZE_INCREMENT) * sizeof (dds_time_t));
stats->values = temp;
stats->valuesMax += TIME_STATS_SIZE_INCREMENT;
}
if (stats->values != NULL && stats->valuesSize < stats->valuesMax)
{
stats->values[stats->valuesSize++] = timing;
}
stats->average = (stats->count * stats->average + timing) / (stats->count + 1);
stats->min = (stats->count == 0 || timing < stats->min) ? timing : stats->min;
stats->max = (stats->count == 0 || timing > stats->max) ? timing : stats->max;
stats->count++;
return stats;
}
static int exampleCompareul (const void* a, const void* b)
{
dds_time_t ul_a = *((dds_time_t*)a);
dds_time_t ul_b = *((dds_time_t*)b);
if (ul_a < ul_b) return -1;
if (ul_a > ul_b) return 1;
return 0;
}
static double exampleGetMedianFromTimeStats (ExampleTimeStats *stats)
{
double median = 0.0;
qsort (stats->values, stats->valuesSize, sizeof (dds_time_t), exampleCompareul);
if (stats->valuesSize % 2 == 0)
{
median = (double)(stats->values[stats->valuesSize / 2 - 1] + stats->values[stats->valuesSize / 2]) / 2;
}
else
{
median = (double)stats->values[stats->valuesSize / 2];
}
return median;
}
static dds_entity_t waitSet;
#ifdef _WIN32
#include <Windows.h>
static bool CtrlHandler (DWORD fdwCtrlType)
{
dds_waitset_set_trigger (waitSet, true);
return true; //Don't let other handlers handle this key
}
#else
static void CtrlHandler (int fdwCtrlType)
{
dds_waitset_set_trigger (waitSet, true);
}
#endif
int main (int argc, char *argv[])
{
dds_entity_t writer;
dds_entity_t reader;
dds_entity_t participant;
dds_entity_t readCond;
ExampleTimeStats roundTrip;
ExampleTimeStats writeAccess;
ExampleTimeStats readAccess;
ExampleTimeStats roundTripOverall;
ExampleTimeStats writeAccessOverall;
ExampleTimeStats readAccessOverall;
unsigned long payloadSize = 0;
unsigned long long numSamples = 0;
bool invalidargs = false;
dds_time_t timeOut = 0;
dds_time_t startTime;
dds_time_t time;
dds_time_t preWriteTime;
dds_time_t postWriteTime;
dds_time_t preTakeTime;
dds_time_t postTakeTime;
dds_time_t difference = 0;
dds_time_t elapsed = 0;
RoundTripModule_DataType pub_data;
RoundTripModule_DataType sub_data[MAX_SAMPLES];
void *samples[MAX_SAMPLES];
dds_sample_info_t info[MAX_SAMPLES];
dds_attach_t wsresults[1];
size_t wsresultsize = 1U;
dds_time_t waitTimeout = DDS_SECS (1);
unsigned long i;
int status;
bool warmUp = true;
/* Register handler for Ctrl-C */
#ifdef _WIN32
SetConsoleCtrlHandler ((PHANDLER_ROUTINE)CtrlHandler, TRUE);
#else
struct sigaction sat, oldAction;
sat.sa_handler = CtrlHandler;
sigemptyset (&sat.sa_mask);
sat.sa_flags = 0;
sigaction (SIGINT, &sat, &oldAction);
#endif
exampleInitTimeStats (&roundTrip);
exampleInitTimeStats (&writeAccess);
exampleInitTimeStats (&readAccess);
exampleInitTimeStats (&roundTripOverall);
exampleInitTimeStats (&writeAccessOverall);
exampleInitTimeStats (&readAccessOverall);
memset (&sub_data, 0, sizeof (sub_data));
memset (&pub_data, 0, sizeof (pub_data));
for (i = 0; i < MAX_SAMPLES; i++)
{
samples[i] = &sub_data[i];
}
participant = prepare_dds(&writer, &reader, &readCond);
setvbuf(stdout, NULL, _IONBF, 0);
if (argc == 2 && strcmp (argv[1], "quit") == 0)
{
printf ("Sending termination request.\n");
/* pong uses a waitset which is triggered by instance disposal, and
quits when it fires. */
dds_sleepfor (DDS_SECS (1));
pub_data.payload._length = 0;
pub_data.payload._buffer = NULL;
pub_data.payload._release = true;
pub_data.payload._maximum = 0;
status = dds_writedispose (writer, &pub_data);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
dds_sleepfor (DDS_SECS (1));
goto done;
}
if (argc == 1)
{
invalidargs = true;
}
if (argc >= 2)
{
payloadSize = atol (argv[1]);
if (payloadSize > 65536)
{
invalidargs = true;
}
}
if (argc >= 3)
{
numSamples = atol (argv[2]);
}
if (argc >= 4)
{
timeOut = atol (argv[3]);
}
if (invalidargs || (argc == 2 && (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0)))
{
printf ("Usage (parameters must be supplied in order):\n"
"./ping [payloadSize (bytes, 0 - 65536)] [numSamples (0 = infinite)] [timeOut (seconds, 0 = infinite)]\n"
"./ping quit - ping sends a quit signal to pong.\n"
"Defaults:\n"
"./ping 0 0 0\n");
return EXIT_FAILURE;
}
printf ("# payloadSize: %lu | numSamples: %llu | timeOut: %" PRIi64 "\n\n", payloadSize, numSamples, timeOut);
pub_data.payload._length = payloadSize;
pub_data.payload._buffer = payloadSize ? dds_alloc (payloadSize) : NULL;
pub_data.payload._release = true;
pub_data.payload._maximum = 0;
for (i = 0; i < payloadSize; i++)
{
pub_data.payload._buffer[i] = 'a';
}
startTime = dds_time ();
printf ("# Waiting for startup jitter to stabilise\n");
while (!dds_triggered (waitSet) && difference < DDS_SECS(5))
{
status = dds_write (writer, &pub_data);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
status = dds_waitset_wait (waitSet, wsresults, wsresultsize, waitTimeout);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
if (status > 0) /* data */
{
status = dds_take (reader, samples, info, MAX_SAMPLES, MAX_SAMPLES);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
}
time = dds_time ();
difference = time - startTime;
}
if (!dds_triggered (waitSet))
{
warmUp = false;
printf("# Warm up complete.\n\n");
printf("# Round trip measurements (in us)\n");
printf("# Round trip time [us] Write-access time [us] Read-access time [us]\n");
printf("# Seconds Count median min Count median min Count median min\n");
}
startTime = dds_time ();
for (i = 0; !dds_triggered (waitSet) && (!numSamples || i < numSamples); i++)
{
/* Write a sample that pong can send back */
preWriteTime = dds_time ();
status = dds_write (writer, &pub_data);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
postWriteTime = dds_time ();
/* Wait for response from pong */
status = dds_waitset_wait (waitSet, wsresults, wsresultsize, waitTimeout);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
if (status != 0)
{
/* Take sample and check that it is valid */
preTakeTime = dds_time ();
status = dds_take (reader, samples, info, MAX_SAMPLES, MAX_SAMPLES);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
postTakeTime = dds_time ();
if (!dds_triggered (waitSet))
{
if (status != 1)
{
fprintf (stdout, "%s%d%s", "ERROR: Ping received ", status,
" samples but was expecting 1. Are multiple pong applications running?\n");
goto done;
}
else if (!info[0].valid_data)
{
printf ("ERROR: Ping received an invalid sample. Has pong terminated already?\n");
goto done;
}
}
/* Update stats */
difference = (postWriteTime - preWriteTime)/DDS_NSECS_IN_USEC;
writeAccess = *exampleAddTimingToTimeStats (&writeAccess, difference);
writeAccessOverall = *exampleAddTimingToTimeStats (&writeAccessOverall, difference);
difference = (postTakeTime - preTakeTime)/DDS_NSECS_IN_USEC;
readAccess = *exampleAddTimingToTimeStats (&readAccess, difference);
readAccessOverall = *exampleAddTimingToTimeStats (&readAccessOverall, difference);
difference = (postTakeTime - preWriteTime)/DDS_NSECS_IN_USEC;
roundTrip = *exampleAddTimingToTimeStats (&roundTrip, difference);
roundTripOverall = *exampleAddTimingToTimeStats (&roundTripOverall, difference);
/* Print stats each second */
difference = (postTakeTime - startTime)/DDS_NSECS_IN_USEC;
if (difference > US_IN_ONE_SEC || (i && i == numSamples))
{
printf
(
"%9" PRIi64 " %9lu %8.0f %8" PRIi64 " %10lu %8.0f %8" PRIi64 " %10lu %8.0f %8" PRIi64 "\n",
elapsed + 1,
roundTrip.count,
exampleGetMedianFromTimeStats (&roundTrip),
roundTrip.min,
writeAccess.count,
exampleGetMedianFromTimeStats (&writeAccess),
writeAccess.min,
readAccess.count,
exampleGetMedianFromTimeStats (&readAccess),
readAccess.min
);
exampleResetTimeStats (&roundTrip);
exampleResetTimeStats (&writeAccess);
exampleResetTimeStats (&readAccess);
startTime = dds_time ();
elapsed++;
}
}
else
{
elapsed += waitTimeout / DDS_NSECS_IN_SEC;
}
if (timeOut && elapsed == timeOut)
{
dds_waitset_set_trigger (waitSet, true);
}
}
if (!warmUp)
{
printf
(
"\n%9s %9lu %8.0f %8" PRIi64 " %10lu %8.0f %8" PRIi64 " %10lu %8.0f %8" PRIi64 "\n",
"# Overall",
roundTripOverall.count,
exampleGetMedianFromTimeStats (&roundTripOverall),
roundTripOverall.min,
writeAccessOverall.count,
exampleGetMedianFromTimeStats (&writeAccessOverall),
writeAccessOverall.min,
readAccessOverall.count,
exampleGetMedianFromTimeStats (&readAccessOverall),
readAccessOverall.min
);
}
done:
#ifdef _WIN32
SetConsoleCtrlHandler (0, FALSE);
#else
sigaction (SIGINT, &oldAction, 0);
#endif
finalize_dds(participant, reader, readCond);
/* Clean up */
exampleDeleteTimeStats (&roundTrip);
exampleDeleteTimeStats (&writeAccess);
exampleDeleteTimeStats (&readAccess);
exampleDeleteTimeStats (&roundTripOverall);
exampleDeleteTimeStats (&writeAccessOverall);
exampleDeleteTimeStats (&readAccessOverall);
for (i = 0; i < MAX_SAMPLES; i++)
{
RoundTripModule_DataType_free (&sub_data[i], DDS_FREE_CONTENTS);
}
RoundTripModule_DataType_free (&pub_data, DDS_FREE_CONTENTS);
return EXIT_SUCCESS;
}
static dds_entity_t prepare_dds(dds_entity_t *writer, dds_entity_t *reader, dds_entity_t *readCond)
{
dds_return_t status;
dds_entity_t topic;
dds_entity_t publisher;
dds_entity_t subscriber;
const char *pubPartitions[] = { "ping" };
const char *subPartitions[] = { "pong" };
dds_qos_t *pubQos;
dds_qos_t *dwQos;
dds_qos_t *drQos;
dds_qos_t *subQos;
dds_entity_t participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
DDS_ERR_CHECK (participant, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
/* A DDS_Topic is created for our sample type on the domain participant. */
topic = dds_create_topic (participant, &RoundTripModule_DataType_desc, "RoundTrip", NULL, NULL);
DDS_ERR_CHECK (topic, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
/* A DDS_Publisher is created on the domain participant. */
pubQos = dds_qos_create ();
dds_qset_partition (pubQos, 1, pubPartitions);
publisher = dds_create_publisher (participant, pubQos, NULL);
DDS_ERR_CHECK (publisher, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
dds_qos_delete (pubQos);
/* A DDS_DataWriter is created on the Publisher & Topic with a modified Qos. */
dwQos = dds_qos_create ();
dds_qset_reliability (dwQos, DDS_RELIABILITY_RELIABLE, DDS_SECS (10));
dds_qset_writer_data_lifecycle (dwQos, false);
*writer = dds_create_writer (publisher, topic, dwQos, NULL);
DDS_ERR_CHECK (*writer, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
dds_qos_delete (dwQos);
/* A DDS_Subscriber is created on the domain participant. */
subQos = dds_qos_create ();
dds_qset_partition (subQos, 1, subPartitions);
subscriber = dds_create_subscriber (participant, subQos, NULL);
DDS_ERR_CHECK (subscriber, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
dds_qos_delete (subQos);
/* A DDS_DataReader is created on the Subscriber & Topic with a modified QoS. */
drQos = dds_qos_create ();
dds_qset_reliability (drQos, DDS_RELIABILITY_RELIABLE, DDS_SECS(10));
*reader = dds_create_reader (subscriber, topic, drQos, NULL);
DDS_ERR_CHECK (*reader, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
dds_qos_delete (drQos);
waitSet = dds_create_waitset (participant);
*readCond = dds_create_readcondition (*reader, DDS_ANY_STATE);
status = dds_waitset_attach (waitSet, *readCond, *reader);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
status = dds_waitset_attach (waitSet, waitSet, waitSet);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
return participant;
}
static void finalize_dds(dds_entity_t participant, dds_entity_t reader, dds_entity_t readCond)
{
dds_return_t status;
/* Disable callbacks */
dds_set_enabled_status (reader, 0);
status = dds_waitset_detach (waitSet, readCond);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
status = dds_waitset_detach (waitSet, waitSet);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
status = dds_delete (readCond);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
status = dds_delete (waitSet);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
status = dds_delete (participant);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
}

View file

@ -0,0 +1,192 @@
#include "ddsc/dds.h"
#include "RoundTrip.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <stdlib.h>
static dds_entity_t waitSet;
#define MAX_SAMPLES 10
/* Forward declarations */
static dds_entity_t prepare_dds(dds_entity_t *writer, dds_entity_t *reader, dds_entity_t *readCond);
static void finalize_dds(dds_entity_t participant, dds_entity_t readCond, RoundTripModule_DataType data[MAX_SAMPLES]);
#ifdef _WIN32
#include <Windows.h>
static bool CtrlHandler (DWORD fdwCtrlType)
{
dds_waitset_set_trigger (waitSet, true);
return true; //Don't let other handlers handle this key
}
#else
static void CtrlHandler (int fdwCtrlType)
{
dds_waitset_set_trigger (waitSet, true);
}
#endif
int main (int argc, char *argv[])
{
dds_duration_t waitTimeout = DDS_INFINITY;
unsigned int i;
int status, samplecount, j;
dds_attach_t wsresults[1];
size_t wsresultsize = 1U;
dds_entity_t participant;
dds_entity_t reader;
dds_entity_t writer;
dds_entity_t readCond;
RoundTripModule_DataType data[MAX_SAMPLES];
void * samples[MAX_SAMPLES];
dds_sample_info_t info[MAX_SAMPLES];
/* Register handler for Ctrl-C */
#ifdef _WIN32
SetConsoleCtrlHandler ((PHANDLER_ROUTINE)CtrlHandler, TRUE);
#else
struct sigaction sat, oldAction;
sat.sa_handler = CtrlHandler;
sigemptyset (&sat.sa_mask);
sat.sa_flags = 0;
sigaction (SIGINT, &sat, &oldAction);
#endif
participant = prepare_dds(&writer, &reader, &readCond);
/* Initialize sample data */
memset (data, 0, sizeof (data));
for (i = 0; i < MAX_SAMPLES; i++)
{
samples[i] = &data[i];
}
while (!dds_triggered (waitSet))
{
/* Wait for a sample from ping */
status = dds_waitset_wait (waitSet, wsresults, wsresultsize, waitTimeout);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
/* Take samples */
samplecount = dds_take (reader, samples, info, MAX_SAMPLES, MAX_SAMPLES);
DDS_ERR_CHECK (samplecount, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
for (j = 0; !dds_triggered (waitSet) && j < samplecount; j++)
{
/* If writer has been disposed terminate pong */
if (info[j].instance_state == DDS_IST_NOT_ALIVE_DISPOSED)
{
printf ("Received termination request. Terminating.\n");
dds_waitset_set_trigger (waitSet, true);
break;
}
else if (info[j].valid_data)
{
/* If sample is valid, send it back to ping */
RoundTripModule_DataType * valid_sample = &data[j];
status = dds_write (writer, valid_sample);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
}
}
}
#ifdef _WIN32
SetConsoleCtrlHandler (0, FALSE);
#else
sigaction (SIGINT, &oldAction, 0);
#endif
/* Clean up */
finalize_dds(participant, readCond, data);
return EXIT_SUCCESS;
}
static void finalize_dds(dds_entity_t participant, dds_entity_t readCond, RoundTripModule_DataType data[MAX_SAMPLES])
{
dds_return_t status = dds_waitset_detach (waitSet, readCond);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
status = dds_waitset_detach (waitSet, waitSet);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
status = dds_delete (readCond);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
status = dds_delete (waitSet);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
status = dds_delete (participant);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
for (unsigned int i = 0; i < MAX_SAMPLES; i++)
{
RoundTripModule_DataType_free (&data[i], DDS_FREE_CONTENTS);
}
}
static dds_entity_t prepare_dds(dds_entity_t *writer, dds_entity_t *reader, dds_entity_t *readCond)
{
const char *pubPartitions[] = { "pong" };
const char *subPartitions[] = { "ping" };
dds_qos_t *qos;
dds_entity_t subscriber;
dds_entity_t publisher;
dds_entity_t topic;
dds_return_t status;
dds_entity_t participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
DDS_ERR_CHECK (participant, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
/* A DDS Topic is created for our sample type on the domain participant. */
topic = dds_create_topic (participant, &RoundTripModule_DataType_desc, "RoundTrip", NULL, NULL);
DDS_ERR_CHECK (topic, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
/* A DDS Publisher is created on the domain participant. */
qos = dds_qos_create ();
dds_qset_partition (qos, 1, pubPartitions);
publisher = dds_create_publisher (participant, qos, NULL);
DDS_ERR_CHECK (publisher, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
dds_qos_delete (qos);
/* A DDS DataWriter is created on the Publisher & Topic with a modififed Qos. */
qos = dds_qos_create ();
dds_qset_reliability (qos, DDS_RELIABILITY_RELIABLE, DDS_SECS(10));
dds_qset_writer_data_lifecycle (qos, false);
*writer = dds_create_writer (publisher, topic, qos, NULL);
DDS_ERR_CHECK (*writer, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
dds_qos_delete (qos);
/* A DDS Subscriber is created on the domain participant. */
qos = dds_qos_create ();
dds_qset_partition (qos, 1, subPartitions);
subscriber = dds_create_subscriber (participant, qos, NULL);
DDS_ERR_CHECK (subscriber, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
dds_qos_delete (qos);
/* A DDS DataReader is created on the Subscriber & Topic with a modified QoS. */
qos = dds_qos_create ();
dds_qset_reliability (qos, DDS_RELIABILITY_RELIABLE, DDS_SECS(10));
*reader = dds_create_reader (subscriber, topic, qos, NULL);
DDS_ERR_CHECK (*reader, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
dds_qos_delete (qos);
waitSet = dds_create_waitset (participant);
*readCond = dds_create_readcondition (*reader, DDS_ANY_STATE);
status = dds_waitset_attach (waitSet, *readCond, *reader);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
status = dds_waitset_attach (waitSet, waitSet, waitSet);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
printf ("Waiting for samples from ping to send back...\n");
fflush (stdout);
return participant;
}

View file

@ -0,0 +1,83 @@
..
Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0 which is available at
http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
v. 1.0 which is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
Roundtrip
==========
Description
***********
The Roundtrip example allows the measurement of roundtrip duration when sending and receiving back a single message.
Design
******
It consists of 2 units:
- Pong: waits for messages from ping and sends the same message back.
- Ping: Sends a message to pong and waits for its return.
Scenario
********
A message is sent by the **ping** executable on the "PING" partition, which the **pong** executable is waiting for.
The **pong** executable sends the same message back on the "PONG" partition, which the **ping** executable is waiting for.
This sequence is repeated a configurable number of times.
The **ping** executable measures:
- writeAccess time: time the write() method took.
- readAccess time: time the take() method took.
- roundTrip time: time between the call to the write() method and the return of the take() method.
- **ping** also calculates min/max/average statistics on these values over a configurable number of samples and/or time out period.
Configurable:
- payloadSize: the size of the payload in bytes.
- numSamples: the number of samples to send.
- timeOut: the number of seconds ping should run for.
Running the example
*******************
It is recommended that you run ping and pong in separate terminals to avoid mixing the output.
- Open 2 terminals.
- In the first terminal start Pong by running pong.
pong usage:
``./pong``
- In the second terminal start Ping by running ping.
ping usage (parameters must be supplied in order):
``./ping [payloadSize (bytes, 0 - 655536)] [numSamples (0 = infinite)] [timeOut (seconds, 0 = infinite)]``
``./ping quit - ping sends a quit signal to pong.``
defaults:
``./ping 0 0 0``
- To achieve optimal performance it is recommended to set the CPU affinity so that ping and pong run on separate CPU cores,
and use real-time scheduling. In a Linux environment this can be achieved as follows:
pong usage:
``taskset -c 0 chrt -f 80 ./pong``
ping usage:
``taskset -c 1 chrt -f 80 ./ping [payloadSize (bytes, 0 - 655536)] [numSamples (0 = infinite)] [timeOut (seconds, 0 = infinite)]``
On Windows the CPU affinity and scheduling class can be set as follows:
pong usage:
``START /affinity 1 /high cmd /k "pong.exe"``
ping usage:
``START /affinity 2 /high cmd /k "ping.exe" [payloadSize (bytes, 0 - 655536)] [numSamples (0 = infinite)] [timeOut (seconds, 0 = infinite)]``

View file

@ -0,0 +1,86 @@
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
'sphinx.ext.coverage',
'sphinx.ext.imgmath',
'sphinx.ext.ifconfig',
'breathe']
# Add any paths that contain templates here, relative to this directory.
#templates_path = ['@CMAKE_CURRENT_SOuRCE_DIR@/_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'examples'
# General information about the project.
project = u'@CMAKE_PROJECT_NAME@'
copyright = u'@sph_conf_copyright@'
author = u'@sph_conf_author@'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y.Z version.
version = u'@sph_conf_version@'
# The full version, including alpha/beta/rc tags.
release = u'@sph_conf_release@'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = []
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'alabaster'
html_show_sourcelink = False
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
html_theme_options = { 'show_powered_by': False }
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['@PROJECT_SOURCE_DIR@/docs/_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# This is required for the alabaster theme
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
html_sidebars = {
'**': [
'about.html',
'navigation.html',
'relations.html', # needs 'show_related': True theme option to display
'searchbox.html',
'donate.html',
]
}

View file

@ -0,0 +1,33 @@
#
# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License v. 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
# v. 1.0 which is available at
# http://www.eclipse.org/org/documents/edl-v10.php.
#
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
#
cmake_minimum_required(VERSION 3.5)
if (NOT TARGET CycloneDDS::ddsc)
# Find the CycloneDDS package. If it is not in a default location, try
# finding it relative to the example where it most likely resides.
find_package(CycloneDDS REQUIRED PATHS "${CMAKE_SOURCE_DIR}/../../")
endif()
# This is a convenience function, provided by the CycloneDDS package,
# that will supply a library target related the the given idl file.
# In short, it takes the idl file, generates the source files with
# the proper data types and compiles them into a library.
idlc_generate(Throughput_lib Throughput.idl)
# Both executables have only one related source file.
add_executable(ThroughputPublisher publisher.c)
add_executable(ThroughputSubscriber subscriber.c)
# Both executables need to be linked to the idl data type library and
# the ddsc API library.
target_link_libraries(ThroughputPublisher Throughput_lib CycloneDDS::ddsc)
target_link_libraries(ThroughputSubscriber Throughput_lib CycloneDDS::ddsc)

View file

@ -0,0 +1,9 @@
module ThroughputModule
{
struct DataType
{
unsigned long long count;
sequence<octet> payload;
};
#pragma keylist DataType
};

View file

@ -0,0 +1,309 @@
#include "ddsc/dds.h"
#include "Throughput.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
/*
* The Throughput example measures data throughput in bytes per second. The publisher
* allows you to specify a payload size in bytes as well as allowing you to specify
* whether to send data in bursts. The publisher will continue to send data forever
* unless a time out is specified. The subscriber will receive data and output the
* total amount received and the data rate in bytes per second. It will also indicate
* if any samples were received out of order. A maximum number of cycles can be
* specified and once this has been reached the subscriber will terminate and output
* totals and averages.
*/
#define MAX_SAMPLES 100
static bool done = false;
/* Forward declarations */
static dds_return_t wait_for_reader(dds_entity_t writer, dds_entity_t participant);
static void start_writing(dds_entity_t writer, ThroughputModule_DataType *sample,
unsigned int burstInterval, unsigned int burstSize, unsigned int timeOut);
static int parse_args(int argc, char **argv, uint32_t *payloadSize, unsigned int *burstInterval,
unsigned int *burstSize, unsigned int *timeOut, char **partitionName);
static dds_entity_t prepare_dds(dds_entity_t *writer, const char *partitionName);
static void finalize_dds(dds_entity_t participant, dds_entity_t writer, ThroughputModule_DataType sample);
/* Functions to handle Ctrl-C presses. */
#ifdef _WIN32
#include <Windows.h>
static int CtrlHandler (DWORD fdwCtrlType)
{
done = true;
return true; /* Don't let other handlers handle this key */
}
#else
struct sigaction oldAction;
static void CtrlHandler (int fdwCtrlType)
{
done = true;
}
#endif
int main (int argc, char **argv)
{
int result = EXIT_SUCCESS;
uint32_t payloadSize = 8192;
unsigned int burstInterval = 0;
unsigned int burstSize = 1;
unsigned int timeOut = 0;
char * partitionName = "Throughput example";
dds_entity_t participant;
dds_entity_t writer;
ThroughputModule_DataType sample;
/* Register handler for Ctrl-C */
#ifdef _WIN32
SetConsoleCtrlHandler ((PHANDLER_ROUTINE) CtrlHandler, true);
#else
struct sigaction sat;
sat.sa_handler = CtrlHandler;
sigemptyset (&sat.sa_mask);
sat.sa_flags = 0;
sigaction (SIGINT, &sat, &oldAction);
#endif
if (parse_args(argc, argv, &payloadSize, &burstInterval, &burstSize, &timeOut, &partitionName) == EXIT_FAILURE) {
return EXIT_FAILURE;
}
participant = prepare_dds(&writer, partitionName);
/* Wait until have a reader */
if (wait_for_reader(writer, participant) == 0) {
printf ("=== [Publisher] Did not discover a reader.\n");
DDS_ERR_CHECK (dds_delete (participant), DDS_CHECK_REPORT | DDS_CHECK_EXIT);
return EXIT_FAILURE;
}
/* Fill the sample payload with data */
sample.count = 0;
sample.payload._buffer = dds_alloc (payloadSize);
sample.payload._length = payloadSize;
sample.payload._release = true;
for (uint32_t i = 0; i < payloadSize; i++) {
sample.payload._buffer[i] = 'a';
}
/* Register the sample instance and write samples repeatedly or until time out */
start_writing(writer, &sample, burstInterval, burstSize, timeOut);
#ifdef _WIN32
SetConsoleCtrlHandler (0, false);
#else
sigaction (SIGINT, &oldAction, 0);
#endif
/* Cleanup */
finalize_dds(participant, writer, sample);
}
static int parse_args(
int argc,
char **argv,
uint32_t *payloadSize,
unsigned int *burstInterval,
unsigned int *burstSize,
unsigned int *timeOut,
char **partitionName)
{
int result = EXIT_SUCCESS;
/*
* Get the program parameters
* Parameters: publisher [payloadSize] [burstInterval] [burstSize] [timeOut] [partitionName]
*/
if (argc == 2 && (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0))
{
printf ("Usage (parameters must be supplied in order):\n");
printf ("./publisher [payloadSize (bytes)] [burstInterval (ms)] [burstSize (samples)] [timeOut (seconds)] [partitionName]\n");
printf ("Defaults:\n");
printf ("./publisher 8192 0 1 0 \"Throughput example\"\n");
return EXIT_FAILURE;
}
if (argc > 1)
{
*payloadSize = atoi (argv[1]); /* The size of the payload in bytes */
}
if (argc > 2)
{
*burstInterval = atoi (argv[2]); /* The time interval between each burst in ms */
}
if (argc > 3)
{
*burstSize = atoi (argv[3]); /* The number of samples to send each burst */
}
if (argc > 4)
{
*timeOut = atoi (argv[4]); /* The number of seconds the publisher should run for (0 = infinite) */
}
if (argc > 5)
{
*partitionName = argv[5]; /* The name of the partition */
}
printf ("payloadSize: %u bytes burstInterval: %u ms burstSize: %u timeOut: %u seconds partitionName: %s\n",
*payloadSize, *burstInterval, *burstSize, *timeOut, *partitionName);
return result;
}
static dds_entity_t prepare_dds(dds_entity_t *writer, const char *partitionName)
{
dds_entity_t participant;
dds_entity_t topic;
dds_entity_t publisher;
const char *pubParts[1];
dds_qos_t *pubQos;
dds_qos_t *dwQos;
/* A domain participant is created for the default domain. */
participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
DDS_ERR_CHECK (participant, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
/* A topic is created for our sample type on the domain participant. */
topic = dds_create_topic (participant, &ThroughputModule_DataType_desc, "Throughput", NULL, NULL);
DDS_ERR_CHECK (topic, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
/* A publisher is created on the domain participant. */
pubQos = dds_qos_create ();
pubParts[0] = partitionName;
dds_qset_partition (pubQos, 1, pubParts);
publisher = dds_create_publisher (participant, pubQos, NULL);
DDS_ERR_CHECK (publisher, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
dds_qos_delete (pubQos);
/* A DataWriter is created on the publisher. */
dwQos = dds_qos_create ();
dds_qset_reliability (dwQos, DDS_RELIABILITY_RELIABLE, DDS_SECS (10));
dds_qset_history (dwQos, DDS_HISTORY_KEEP_ALL, 0);
dds_qset_resource_limits (dwQos, MAX_SAMPLES, DDS_LENGTH_UNLIMITED, DDS_LENGTH_UNLIMITED);
*writer = dds_create_writer (publisher, topic, dwQos, NULL);
DDS_ERR_CHECK (*writer, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
dds_qos_delete (dwQos);
/* Enable write batching */
dds_write_set_batch (true);
return participant;
}
static dds_return_t wait_for_reader(dds_entity_t writer, dds_entity_t participant)
{
printf ("\n=== [Publisher] Waiting for a reader ...\n");
dds_return_t ret;
dds_entity_t waitset;
ret = dds_set_enabled_status(writer, DDS_PUBLICATION_MATCHED_STATUS);
DDS_ERR_CHECK (ret, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
waitset = dds_create_waitset(participant);
DDS_ERR_CHECK (waitset, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
ret = dds_waitset_attach(waitset, writer, (dds_attach_t)NULL);
DDS_ERR_CHECK (waitset, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
ret = dds_waitset_wait(waitset, NULL, 0, DDS_SECS(30));
DDS_ERR_CHECK (ret, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
return ret;
}
static void start_writing(
dds_entity_t writer,
ThroughputModule_DataType *sample,
unsigned int burstInterval,
unsigned int burstSize,
unsigned int timeOut)
{
bool timedOut = false;
dds_time_t pubStart = dds_time ();
dds_time_t now;
dds_time_t deltaTv;
dds_return_t status;
if (!done)
{
dds_time_t burstStart = pubStart;
unsigned int burstCount = 0;
printf ("=== [Publisher] Writing samples...\n");
while (!done && !timedOut)
{
/* Write data until burst size has been reached */
if (burstCount < burstSize)
{
status = dds_write (writer, sample);
if (dds_err_nr(status) == DDS_RETCODE_TIMEOUT)
{
timedOut = true;
}
else
{
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
sample->count++;
burstCount++;
}
}
else if (burstInterval)
{
/* Sleep until burst interval has passed */
dds_time_t time = dds_time ();
deltaTv = time - burstStart;
if (deltaTv < DDS_MSECS (burstInterval))
{
dds_write_flush (writer);
dds_sleepfor (DDS_MSECS (burstInterval) - deltaTv);
}
burstStart = dds_time ();
burstCount = 0;
}
else
{
burstCount = 0;
}
if (timeOut)
{
now = dds_time ();
deltaTv = now - pubStart;
if ((deltaTv) > DDS_SECS (timeOut))
{
timedOut = true;
}
}
}
dds_write_flush (writer);
if (done)
{
printf ("=== [Publisher] Terminated, %llu samples written.\n", (unsigned long long) sample->count);
}
else
{
printf ("=== [Publisher] Timed out, %llu samples written.\n", (unsigned long long) sample->count);
}
}
}
static void finalize_dds(dds_entity_t participant, dds_entity_t writer, ThroughputModule_DataType sample)
{
dds_return_t status = dds_dispose (writer, &sample);
if (dds_err_nr (status) != DDS_RETCODE_TIMEOUT)
{
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
}
dds_free (sample.payload._buffer);
status = dds_delete (participant);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
}

View file

@ -0,0 +1,99 @@
..
Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0 which is available at
http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
v. 1.0 which is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
Throughput
==========
Description
***********
The Throughput example allows the measurement of data throughput when receiving samples from a publisher.
Design
******
It consists of 2 units:
- Publisher: sends samples at a specified size and rate.
- Subscriber: Receives samples and outputs statistics about throughput
Scenario
********
The **publisher** sends samples and allows you to specify a payload size in bytes as well as allowing you to specify whether
to send data in bursts. The **publisher** will continue to send data forever unless a time-out is specified.
Configurable:
- payloadSize: the size of the payload in bytes
- burstInterval: the time interval between each burst in ms
- burstSize: the number of samples to send each burst
- timeOut: the number of seconds the publisher should run for (0=infinite)
- partitionName: the name of the partition
The **subscriber** will receive data and output the total amount received and the data-rate in bytes-per-second. It will
also indicate if any samples were received out-of-order. A maximum number of cycles can be specified and once this has
been reached the subscriber will terminate and output totals and averages.
The **subscriber** executable measures:
- transferred: the total amount of data transferred in bytes.
- outOfOrder: the number of samples that were received out of order.
- transfer rate: the data transfer rate in bytes per second.
- subscriber also calculates statistics on these values over a configurable number of cycles.
Configurable:
- maxCycles: the number of times to output statistics before terminating
- pollingDelay
- partitionName: the name of the partition
Running the example
*******************
It is recommended that you run ping and pong in separate terminals to avoid mixing the output.
- Open 2 terminals.
- In the first terminal start Publisher by running publisher
publisher usage (parameters must be supplied in order):
``./publisher [payloadSize (bytes)] [burstInterval (ms)] [burstSize (samples)] [timeOut (seconds)] [partitionName]``
defaults:
``./publisher 8192 0 1 0 "Throughput example"``
- In the second terminal start Ping by running subscriber
subscriber usage (parameters must be supplied in order):
``./subscriber [maxCycles (0=infinite)] [pollingDelay (ms, 0 = event based)] [partitionName]``
defaults:
``./subscriber 0 0 "Throughput example"``
- To achieve optimal performance it is recommended to set the CPU affinity so that ping and pong run on separate CPU cores,
and use real-time scheduling. In a Linux environment this can be achieved as follows:
publisher usage:
``taskset -c 0 chrt -f 80 ./publisher [payloadSize (bytes)] [burstInterval (ms)] [burstSize (samples)] [timeOut (seconds)] [partitionName]``
subscriber usage:
``taskset -c 1 chrt -f 80 ./subscriber [maxCycles (0 = infinite)] [pollingDelay (ms, 0 = event based)] [partitionName]``
On Windows the CPU affinity and prioritized scheduling class can be set as follows:
publisher usage:
``START /affinity 1 /high cmd /k "publisher.exe" [payloadSize (bytes)] [burstInterval (ms)] [burstSize (samples)] [timeOut (seconds)] [partitionName]``
subscriber usage:
``START /affinity 2 /high cmd /k "subscriber.exe" [maxCycles (0 = infinite)] [pollingDelay (ms, 0 = event based)] [partitionName]``

View file

@ -0,0 +1,426 @@
#include "ddsc/dds.h"
#include "Throughput.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <assert.h>
/*
* The Throughput example measures data throughput in bytes per second. The publisher
* allows you to specify a payload size in bytes as well as allowing you to specify
* whether to send data in bursts. The publisher will continue to send data forever
* unless a time out is specified. The subscriber will receive data and output the
* total amount received and the data rate in bytes per second. It will also indicate
* if any samples were received out of order. A maximum number of cycles can be
* specified and once this has been reached the subscriber will terminate and output
* totals and averages.
*/
#define BYTES_PER_SEC_TO_MEGABITS_PER_SEC 125000
#define MAX_SAMPLES 100
typedef struct HandleEntry
{
dds_instance_handle_t handle;
unsigned long long count;
struct HandleEntry * next;
} HandleEntry;
typedef struct HandleMap
{
HandleEntry *entries;
} HandleMap;
static unsigned long pollingDelay = 0;
static HandleMap * imap;
static unsigned long long outOfOrder = 0;
static unsigned long long total_bytes = 0;
static unsigned long long total_samples = 0;
static dds_time_t startTime = 0;
static dds_time_t time_now = 0;
static dds_time_t prev_time = 0;
static unsigned long payloadSize = 0;
static ThroughputModule_DataType data [MAX_SAMPLES];
static void * samples[MAX_SAMPLES];
static dds_entity_t waitSet;
static dds_entity_t pollingWaitset;
static bool done = false;
/* Forward declarations */
static HandleMap * HandleMap__alloc (void);
static void HandleMap__free (HandleMap *map);
static HandleEntry * store_handle (HandleMap *map, dds_instance_handle_t key);
static HandleEntry * retrieve_handle (HandleMap *map, dds_instance_handle_t key);
static void data_available_handler (dds_entity_t reader, void *arg);
static int parse_args(int argc, char **argv, unsigned long long *maxCycles, char **partitionName);
static void process_samples(unsigned long long maxCycles);
static dds_entity_t prepare_dds(dds_entity_t *reader, const char *partitionName);
static void finalize_dds(dds_entity_t participant);
/* Functions to handle Ctrl-C presses. */
#ifdef _WIN32
#include <Windows.h>
static int CtrlHandler (DWORD fdwCtrlType)
{
dds_waitset_set_trigger (waitSet, true);
done = true;
return true; /* Don't let other handlers handle this key */
}
#else
struct sigaction oldAction;
static void CtrlHandler (int fdwCtrlType)
{
dds_waitset_set_trigger (waitSet, true);
done = true;
}
#endif
int main (int argc, char **argv)
{
unsigned long long maxCycles = 0;
char *partitionName = "Throughput example";
dds_entity_t participant;
dds_entity_t reader;
time_now = dds_time ();
prev_time = time_now;
/* Register handler for Ctrl-C */
#ifdef _WIN32
SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, true);
#else
struct sigaction sat;
sat.sa_handler = CtrlHandler;
sigemptyset(&sat.sa_mask);
sat.sa_flags = 0;
sigaction (SIGINT, &sat, &oldAction);
#endif
if (parse_args(argc, argv, &maxCycles, &partitionName) == EXIT_FAILURE)
{
return EXIT_FAILURE;
}
printf ("Cycles: %llu | PollingDelay: %lu | Partition: %s\n",
maxCycles, pollingDelay, partitionName);
participant = prepare_dds(&reader, partitionName);
printf ("=== [Subscriber] Waiting for samples...\n");
/* Process samples until Ctrl-C is pressed or until maxCycles */
/* has been reached (0 = infinite) */
process_samples(maxCycles);
/* Finished, disable callbacks */
dds_set_enabled_status (reader, 0);
HandleMap__free (imap);
#ifdef _WIN32
SetConsoleCtrlHandler (0, FALSE);
#else
sigaction (SIGINT, &oldAction, 0);
#endif
/* Clean up */
finalize_dds(participant);
return EXIT_SUCCESS;
}
/*
* This struct contains all of the entities used in the publisher and subscriber.
*/
static HandleMap * HandleMap__alloc (void)
{
HandleMap * map = malloc (sizeof (*map));
assert(map);
memset (map, 0, sizeof (*map));
return map;
}
static void HandleMap__free (HandleMap *map)
{
HandleEntry * entry;
while (map->entries)
{
entry = map->entries;
map->entries = entry->next;
free (entry);
}
free (map);
}
static HandleEntry * store_handle (HandleMap *map, dds_instance_handle_t key)
{
HandleEntry * entry = malloc (sizeof (*entry));
assert(entry);
memset (entry, 0, sizeof (*entry));
entry->handle = key;
entry->next = map->entries;
map->entries = entry;
return entry;
}
static HandleEntry * retrieve_handle (HandleMap *map, dds_instance_handle_t key)
{
HandleEntry * entry = map->entries;
while (entry)
{
if (entry->handle == key)
{
break;
}
entry = entry->next;
}
return entry;
}
static void data_available_handler (dds_entity_t reader, void *arg)
{
int samples_received;
dds_sample_info_t info [MAX_SAMPLES];
dds_instance_handle_t ph = 0;
HandleEntry * current = NULL;
if (startTime == 0)
{
startTime = dds_time ();
}
/* Take samples and iterate through them */
samples_received = dds_take (reader, samples, info, MAX_SAMPLES, MAX_SAMPLES);
DDS_ERR_CHECK (samples_received, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
for (int i = 0; !done && i < samples_received; i++)
{
if (info[i].valid_data)
{
ph = info[i].publication_handle;
current = retrieve_handle (imap, ph);
ThroughputModule_DataType * this_sample = &data[i];
if (current == NULL)
{
current = store_handle (imap, ph);
current->count = this_sample->count;
}
if (this_sample->count != current->count)
{
outOfOrder++;
}
current->count = this_sample->count + 1;
/* Add the sample payload size to the total received */
payloadSize = this_sample->payload._length;
total_bytes += payloadSize + 8;
total_samples++;
}
}
time_now = dds_time ();
if ((pollingDelay == 0) && (time_now > (prev_time + DDS_SECS (1))))
{
dds_waitset_set_trigger (pollingWaitset, true);
}
}
static int parse_args(int argc, char **argv, unsigned long long *maxCycles, char **partitionName)
{
/*
* Get the program parameters
* Parameters: subscriber [maxCycles] [pollingDelay] [partitionName]
*/
if (argc == 2 && (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0))
{
printf ("Usage (parameters must be supplied in order):\n");
printf ("./subscriber [maxCycles (0 = infinite)] [pollingDelay (ms, 0 = event based)] [partitionName]\n");
printf ("Defaults:\n");
printf ("./subscriber 0 0 \"Throughput example\"\n");
return EXIT_FAILURE;
}
if (argc > 1)
{
*maxCycles = atoi (argv[1]); /* The number of times to output statistics before terminating */
}
if (argc > 2)
{
pollingDelay = atoi (argv[2]); /* The number of ms to wait between reads (0 = event based) */
}
if (argc > 3)
{
*partitionName = argv[3]; /* The name of the partition */
}
return EXIT_SUCCESS;
}
static void process_samples(unsigned long long maxCycles)
{
dds_return_t status;
unsigned long long prev_bytes = 0;
unsigned long long prev_samples = 0;
dds_attach_t wsresults[1];
size_t wsresultsize = 1U;
dds_time_t deltaTv;
bool first_batch = true;
unsigned long cycles = 0;
double deltaTime = 0;
while (!done && (maxCycles == 0 || cycles < maxCycles))
{
if (pollingDelay)
{
dds_sleepfor (DDS_MSECS (pollingDelay));
}
else
{
status = dds_waitset_wait (waitSet, wsresults, wsresultsize, DDS_INFINITY);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
if ((status > 0 ) && (dds_triggered (pollingWaitset)))
{
dds_waitset_set_trigger (pollingWaitset, false);
}
}
if (!first_batch)
{
deltaTv = time_now - prev_time;
deltaTime = (double) deltaTv / DDS_NSECS_IN_SEC;
prev_time = time_now;
printf
(
"=== [Subscriber] Payload size: %lu | Total received: %llu samples, %llu bytes | Out of order: %llu samples "
"Transfer rate: %.2lf samples/s, %.2lf Mbit/s\n",
payloadSize, total_samples, total_bytes, outOfOrder,
(deltaTime) ? ((total_samples - prev_samples) / deltaTime) : 0,
(deltaTime) ? (((total_bytes - prev_bytes) / BYTES_PER_SEC_TO_MEGABITS_PER_SEC) / deltaTime) : 0
);
cycles++;
}
else
{
prev_time = time_now;
first_batch = false;
}
/* Update the previous values for next iteration */
prev_bytes = total_bytes;
prev_samples = total_samples;
}
/* Output totals and averages */
deltaTv = time_now - startTime;
deltaTime = (double) (deltaTv / DDS_NSECS_IN_SEC);
printf ("\nTotal received: %llu samples, %llu bytes\n", total_samples, total_bytes);
printf ("Out of order: %llu samples\n", outOfOrder);
printf ("Average transfer rate: %.2lf samples/s, ", total_samples / deltaTime);
printf ("%.2lf Mbit/s\n", (total_bytes / BYTES_PER_SEC_TO_MEGABITS_PER_SEC) / deltaTime);
}
static dds_entity_t prepare_dds(dds_entity_t *reader, const char *partitionName)
{
dds_return_t status;
dds_entity_t topic;
dds_entity_t subscriber;
dds_listener_t *rd_listener;
dds_entity_t participant;
uint32_t maxSamples = 400;
const char *subParts[1];
dds_qos_t *subQos = dds_qos_create ();
dds_qos_t *drQos = dds_qos_create ();
/* A Participant is created for the default domain. */
participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
DDS_ERR_CHECK (participant, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
/* A Topic is created for our sample type on the domain participant. */
topic = dds_create_topic (participant, &ThroughputModule_DataType_desc, "Throughput", NULL, NULL);
DDS_ERR_CHECK (topic, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
/* A Subscriber is created on the domain participant. */
subParts[0] = partitionName;
dds_qset_partition (subQos, 1, subParts);
subscriber = dds_create_subscriber (participant, subQos, NULL);
DDS_ERR_CHECK (subscriber, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
dds_qos_delete (subQos);
/* A Reader is created on the Subscriber & Topic with a modified Qos. */
dds_qset_reliability (drQos, DDS_RELIABILITY_RELIABLE, DDS_SECS (10));
dds_qset_history (drQos, DDS_HISTORY_KEEP_ALL, 0);
dds_qset_resource_limits (drQos, maxSamples, DDS_LENGTH_UNLIMITED, DDS_LENGTH_UNLIMITED);
rd_listener = dds_listener_create(NULL);
dds_lset_data_available(rd_listener, data_available_handler);
/* A Read Condition is created which is triggered when data is available to read */
waitSet = dds_create_waitset (participant);
DDS_ERR_CHECK (waitSet, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
pollingWaitset = dds_create_waitset (participant);
DDS_ERR_CHECK (pollingWaitset, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
status = dds_waitset_attach (waitSet, pollingWaitset, pollingWaitset);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
status = dds_waitset_attach (waitSet, waitSet, waitSet);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
imap = HandleMap__alloc ();
memset (data, 0, sizeof (data));
for (unsigned int i = 0; i < MAX_SAMPLES; i++)
{
samples[i] = &data[i];
}
*reader = dds_create_reader (subscriber, topic, drQos, rd_listener);
DDS_ERR_CHECK (*reader, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
dds_qos_delete (drQos);
dds_listener_delete(rd_listener);
return participant;
}
static void finalize_dds(dds_entity_t participant)
{
dds_return_t status;
for (unsigned int i = 0; i < MAX_SAMPLES; i++)
{
ThroughputModule_DataType_free (&data[i], DDS_FREE_CONTENTS);
}
status = dds_waitset_detach (waitSet, waitSet);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
status = dds_waitset_detach (waitSet, pollingWaitset);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
status = dds_delete (pollingWaitset);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
status = dds_delete (waitSet);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
status = dds_delete (participant);
DDS_ERR_CHECK (status, DDS_CHECK_REPORT | DDS_CHECK_EXIT);
}