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_loanafter read/take operations
Next Steps
- Hello World C - Complete tutorial
- C++ API - C++ language bindings
- Python API - Python language bindings