nros C++ API
Lightweight ROS 2 client for embedded real-time systems (C++ headers)
Loading...
Searching...
No Matches
node.hpp
Go to the documentation of this file.
1// nros-cpp: Node class
2// Freestanding C++ — no exceptions, no STL required
3
10#ifndef NROS_CPP_NODE_HPP
11#define NROS_CPP_NODE_HPP
12
13#include <cstdint>
14#include <cstddef>
15#include <type_traits> // Phase 189.M3.3.e — SFINAE on the callback-style create_service
16#if defined(NROS_CPP_STD) || (__STDC_HOSTED__ + 0)
17#include <cstdlib> // getenv — Phase 123.B.3 env-aware init
18#if defined(NROS_CPP_STD) || (__STDC_HOSTED__ + 0)
19#include <cstdio> // fopen — Phase 212.L.5 init_with_launch path-exists check
20#endif
21#endif
22
23// Phase 118.D: ffi.h MUST come before qos.hpp so qos.hpp's
24// `#ifndef NROS_CPP_FFI_H` guard sees the canonical types and skips
25// its local redefinitions.
26#include "nros_cpp_ffi.h"
27
28#include "nros/result.hpp"
29#include "nros/nros_cpp_config_generated.h"
30#include "nros/qos.hpp"
31// Phase 189.M3.1 — rclcpp-style named-options structs
32// (`SubscriptionOptions` / `PublisherOptions`) used by the 4-arg
33// `create_subscription` / `create_publisher` overloads below.
34#include "nros/options.hpp"
35// Phase 84.G8: heavy entity headers (publisher / subscription / service /
36// client / action_server / action_client) are no longer pulled in here.
37// Each entity header provides the out-of-line definition of its
38// corresponding `Node::create_X<T>()` template and includes `node.hpp`
39// itself. Consumers that #include `nros/nros.hpp` (the umbrella) still
40// get every entity + every create method via that path; consumers that
41// only want lightweight Node access can include this header directly
42// and pay for only the light entities (timer, guard_condition,
43// executor) below.
44#include "nros/timer.hpp"
46#include "nros/executor.hpp"
47// Phase 273 (RFC-0047) — callback-group token (value type, no heap).
48#include "nros/callback_group.hpp"
49
50#ifdef NROS_RMW_CYCLONEDDS
51extern "C" int32_t nros_rmw_cyclonedds_register(void);
52#endif
53#if defined(NROS_RMW_XRCE) || defined(NROS_RMW_XRCE_CFFI)
54extern "C" int32_t nros_rmw_xrce_register(void);
55#endif
56#ifdef NROS_RMW_ZENOH_CFFI
57extern "C" int32_t nros_rmw_zenoh_register(void);
58#endif
59#ifdef NROS_RMW_UORB
60extern "C" int32_t nros_rmw_uorb_register(void);
61#endif
62
63// Issue #229 pin (cross-space, C++-FFI half): ErrorCode must stay
64// value-identical to the NROS_CPP_RET_* codes (nros_cpp_ffi.h, included
65// above) that every shim below feeds into Result().
66static_assert(NROS_CPP_RET_NOT_FOUND == -4 && NROS_CPP_RET_ALREADY_EXISTS == -5 &&
67 NROS_CPP_RET_FULL == -6 && NROS_CPP_RET_NOT_INIT == -7 &&
68 NROS_CPP_RET_TRY_AGAIN == -14 && NROS_CPP_RET_REENTRANT == -15 &&
69 NROS_CPP_RET_UNSUPPORTED == -16,
70 "nros_cpp_ret_t diverged from the shared numbering (issue #229)");
71
72namespace nros {
73
74// Phase 84.G8: forward declarations of the heavy entity class
75// templates. Full definitions live in the corresponding `*.hpp`,
76// which also provide the out-of-line `Node::create_X<>` template
77// bodies — consumers only pay for the entities they #include.
78template <typename M> class Publisher;
79template <typename M> class Subscription;
80template <typename S> class Service;
81template <typename S> class Client;
82template <typename A> class ActionServer;
83template <typename A> class ActionClient;
84// Phase 122.3.d.b — L1 polling-mode action wrappers.
85template <typename A> class PollingActionServer;
86template <typename A> class PollingActionClient;
87// Phase 242.1 (RFC-0044) — rclcpp-faithful IS-A-node base. It wraps an owned
88// `Node` and creates that node against an executor-bound handle in its ctor, so
89// it needs friend access to set `executor_handle_` + call `Node::create`
90// (the same private-create pattern `Executor` / `NodeBuilder` already use).
91class ComponentNode;
92
100inline constexpr uint8_t kDomainIdExplicitZero = 255;
101
112inline Result init(const char* locator = nullptr, uint8_t domain_id = 0);
113
133inline Result init(const char* locator, uint8_t domain_id, const char* session_name);
134
153inline Result init_with_launch_auto(int argc = 0, char** argv = nullptr,
154 const char* session_name = nullptr);
155
162inline Result init_with_launch(const char* path, int argc = 0, char** argv = nullptr,
163 const char* session_name = nullptr);
164
168inline Result shutdown();
169
181class Node {
182 public:
184 Node() : handle_(), initialized_(false), executor_handle_(nullptr) {}
185
192 static Result create(Node& out, const char* name, const char* ns = nullptr) {
193 if (!out.executor_handle_) {
195 }
196
197 nros_cpp_ret_t ret = nros_cpp_node_create(out.executor_handle_, name, ns, &out.handle_);
198
199 if (ret == 0) {
200 out.initialized_ = true;
201 }
202 return Result(ret);
203 }
204
206 const char* get_name() const {
207 if (!initialized_) return "";
208 return nros_cpp_node_get_name(&handle_);
209 }
210
212 const char* get_namespace() const {
213 if (!initialized_) return "";
214 return nros_cpp_node_get_namespace(&handle_);
215 }
216
223 const void* get_logger() const {
224 if (!initialized_) return nullptr;
225 return nros_cpp_node_get_logger(&handle_);
226 }
227
229 bool is_valid() const { return initialized_; }
230
246 const nros_cpp_node_t* ffi_handle() const { return initialized_ ? &handle_ : nullptr; }
247
259 if (initialized_) {
260 ::nros_cpp_node_set_qos_overrides(&handle_, overrides, len);
261 }
262 }
263
270 void* executor_handle() const { return initialized_ ? executor_handle_ : nullptr; }
271
278 template <typename M>
280 const QoS& qos = QoS::default_profile());
281
294 template <typename M>
295 Result create_publisher(Publisher<M>& out, const char* topic, const QoS& qos,
297
304 template <typename M>
306 const QoS& qos = QoS::default_profile());
307
320 template <typename M>
323
342 template <
343 typename M, typename F,
344 typename = typename std::enable_if<std::is_convertible<F, void (*)(const M&)>::value>::type>
346 const QoS& qos = QoS::default_profile(),
347 const SubscriptionOptions& options = {});
348
356 template <typename M, typename F,
357 typename = typename std::enable_if<
358 std::is_convertible<F, void (*)(const M&, const uint8_t*, size_t)>::value>::type>
359 Result create_subscription_with_info(Subscription<M>& out, const char* topic, F callback,
360 const QoS& qos = QoS::default_profile(),
361 const SubscriptionOptions& options = {});
362
363#if defined(NANO_ROS_SAFETY_E2E)
378 template <typename M, typename F,
379 typename = typename std::enable_if<std::is_convertible<
380 F, void (*)(const M&, const nros_cpp_integrity_status_t&)>::value>::type>
381 Result create_subscription_with_safety(Subscription<M>& out, const char* topic, F callback,
382 const QoS& qos = QoS::default_profile(),
383 const SubscriptionOptions& options = {});
384#endif // NANO_ROS_SAFETY_E2E
385
392 template <typename S>
393 Result create_service(Service<S>& out, const char* service_name,
394 const QoS& qos = QoS::services());
395
408 template <typename S, typename F,
409 typename = typename std::enable_if<std::is_convertible<
410 F, void (*)(const typename S::Request&, typename S::Response&)>::value>::type>
411 Result create_service(Service<S>& out, const char* service_name, F callback,
412 const QoS& qos = QoS::services(), const ServiceOptions& options = {});
413
420 template <typename S>
421 Result create_client(Client<S>& out, const char* service_name,
422 const QoS& qos = QoS::services());
423
434 template <typename S, typename F,
435 typename = typename std::enable_if<
436 std::is_convertible<F, void (*)(const typename S::Response&)>::value>::type>
437 Result create_client(Client<S>& out, const char* service_name, F callback,
438 const QoS& qos = QoS::services(), const ClientOptions& options = {});
439
450 template <typename A>
451 Result create_action_server(ActionServer<A>& out, const char* action_name,
452 const QoS& qos = QoS::services(),
453 const ActionServerOptions& options = {});
454
461 template <typename A>
462 Result create_action_client(ActionClient<A>& out, const char* action_name,
463 const QoS& qos = QoS::services());
464
468 template <typename A>
470
472 template <typename A>
474
484 void* context = nullptr) {
485 if (!initialized_) return Result(ErrorCode::NotInitialized);
486 size_t handle_id = 0;
488 nros_cpp_timer_create(executor_handle_, period_ms, callback, context, &handle_id);
489 if (ret == 0) {
490 out.executor_ = executor_handle_;
491 out.handle_id_ = handle_id;
492 out.initialized_ = true;
493 }
494 return Result(ret);
495 }
496
506 void* context = nullptr) {
507 if (!initialized_) return Result(ErrorCode::NotInitialized);
508 size_t handle_id = 0;
510 context, &handle_id);
511 if (ret == 0) {
512 out.executor_ = executor_handle_;
513 out.handle_id_ = handle_id;
514 out.initialized_ = true;
515 }
516 return Result(ret);
517 }
518
519 // -- Phase 273 (RFC-0047) — Callback-group API -------------------------
520
530
543 nros_cpp_timer_callback_t callback, void* context = nullptr) {
544 if (!initialized_) return Result(ErrorCode::NotInitialized);
545 size_t handle_id = 0;
547 executor_handle_, &handle_, period_ms, callback, context, group.get_name(), &handle_id);
548 if (ret == 0) {
549 out.executor_ = executor_handle_;
550 out.handle_id_ = handle_id;
551 out.initialized_ = true;
552 }
553 return Result(ret);
554 }
555
570 template <
571 typename M, typename F,
572 typename = typename std::enable_if<std::is_convertible<F, void (*)(const M&)>::value>::type>
574 const char* topic, F callback,
575 const QoS& qos = QoS::default_profile(),
576 const SubscriptionOptions& options = {});
577
589 template <typename M>
591 const char* topic, const QoS& qos = QoS::default_profile()) {
593 }
594
603 void* context = nullptr) {
604 if (!initialized_) return Result(ErrorCode::NotInitialized);
606 nros_cpp_guard_condition_create(executor_handle_, callback, context, out.storage_);
607 if (ret == 0) {
608 out.initialized_ = true;
609 }
610 return Result(ret);
611 }
612
615 if (initialized_) {
616 nros_cpp_node_destroy(&handle_);
617 initialized_ = false;
618 }
619 }
620
621 // Move semantics (non-copyable)
623 : handle_(other.handle_), initialized_(other.initialized_),
624 executor_handle_(other.executor_handle_) {
625 other.initialized_ = false;
626 other.executor_handle_ = nullptr;
627 }
628
630 if (this != &other) {
631 if (initialized_) {
632 nros_cpp_node_destroy(&handle_);
633 }
634 handle_ = other.handle_;
635 initialized_ = other.initialized_;
636 executor_handle_ = other.executor_handle_;
637 other.initialized_ = false;
638 other.executor_handle_ = nullptr;
639 }
640 return *this;
641 }
642
643 private:
644 Node(const Node&) = delete;
645 Node& operator=(const Node&) = delete;
646
647 nros_cpp_node_t handle_;
648 bool initialized_;
649 void* executor_handle_; // Set by nros::init() via friendship
650
651 friend class Executor;
652 friend class NodeBuilder;
653 friend class ComponentNode; // Phase 242.1 — ctor-creates the owned node
654 friend Result init(const char* locator, uint8_t domain_id);
655 friend Result init(const char* locator, uint8_t domain_id, const char* session_name);
656 friend Result shutdown();
657 friend bool ok();
658 friend Result create_node(Node& out, const char* name, const char* ns);
659 friend Result create_node_on(Node& out, void* executor_handle, const char* name,
660 const char* ns);
662 friend Result spin();
664 friend void* global_handle();
665
666 // Global executor inline storage for init/shutdown free functions.
667 //
668 // Use a template-static-member trick instead of a function-local static.
669 // Function-local statics need __cxa_guard_acquire/release on first-call
670 // initialisation; on NuttX the resulting guard logic returns NULL for
671 // the storage pointer (observed empirically with LTO on armv7a-nuttx-eabihf,
672 // even with constant-initialisation `= {}`). A template static member is
673 // emitted into .bss like a file-scope variable and gets COMDAT-folded by
674 // the linker, sidestepping the guarded-init path entirely.
675 template <int = 0> struct GlobalStorageHolder {
676 alignas(8) static uint8_t storage[NROS_CPP_EXECUTOR_STORAGE_SIZE];
677 static bool initialized;
678 };
679 static uint8_t* global_storage() { return GlobalStorageHolder<>::storage; }
680 static bool& global_initialized() { return GlobalStorageHolder<>::initialized; }
681};
682
683// Out-of-class definitions for Node::GlobalStorageHolder<> — the template
684// machinery means these get emitted as COMDAT symbols, so multiple TUs
685// including this header all collapse to a single .bss allocation.
686template <int N>
687alignas(8) uint8_t Node::GlobalStorageHolder<N>::storage[NROS_CPP_EXECUTOR_STORAGE_SIZE] = {};
688template <int N> bool Node::GlobalStorageHolder<N>::initialized = false;
689
690// -- Free function implementations --
691
692inline Result init(const char* locator, uint8_t domain_id) {
693#if defined(NROS_CPP_STD) || (__STDC_HOSTED__ + 0)
694 // Phase 123.B.3 — on hosted builds, fall through to env vars
695 // ($NROS_LOCATOR / $ROS_DOMAIN_ID) so the no-arg `nros::init()`
696 // call works without `getenv()` boilerplate in user code.
697 // Explicit non-null `locator` / non-zero `domain_id` still win.
698 // Phase-287 W6 — the hard "tcp/127.0.0.1:7447" fallback moved BELOW the
699 // baked-macro check: threadx-linux is a HOSTED embedded target, and the
700 // eager default here shadowed its baked `NROS_ENTRY_LOCATOR` port.
701 // RFC-0045 / issue #206 — the env overlay (NROS_LOCATOR / ROS_DOMAIN_ID /
702 // NROS_NODE_NAME) moved into the shared Rust resolver behind
703 // nros_cpp_init (precedence model A: hosted env > this baked chain >
704 // compiled default; malformed or >232 ROS_DOMAIN_ID is an init ERROR,
705 // never a silent domain 0). This header only assembles the baked rung.
706#endif
707 // Baked compile-time locator (embedded gate) beats the local default but
708 // loses to an explicit arg; the hosted env rung (in the Rust resolver)
709 // overrides all of these (phase-287 W6 + #206; see the 3-arg overload).
710#ifdef NROS_ENTRY_LOCATOR
711 if (locator == nullptr) {
712 locator = NROS_ENTRY_LOCATOR;
713 }
714#endif
715#if defined(NROS_CPP_STD) || (__STDC_HOSTED__ + 0)
716 if (locator == nullptr) {
717 locator = "tcp/127.0.0.1:7447";
718 }
719#endif
720 // Phase 266 (W6) — unified default session name "node" across C, C++, and Rust.
721 return init(locator, domain_id, "node");
722}
723
724inline Result init(const char* locator, uint8_t domain_id, const char* session_name) {
725 // NROS_CPP_RET_INVALID_ARGUMENT = -3 (defined in nros_cpp_ffi.h
726 // which isn't included from this header — duplicate the value
727 // inline; generated header is the source of truth).
728 if (session_name == nullptr) {
729 return Result(-3);
730 }
731#if defined(NROS_CPP_STD) || (__STDC_HOSTED__ + 0)
732 // Issue #39 — apply the same `$NROS_LOCATOR` / `$ROS_DOMAIN_ID` env
733 // fallback as the 2-arg `init()` when `locator` is null / `domain_id` is
734 // 0. This makes `init_with_launch_auto()` (which delegates here with a
735 // null locator) honor the env overlay instead of passing a null locator
736 // to the backend → TransportError / degraded session.
737 // Phase-287 W6 — the hard local default moved BELOW the baked-macro check
738 // (threadx-linux is hosted; the eager default shadowed its baked port).
739 // RFC-0045 / issue #206 — the env overlay (NROS_LOCATOR / ROS_DOMAIN_ID /
740 // NROS_NODE_NAME) moved into the shared Rust resolver behind
741 // nros_cpp_init (precedence model A: hosted env > this baked chain >
742 // compiled default; malformed or >232 ROS_DOMAIN_ID is an init ERROR,
743 // never a silent domain 0). This header only assembles the baked rung.
744#endif
745 // Phase-287 W6 — compile-time connect defaults, so ONE portable source
746 // works native + embedded. `NROS_ENTRY_LOCATOR` / `NROS_ENTRY_DOMAIN_ID`
747 // are target compile definitions the embedded board gate bakes
748 // (NanoRosEntry.cmake; Kconfig on Zephyr via <nros/main.hpp>); on native
749 // they are undefined. Precedence (model A, RFC-0045/#206): env (hosted,
750 // applied in the Rust resolver) > explicit arg > baked macro > default.
751#ifdef NROS_ENTRY_LOCATOR
752 if (locator == nullptr) {
753 locator = NROS_ENTRY_LOCATOR;
754 }
755#endif
756#ifdef NROS_ENTRY_DOMAIN_ID
757 // Only the UNSET sentinel (0) folds the baked macro in; an explicit
758 // argument — including kDomainIdExplicitZero (255) for a literal
759 // domain 0 (issue #227) — passes through untouched.
760 if (domain_id == 0) {
761 domain_id = static_cast<uint8_t>(NROS_ENTRY_DOMAIN_ID);
762 }
763#endif
764#if defined(NROS_CPP_STD) || (__STDC_HOSTED__ + 0)
765 // Hosted local-router default — LAST, after env + baked macro.
766 if (locator == nullptr) {
767 locator = "tcp/127.0.0.1:7447";
768 }
769#endif
770 // Phase 128.C.1 — RMW-blind init. Every backend (cyclonedds,
771 // xrce, dds, zenoh, uorb, …) contributes its registration entry
772 // to the `RMW_INIT_ENTRIES` linker section via the
773 // `NROS_RMW_REGISTER_BACKEND` macro (C/C++) or
774 // `#[linkme::distributed_slice]` (Rust). The cffi runtime's
775 // section walker fires inside `nros_cpp_init` and dispatches to
776 // whichever backends were linked into this binary. No
777 // `#ifdef NROS_RMW_*` chain here, no CMake-driven fan-out — the
778 // user's `target_link_libraries(... NanoRos::Rmw::<name>)` is
779 // the only selector.
781 nros_cpp_init(locator, domain_id, session_name, nullptr, Node::global_storage());
782 if (ret == 0) {
783 Node::global_initialized() = true;
784 }
785 return Result(ret);
786}
787
788inline Result shutdown() {
789 if (!Node::global_initialized()) {
790 return Result::success();
791 }
792 nros_cpp_ret_t ret = nros_cpp_fini(Node::global_storage());
793 Node::global_initialized() = false;
794 return Result(ret);
795}
796
797// -- Phase 212.L.5 launch-aware init --
798//
799// Both `init_with_launch_auto` and `init_with_launch(path)` delegate to
800// the existing 3-arg `init` after resolving the launch overlay (today:
801// env vars only — see header docs for the follow-up plan). The session
802// name falls back to `"nros_cpp"` so existing callsites keep working.
803
804inline Result init_with_launch_auto(int argc, char** argv, const char* session_name) {
805 (void)argc;
806 (void)argv;
807 // TODO (Phase 212.L.5 follow-up):
808 // 1. If $NROS_RUNTIME_OVERLAY is set, read the JSON sidecar and
809 // fold its params/remaps/env into the init call.
810 // 2. Else walk <CARGO_MANIFEST_DIR>/launch/* and parse the XML
811 // in-process.
812 // For now the env overlay (NROS_LOCATOR / ROS_DOMAIN_ID consumed by
813 // the 2-arg `init`) is the only channel.
814 const char* name = (session_name != nullptr) ? session_name : "nros_cpp";
815 return init(nullptr, 0, name);
816}
817
818inline Result init_with_launch(const char* path, int argc, char** argv, const char* session_name) {
819 (void)argc;
820 (void)argv;
821 // NROS_CPP_RET_INVALID_ARGUMENT = -3 (mirrors the 3-arg init guard).
822 if (path == nullptr) {
823 return Result(-3);
824 }
825#if defined(NROS_CPP_STD) || (__STDC_HOSTED__ + 0)
826 // Verify the file exists so misspelled paths fail fast at init time
827 // instead of surfacing as a silently-empty overlay later.
828 if (FILE* f = std::fopen(path, "rb")) {
829 std::fclose(f);
830 } else {
832 }
833#endif
834 // TODO (Phase 212.L.5 follow-up): parse `path` as launch XML and
835 // fold params/remaps/env into the init call. Today the env overlay
836 // is the only channel.
837 const char* name = (session_name != nullptr) ? session_name : "nros_cpp";
838 return init(nullptr, 0, name);
839}
840
842inline bool ok() {
843 return Node::global_initialized();
844}
845
853inline Result create_node(Node& out, const char* name, const char* ns = nullptr) {
854 if (!Node::global_initialized()) {
856 }
857 out.executor_handle_ = Node::global_storage();
858 return Node::create(out, name, ns);
859}
860
872inline Result create_node_on(Node& out, void* executor_handle, const char* name,
873 const char* ns = nullptr) {
874 if (executor_handle == nullptr) {
876 }
877 out.executor_handle_ = executor_handle;
878 return Node::create(out, name, ns);
879}
880
884inline Expected<Node> make_node(const char* name, const char* ns = nullptr) {
885 Node n;
887 if (!r.ok()) return Expected<Node>::error(r);
888 return Expected<Node>::ok(::std::move(n));
889}
890
891// -- Executor::create_node implementation (requires full Node definition) --
892
893inline Result Executor::create_node(Node& out, const char* name, const char* ns) {
894 if (!initialized_) return Result(ErrorCode::NotInitialized);
895 out.executor_handle_ = storage_;
896 return Node::create(out, name, ns);
897}
898
899// -- Phase 104.C.9 — NodeBuilder ----------------------------------------
900//
901// Mirrors Rust's `Executor::node_builder(name).rmw(...).locator(...).
902// domain_id(...).namespace(...).sched(...).build()` chain. The C++
903// wrapper is value-typed and stack-allocated; it accumulates options
904// into an inline `nros_cpp_node_options_t` and ships it to
905// `nros_cpp_node_create_ex` on `.build()`.
906//
907// Usage:
908// ```cpp
909// nros::Node node;
910// NROS_TRY(executor.node_builder("egress")
911// .rmw("cyclonedds")
912// .domain_id(0)
913// .build(node));
914// ```
915
917 public:
918 NodeBuilder(void* executor_handle, const char* name)
919 : executor_handle_(executor_handle), name_(name),
921
926 NodeBuilder& rmw(const char* name) {
927 copy_bounded(name, options_.rmw_name, &options_.rmw_name_len, NROS_CPP_RMW_NAME_LEN);
928 return *this;
929 }
930
933 NodeBuilder& locator(const char* loc) {
934 copy_bounded(loc, options_.locator, &options_.locator_len, NROS_CPP_LOCATOR_LEN);
935 return *this;
936 }
937
941 options_.domain_id_override = id;
942 return *this;
943 }
944
947 NodeBuilder& namespace_(const char* ns) {
948 copy_bounded(ns, options_.namespace_, &options_.namespace_len, NROS_CPP_NAMESPACE_LEN);
949 return *this;
950 }
951
955 options_.sched_context_id = sc_id;
956 return *this;
957 }
958
961 if (!executor_handle_) return Result(ErrorCode::NotInitialized);
962 out.executor_handle_ = executor_handle_;
964 nros_cpp_node_create_ex(executor_handle_, name_, &options_, &out.handle_);
965 if (ret == 0) {
966 out.initialized_ = true;
967 }
968 return Result(ret);
969 }
970
971 private:
972 static void copy_bounded(const char* src, uint8_t* dst, size_t* dst_len, size_t cap) {
973 size_t n = 0;
974 if (src != nullptr) {
975 while (src[n] != '\0' && n < cap) {
976 dst[n] = static_cast<uint8_t>(src[n]);
977 ++n;
978 }
979 }
980 // Zero out the tail so stale bytes don't leak across reuses.
981 for (size_t i = n; i < cap; ++i) {
982 dst[i] = 0;
983 }
984 *dst_len = n;
985 }
986
987 void* executor_handle_;
988 const char* name_;
989 nros_cpp_node_options_t options_;
990};
991
993 return NodeBuilder(initialized_ ? handle() : nullptr, name);
994}
995
996} // namespace nros
997
998#endif // NROS_CPP_NODE_HPP
NodeBuilder node_builder(const char *name)
Definition node.hpp:992
void * handle()
Definition executor.hpp:166
Result create_node(Node &out, const char *name, const char *ns=nullptr)
Definition node.hpp:893
ErrorCode error() const
Definition result.hpp:218
bool ok() const
Definition result.hpp:211
Definition future.hpp:40
Definition guard_condition.hpp:45
Definition node.hpp:916
NodeBuilder & domain_id(uint32_t id)
Definition node.hpp:940
NodeBuilder & sched(uint8_t sc_id)
Definition node.hpp:954
NodeBuilder(void *executor_handle, const char *name)
Definition node.hpp:918
NodeBuilder & rmw(const char *name)
Definition node.hpp:926
NodeBuilder & locator(const char *loc)
Definition node.hpp:933
NodeBuilder & namespace_(const char *ns)
Definition node.hpp:947
Result build(Node &out) const
Materialize the Node.
Definition node.hpp:960
Definition node.hpp:181
friend Result init(const char *locator, uint8_t domain_id)
Definition node.hpp:692
Result create_subscription_in(const CallbackGroup &group, Subscription< M > &out, const char *topic, F callback, const QoS &qos=QoS::default_profile(), const SubscriptionOptions &options={})
Definition subscription.hpp:622
Result create_polling_action_server(PollingActionServer< A > &out, const char *action_name)
Result create_client(Client< S > &out, const char *service_name, const QoS &qos=QoS::services())
Definition client.hpp:240
friend class ComponentNode
Definition node.hpp:653
Result create_action_server(ActionServer< A > &out, const char *action_name, const QoS &qos=QoS::services(), const ActionServerOptions &options={})
Definition action_server.hpp:350
friend class NodeBuilder
Definition node.hpp:652
const void * get_logger() const
Definition node.hpp:223
friend bool ok()
Check if the nros session is initialized.
Definition node.hpp:842
const nros_cpp_node_t * ffi_handle() const
Definition node.hpp:246
const char * get_namespace() const
Get the node namespace.
Definition node.hpp:212
CallbackGroup create_callback_group(const char *name)
Definition node.hpp:529
Result create_publisher_in(const CallbackGroup &, Publisher< M > &out, const char *topic, const QoS &qos=QoS::default_profile())
Definition node.hpp:590
friend Result spin()
Definition nros.hpp:78
Result create_subscription(Subscription< M > &out, const char *topic, const QoS &qos=QoS::default_profile())
Definition subscription.hpp:513
Result create_action_client(ActionClient< A > &out, const char *action_name, const QoS &qos=QoS::services())
Definition action_client.hpp:399
void * executor_handle() const
Definition node.hpp:270
friend Result create_node(Node &out, const char *name, const char *ns)
Definition node.hpp:853
Result create_timer(Timer &out, uint64_t period_ms, nros_cpp_timer_callback_t callback, void *context=nullptr)
Definition node.hpp:483
friend class Executor
Definition node.hpp:651
Node(Node &&other)
Definition node.hpp:622
Result create_service(Service< S > &out, const char *service_name, const QoS &qos=QoS::services())
Definition service.hpp:214
~Node()
Destructor — releases node resources.
Definition node.hpp:614
Result create_publisher(Publisher< M > &out, const char *topic, const QoS &qos=QoS::default_profile())
Definition publisher.hpp:272
static Result create(Node &out, const char *name, const char *ns=nullptr)
Definition node.hpp:192
Result create_subscription_with_info(Subscription< M > &out, const char *topic, F callback, const QoS &qos=QoS::default_profile(), const SubscriptionOptions &options={})
Definition subscription.hpp:663
Node()
Default constructor — creates an uninitialized node.
Definition node.hpp:184
bool is_valid() const
Check if the node is initialized and valid.
Definition node.hpp:229
Result create_polling_action_client(PollingActionClient< A > &out, const char *action_name)
Phase 122.3.d.b — Create an L1 polling-mode action client.
friend void * global_handle()
Definition nros.hpp:51
friend Result spin_once(int32_t timeout_ms)
Definition nros.hpp:63
Result create_timer_oneshot(Timer &out, uint64_t delay_ms, nros_cpp_timer_callback_t callback, void *context=nullptr)
Definition node.hpp:505
Result create_timer_in(const CallbackGroup &group, Timer &out, uint64_t period_ms, nros_cpp_timer_callback_t callback, void *context=nullptr)
Definition node.hpp:542
Result create_guard_condition(GuardCondition &out, nros_cpp_guard_callback_t callback, void *context=nullptr)
Definition node.hpp:602
void set_qos_overrides(const nros_cpp_qos_override_t *overrides, size_t len)
Definition node.hpp:258
friend Result shutdown()
Definition node.hpp:788
friend Result create_node_on(Node &out, void *executor_handle, const char *name, const char *ns)
Definition node.hpp:872
const char * get_name() const
Get the node name.
Definition node.hpp:206
Node & operator=(Node &&other)
Definition node.hpp:629
Definition node.hpp:86
Definition node.hpp:85
Definition qos.hpp:68
static constexpr QoS default_profile()
Default profile: RELIABLE + VOLATILE + KEEP_LAST(10).
Definition qos.hpp:170
static constexpr QoS services()
Services profile: RELIABLE + VOLATILE + KEEP_LAST(10).
Definition qos.hpp:176
Definition result.hpp:87
static constexpr Result success()
Named constructors.
Definition result.hpp:109
Definition timer.hpp:42
nros::Executor — drives transport I/O and dispatches callbacks.
int nros_cpp_ret_t
Definition future.hpp:20
nros::GuardCondition — cross-thread wake source.
Definition nros.hpp:43
Result init_with_launch(const char *path, int argc=0, char **argv=nullptr, const char *session_name=nullptr)
Definition node.hpp:818
Expected< Node > make_node(const char *name, const char *ns=nullptr)
Definition node.hpp:884
Result shutdown()
Definition node.hpp:788
bool ok()
Check if the nros session is initialized.
Definition node.hpp:842
constexpr uint8_t kDomainIdExplicitZero
Definition node.hpp:100
Result init_with_launch_auto(int argc=0, char **argv=nullptr, const char *session_name=nullptr)
Definition node.hpp:804
Result init(const char *locator=nullptr, uint8_t domain_id=0)
Definition node.hpp:692
Result create_node(Node &out, const char *name, const char *ns=nullptr)
Definition node.hpp:853
Result create_node_on(Node &out, void *executor_handle, const char *name, const char *ns=nullptr)
Definition node.hpp:872
nros::QoS — full DDS-shaped QoS settings (Phase 108.B.7).
nros::Result, nros::ErrorCode, and the NROS_TRY macro.
nros::Timer — periodic callback driven by the executor.