Skip to main content

Hello World in C++

This tutorial covers building the temperature sensor application using modern C++17 with HDDS.

Time: ~10 minutes Prerequisites: HDDS C++ library installed

Step 1: Create the IDL File

Create Temperature.idl:

module sensors {
@topic
struct Temperature {
@key string sensor_id;
float value;
unsigned long long timestamp;
};
};

Step 2: Generate C++ Code

hdds-gen -l cpp Temperature.idl

This generates:

  • Temperature.hpp - Type definitions with modern C++ features
  • Temperature.cpp - Serialization implementation

Step 3: Create the Publisher

Create publisher.cpp:

#include <iostream>
#include <chrono>
#include <thread>

#include <hdds/hdds.hpp>
#include "Temperature.hpp"

using namespace std::chrono_literals;

int main() {
std::cout << "Starting temperature publisher..." << std::endl;

try {
// 1. Create DomainParticipant
hdds::DomainParticipant participant(0);
std::cout << "Joined domain 0" << std::endl;

// 2. Create Topic
auto topic = participant.create_topic<sensors::Temperature>("temperature/room1");
std::cout << "Created topic: temperature/room1" << std::endl;

// 3. Create Publisher and DataWriter
auto publisher = participant.create_publisher();
auto writer = publisher.create_writer(topic);
std::cout << "DataWriter created, waiting for subscribers..." << std::endl;

// 4. Wait for subscribers
writer.wait_for_subscribers(1, 30s);
std::cout << "Subscriber connected!" << std::endl;

// 5. Publish temperature readings
for (int i = 0; i < 10; ++i) {
sensors::Temperature temp;
temp.sensor_id = "sensor-001";
temp.value = 22.0f + (i * 0.5f);
temp.timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()
).count();

writer.write(temp);
std::cout << "Published: sensor=" << temp.sensor_id
<< ", temp=" << temp.value << "°C" << std::endl;

std::this_thread::sleep_for(1s);
}

std::cout << "Publisher finished" << std::endl;

} catch (const hdds::Exception& e) {
std::cerr << "HDDS Error: " << e.what() << std::endl;
return 1;
}

return 0;
}

Step 4: Create the Subscriber

Create subscriber.cpp:

#include <iostream>
#include <chrono>

#include <hdds/hdds.hpp>
#include "Temperature.hpp"

using namespace std::chrono_literals;

int main() {
std::cout << "Starting temperature subscriber..." << std::endl;

try {
// 1. Create DomainParticipant
hdds::DomainParticipant participant(0);
std::cout << "Joined domain 0" << std::endl;

// 2. Create Topic
auto topic = participant.create_topic<sensors::Temperature>("temperature/room1");
std::cout << "Created topic: temperature/room1" << std::endl;

// 3. Create Subscriber and DataReader
auto subscriber = participant.create_subscriber();
auto reader = subscriber.create_reader(topic);
std::cout << "DataReader created, waiting for data..." << std::endl;

// 4. Read samples in a loop
while (true) {
if (reader.wait_for_data(5s)) {
// Take all available samples
for (auto& sample : reader.take()) {
std::cout << "Received: sensor=" << sample.data().sensor_id
<< ", temp=" << sample.data().value << "°C"
<< ", time=" << sample.data().timestamp << std::endl;
}
} else {
std::cout << "No data received in 5 seconds, waiting..." << std::endl;
}
}

} catch (const hdds::Exception& e) {
std::cerr << "HDDS Error: " << e.what() << std::endl;
return 1;
}

return 0;
}

Step 5: Create CMakeLists.txt

cmake_minimum_required(VERSION 3.16)
project(hdds-hello-world CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(hdds REQUIRED)

# Generate type support
hdds_generate_cpp(GENERATED_SRCS Temperature.idl)

# Publisher
add_executable(publisher publisher.cpp ${GENERATED_SRCS})
target_link_libraries(publisher PRIVATE hdds::hdds-cpp)

# Subscriber
add_executable(subscriber subscriber.cpp ${GENERATED_SRCS})
target_link_libraries(subscriber PRIVATE hdds::hdds-cpp)

Step 6: Build and Run

mkdir build && cd build
cmake ..
cmake --build .

# Terminal 1
./subscriber

# Terminal 2
./publisher

Modern C++ Features

Range-based Iteration

for (auto& sample : reader.take()) {
if (sample.info().valid_data) {
process(sample.data());
}
}

Lambda Callbacks

reader.on_data_available([](auto& reader) {
for (auto& sample : reader.take()) {
std::cout << "Received: " << sample.data().value << std::endl;
}
});

Async/Await (C++20)

#include <hdds/hdds_async.hpp>

hdds::task<void> run_subscriber() {
hdds::DomainParticipant participant(0);
auto topic = participant.create_topic<sensors::Temperature>("temperature/room1");
auto reader = participant.create_subscriber().create_reader(topic);

while (true) {
auto samples = co_await reader.take_async();
for (auto& sample : samples) {
std::cout << "Received: " << sample.data().value << std::endl;
}
}
}

RAII Resource Management

All HDDS C++ objects use RAII. No manual cleanup needed:

{
hdds::DomainParticipant participant(0);
auto writer = participant.create_publisher()
.create_writer(topic);
writer.write(data);
} // Everything cleaned up automatically

QoS Configuration

// Reliable with history
auto writer_qos = hdds::DataWriterQos()
.reliability(hdds::Reliability::Reliable(1s))
.history(hdds::History::KeepLast(10))
.durability(hdds::Durability::TransientLocal);

auto writer = publisher.create_writer(topic, writer_qos);

What's Next?