|
nros C++ API
Lightweight ROS 2 client for embedded real-time systems (C++ headers)
|
Typedefs | |
| using | PumpFn = nros_cpp_ret_t (*)(void*) |
| using | TakeSeqFn = nros_cpp_ret_t (*)(void*, uint8_t*, size_t, size_t*, int64_t*) |
Enumerations | |
| enum | SubscriptionCallbackShape { SUB_SHAPE_NONE = 0 , SUB_SHAPE_REF = 1 , SUB_SHAPE_CONST_SHARED_PTR = 2 , SUB_SHAPE_SHARED_PTR = 3 , SUB_SHAPE_UNIQUE_PTR = 4 } |
Functions | |
| void | abort_failed_create (const char *verb, const char *name, int32_t code) |
| template<class A> | |
| nros_cpp_action_hashes_t | action_endpoint_hashes () |
| int32_t | apply_ros_args (void *executor, int argc, char const *const *argv) |
| constexpr bool | argv_has_ros_args (int argc, char const *const *argv, int i=0) |
| inline ::rclcpp::Node & | as_node_ref (::rclcpp::Node &n) |
| inline ::rclcpp::Node & | as_node_ref (::rclcpp::Node *n) |
| inline ::rclcpp::Node & | as_node_ref (const ::rclcpp::Node::SharedPtr &n) |
| template<typename NodePtr> | |
| void | check_node_on_executor (const NodePtr &node, void *executor, bool process) |
| phase-515 P2 — the add_node check, against one executor handle. | |
| template<typename M, typename Cb> | |
| Subscription< M >::SharedPtr | create_subscription_dispatch (::rclcpp::Node &node, const char *topic, const ::rclcpp::QoS &qos, Cb cb, ::rclcpp::tr::false_type) |
| The one-argument callback path (void(const M&), or a hosted pointer shape). | |
| template<typename M, typename Cb> | |
| Subscription< M >::SharedPtr | create_subscription_dispatch (::rclcpp::Node &node, const char *topic, const ::rclcpp::QoS &qos, Cb cb, ::rclcpp::tr::true_type) |
| const char * | declared_durability_spelling (int ordinal) |
| The contract spelling of a durability ordinal, for the report above. | |
| const char * | declared_reliability_spelling (int ordinal) |
| The contract spelling of a reliability ordinal, for the report above. | |
| void | finish_declared_callback_groups (::rclcpp::Node &node, const DeclaredCallbackGroups &groups) |
| template<typename F> | |
| bool | future_is_ready (F &f) |
| Result | init_honouring_ros_args (int argc, char const *const *argv, const char *name) |
| constexpr bool | is_ros_args_flag (char const *s, int i=0) |
| inline ::rclcpp::MessageInfo | message_info_from_ffi (const nros_cpp_message_info_t &c) |
| Issue 2036 — the MessageInfo the runtime reported, in upstream's layout. | |
| constexpr QoS | qos_all_unknown () |
| constexpr Duration | qos_best_available_duration () |
| constexpr DurabilityPolicy | qos_durability_from_rmw (rmw_qos_durability_policy_t p) |
| constexpr rmw_qos_durability_policy_t | qos_durability_to_rmw (DurabilityPolicy p) |
| constexpr QoS | qos_from_ffi (const nros_cpp_qos_t &f) |
| constexpr HistoryPolicy | qos_history_from_rmw (rmw_qos_history_policy_t p) |
| constexpr rmw_qos_history_policy_t | qos_history_to_rmw (HistoryPolicy p) |
| constexpr LivelinessPolicy | qos_liveliness_from_rmw (rmw_qos_liveliness_policy_t p) |
| constexpr rmw_qos_liveliness_policy_t | qos_liveliness_to_rmw (LivelinessPolicy p) |
| constexpr ReliabilityPolicy | qos_reliability_from_rmw (rmw_qos_reliability_policy_t p) |
| constexpr rmw_qos_reliability_policy_t | qos_reliability_to_rmw (ReliabilityPolicy p) |
| constexpr nros_cpp_qos_t | qos_to_ffi (const QoS &qos) |
| constexpr rmw_qos_profile_t | qos_to_rmw (const QoS &q) |
| constexpr Duration | qos_window_duration (uint32_t ms) |
| constexpr uint32_t | qos_window_from_rmw (const rmw_time_t &t) |
| constexpr uint32_t | qos_window_ms (const Duration &d) |
| constexpr rmw_time_t | qos_window_to_rmw (uint32_t ms) |
| template<typename M, typename Fn> | |
| Result | register_subscription_capturing (::rclcpp::Node &node, const char *topic, const QoS &qos, const Fn &fn, size_t *out_handle_id) |
| template<typename Cb> | |
| TimerHandle | register_timer_capturing (::rclcpp::Node &node, rcl_clock_type_t clock_type, Duration period, Cb &&cb, const char *verb, const CallbackGroup *group=nullptr, bool autostart=true) |
| void | report_callback_group_mismatch (const char *node_name, const char *how, const char *name, int len, const char *list) |
| void | report_component_failure (const char *node_name, const char *what, int32_t code) |
| void | report_declared_depth_mismatch (const char *node_name, const char *topic, int declared, int passed) |
| void | report_declared_param_mismatch (const char *fqn, const char *param, const char *contract, int declared, int passed) |
| void | report_declared_policy_mismatch (const char *node_name, const char *topic, const char *policy, const char *declared, const char *passed) |
| void | require_created (::rclcpp::Result r, const char *verb, const char *name) |
| template<typename Future> | |
| FutureReturnCode | spin_executor_until_future_complete (void *executor, Future &future, int32_t timeout_ms, bool process) |
| template<typename T> | |
| T && | sub_declval () noexcept |
| Unevaluated-only declval, so the detection below needs no <utility>. | |
| ClockValuePtr | timer_clock (void *executor, size_t handle_id) |
Variables | |
| constexpr int32_t | DECLARED_DEPTH_MISMATCH = -403 |
| constexpr int32_t | DECLARED_PARAM_MISMATCH = -446 |
| constexpr int32_t | DECLARED_QOS_MISMATCH = DECLARED_DEPTH_MISMATCH |
| constexpr int | MAX_STALE_DRAIN_PER_POLL = 8 |
| constexpr int64_t | SEQUENCE_ID_UNKNOWN = (-9223372036854775807LL - 1) |
rclcpp::spin_until_future_complete(node, future[, timeout]).
ADOPT-BOUNDED: the timeout is int32_t MILLISECONDS (-1 = unbounded, the default), not a std::chrono::duration, so a ported 1s argument does not compile. It spins the PROCESS executor in 10 ms spin_once slices — there is one executor per task (RFC-0002) and no executor argument — so the deadline is quantised to 10 ms. Returns upstream's FutureReturnCode.
phase-488 — the future is taken by FORWARDING reference. It was const Future&, which no rclcpp::Future could bind: its is_ready() caches the reply and is non-const, so spin_until_future_complete(node, client->send_request(req)) — the pairing the poll client's own doc recommends — did not compile, and the only thing the drift snippet ever passed was a fake with a const is_ready(). Both now bind.
| using rclcpp::detail::PumpFn = nros_cpp_ret_t (*)(void*) |
Issue 2011 — what an ACTION future polls: one pass of the action client's own dispatch (nros_cpp_action_client_poll), which takes any reply off the wire and hands it to the client's callbacks — and so, keyed by goal id, to the future waiting on that goal. A reply the executor dispatched during spin_once arrives the same way, so a future gets its reply whichever path took it.
| using rclcpp::detail::TakeSeqFn = nros_cpp_ret_t (*)(void*, uint8_t*, size_t, size_t*, int64_t*) |
The take hook a service future polls: one reply, its length AND the id of the request it answers (nros_cpp_service_client_take_response_seq).
The shapes, in detection order. const M& first, so a callable taking M by value or auto keeps the allocation-free path.
|
inline |
What upstream's throw becomes here — phase-428 W5 finding 9.
The create_* verbs on rclcpp::Node (then nros::Node, reached as rclcpp::Node through an alias since phase-427 W1-W3) used to write (void)this->create_…(…) and return the shared_ptr regardless. The (void) was not incidental: rclcpp::Result carries [[nodiscard]] (result.hpp, phase-428 W6), and the casts SUPPRESSED the one signal that existed. Measured, because the claim is easy to overstate: no C++ lane in this tree compiles with -Werror, so a bare discard here is a -Wunused-result WARNING and just check cpp stays green through it — the Rust-side -D warnings has no C++ counterpart. Even at full strength it would only have told the AUTHOR of this header, never the porting user, which is why the fix is a runtime refusal rather than a lint.
Every alternative was weighed against RFC-0089 Part I ("a difference must be one the compiler points at, and where it cannot be, it must be loud by other means"):
So: the loudest thing available, at the earliest point the defect is knowable, which is the CALL. This is the identical shape rclcpp::init(argc, argv) uses for --ros-args a few lines below, and it is what an uncaught upstream throw actually does to a tutorial main — terminate with a diagnostic, rather than continue with a dead object.
The failure is still HANDLEABLE: the underlying out-ref rclcpp::Node verbs return rclcpp::Result into caller-owned storage, and the message names them.
|
inline |
|
inline |
Honour --ros-args through nros_cpp_install_argv_remaps — the ONE C++ spelling, used by rclcpp::init(argc, argv) and rclcpp::init_in(argc, argv). executor == nullptr validates only. Logs the refusal, naming the token, and returns the FFI's code (0 on success).
|
constexpr |
| inline ::rclcpp::Node & rclcpp::detail::as_node_ref | ( | ::rclcpp::Node & | n | ) |
| inline ::rclcpp::Node & rclcpp::detail::as_node_ref | ( | ::rclcpp::Node * | n | ) |
| inline ::rclcpp::Node & rclcpp::detail::as_node_ref | ( | const ::rclcpp::Node::SharedPtr & | n | ) |
NodeT in upstream's signature is anything node-shaped — this, a reference, or (hosted) a shared_ptr, whose overload is in the hosted block above. One overload set, so the free function does not need three copies. phase-482 W2 — Node::SharedPtr is a freestanding handle.
|
inline |
phase-515 P2 — the add_node check, against one executor handle.
|
inline |
The one-argument callback path (void(const M&), or a hosted pointer shape).
|
inline |
Issue 2036 — the two-argument path: the callback also takes const rclcpp::MessageInfo&, so the runtime takes each sample with its metadata. Hosted only (the callable lives on the heap).
|
inline |
The contract spelling of a durability ordinal, for the report above.
|
inline |
The contract spelling of a reliability ordinal, for the report above.
|
inline |
phase-459 W6 — the post-constructor half: every declared group must have been created (node-level placement — one declared, none created — is allowed; see first_uncreated_callback_group). Called by BOTH constructors of a component: the NROS_COMPONENT factory and the generated C++ entry, which builds a workspace's components itself.
|
inline |
Issue 2027 — "has this future completed?" for each future shape spin_until_future_complete takes: anything with is_ready() (rclcpp::Future, rclcpp_action::detail::DrivenSharedFuture, which also drives its client) and, hosted, a bare std::shared_future / std::future (a zero-length wait_for).
|
inline |
Validate, open, install — so a refused vector never opens a session, and a rule that does not fit closes the one it opened rather than leaving it running without the remap.
|
constexpr |
Does this argv carry --ros-args? Factored out of init so the decision is TESTABLE: an abort inside init can only be exercised by a process that then dies, which is the shape of a check nothing ever runs. constexpr, and that is the point: it makes the predicate assertable with a static_assert, so its cases run in every check cpp with no link and no process. std::strcmp is not constexpr in C++14, hence the open-coded compare.
| inline ::rclcpp::MessageInfo rclcpp::detail::message_info_from_ffi | ( | const nros_cpp_message_info_t & | c | ) |
Issue 2036 — the MessageInfo the runtime reported, in upstream's layout.
|
constexpr |
The all-absent profile — issue 1437.
Every policy UNKNOWN: "there is nothing here that can tell you". What a get_actual_qos() returns when the handle it was asked of is not live, so the answer is never a plausible-looking concrete profile the caller would then compare against its request and find agreeable. QOS_PROFILE_UNKNOWN in Rust, NROS_RMW_QOS_PROFILE_UNKNOWN across the RMW ABI; this is the same statement in this header's vocabulary.
Written from the rclcpp:: enumerators and static_cast across, NOT from the NROS_CPP_QOS_* ones: this header defines those itself only when nros_cpp_ffi.h was NOT included first, and when it WAS, cbindgen has spelled them nros_cpp_qos_reliability_t_NROS_CPP_QOS_RELIABILITY_UNKNOWN — type-name-prefixed. So a bare enumerator here compiles in one include order and not the other, which is how the first version of this function broke the C++ surface extraction while every C++ test still passed.
|
constexpr |
The best-available window — issue 1973.
Upstream spells it RMW_QOS_DEADLINE_BEST_AVAILABLE / RMW_QOS_LIVELINESS_LEASE_DURATION_BEST_AVAILABLE, both RMW_DURATION_INFINITE - 1 = INT64_MAX - 1 ns. As a Duration it is that same value, and qos_window_ms lowers it — and only it — onto the C ABI's NROS_RMW_DURATION_BEST_AVAILABLE_MS (UINT32_MAX - 1).
|
constexpr |
|
constexpr |
|
constexpr |
issue 1437 — declared here, defined below QoS, and named as a friend of it. See the definition for what it is for and why it is the one function in this header that writes QoS's members.
The inverse of qos_to_ffi — issue 1437.
Used by the get_actual_qos() family, which is the only direction that produces a profile the CALLER did not write. The four static_casts are the same value-for-value mirror qos_to_ffi relies on in the other direction: rclcpp::ReliabilityPolicy and nros_cpp_qos_reliability_t agree enumerator for enumerator, sentinels included, and the static_asserts in tests/compile/qos_policy_accessors.cpp measure that rather than trusting it. Neither vocabulary is the RMW ABI's, whose numbering differs from both in all four enums — nothing here may be cast to an NROS_RMW_* value.
Writes QoS's members directly — see the friend declaration on the class for why this one function may and no setter can. The three windows are stored as the milliseconds the ABI carries, so the round-trip through qos_to_ffi is exact.
|
constexpr |
|
constexpr |
|
constexpr |
|
constexpr |
|
constexpr |
|
constexpr |
|
constexpr |
QoS → the by-value C ABI record, in ONE place.
Ten call sites across publisher.hpp / subscription.hpp / service.hpp / client.hpp / action_{server,client}.hpp / component.hpp open-coded this ten-field copy. A field appended to nros_cpp_qos_t then has ten places to be missed, which is the hand-mirror class issue 0160 records; phase-379 W5 folded them into this one function while renaming the accessors they called. constexpr so a fixed profile's marshalled form is checkable at compile time (qos_policy_accessors.cpp static_asserts the millisecond fields); value-initialised because C++14 forbids an uninitialised local in a constexpr function, and zeroing ten fields we then overwrite costs nothing.
|
constexpr |
QoS → upstream's struct, field by field. tx_express has no upstream field and is dropped, as it is from every upstream-shaped read.
|
constexpr |
The inverse: the C ABI's milliseconds as a Duration. Exact, and exact in both directions — qos_window_ms(qos_window_duration(ms)) == ms — the best-available sentinel included.
|
constexpr |
The inverse, rounding as qos_window_ms does: up to the next whole millisecond, saturating to infinite, never wrapping into a short window.
|
constexpr |
Milliseconds one QoS window is worth, at the Duration → C-ABI boundary.
The C ABI is uint32_t milliseconds (nros_cpp_qos_t.deadline_ms and siblings) and 0 there means INFINITE, so truncation is not a rounding question — a 500 µs deadline truncated to 0 would silently mean "no deadline at all". So:
|
constexpr |
A C ABI window (milliseconds, 0 = unset) as upstream's rmw_time_t.
0 is upstream's UNSPECIFIED {0, 0}, which is what every upstream profile states and what both sides read as "no window". The two sentinels map onto upstream's: UINT32_MAX (explicit infinite) onto RMW_DURATION_INFINITE, UINT32_MAX - 1 (best available) onto RMW_QOS_DEADLINE_BEST_AVAILABLE.
|
inline |
phase-456 W2 — register a capturing callback, with the capture in the ARENA.
The bridge between rclcpp::InplaceFn and nros_cpp_subscription_register_capturing: the callable's bytes are handed to the runtime, which copies them into the arena entry and makes the dispatch context its own copy. Nothing of ours survives this call, which is what lets the returned handle be two words.
The invoker is a non-capturing lambda, so it decays to a plain function pointer — the arena's callback field is one, and a capturing trampoline could not be stored there.
|
inline |
Register cb as a timer on clock_type, its callable held by the arena.
The bridge between rclcpp::InplaceFn and nros_cpp_timer_create_capturing_with_info, the timer twin of register_subscription_capturing. The InplaceFn's bytes are COPIED into the arena; on success this object relinquishes them without destroying, because the arena's copy now owns the callable and its destroy hook runs clear() on that copy when the timer is released. A capture that owns something (a std::string, a shared_ptr) is destroyed exactly once, there.
Issue 1974: every callable goes through the call-info entry point. One taking const TimerInfo& receives the executor's expected/actual call times; a void() one ignores them at no capture cost. group (may be null) and autostart are Jazzy's trailing create_*timer arguments: autostart == false registers the timer cancelled until reset().
|
inline |
phase-459 W6 – the boot-time diagnostic for a callback group the code and the registration's CALLBACK_GROUPS disagree on. how is "created" (the code made a group the keyword did not declare) or "declared" (the keyword declared one the constructor never made). Names both sides: the group, and the declared list it was checked against. name is not NUL-terminated at len when it points into that list.
|
inline |
Boot-failure diagnostic (RFC-0044 Q2, refined in 242.4; moved off ComponentNode onto Node by phase-427 W4).
A failed entity/param creation in a node constructor is unrecoverable on firmware (boot is all-or-nothing) — but the constructor does not abort. It records the ok() latch and the generated entry / single-node carrier checks it post-construct, then halts boot naming the failing node via this helper. Hosted builds also print to stderr; freestanding builds get the overridable sink, whose default is nros_log (issue 1576). NOT [[noreturn]] — the caller decides how to halt.
|
inline |
The boot-time diagnostic for that disagreement — the runtime twin of the static_assert, and it prints the same three facts: the topic, the depth the declaration states, and the depth the code passed.
|
inline |
The boot-time diagnostic for that disagreement. It names the node, the parameter and the contract, and for a type mismatch both types, because set_error records one const char* and a boot failure that says only "parameter disagrees" leaves the reader to grep two files for the pair.
|
inline |
The boot-time diagnostic for a POLICY disagreement. policy is "reliability" or "durability"; declared and passed are the contract's own spellings ("best_effort", "transient_local", ...).
|
inline |
The one spelling every create_* verb uses. Takes the Result by value so the [[nodiscard]] is consumed HERE and cannot be silently dropped again.
|
inline |
phase-515 P1 — spin_until_future_complete on ONE executor handle: the free function's loop (10 ms spin_once slices, the future re-checked after each, a deadline only when timeout_ms >= 0), shared by rclcpp::Executor and executors::SingleThreadedExecutor. process says which "still running?" applies: the process executor's rclcpp::ok(), or, for an explicit executor that rclcpp::init never saw, only the termination request (SIGINT) every spin honours.
|
noexcept |
Unevaluated-only declval, so the detection below needs no <utility>.
|
inline |
The clock a registered timer runs on, read back from the EXECUTOR (issue 1975) – one reader for Timer::get_clock and TimerOps::get_clock. A handle the executor cannot answer for yields an invalid clock, which the returned value's operator bool reports.
|
constexpr |
phase-403 step 2 — the code set_error records when a subscription's QoS depth disagrees with the depth its system's contract declared.
Named after the phase rather than borrowed from nros_cpp_ret_t: this is not a backend failure, it is the image contradicting its own manifest, and a code that also means "the RMW said no" would send the reader to the wrong half of the tree.
|
constexpr |
phase-446 W6 – the code set_error records when a node declares a parameter its contract does not declare, or with another type.
|
constexpr |
issue 1256 – the code set_error records when a subscription's QoS RELIABILITY or DURABILITY disagrees with what its contract declared. The same number as DECLARED_DEPTH_MISMATCH: both are the image contradicting its own contract, and the FFI seam reports either as -403. The diagnostic printed beside it names which policy.
|
constexpr |
Issue 2009 — stale replies one poll drops before reporting "nothing yet"; the twin of Rust's nros_rmw::MAX_STALE_DRAIN_PER_POLL.
|
constexpr |
Issue 2009 — the id a backend reports when it cannot assign one: the RMW ABI's NROS_RMW_SEQUENCE_ID_UNKNOWN (INT64_MIN). polling_client.hpp asserts it equals the FFI's NROS_CPP_SEQUENCE_ID_UNKNOWN.