Skip to main content

Hello World in C

In this tutorial, you'll build the same temperature sensor application using the HDDS C bindings.

Time: ~10 minutes Prerequisites: HDDS C library installed

Step 1: Create the IDL File

First, define the data type in IDL format. Create Temperature.idl:

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

Step 2: Generate C Code

Use hdds_gen to generate the C type support:

hdds-gen -l c Temperature.idl

This generates:

  • Temperature.h - Type definitions
  • Temperature.c - Serialization code

Step 3: Create the Publisher

Create publisher.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>

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

int main(int argc, char** argv) {
printf("Starting temperature publisher...\n");

// 1. Create DomainParticipant on domain 0
hdds_participant_t* participant = hdds_participant_create(0, NULL);
if (!participant) {
fprintf(stderr, "Failed to create participant\n");
return 1;
}
printf("Joined domain 0\n");

// 2. Register the type
hdds_type_support_t* type_support = sensors_Temperature_get_type_support();
hdds_participant_register_type(participant, type_support, "sensors::Temperature");

// 3. Create Topic
hdds_topic_t* topic = hdds_topic_create(
participant,
"temperature/room1",
"sensors::Temperature",
NULL // Default QoS
);
if (!topic) {
fprintf(stderr, "Failed to create topic\n");
return 1;
}
printf("Created topic: temperature/room1\n");

// 4. Create Publisher
hdds_publisher_t* publisher = hdds_publisher_create(participant, NULL);

// 5. Create DataWriter
hdds_writer_t* writer = hdds_writer_create(publisher, topic, NULL);
if (!writer) {
fprintf(stderr, "Failed to create writer\n");
return 1;
}
printf("DataWriter created, waiting for subscribers...\n");

// 6. Wait for subscribers
hdds_writer_wait_for_subscribers(writer, 1, 30000); // 30 second timeout
printf("Subscriber connected!\n");

// 7. Publish temperature readings
sensors_Temperature temp;
strcpy(temp.sensor_id, "sensor-001");

for (int i = 0; i < 10; i++) {
temp.value = 22.0f + (i * 0.5f);
temp.timestamp = (unsigned long long)time(NULL) * 1000;

hdds_return_t ret = hdds_writer_write(writer, &temp);
if (ret != HDDS_OK) {
fprintf(stderr, "Write failed: %d\n", ret);
} else {
printf("Published: sensor=%s, temp=%.1f°C\n",
temp.sensor_id, temp.value);
}

sleep(1);
}

printf("Publisher finished\n");

// 8. Cleanup
hdds_writer_delete(writer);
hdds_publisher_delete(publisher);
hdds_topic_delete(topic);
hdds_participant_delete(participant);

return 0;
}

Step 4: Create the Subscriber

Create subscriber.c:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

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

int main(int argc, char** argv) {
printf("Starting temperature subscriber...\n");

// 1. Create DomainParticipant
hdds_participant_t* participant = hdds_participant_create(0, NULL);
if (!participant) {
fprintf(stderr, "Failed to create participant\n");
return 1;
}
printf("Joined domain 0\n");

// 2. Register the type
hdds_type_support_t* type_support = sensors_Temperature_get_type_support();
hdds_participant_register_type(participant, type_support, "sensors::Temperature");

// 3. Create Topic
hdds_topic_t* topic = hdds_topic_create(
participant,
"temperature/room1",
"sensors::Temperature",
NULL
);
printf("Created topic: temperature/room1\n");

// 4. Create Subscriber
hdds_subscriber_t* subscriber = hdds_subscriber_create(participant, NULL);

// 5. Create DataReader
hdds_reader_t* reader = hdds_reader_create(subscriber, topic, NULL);
printf("DataReader created, waiting for data...\n");

// 6. Read samples in a loop
sensors_Temperature temp;
hdds_sample_info_t info;

while (true) {
// Wait for data with 5 second timeout
hdds_return_t ret = hdds_reader_wait_for_data(reader, 5000);

if (ret == HDDS_OK) {
// Take all available samples
while (hdds_reader_take(reader, &temp, &info) == HDDS_OK) {
if (info.valid_data) {
printf("Received: sensor=%s, temp=%.1f°C, time=%llu\n",
temp.sensor_id, temp.value, temp.timestamp);
}
}
} else if (ret == HDDS_TIMEOUT) {
printf("No data received in 5 seconds, waiting...\n");
} else {
fprintf(stderr, "Error waiting for data: %d\n", ret);
break;
}
}

// 7. Cleanup
hdds_reader_delete(reader);
hdds_subscriber_delete(subscriber);
hdds_topic_delete(topic);
hdds_participant_delete(participant);

return 0;
}

Step 5: Create the Makefile

Create Makefile:

CC = gcc
CFLAGS = -Wall -Wextra -O2 $(shell pkg-config --cflags hdds)
LDFLAGS = $(shell pkg-config --libs hdds)

# Generated files
GEN_SRCS = Temperature.c
GEN_HDRS = Temperature.h

all: publisher subscriber

# Generate type support from IDL
$(GEN_SRCS) $(GEN_HDRS): Temperature.idl
hdds-gen -l c $<

publisher: publisher.c $(GEN_SRCS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)

subscriber: subscriber.c $(GEN_SRCS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)

clean:
rm -f publisher subscriber $(GEN_SRCS) $(GEN_HDRS)

.PHONY: all clean

Step 6: Build and Run

# Generate code and build
make

# Terminal 1 - Start subscriber
./subscriber

# Terminal 2 - Start publisher
./publisher

Using CMake

Alternatively, use CMake. Create CMakeLists.txt:

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

find_package(hdds REQUIRED)

# Generate type support
hdds_generate_c(GENERATED_SRCS Temperature.idl)

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

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

Build with CMake:

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

C API Reference

Key Functions

FunctionDescription
hdds_participant_create(domain, qos)Create a domain participant
hdds_topic_create(participant, name, type, qos)Create a topic
hdds_publisher_create(participant, qos)Create a publisher
hdds_writer_create(publisher, topic, qos)Create a data writer
hdds_writer_write(writer, data)Write a sample
hdds_subscriber_create(participant, qos)Create a subscriber
hdds_reader_create(subscriber, topic, qos)Create a data reader
hdds_reader_take(reader, data, info)Take a sample
hdds_reader_read(reader, data, info)Read without removing

Error Handling

hdds_return_t ret = hdds_writer_write(writer, &data);
if (ret != HDDS_OK) {
const char* msg = hdds_error_message(ret);
fprintf(stderr, "Error: %s\n", msg);
}

What's Next?