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 definitionsTemperature.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
| Function | Description |
|---|---|
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?
- Hello World C++ - C++ version
- C API Reference - Complete C API documentation
- hdds_gen CLI - Code generator options