Skip to main content

C API Reference

HDDS provides C bindings through hdds-c, offering a stable ABI for C applications and FFI integration.

Installation

# Build from source
git clone https://github.com/example/hdds.git
cd hdds
cargo build --release -p hdds-c

# Install headers and library
sudo cp target/release/libhdds.so /usr/local/lib/
sudo cp crates/hdds-c/include/*.h /usr/local/include/hdds/
sudo ldconfig

# CMake integration
find_package(hdds_c REQUIRED)
target_link_libraries(myapp hdds::hdds_c)

Header Files

#include <hdds/hdds.h>       // Main API
#include <hdds/qos.h> // QoS types
#include <hdds/status.h> // Status types
#include <hdds/error.h> // Error codes

Return Codes

typedef enum {
HDDS_OK = 0,
HDDS_ERROR = 1,
HDDS_UNSUPPORTED = 2,
HDDS_BAD_PARAMETER = 3,
HDDS_PRECONDITION_NOT_MET = 4,
HDDS_OUT_OF_RESOURCES = 5,
HDDS_NOT_ENABLED = 6,
HDDS_IMMUTABLE_POLICY = 7,
HDDS_INCONSISTENT_POLICY = 8,
HDDS_ALREADY_DELETED = 9,
HDDS_TIMEOUT = 10,
HDDS_NO_DATA = 11
} hdds_return_t;

Domain Participant

Creation

// Create participant with default QoS
hdds_domain_participant_t* participant =
hdds_create_participant(0, NULL); // domain_id, qos

if (participant == NULL) {
fprintf(stderr, "Failed to create participant\n");
return 1;
}

// Create with custom QoS
hdds_participant_qos_t qos;
hdds_participant_qos_default(&qos);
qos.entity_name = "MySensor";

hdds_domain_participant_t* participant =
hdds_create_participant(0, &qos);

Operations

// Get domain ID
uint32_t domain_id = hdds_participant_get_domain_id(participant);

// Get instance handle
hdds_instance_handle_t handle;
hdds_participant_get_instance_handle(participant, &handle);

// Enable (if created disabled)
hdds_return_t ret = hdds_participant_enable(participant);

// Delete participant
hdds_delete_participant(participant);

Topics

Type Registration

// Generated type support
#include "SensorData_ts.h"

// Register type
hdds_return_t ret = SensorData_register_type(
participant,
"SensorData" // type name (NULL for default)
);

Topic Creation

// Create topic with default QoS
hdds_topic_t* topic = hdds_create_topic(
participant,
"SensorTopic", // topic name
"SensorData", // type name
NULL // qos (NULL = default)
);

// Create with custom QoS
hdds_topic_qos_t topic_qos;
hdds_topic_qos_default(&topic_qos);
topic_qos.reliability.kind = HDDS_RELIABLE;
topic_qos.durability.kind = HDDS_TRANSIENT_LOCAL;

hdds_topic_t* topic = hdds_create_topic(
participant, "SensorTopic", "SensorData", &topic_qos);

// Delete topic
hdds_delete_topic(participant, topic);

Publisher

// Create publisher
hdds_publisher_t* publisher = hdds_create_publisher(
participant,
NULL // qos (NULL = default)
);

// With QoS
hdds_publisher_qos_t pub_qos;
hdds_publisher_qos_default(&pub_qos);
pub_qos.partition.names = (const char*[]){"sensor_data"};
pub_qos.partition.count = 1;

hdds_publisher_t* publisher =
hdds_create_publisher(participant, &pub_qos);

// Delete publisher
hdds_delete_publisher(participant, publisher);

DataWriter

Creation

// Create writer with default QoS
hdds_datawriter_t* writer = hdds_create_datawriter(
publisher,
topic,
NULL // qos
);

// With custom QoS
hdds_datawriter_qos_t qos;
hdds_datawriter_qos_default(&qos);
qos.reliability.kind = HDDS_RELIABLE;
qos.reliability.max_blocking_time.sec = 1;
qos.reliability.max_blocking_time.nanosec = 0;
qos.history.kind = HDDS_KEEP_LAST;
qos.history.depth = 10;

hdds_datawriter_t* writer =
hdds_create_datawriter(publisher, topic, &qos);

Write Operations

// Write sample
SensorData sample = {
.sensor_id = 1,
.value = 25.5f,
.timestamp = get_time_ns()
};

hdds_return_t ret = SensorData_write(writer, &sample);
if (ret != HDDS_OK) {
fprintf(stderr, "Write failed: %d\n", ret);
}

// Write with timestamp
hdds_time_t ts = { .sec = 0, .nanosec = 0 };
ret = SensorData_write_w_timestamp(writer, &sample, &ts);

// Write with instance handle
hdds_instance_handle_t handle;
ret = SensorData_register_instance(writer, &sample, &handle);
ret = SensorData_write_w_handle(writer, &sample, &handle);

Instance Management

// Register instance
hdds_instance_handle_t handle;
hdds_return_t ret = SensorData_register_instance(
writer, &sample, &handle);

// Unregister instance
ret = SensorData_unregister_instance(writer, &sample, &handle);

// Dispose instance
ret = SensorData_dispose(writer, &sample, &handle);

Status

// Publication matched
hdds_publication_matched_status_t status;
hdds_datawriter_get_publication_matched_status(writer, &status);
printf("Matched readers: %d\n", status.current_count);

// Offered deadline missed
hdds_offered_deadline_missed_status_t deadline_status;
hdds_datawriter_get_offered_deadline_missed_status(writer, &deadline_status);

// Wait for acknowledgments
hdds_duration_t timeout = { .sec = 5, .nanosec = 0 };
ret = hdds_datawriter_wait_for_acknowledgments(writer, &timeout);

Subscriber

// Create subscriber
hdds_subscriber_t* subscriber = hdds_create_subscriber(
participant,
NULL // qos
);

// With QoS
hdds_subscriber_qos_t sub_qos;
hdds_subscriber_qos_default(&sub_qos);
sub_qos.partition.names = (const char*[]){"sensor_data"};
sub_qos.partition.count = 1;

hdds_subscriber_t* subscriber =
hdds_create_subscriber(participant, &sub_qos);

// Delete subscriber
hdds_delete_subscriber(participant, subscriber);

DataReader

Creation

// Create reader
hdds_datareader_t* reader = hdds_create_datareader(
subscriber,
topic,
NULL // qos
);

// With QoS
hdds_datareader_qos_t qos;
hdds_datareader_qos_default(&qos);
qos.reliability.kind = HDDS_RELIABLE;
qos.history.kind = HDDS_KEEP_LAST;
qos.history.depth = 100;

hdds_datareader_t* reader =
hdds_create_datareader(subscriber, topic, &qos);

Read Operations

// Allocate sample sequence
SensorData_seq samples;
SensorData_seq_init(&samples, 100); // max samples

hdds_sample_info_seq_t infos;
hdds_sample_info_seq_init(&infos, 100);

// Read (keeps in cache)
hdds_return_t ret = SensorData_read(
reader,
&samples,
&infos,
100, // max_samples
HDDS_ANY_SAMPLE_STATE,
HDDS_ANY_VIEW_STATE,
HDDS_ANY_INSTANCE_STATE
);

// Take (removes from cache)
ret = SensorData_take(
reader,
&samples,
&infos,
100,
HDDS_ANY_SAMPLE_STATE,
HDDS_ANY_VIEW_STATE,
HDDS_ANY_INSTANCE_STATE
);

// Process samples
for (size_t i = 0; i < samples.length; i++) {
if (infos.buffer[i].valid_data) {
SensorData* sample = &samples.buffer[i];
printf("Sensor %u: %.2f\n", sample->sensor_id, sample->value);
}
}

// Return loan
SensorData_return_loan(reader, &samples, &infos);

// Free sequences
SensorData_seq_fini(&samples);
hdds_sample_info_seq_fini(&infos);

Status

// Subscription matched
hdds_subscription_matched_status_t status;
hdds_datareader_get_subscription_matched_status(reader, &status);
printf("Matched writers: %d\n", status.current_count);

// Data available
hdds_data_available_status_t data_status;
hdds_datareader_get_data_available_status(reader, &data_status);

Listeners

DataWriter Listener

void on_publication_matched(
hdds_datawriter_t* writer,
const hdds_publication_matched_status_t* status,
void* user_data)
{
printf("Matched readers changed: %d -> %d\n",
status->current_count - status->current_count_change,
status->current_count);
}

void on_offered_deadline_missed(
hdds_datawriter_t* writer,
const hdds_offered_deadline_missed_status_t* status,
void* user_data)
{
fprintf(stderr, "Deadline missed: %d\n", status->total_count);
}

// Set listener
hdds_datawriter_listener_t listener = {
.on_publication_matched = on_publication_matched,
.on_offered_deadline_missed = on_offered_deadline_missed,
.user_data = my_context
};

hdds_datawriter_set_listener(writer, &listener, HDDS_STATUS_MASK_ALL);

DataReader Listener

void on_data_available(
hdds_datareader_t* reader,
void* user_data)
{
SensorData_seq samples;
SensorData_seq_init(&samples, 10);

hdds_sample_info_seq_t infos;
hdds_sample_info_seq_init(&infos, 10);

if (SensorData_take(reader, &samples, &infos, 10,
HDDS_ANY_SAMPLE_STATE, HDDS_ANY_VIEW_STATE,
HDDS_ANY_INSTANCE_STATE) == HDDS_OK)
{
for (size_t i = 0; i < samples.length; i++) {
if (infos.buffer[i].valid_data) {
process_sample(&samples.buffer[i]);
}
}
SensorData_return_loan(reader, &samples, &infos);
}

SensorData_seq_fini(&samples);
hdds_sample_info_seq_fini(&infos);
}

void on_subscription_matched(
hdds_datareader_t* reader,
const hdds_subscription_matched_status_t* status,
void* user_data)
{
printf("Matched writers: %d\n", status->current_count);
}

// Set listener
hdds_datareader_listener_t listener = {
.on_data_available = on_data_available,
.on_subscription_matched = on_subscription_matched,
.user_data = my_context
};

hdds_datareader_set_listener(reader, &listener, HDDS_STATUS_MASK_ALL);

WaitSet

// Create waitset
hdds_waitset_t* waitset = hdds_waitset_create();

// Create read condition
hdds_readcondition_t* cond = hdds_datareader_create_readcondition(
reader,
HDDS_NOT_READ_SAMPLE_STATE,
HDDS_ANY_VIEW_STATE,
HDDS_ALIVE_INSTANCE_STATE
);

// Attach condition
hdds_waitset_attach_condition(waitset, (hdds_condition_t*)cond);

// Wait loop
hdds_condition_t* active[10];
size_t active_count;
hdds_duration_t timeout = { .sec = 1, .nanosec = 0 };

while (running) {
hdds_return_t ret = hdds_waitset_wait(
waitset, active, 10, &active_count, &timeout);

if (ret == HDDS_OK) {
for (size_t i = 0; i < active_count; i++) {
if (active[i] == (hdds_condition_t*)cond) {
// Read data...
}
}
}
}

// Cleanup
hdds_waitset_detach_condition(waitset, (hdds_condition_t*)cond);
hdds_datareader_delete_readcondition(reader, cond);
hdds_waitset_destroy(waitset);

QoS Structures

Reliability QoS

typedef enum {
HDDS_BEST_EFFORT = 0,
HDDS_RELIABLE = 1
} hdds_reliability_kind_t;

typedef struct {
hdds_reliability_kind_t kind;
hdds_duration_t max_blocking_time;
} hdds_reliability_qos_t;

Durability QoS

typedef enum {
HDDS_VOLATILE = 0,
HDDS_TRANSIENT_LOCAL = 1,
HDDS_TRANSIENT = 2,
HDDS_PERSISTENT = 3
} hdds_durability_kind_t;

typedef struct {
hdds_durability_kind_t kind;
} hdds_durability_qos_t;

History QoS

typedef enum {
HDDS_KEEP_LAST = 0,
HDDS_KEEP_ALL = 1
} hdds_history_kind_t;

typedef struct {
hdds_history_kind_t kind;
int32_t depth;
} hdds_history_qos_t;

Complete Example

#include <hdds/hdds.h>
#include <stdio.h>
#include <signal.h>
#include "SensorData.h"
#include "SensorData_ts.h"

static volatile int running = 1;

void sigint_handler(int sig) {
running = 0;
}

int main(int argc, char* argv[]) {
signal(SIGINT, sigint_handler);

// Create participant
hdds_domain_participant_t* participant =
hdds_create_participant(0, NULL);
if (!participant) {
fprintf(stderr, "Failed to create participant\n");
return 1;
}

// Register type
SensorData_register_type(participant, NULL);

// Create topic
hdds_topic_t* topic = hdds_create_topic(
participant, "SensorTopic", "SensorData", NULL);

// Create publisher and writer
hdds_publisher_t* publisher =
hdds_create_publisher(participant, NULL);

hdds_datawriter_qos_t qos;
hdds_datawriter_qos_default(&qos);
qos.reliability.kind = HDDS_RELIABLE;

hdds_datawriter_t* writer =
hdds_create_datawriter(publisher, topic, &qos);

// Publish loop
SensorData sample = { .sensor_id = 1 };
uint32_t count = 0;

while (running) {
sample.value = 20.0f + (float)(count % 20);
sample.timestamp = get_time_ns();

if (SensorData_write(writer, &sample) == HDDS_OK) {
printf("Published: sensor=%u value=%.1f\n",
sample.sensor_id, sample.value);
}

count++;
usleep(100000); // 100ms
}

// Cleanup
hdds_delete_datawriter(publisher, writer);
hdds_delete_publisher(participant, publisher);
hdds_delete_topic(participant, topic);
hdds_delete_participant(participant);

return 0;
}

Thread Safety

  • Factory operations are thread-safe
  • Participant/Publisher/Subscriber operations are thread-safe
  • DataWriter: single writer is NOT thread-safe for concurrent writes
  • DataReader: single reader is NOT thread-safe for concurrent takes

For concurrent access, use external synchronization or separate entities per thread.

Memory Management

  • All hdds_create_* functions allocate memory
  • Corresponding hdds_delete_* must be called to free
  • Sequences must be initialized before use and finalized after
  • Use *_return_loan after read/take operations

Next Steps