|
nros rmw-cffi
C vtable for plugging a third-party RMW backend into nros
|
Typed entity structs for the nros RMW C surface. More...


Go to the source code of this file.
Data Structures | |
| struct | rmw_byte_span_t |
| struct | rmw_client_t |
| struct | rmw_gid_t |
| struct | rmw_message_info_t |
| struct | rmw_message_type_support_t |
| struct | rmw_mut_byte_span_t |
| struct | rmw_network_flow_endpoint_t |
| struct | rmw_node_t |
| struct | rmw_publisher_options_t |
| struct | rmw_publisher_t |
| struct | rmw_qos_profile_t |
| struct | rmw_service_t |
| struct | rmw_service_type_support_t |
| struct | rmw_session_options_t |
| struct | rmw_session_property_t |
| struct | rmw_session_t |
| struct | rmw_subscription_options_t |
| struct | rmw_subscription_t |
| struct | rmw_topic_endpoint_info_t |
Macros | |
| #define | NROS_RMW_DURABILITY_SYSTEM_DEFAULT 0 |
| #define | NROS_RMW_DURABILITY_TRANSIENT_LOCAL 1 |
| #define | NROS_RMW_DURABILITY_UNKNOWN 3 |
| #define | NROS_RMW_DURABILITY_VOLATILE 2 |
| #define | NROS_RMW_DURATION_INFINITE_MS UINT32_MAX |
| #define | NROS_RMW_HISTORY_KEEP_ALL 2 |
| #define | NROS_RMW_HISTORY_KEEP_LAST 1 |
| #define | NROS_RMW_HISTORY_SYSTEM_DEFAULT 0 |
| #define | NROS_RMW_HISTORY_UNKNOWN 3 |
| #define | NROS_RMW_QOS_PROFILE_DEFAULT |
| #define | NROS_RMW_QOS_PROFILE_PARAMETERS |
| #define | NROS_RMW_QOS_PROFILE_SENSOR_DATA |
| #define | NROS_RMW_QOS_PROFILE_SERVICES_DEFAULT NROS_RMW_QOS_PROFILE_DEFAULT |
| #define | NROS_RMW_QOS_PROFILE_SYSTEM_DEFAULT |
| #define | NROS_RMW_RELIABILITY_BEST_EFFORT 2 |
| #define | NROS_RMW_RELIABILITY_RELIABLE 1 |
| #define | NROS_RMW_RELIABILITY_SYSTEM_DEFAULT 0 |
| #define | NROS_RMW_RELIABILITY_UNKNOWN 3 |
| #define | RMW_GID_STORAGE_SIZE 24u |
| #define | RMW_INET_ADDRSTRLEN 48 |
| #define | RMW_MESSAGE_INFO_SEQUENCE_NUMBER_UNSUPPORTED UINT64_MAX |
| #define | RMW_SESSION_MAX_PROPERTIES 16 |
Typedefs | |
| typedef void(* | rmw_content_filter_visit_fn) (void *ctx, const char *expression, const char *const *parameters, size_t parameter_count) |
| typedef bool(* | rmw_network_flow_endpoint_visit_fn) (void *ctx, const rmw_network_flow_endpoint_t *endpoint) |
| typedef int64_t | rmw_time_point_value_t |
Functions | |
| rmw_ret_t | nros_rmw_qos_incompatibility_mask (rmw_qos_profile_t offered, rmw_qos_profile_t requested, rmw_qos_compatibility_type_t *compatibility, uint32_t *clash_mask) |
| rmw_ret_t | rmw_compare_gids_equal (const rmw_gid_t *gid1, const rmw_gid_t *gid2, bool *result) |
| rmw_ret_t | rmw_qos_profile_check_compatible (rmw_qos_profile_t publisher_profile, rmw_qos_profile_t subscription_profile, rmw_qos_compatibility_type_t *compatibility, char *reason, size_t reason_size) |
Typed entity structs for the nros RMW C surface.
Same shape as upstream rmw.h's rmw_publisher_t / rmw_subscription_t family: visible metadata + a void * data tail (named backend_data here). No generic-handle typedef.
Lifetime rule. All const char * string fields are borrowed pointers — the storage pointing at them is owned by the caller (the runtime) and must outlive the entity. Backends never free or reallocate these strings; they hold them as-is for the entity's lifetime.
ABI commitment. These structs are part of the public ABI. Adding or reordering fields is a major version bump. Backends compile against this header and consumers compile against backend libraries — both sides must agree on the layout.
Forward-compat reserved bytes. Each entity carries an explicit _reserved[N] byte array sized to fill the natural alignment slot before backend_data. New fields up to N bytes can be added later without changing the struct's overall size or any field's offset after backend_data. Backends and runtime must zero the reserved bytes; the runtime relies on them being zero on read.
No-alloc + no-std preserved. No struct here owns heap-allocated storage. All metadata is either inline POD or a borrowed pointer.
| #define NROS_RMW_DURABILITY_SYSTEM_DEFAULT 0 |
Durability policy values for rmw_qos_profile_t::durability.
| #define NROS_RMW_DURABILITY_TRANSIENT_LOCAL 1 |
| #define NROS_RMW_DURABILITY_UNKNOWN 3 |
| #define NROS_RMW_DURABILITY_VOLATILE 2 |
| #define NROS_RMW_DURATION_INFINITE_MS UINT32_MAX |
Explicit infinite spelling for the u32-ms duration fields (phase-301, issue 0241). Semantically identical to 0 (no check) but lets a caller distinguish "I mean infinite" from "I left it unset".
| #define NROS_RMW_HISTORY_KEEP_ALL 2 |
| #define NROS_RMW_HISTORY_KEEP_LAST 1 |
| #define NROS_RMW_HISTORY_SYSTEM_DEFAULT 0 |
History policy values for rmw_qos_profile_t::history.
| #define NROS_RMW_HISTORY_UNKNOWN 3 |
| #define NROS_RMW_QOS_PROFILE_DEFAULT |
rmw_qos_profile_default-equivalent: reliable + volatile + keep-last(10), automatic liveliness, no deadline / lifespan.
| #define NROS_RMW_QOS_PROFILE_PARAMETERS |
rmw_qos_profile_parameters-equivalent: reliable + volatile + keep-last(1000).
| #define NROS_RMW_QOS_PROFILE_SENSOR_DATA |
rmw_qos_profile_sensor_data-equivalent: best-effort + volatile + keep-last(5).
| #define NROS_RMW_QOS_PROFILE_SERVICES_DEFAULT NROS_RMW_QOS_PROFILE_DEFAULT |
rmw_qos_profile_services_default-equivalent: reliable + volatile + keep-last(10).
| #define NROS_RMW_QOS_PROFILE_SYSTEM_DEFAULT |
rmw_qos_profile_system_default-equivalent: every field is the sentinel.
issue 0829. This aliased NROS_RMW_QOS_PROFILE_DEFAULT until 2026-09-03, which made SYSTEM_DEFAULT a byte-for-byte synonym for a concrete RELIABLE / VOLATILE / KEEP_LAST(10) profile — i.e. the constant said nothing of its own. Upstream's rmw_qos_profile_system_default names no concrete policy either; it is all sentinel, and the RMW resolves it. The two reference RMWs resolve the SAME sentinel differently — rmw_cyclonedds_cpp's create_readwrite_qos gives KEEP_LAST, 1, while rmw_zenoh_cpp's QoS::QoS() gives RMW_ZENOH_DEFAULT_HISTORY_DEPTH, which is 42 — so no number baked here could be right.
NOT AN ABI BREAK: no struct layout moved and no policy value was renumbered. What changed is the BYTES this macro expands to, so a caller that recompiles against this header and uses this constant now sends sentinels where it used to send depth 10. That is the intended fix, and nothing in this repository used the macro. Every field being zero also means this is what a memset of rmw_qos_profile_t gives, so the ABI stops having two answers for the same bytes.
Which concrete values a sentinel becomes is the BACKEND's answer, applied at its create entry: cyclonedds resolves to RELIABLE / VOLATILE / KEEP_LAST(1), mirroring rmw_cyclonedds_cpp; xrce resolves the three policies the same way and leaves the depth for the Agent; zenoh resolves the depth to the ring the shim actually enforces.
| #define NROS_RMW_RELIABILITY_BEST_EFFORT 2 |
| #define NROS_RMW_RELIABILITY_RELIABLE 1 |
| #define NROS_RMW_RELIABILITY_SYSTEM_DEFAULT 0 |
Reliability policy values for rmw_qos_profile_t::reliability.
| #define NROS_RMW_RELIABILITY_UNKNOWN 3 |
The backend could not determine this policy. See the note on rmw_qos_profile_t about partial answers.
| #define RMW_GID_STORAGE_SIZE 24u |
Storage size of a GID, in bytes. Upstream's RMW_GID_STORAGE_SIZE.
| #define RMW_INET_ADDRSTRLEN 48 |
Upstream's value, kept exactly: it sizes a field that crosses the ABI, and upstream took it from linux/inet.h for the same reason.
| #define RMW_MESSAGE_INFO_SEQUENCE_NUMBER_UNSUPPORTED UINT64_MAX |
Sentinel for a sequence number the backend does not populate. Upstream's RMW_MESSAGE_INFO_SEQUENCE_NUMBER_UNSUPPORTED.
| #define RMW_SESSION_MAX_PROPERTIES 16 |
Upper bound on rmw_session_options_t::property_count.
The seam marshals the properties through a stack array, so it needs a bound; 16 is chosen to clear the largest configuration anyone can actually state at once (zenoh-pico defines 23 run-time keys, but mode and connect arrive as dedicated create_session arguments and the 13 TLS keys split into a listen-side and a connect-side set — a full mTLS client is ~10). A caller that exceeds it is REFUSED, never truncated.
| typedef void(* rmw_content_filter_visit_fn) (void *ctx, const char *expression, const char *const *parameters, size_t parameter_count) |
Visit a subscription's content filter. Return value ignored: there is exactly one filter per subscription, so this is a callback only to avoid handing back an allocated rmw_subscription_content_filter_options_t.
expression and every parameters[i] are BORROWED for the call. A subscription with no filter is reported as expression == NULL, which is what upstream's empty options struct means.
| typedef bool(* rmw_network_flow_endpoint_visit_fn) (void *ctx, const rmw_network_flow_endpoint_t *endpoint) |
Visit one network flow endpoint. Return false to stop.
Upstream fills an ALLOCATING rmw_network_flow_endpoint_array_t through an rcutils_allocator_t *. There is no allocator at this seam and the flow count is a property of the OS's routing, not of anything the caller can size in advance — so it streams, exactly like the graph slots.
| typedef int64_t rmw_time_point_value_t |
Nanoseconds since a clock's epoch — upstream's rmw_time_point_value_t.
| enum nros_rmw_qos_clash_t |
Which policies clashed, as a bitmask. A nano-ros extension: upstream reports the reason only as prose, which a target cannot act on.
| Enumerator | |
|---|---|
| NROS_RMW_QOS_CLASH_NONE | |
| NROS_RMW_QOS_CLASH_RELIABILITY | |
| NROS_RMW_QOS_CLASH_DURABILITY | |
| NROS_RMW_QOS_CLASH_DEADLINE | |
| NROS_RMW_QOS_CLASH_LIVELINESS_KIND | |
| NROS_RMW_QOS_CLASH_LIVELINESS_LEASE | |
| enum rmw_endpoint_type_t |
| enum rmw_feature_t |
Upstream rmw_feature_t — an optional piece of CONTENT a backend may or may not populate. Upstream defines exactly these two, both about whether message-info sequence numbers are real. Values mirror upstream's.
| Enumerator | |
|---|---|
| RMW_FEATURE_MESSAGE_INFO_PUBLICATION_SEQUENCE_NUMBER | |
| RMW_FEATURE_MESSAGE_INFO_RECEPTION_SEQUENCE_NUMBER | |
Liveliness kind values for rmw_qos_profile_t::liveliness_kind.
Upstream's numbering (W5/B2). MANUAL_BY_NODE and MANUAL_BY_TOPIC were SWAPPED here until 2026-08-24 — 2 meant BY_TOPIC to us and BY_NODE to upstream — which the cyclonedds backend then translated into a real DDS liveliness kind a ROS peer matches on.
| enum rmw_log_severity_t |
Log severity — upstream rmw_log_severity_t, values included.
The values are rcutils' ladder (DEBUG 10, INFO 20, …), not a dense 0..N, so they are written out rather than renumbered: a caller that has an rcutils severity in hand can pass it straight through.
There is no TRACE. nros_log::Severity has one, and it maps to DEBUG crossing this seam — losing a distinction upstream never had is better than inventing a value a ROS-side caller cannot produce.
| Enumerator | |
|---|---|
| RMW_LOG_SEVERITY_UNSET | |
| RMW_LOG_SEVERITY_DEBUG | |
| RMW_LOG_SEVERITY_INFO | |
| RMW_LOG_SEVERITY_WARN | |
| RMW_LOG_SEVERITY_ERROR | |
| RMW_LOG_SEVERITY_FATAL | |
Verdict of a QoS compatibility check. Upstream rmw_qos_compatibility_type_t, values included.
WARNING means "compatible as far as could be checked, but at least one
policy on one side is `*_UNKNOWN`" — the backend could not read it back. Reachable since W5/B2 gave the policies an UNKNOWN encoding; it was defined and unreachable before that, so the value could not be reused for anything else in the meantime.
A definite clash OUTRANKS an unknown: if the policies that COULD be compared are already incompatible the verdict is ERROR, because softening it to a warning would hide something the caller can act on.
| Enumerator | |
|---|---|
| RMW_QOS_COMPATIBILITY_OK | |
| RMW_QOS_COMPATIBILITY_WARNING | |
| RMW_QOS_COMPATIBILITY_ERROR | |
| rmw_ret_t nros_rmw_qos_incompatibility_mask | ( | rmw_qos_profile_t | offered, |
| rmw_qos_profile_t | requested, | ||
| rmw_qos_compatibility_type_t * | compatibility, | ||
| uint32_t * | clash_mask | ||
| ) |
Which policies of offered (a publisher's) and requested (a subscription's) are incompatible, as a bitmask — no strings, so an image that only needs the verdict never links the reason table.
Argument order is upstream's: publisher profile first.
Writes *compatibility and *clash_mask on NROS_RMW_RET_OK; NROS_RMW_RET_INVALID_ARGUMENT if either out-parameter is NULL.
Upstream rmw_compare_gids_equal. Exact parity.
Equal means the same implementation_identifier AND the same 24 bytes. Gids from different backends are never equal — which matters more here than upstream, because nros_rmw_cffi_register_named admits several backends in one image.
Comparison is over the WHOLE array, so a producer must zero-pad; see rmw_gid_t.
| rmw_ret_t rmw_qos_profile_check_compatible | ( | rmw_qos_profile_t | publisher_profile, |
| rmw_qos_profile_t | subscription_profile, | ||
| rmw_qos_compatibility_type_t * | compatibility, | ||
| char * | reason, | ||
| size_t | reason_size | ||
| ) |
Upstream rmw_qos_profile_check_compatible. Exact parity.
reason may be NULL with reason_size 0 — the create-time path, which wants the verdict and nothing else.
The reason is SELECTED, never FORMATTED: each clash bit maps to one static const char[] and they are appended by a bounded copy. Upstream's implementations use snprintf, which would drag the printf engine into images that deliberately excluded it.
Truncation is NOT failure: the buffer is always NUL-terminated and the verdict is still written. Returning BUFFER_TOO_SMALL would make a small-buffer caller lose the load-bearing half of the answer.