File astutedds.h
File List > astutedds > c > astutedds.h
Go to the documentation of this file
//
// Copyright (c) 2026, Astute Systems PTY LTD
//
// This file is part of the Astute DDS developed by Astute Systems.
//
// See the commercial LICENSE file in the project root for full license details.
//
// @file astutedds.h
// @brief AstuteDDS C API — opaque-handle interface for FFI consumers.
//
// All DDS entities are exposed as opaque pointers. The caller must never
// dereference them directly. Lifetime rules mirror the DDS specification:
//
// DomainParticipant owns Topic | Publisher | Subscriber
// Publisher owns DataWriter
// Subscriber owns DataReader
//
// Every create_* call must be matched by the corresponding delete_* call.
// Deleting a parent before its children is undefined behaviour.
//
#ifndef ASTUTEDDS_C_ASTUTEDDS_H
#define ASTUTEDDS_C_ASTUTEDDS_H
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
// ── Opaque handle types ───────────────────────────────────────────────────────
typedef struct AstuteDDS_Participant_s *AstuteDDS_Participant;
typedef struct AstuteDDS_Topic_s *AstuteDDS_Topic;
typedef struct AstuteDDS_Publisher_s *AstuteDDS_Publisher;
typedef struct AstuteDDS_Subscriber_s *AstuteDDS_Subscriber;
typedef struct AstuteDDS_DataWriter_s *AstuteDDS_DataWriter;
typedef struct AstuteDDS_DataReader_s *AstuteDDS_DataReader;
// ── Return codes ──────────────────────────────────────────────────────────────
typedef enum
{
ASTUTEDDS_OK = 0,
ASTUTEDDS_ERROR = 1,
ASTUTEDDS_UNSUPPORTED = 2,
ASTUTEDDS_BAD_PARAM = 3,
ASTUTEDDS_PRECONDITION = 4,
ASTUTEDDS_OUT_OF_RESOURCES = 5,
ASTUTEDDS_NOT_ENABLED = 6,
ASTUTEDDS_TIMEOUT = 10,
ASTUTEDDS_NO_DATA = 11,
} AstuteDDS_ReturnCode;
// ── Reliability / History kind enums ─────────────────────────────────────────
typedef enum { ASTUTEDDS_BEST_EFFORT = 0, ASTUTEDDS_RELIABLE = 1 } AstuteDDS_Reliability;
typedef enum { ASTUTEDDS_KEEP_LAST = 0, ASTUTEDDS_KEEP_ALL = 1 } AstuteDDS_HistoryKind;
typedef enum { ASTUTEDDS_VOLATILE = 0, ASTUTEDDS_TRANSIENT_LOCAL = 1 } AstuteDDS_Durability;
typedef enum
{
ASTUTEDDS_AUTOMATIC_LIVELINESS = 0,
ASTUTEDDS_MANUAL_BY_PARTICIPANT_LIVELINESS = 1,
ASTUTEDDS_MANUAL_BY_TOPIC_LIVELINESS = 2
} AstuteDDS_LivelinessKind;
#define ASTUTEDDS_DURATION_INFINITE (INT64_C(0x7fffffffffffffff))
// ── QoS structs ───────────────────────────────────────────────────────────────
typedef struct
{
AstuteDDS_Reliability reliability;
AstuteDDS_HistoryKind history_kind;
int32_t history_depth;
AstuteDDS_Durability durability;
AstuteDDS_LivelinessKind liveliness_kind;
int64_t liveliness_lease_duration_ns;
int64_t deadline_period_ns;
int64_t lifespan_duration_ns;
const char *const *partitions;
size_t partition_count;
} AstuteDDS_DataWriterQos;
typedef struct
{
AstuteDDS_Reliability reliability;
AstuteDDS_HistoryKind history_kind;
int32_t history_depth;
AstuteDDS_Durability durability;
int ignore_local_publications;
AstuteDDS_LivelinessKind liveliness_kind;
int64_t liveliness_lease_duration_ns;
int64_t deadline_period_ns;
int64_t lifespan_duration_ns;
const char *const *partitions;
size_t partition_count;
} AstuteDDS_DataReaderQos;
// ── Sample received by DataReader ─────────────────────────────────────────────
typedef struct
{
const uint8_t *data;
size_t length;
int valid;
} AstuteDDS_Sample;
// ── Default QoS helpers ───────────────────────────────────────────────────────
static inline AstuteDDS_DataWriterQos astutedds_default_datawriter_qos(void)
{
AstuteDDS_DataWriterQos q;
q.reliability = ASTUTEDDS_RELIABLE;
q.history_kind = ASTUTEDDS_KEEP_LAST;
q.history_depth = 1;
q.durability = ASTUTEDDS_VOLATILE;
q.liveliness_kind = ASTUTEDDS_AUTOMATIC_LIVELINESS;
q.liveliness_lease_duration_ns = ASTUTEDDS_DURATION_INFINITE;
q.deadline_period_ns = ASTUTEDDS_DURATION_INFINITE;
q.lifespan_duration_ns = ASTUTEDDS_DURATION_INFINITE;
q.partitions = NULL;
q.partition_count = 0;
return q;
}
static inline AstuteDDS_DataReaderQos astutedds_default_datareader_qos(void)
{
AstuteDDS_DataReaderQos q;
q.reliability = ASTUTEDDS_RELIABLE;
q.history_kind = ASTUTEDDS_KEEP_LAST;
q.history_depth = 1;
q.durability = ASTUTEDDS_VOLATILE;
q.ignore_local_publications = 0;
q.liveliness_kind = ASTUTEDDS_AUTOMATIC_LIVELINESS;
q.liveliness_lease_duration_ns = ASTUTEDDS_DURATION_INFINITE;
q.deadline_period_ns = ASTUTEDDS_DURATION_INFINITE;
q.lifespan_duration_ns = ASTUTEDDS_DURATION_INFINITE;
q.partitions = NULL;
q.partition_count = 0;
return q;
}
// ── DomainParticipant ─────────────────────────────────────────────────────────
AstuteDDS_Participant astutedds_create_participant(uint32_t domain_id);
void astutedds_delete_participant(AstuteDDS_Participant p);
AstuteDDS_ReturnCode astutedds_participant_set_user_data(
AstuteDDS_Participant p,
const uint8_t *data,
size_t length);
// ── Topic ────────────────────────────────────────────────────────────────────
AstuteDDS_Topic astutedds_create_topic(
AstuteDDS_Participant p,
const char *topic_name,
const char *type_name);
void astutedds_delete_topic(AstuteDDS_Participant p, AstuteDDS_Topic t);
const char *astutedds_topic_name(AstuteDDS_Topic t);
const char *astutedds_topic_type_name(AstuteDDS_Topic t);
// ── Publisher ─────────────────────────────────────────────────────────────────
AstuteDDS_Publisher astutedds_create_publisher(AstuteDDS_Participant p);
void astutedds_delete_publisher(AstuteDDS_Participant p, AstuteDDS_Publisher pub);
// ── DataWriter ────────────────────────────────────────────────────────────────
AstuteDDS_DataWriter astutedds_create_datawriter(
AstuteDDS_Publisher pub,
AstuteDDS_Topic topic,
const AstuteDDS_DataWriterQos *qos);
void astutedds_delete_datawriter(AstuteDDS_Publisher pub, AstuteDDS_DataWriter w);
AstuteDDS_ReturnCode astutedds_write(
AstuteDDS_DataWriter w,
const uint8_t *data,
size_t len);
// ── Subscriber ───────────────────────────────────────────────────────────────
AstuteDDS_Subscriber astutedds_create_subscriber(AstuteDDS_Participant p);
void astutedds_delete_subscriber(AstuteDDS_Participant p, AstuteDDS_Subscriber sub);
// ── DataReader ────────────────────────────────────────────────────────────────
AstuteDDS_DataReader astutedds_create_datareader(
AstuteDDS_Subscriber sub,
AstuteDDS_Topic topic,
const AstuteDDS_DataReaderQos *qos);
void astutedds_delete_datareader(AstuteDDS_Subscriber sub, AstuteDDS_DataReader r);
AstuteDDS_ReturnCode astutedds_take_next(AstuteDDS_DataReader r, AstuteDDS_Sample *out);
size_t astutedds_unread_count(AstuteDDS_DataReader r);
// ── Graph / discovery ─────────────────────────────────────────────────────────
typedef void (*AstuteDDS_TopicCallback)(
void * user_data,
const char * topic_name,
const char * type_name);
void astutedds_get_topic_names_and_types(
AstuteDDS_Participant p,
AstuteDDS_TopicCallback callback,
void * user_data);
// ── Entity identity (§1.2, §1.3) ──────────────────────────────────────────────
typedef struct
{
uint8_t bytes[16];
} AstuteDDS_Gid;
AstuteDDS_ReturnCode astutedds_participant_get_gid(
AstuteDDS_Participant p,
AstuteDDS_Gid *out);
AstuteDDS_ReturnCode astutedds_datawriter_get_gid(
AstuteDDS_DataWriter w,
AstuteDDS_Gid *out);
AstuteDDS_ReturnCode astutedds_datareader_get_gid(
AstuteDDS_DataReader r,
AstuteDDS_Gid *out);
// ── QoS read-back (§1.5) ─────────────────────────────────────────────────────
AstuteDDS_ReturnCode astutedds_datawriter_get_qos(
AstuteDDS_DataWriter w,
AstuteDDS_DataWriterQos *out);
AstuteDDS_ReturnCode astutedds_datareader_get_qos(
AstuteDDS_DataReader r,
AstuteDDS_DataReaderQos *out);
// ── Endpoint enumeration (§1.2) ──────────────────────────────────────────────
typedef struct
{
int kind;
AstuteDDS_Gid endpoint_gid;
AstuteDDS_Gid participant_gid;
const char *topic_name;
const char *type_name;
const uint8_t *participant_user_data;
size_t participant_user_data_len;
const char *participant_name;
/* Effective RxO QoS snapshot */
AstuteDDS_Reliability reliability;
AstuteDDS_Durability durability;
} AstuteDDS_EndpointInfo;
typedef void (*AstuteDDS_EndpointCallback)(
void *user_data,
const AstuteDDS_EndpointInfo *info);
void astutedds_enumerate_publications(
AstuteDDS_Participant p,
AstuteDDS_EndpointCallback callback,
void *user_data);
void astutedds_enumerate_subscriptions(
AstuteDDS_Participant p,
AstuteDDS_EndpointCallback callback,
void *user_data);
/* ── Entity status + listener callbacks (§1.1) ─────────────────────────── */
typedef struct
{
int32_t total_count;
int32_t total_count_change;
int32_t current_count;
int32_t current_count_change;
int32_t last_subscription_handle;
} AstuteDDS_PublicationMatchedStatus;
typedef struct
{
int32_t total_count;
int32_t total_count_change;
int32_t current_count;
int32_t current_count_change;
int32_t last_publication_handle;
} AstuteDDS_SubscriptionMatchedStatus;
typedef struct
{
int32_t total_count;
int32_t total_count_change;
int32_t last_policy_id;
} AstuteDDS_OfferedIncompatibleQosStatus;
typedef struct
{
int32_t total_count;
int32_t total_count_change;
int32_t last_policy_id;
} AstuteDDS_RequestedIncompatibleQosStatus;
typedef struct
{
int32_t total_count;
int32_t total_count_change;
} AstuteDDS_LivelinessLostStatus;
typedef struct
{
int32_t alive_count;
int32_t not_alive_count;
int32_t alive_count_change;
int32_t not_alive_count_change;
int32_t last_publication_handle;
} AstuteDDS_LivelinessChangedStatus;
typedef struct
{
int32_t total_count;
int32_t total_count_change;
int32_t last_instance_handle;
} AstuteDDS_OfferedDeadlineMissedStatus;
typedef struct
{
int32_t total_count;
int32_t total_count_change;
int32_t last_instance_handle;
} AstuteDDS_RequestedDeadlineMissedStatus;
typedef struct
{
int32_t total_count;
int32_t total_count_change;
} AstuteDDS_SampleLostStatus;
AstuteDDS_ReturnCode astutedds_datawriter_get_publication_matched_status(
AstuteDDS_DataWriter w,
AstuteDDS_PublicationMatchedStatus *out);
AstuteDDS_ReturnCode astutedds_datawriter_get_offered_incompatible_qos_status(
AstuteDDS_DataWriter w,
AstuteDDS_OfferedIncompatibleQosStatus *out);
AstuteDDS_ReturnCode astutedds_datareader_get_subscription_matched_status(
AstuteDDS_DataReader r,
AstuteDDS_SubscriptionMatchedStatus *out);
AstuteDDS_ReturnCode astutedds_datareader_get_requested_incompatible_qos_status(
AstuteDDS_DataReader r,
AstuteDDS_RequestedIncompatibleQosStatus *out);
AstuteDDS_ReturnCode astutedds_datawriter_get_liveliness_lost_status(
AstuteDDS_DataWriter w,
AstuteDDS_LivelinessLostStatus *out);
AstuteDDS_ReturnCode astutedds_datawriter_assert_liveliness(
AstuteDDS_DataWriter w);
AstuteDDS_ReturnCode astutedds_datareader_get_liveliness_changed_status(
AstuteDDS_DataReader r,
AstuteDDS_LivelinessChangedStatus *out);
AstuteDDS_ReturnCode astutedds_datawriter_get_offered_deadline_missed_status(
AstuteDDS_DataWriter w,
AstuteDDS_OfferedDeadlineMissedStatus *out);
AstuteDDS_ReturnCode astutedds_datareader_get_requested_deadline_missed_status(
AstuteDDS_DataReader r,
AstuteDDS_RequestedDeadlineMissedStatus *out);
AstuteDDS_ReturnCode astutedds_datareader_get_sample_lost_status(
AstuteDDS_DataReader r,
AstuteDDS_SampleLostStatus *out);
/* Listener callback typedefs. Every callback receives the entity handle,
* a pointer to the newly-updated status snapshot (owned by the DDS core
* for the duration of the callback), and the caller-supplied user_data. */
typedef void (*AstuteDDS_PublicationMatchedCallback)(
void *user_data,
AstuteDDS_DataWriter writer,
const AstuteDDS_PublicationMatchedStatus *status);
typedef void (*AstuteDDS_OfferedIncompatibleQosCallback)(
void *user_data,
AstuteDDS_DataWriter writer,
const AstuteDDS_OfferedIncompatibleQosStatus *status);
typedef void (*AstuteDDS_SubscriptionMatchedCallback)(
void *user_data,
AstuteDDS_DataReader reader,
const AstuteDDS_SubscriptionMatchedStatus *status);
typedef void (*AstuteDDS_RequestedIncompatibleQosCallback)(
void *user_data,
AstuteDDS_DataReader reader,
const AstuteDDS_RequestedIncompatibleQosStatus *status);
typedef void (*AstuteDDS_DataAvailableCallback)(
void *user_data,
AstuteDDS_DataReader reader);
typedef void (*AstuteDDS_LivelinessLostCallback)(
void *user_data,
AstuteDDS_DataWriter writer,
const AstuteDDS_LivelinessLostStatus *status);
typedef void (*AstuteDDS_LivelinessChangedCallback)(
void *user_data,
AstuteDDS_DataReader reader,
const AstuteDDS_LivelinessChangedStatus *status);
typedef void (*AstuteDDS_OfferedDeadlineMissedCallback)(
void *user_data,
AstuteDDS_DataWriter writer,
const AstuteDDS_OfferedDeadlineMissedStatus *status);
typedef void (*AstuteDDS_RequestedDeadlineMissedCallback)(
void *user_data,
AstuteDDS_DataReader reader,
const AstuteDDS_RequestedDeadlineMissedStatus *status);
typedef void (*AstuteDDS_SampleLostCallback)(
void *user_data,
AstuteDDS_DataReader reader,
const AstuteDDS_SampleLostStatus *status);
typedef struct
{
AstuteDDS_PublicationMatchedCallback on_publication_matched;
AstuteDDS_OfferedIncompatibleQosCallback on_offered_incompatible_qos;
AstuteDDS_LivelinessLostCallback on_liveliness_lost;
AstuteDDS_OfferedDeadlineMissedCallback on_offered_deadline_missed;
void *user_data;
} AstuteDDS_DataWriterListener;
typedef struct
{
AstuteDDS_SubscriptionMatchedCallback on_subscription_matched;
AstuteDDS_RequestedIncompatibleQosCallback on_requested_incompatible_qos;
AstuteDDS_DataAvailableCallback on_data_available;
AstuteDDS_LivelinessChangedCallback on_liveliness_changed;
AstuteDDS_RequestedDeadlineMissedCallback on_requested_deadline_missed;
AstuteDDS_SampleLostCallback on_sample_lost;
void *user_data;
} AstuteDDS_DataReaderListener;
AstuteDDS_ReturnCode astutedds_datawriter_set_listener(
AstuteDDS_DataWriter w,
const AstuteDDS_DataWriterListener *listener);
AstuteDDS_ReturnCode astutedds_datareader_set_listener(
AstuteDDS_DataReader r,
const AstuteDDS_DataReaderListener *listener);
/* ── §1.4 Request / Reply (RPC) primitives ─────────────────────────────
*
* These wrap dcps::Requester / dcps::Replier. They implement the
* DDS-RPC pattern: two topics per service (rq/<svc>Request and
* rr/<svc>Reply), a 16-byte requester GID + 8-byte little-endian
* sequence number prepended to every payload, and reply filtering by
* GID on the requester side. The RMW layer's hand-rolled correlation
* header (rmw_astutedds_cpp/jazzy/src/rpc.cpp) can be collapsed onto
* these calls.
*/
typedef struct AstuteDDS_Requester_s *AstuteDDS_Requester;
typedef struct AstuteDDS_Replier_s *AstuteDDS_Replier;
typedef struct
{
AstuteDDS_Reliability reliability;
AstuteDDS_HistoryKind history_kind;
int32_t history_depth;
AstuteDDS_Durability durability;
} AstuteDDS_RequesterQos;
typedef AstuteDDS_RequesterQos AstuteDDS_ReplierQos;
static inline AstuteDDS_RequesterQos astutedds_default_requester_qos(void)
{
AstuteDDS_RequesterQos q;
q.reliability = ASTUTEDDS_RELIABLE;
q.history_kind = ASTUTEDDS_KEEP_LAST;
q.history_depth = 10;
q.durability = ASTUTEDDS_VOLATILE;
return q;
}
static inline AstuteDDS_ReplierQos astutedds_default_replier_qos(void)
{
return astutedds_default_requester_qos();
}
AstuteDDS_Requester astutedds_create_requester(
AstuteDDS_Participant participant,
const char *service_name,
const char *request_type_name,
const char *reply_type_name,
const AstuteDDS_RequesterQos *qos);
void astutedds_delete_requester(AstuteDDS_Participant participant,
AstuteDDS_Requester requester);
AstuteDDS_ReturnCode astutedds_requester_get_gid(
AstuteDDS_Requester requester,
uint8_t *out_gid);
AstuteDDS_ReturnCode astutedds_requester_send_request(
AstuteDDS_Requester requester,
const uint8_t *payload,
size_t payload_length,
int64_t *out_sequence_number);
AstuteDDS_ReturnCode astutedds_requester_take_reply(
AstuteDDS_Requester requester,
const uint8_t **out_payload,
size_t *out_payload_length,
int64_t *out_sequence_number);
AstuteDDS_DataReader astutedds_requester_get_reply_reader(
AstuteDDS_Requester requester);
AstuteDDS_DataWriter astutedds_requester_get_request_writer(
AstuteDDS_Requester requester);
AstuteDDS_Replier astutedds_create_replier(
AstuteDDS_Participant participant,
const char *service_name,
const char *request_type_name,
const char *reply_type_name,
const AstuteDDS_ReplierQos *qos);
void astutedds_delete_replier(AstuteDDS_Participant participant,
AstuteDDS_Replier replier);
AstuteDDS_ReturnCode astutedds_replier_take_request(
AstuteDDS_Replier replier,
const uint8_t **out_payload,
size_t *out_payload_length,
uint8_t *out_client_gid,
int64_t *out_sequence_number);
AstuteDDS_ReturnCode astutedds_replier_send_reply(
AstuteDDS_Replier replier,
const uint8_t *client_gid,
int64_t sequence_number,
const uint8_t *payload,
size_t payload_length);
AstuteDDS_DataReader astutedds_replier_get_request_reader(
AstuteDDS_Replier replier);
AstuteDDS_DataWriter astutedds_replier_get_reply_writer(
AstuteDDS_Replier replier);
/* ── §1.6 Data-arrival file descriptor (WaitSet / rmw_wait integration) ─
*
* Returns an eventfd(2) that becomes readable when new samples arrive on
* this DataReader. Suitable for select()/poll()/epoll() integration —
* lets an executor block on data arrival instead of polling
* astutedds_unread_count(). The fd is created lazily on the first
* call and reused for the lifetime of the DataReader (subsequent calls
* return the same value). Ownership stays with AstuteDDS; the fd is
* closed automatically when the DataReader is deleted.
*
* The fd is in semaphore mode so each read(fd, buf, 8) consumes exactly
* one arrival credit. Callers that want edge-triggered semantics
* (drain all pending credits and then treat as a single wake-up) can
* use astutedds_datareader_drain_read_fd() below.
*
* @return A non-negative eventfd on success, or -1 if the reader is
* NULL or the eventfd() syscall fails.
*/
int astutedds_datareader_get_read_fd(AstuteDDS_DataReader r);
AstuteDDS_ReturnCode astutedds_datareader_drain_read_fd(int fd);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // ASTUTEDDS_C_ASTUTEDDS_H