nros C++ API
Lightweight ROS 2 client for embedded real-time systems (C++ headers)
Loading...
Searching...
No Matches
server.hpp
Go to the documentation of this file.
1// nros-cpp: Action server class
2// Freestanding C++ — no exceptions, no STL required
3
10#ifndef NROS_RCLCPP_ACTION_SERVER_HPP
11#define NROS_RCLCPP_ACTION_SERVER_HPP
12
13#include <cstdint>
14#include <cstddef>
15#include <string.h>
16
17#include "rclcpp/detail/callback_context.hpp" // phase-456 W3's one-word context carrier
19#include "rclcpp/detail/entity_name.hpp" // phase-444 — the one entity-name copy
20#include "rclcpp/result.hpp"
21// issue 0964 — the feedback/result TX buffers below size through
22// `detail::buffer_bounds`, so this header needs it directly rather than by
23// luck through a transitive include.
24#include "rclcpp/size_bound.hpp"
25
26// Phase 118.D — most action_server FFI symbols come from
27// `nros_cpp_ffi.h`; cbindgen renders Rust `*const [u8; 16]` as
28// pointer-to-array (`const uint8_t (*goal_id)[16]`), so callsites
29// below `reinterpret_cast` from the array-decay shape used in C++
30// member-function signatures.
31//
32// `nros_cpp_action_server_set_callbacks` is excluded from cbindgen
33// output (its Rust signature uses `Option<extern "C" fn(...)>`,
34// which cbindgen renders as opaque structs). Declare locally below
35// with plain function-pointer typedefs that match the actual ABI.
36#include "rclcpp/detail/nros_cpp_ffi.h"
37
38extern "C" {
39typedef int32_t (*nros_cpp_goal_callback_t)(const uint8_t goal_id[16], const uint8_t* data,
40 size_t len, void* ctx);
41typedef int32_t (*nros_cpp_cancel_callback_t)(const uint8_t goal_id[16], void* ctx);
42/* Issue 0796 — post-accept hook. Excluded from cbindgen for the same reason as
43 * the two above (`Option<extern "C" fn>` renders as an opaque struct), so this
44 * declaration is MIRRORED in `rclc/component.h` as well; `just check c`'s
45 * cross-include TU is the gate that catches a half-updated mirror. */
46typedef void (*nros_cpp_accepted_callback_t)(const uint8_t goal_id[16], void* ctx);
47
50 void* ctx);
53 void* ctx);
54} // extern "C"
55
56namespace rclcpp {
57namespace detail {
58
59// Issue 1913 — the hash each of an action's five endpoints is keyed on. An
60// Iron+ peer keys every endpoint on its own type, so the one `Goal::TYPE_HASH`
61// these entry points used to pass matched none of them. Generated action types
62// carry the five as `<Endpoint>_HASH` members; a type generated by an older
63// `nros` does not, and gets all-NULL, which the runtime reads as "use the type
64// hash" (the old behaviour). C++14, so detection is spelled by hand.
65template <class...> struct nros_void_ {
66 typedef void type;
67};
68
69template <class A, class = void> struct action_endpoint_hashes_of {
71 nros_cpp_action_hashes_t h = {nullptr, nullptr, nullptr, nullptr, nullptr};
72 return h;
73 }
74};
75
76template <class A>
78 typename nros_void_<decltype(A::SEND_GOAL_SERVICE_HASH)>::type> {
80 nros_cpp_action_hashes_t h = {A::SEND_GOAL_SERVICE_HASH, A::CANCEL_GOAL_SERVICE_HASH,
81 A::GET_RESULT_SERVICE_HASH, A::FEEDBACK_MESSAGE_HASH,
82 A::STATUS_MESSAGE_HASH};
83 return h;
84 }
85};
86
90
91} // namespace detail
92} // namespace rclcpp
93
94// phase-483 W1: the goal vocabulary lives in `rclcpp_action::`, where upstream
95// keeps it. It was `nros::` until then, and `rclcpp_action::` re-exported two
96// of the five names.
97namespace rclcpp_action {
98
124struct GoalUUID {
126 static const size_t SIZE = 16;
127
129 uint8_t uuid[16];
130
132 GoalUUID() : uuid{} {}
133
135 explicit GoalUUID(const uint8_t* src) : uuid{} {
136 for (size_t i = 0; i < SIZE; ++i) {
137 uuid[i] = src[i];
138 }
139 }
140
142 uint8_t* data() { return uuid; }
143 const uint8_t* data() const { return uuid; }
144
146 bool is_zero() const {
147 for (size_t i = 0; i < SIZE; ++i) {
148 if (uuid[i] != 0) return false;
149 }
150 return true;
151 }
152
153 bool operator==(const GoalUUID& other) const {
154 for (size_t i = 0; i < SIZE; ++i) {
155 if (uuid[i] != other.uuid[i]) return false;
156 }
157 return true;
158 }
159
160 bool operator!=(const GoalUUID& other) const { return !(*this == other); }
161
165 bool operator<(const GoalUUID& other) const {
166 for (size_t i = 0; i < SIZE; ++i) {
167 if (uuid[i] != other.uuid[i]) return uuid[i] < other.uuid[i];
168 }
169 return false;
170 }
171};
172
173static_assert(sizeof(GoalUUID) == 16,
174 "rclcpp_action::GoalUUID must be exactly the 16 bytes the FFI passes as uint8_t[16]");
175static_assert(alignof(GoalUUID) == alignof(uint8_t),
176 "rclcpp_action::GoalUUID must not add alignment over its uint8_t[16]");
177
189static const size_t ACTION_NAME_MAX = 256;
190
204enum class GoalResponse : int8_t {
205 REJECT = 1,
208};
209
224enum class CancelResponse : int8_t {
225 REJECT = 1,
226 ACCEPT = 2,
227};
228
235 return (r == GoalResponse::ACCEPT_AND_EXECUTE) ? 1
236 : (r == GoalResponse::ACCEPT_AND_DEFER) ? 2
237 : 0;
238}
239
243 return (r == CancelResponse::ACCEPT) ? 1 : 0;
244}
245
254 Ok = 0,
255 Rejected = 1,
256 UnknownGoal = 2,
257 GoalTerminated = 3,
258};
259
262enum class GoalStatus : int8_t {
263 Unknown = 0,
264 Accepted = 1,
265 Executing = 2,
266 Canceling = 3,
267 Succeeded = 4,
268 Canceled = 5,
269 Aborted = 6,
270};
271
272} // namespace rclcpp_action
273
281namespace rclcpp {
282class Node;
283}
284
285// ============================================================================
286// `rclcpp_action::Server<A>` -- DEFINED here (RFC-0089: rclcpp_action:: is the home)
287// ============================================================================
288//
289// phase-428: the definition moved from `nros::ActionServer<A>` to
290// `rclcpp_action::Server<A>` (the `nros::` alias went in phase-483 W1). This one
291// is a RENAME as well as a move -- upstream's namespace already says "action",
292// so the type is `Server`, not `ActionServer`.
293//
294// The vocabulary the signatures use (`GoalUUID`, `GoalResponse`,
295// `CancelResponse`, `GoalStatus`, `CancelReturnCode`) is declared above, in
296// `rclcpp_action::` where upstream keeps it (phase-483 W1; it was `nros::`
297// before). `GoalResponse` and `CancelResponse` carry upstream's values since
298// issue 1637, so a ported `rclcpp_action::GoalResponse::REJECT` compiles AND
299// means what it meant upstream. Before that they were 0-based, and exposing
300// them under the upstream name would have turned a compile error into a silent
301// renumbering.
302namespace rclcpp_action {
303
340template <typename A> class Server {
341 public:
342 using GoalType = typename A::Goal;
343 using ResultType = typename A::Result;
344 using FeedbackType = typename A::Feedback;
345
348 const GoalType& goal);
351 const GoalType& goal, void* ctx);
356 void* ctx);
358 using TypedAcceptedFn = void (*)(const uint8_t uuid[16]);
360 using TypedAcceptedFnWithCtx = void (*)(const uint8_t uuid[16], void* ctx);
363
371 if (!initialized_) return ::rclcpp::Result(::rclcpp::ErrorCode::NotInitialized);
372 user_goal_fn_ = TypedGoalFn(f); // compile error if F is not convertible
373 user_goal_fn_ctx_ = nullptr; // mutually exclusive with _with_ctx
374 user_goal_ctx_ = nullptr;
375 return install_callbacks();
376 }
377
386 if (!initialized_) return ::rclcpp::Result(::rclcpp::ErrorCode::NotInitialized);
387 user_goal_fn_ctx_ = f;
388 user_goal_ctx_ = ctx;
389 user_goal_fn_ = nullptr;
390 return install_callbacks();
391 }
392
397 if (!initialized_) return ::rclcpp::Result(::rclcpp::ErrorCode::NotInitialized);
398 user_cancel_fn_ = TypedCancelFn(f); // compile error if F is not convertible
399 user_cancel_fn_ctx_ = nullptr; // mutually exclusive with _with_ctx
400 user_cancel_ctx_ = nullptr;
401 return install_callbacks();
402 }
403
411 if (!initialized_) return ::rclcpp::Result(::rclcpp::ErrorCode::NotInitialized);
412 user_cancel_fn_ctx_ = f;
413 user_cancel_ctx_ = ctx;
414 user_cancel_fn_ = nullptr;
415 return install_callbacks();
416 }
417
439 if (!initialized_) return ::rclcpp::Result(::rclcpp::ErrorCode::NotInitialized);
440 user_accepted_fn_ = TypedAcceptedFn(f); // compile error if F is not convertible
441 user_accepted_fn_ctx_ = nullptr; // mutually exclusive with _with_ctx
442 user_accepted_ctx_ = nullptr;
443 return install_callbacks();
444 }
445
451 if (!initialized_) return ::rclcpp::Result(::rclcpp::ErrorCode::NotInitialized);
452 user_accepted_fn_ctx_ = f;
453 user_accepted_ctx_ = ctx;
454 user_accepted_fn_ = nullptr;
455 return install_callbacks();
456 }
457
467 ::rclcpp::Result publish_feedback(const uint8_t goal_id[16], const FeedbackType& feedback) {
468 if (!initialized_) return ::rclcpp::Result(::rclcpp::ErrorCode::NotInitialized);
469
470 uint8_t buf[::rclcpp::detail::buffer_bounds<FeedbackType>::tx];
471 size_t len = 0;
472 if (FeedbackType::ffi_serialize(&feedback, buf, sizeof(buf), &len) != 0) {
473 return ::rclcpp::Result(::rclcpp::ErrorCode::Error);
474 }
475 return ::rclcpp::Result(nros_cpp_action_server_publish_feedback(
476 storage_, executor_, reinterpret_cast<const uint8_t(*)[16]>(goal_id), buf, len));
477 }
478
493 const ResultType& result) {
494 if (!initialized_) return ::rclcpp::Result(::rclcpp::ErrorCode::NotInitialized);
495
496 uint8_t buf[::rclcpp::detail::buffer_bounds<ResultType>::tx];
497 size_t len = 0;
498 if (ResultType::ffi_serialize(&result, buf, sizeof(buf), &len) != 0) {
499 return ::rclcpp::Result(::rclcpp::ErrorCode::Error);
500 }
501 return ::rclcpp::Result(nros_cpp_action_server_complete_goal(
502 storage_, executor_, reinterpret_cast<const uint8_t(*)[16]>(goal_id),
503 static_cast<int32_t>(status), buf, len));
504 }
505
508 ::rclcpp::Result complete_goal(const uint8_t goal_id[16], const ResultType& result) {
509 return complete_goal(goal_id, ::rclcpp_action::GoalStatus::Succeeded, result);
510 }
511
513 ::rclcpp::Result publish_feedback(const ::rclcpp_action::GoalUUID& goal_id,
514 const FeedbackType& feedback) {
515 return publish_feedback(goal_id.data(), feedback);
516 }
517
519 ::rclcpp::Result complete_goal(const ::rclcpp_action::GoalUUID& goal_id,
521 return complete_goal(goal_id.data(), status, result);
522 }
523
525 ::rclcpp::Result complete_goal(const ::rclcpp_action::GoalUUID& goal_id,
526 const ResultType& result) {
527 return complete_goal(goal_id.data(), ::rclcpp_action::GoalStatus::Succeeded, result);
528 }
529
546 ::rclcpp::Result succeed(const uint8_t goal_id[16], const ResultType& result) {
547 return complete_goal(goal_id, ::rclcpp_action::GoalStatus::Succeeded, result);
548 }
549
554 ::rclcpp::Result abort(const uint8_t goal_id[16], const ResultType& result) {
555 return complete_goal(goal_id, ::rclcpp_action::GoalStatus::Aborted, result);
556 }
557
566 ::rclcpp::Result canceled(const uint8_t goal_id[16], const ResultType& result) {
567 return complete_goal(goal_id, ::rclcpp_action::GoalStatus::Canceled, result);
568 }
569
571 ::rclcpp::Result succeed(const ::rclcpp_action::GoalUUID& goal_id, const ResultType& result) {
572 return complete_goal(goal_id.data(), ::rclcpp_action::GoalStatus::Succeeded, result);
573 }
574
576 ::rclcpp::Result abort(const ::rclcpp_action::GoalUUID& goal_id, const ResultType& result) {
577 return complete_goal(goal_id.data(), ::rclcpp_action::GoalStatus::Aborted, result);
578 }
579
581 ::rclcpp::Result canceled(const ::rclcpp_action::GoalUUID& goal_id, const ResultType& result) {
582 return complete_goal(goal_id.data(), ::rclcpp_action::GoalStatus::Canceled, result);
583 }
584
607 if (!initialized_) return ::rclcpp::Result(::rclcpp::ErrorCode::NotInitialized);
608 TypedVisitorFn visitor = TypedVisitorFn(f); // compile error if F is not convertible
609
610 auto trampoline = [](const uint8_t goal_id[16], int8_t status, void* ctx) {
611 TypedVisitorFn fn = ::rclcpp::detail::fn_from_context<TypedVisitorFn>(ctx);
612 if (fn == nullptr) return;
613 fn(goal_id, static_cast<::rclcpp_action::GoalStatus>(status));
614 };
615 return ::rclcpp::Result(nros_cpp_action_server_for_each_active_goal(
616 storage_, executor_,
617 reinterpret_cast<void (*)(const uint8_t(*)[16], int8_t, void*)>(+trampoline),
618 ::rclcpp::detail::fn_to_context(visitor)));
619 }
620
643 const char* get_action_name() const { return initialized_ ? action_name_ : ""; }
644
652 bool goal_exists(const uint8_t goal_id[16]) const {
653 if (!initialized_) return false;
654 return nros_cpp_action_server_goal_exists(storage_, executor_,
655 reinterpret_cast<const uint8_t(*)[16]>(goal_id));
656 }
657
659 bool goal_exists(const ::rclcpp_action::GoalUUID& goal_id) const {
660 return goal_exists(goal_id.data());
661 }
662
664 bool is_valid() const { return initialized_; }
665
681 if (initialized_) {
682 nros_cpp_action_server_detach(storage_, executor_);
684 initialized_ = false;
685 }
686 }
687
688 // Move semantics (non-copyable). Relocation goes through the
689 // `nros_cpp_action_server_relocate` runtime call (Phase 84.C1) and
690 // then `install_callbacks()` re-registers the goal/cancel trampolines
691 // with the new `this` as the arena callback context — this is the one
692 // type in nros-cpp that registers its storage address externally.
694 : executor_(other.executor_), user_goal_fn_(other.user_goal_fn_),
695 user_goal_fn_ctx_(other.user_goal_fn_ctx_), user_goal_ctx_(other.user_goal_ctx_),
696 user_cancel_fn_(other.user_cancel_fn_), user_cancel_fn_ctx_(other.user_cancel_fn_ctx_),
697 user_cancel_ctx_(other.user_cancel_ctx_), user_accepted_fn_(other.user_accepted_fn_),
698 user_accepted_fn_ctx_(other.user_accepted_fn_ctx_),
699 user_accepted_ctx_(other.user_accepted_ctx_), action_name_{},
700 initialized_(other.initialized_) {
701 ::memcpy(action_name_, other.action_name_, sizeof(action_name_));
702 if (other.initialized_) {
703 nros_cpp_action_server_relocate(other.storage_, storage_);
704 other.initialized_ = false;
705 install_callbacks();
706 }
707 }
708
710 if (this != &other) {
711 if (initialized_) {
712 // issue 1496 — same pairing as `~Server()`: release the arena
713 // entry this storage owns before the storage is overwritten by
714 // the relocate below.
715 nros_cpp_action_server_detach(storage_, executor_);
717 }
718 executor_ = other.executor_;
719 user_goal_fn_ = other.user_goal_fn_;
720 user_goal_fn_ctx_ = other.user_goal_fn_ctx_;
721 user_goal_ctx_ = other.user_goal_ctx_;
722 user_cancel_fn_ = other.user_cancel_fn_;
723 user_cancel_fn_ctx_ = other.user_cancel_fn_ctx_;
724 user_cancel_ctx_ = other.user_cancel_ctx_;
725 user_accepted_fn_ = other.user_accepted_fn_;
726 user_accepted_fn_ctx_ = other.user_accepted_fn_ctx_;
727 user_accepted_ctx_ = other.user_accepted_ctx_;
728 ::memcpy(action_name_, other.action_name_, sizeof(action_name_));
729 initialized_ = other.initialized_;
730 if (other.initialized_) {
731 nros_cpp_action_server_relocate(other.storage_, storage_);
732 other.initialized_ = false;
733 install_callbacks();
734 }
735 }
736 return *this;
737 }
738
742 : executor_(nullptr), user_goal_fn_(nullptr), user_goal_fn_ctx_(nullptr),
743 user_goal_ctx_(nullptr), user_cancel_fn_(nullptr), user_cancel_fn_ctx_(nullptr),
744 user_cancel_ctx_(nullptr), user_accepted_fn_(nullptr), user_accepted_fn_ctx_(nullptr),
745 user_accepted_ctx_(nullptr), action_name_{}, initialized_(false) {}
746
747 private:
748 Server(const Server&) = delete;
749 Server& operator=(const Server&) = delete;
750
751 friend class ::rclcpp::Node;
752
753 // ── C trampolines ───────────────────────────────────────────────
754 //
755 // `ctx` is a pointer to this `ActionServer<A>` instance, so the
756 // trampoline reads the user's stored function pointer via the
757 // instance's own fields — no shared mutable statics.
758
759 static int32_t goal_trampoline(const uint8_t goal_id[16], const uint8_t* data, size_t len,
760 void* ctx) {
761 auto* self = static_cast<Server*>(ctx);
762 if (!self) return ::rclcpp_action::to_ffi(::rclcpp_action::GoalResponse::REJECT);
763 GoalType g;
764 if (GoalType::ffi_deserialize(data, len, &g) != 0) {
765 return ::rclcpp_action::to_ffi(::rclcpp_action::GoalResponse::REJECT);
766 }
767 if (self->user_goal_fn_ctx_ != nullptr) {
768 return ::rclcpp_action::to_ffi(
769 self->user_goal_fn_ctx_(goal_id, g, self->user_goal_ctx_));
770 }
771 if (self->user_goal_fn_ != nullptr) {
772 return ::rclcpp_action::to_ffi(self->user_goal_fn_(goal_id, g));
773 }
774 return ::rclcpp_action::to_ffi(::rclcpp_action::GoalResponse::REJECT);
775 }
776
777 static int32_t cancel_trampoline(const uint8_t goal_id[16], void* ctx) {
778 auto* self = static_cast<Server*>(ctx);
779 if (!self) return ::rclcpp_action::to_ffi(::rclcpp_action::CancelResponse::ACCEPT);
780 if (self->user_cancel_fn_ctx_ != nullptr) {
781 return ::rclcpp_action::to_ffi(
782 self->user_cancel_fn_ctx_(goal_id, self->user_cancel_ctx_));
783 }
784 if (self->user_cancel_fn_ != nullptr) {
785 return ::rclcpp_action::to_ffi(self->user_cancel_fn_(goal_id));
786 }
787 return ::rclcpp_action::to_ffi(::rclcpp_action::CancelResponse::ACCEPT);
788 }
789
790 static void accepted_trampoline(const uint8_t goal_id[16], void* ctx) {
791 auto* self = static_cast<Server*>(ctx);
792 if (!self) return;
793 if (self->user_accepted_fn_ctx_ != nullptr) {
794 self->user_accepted_fn_ctx_(goal_id, self->user_accepted_ctx_);
795 return;
796 }
797 if (self->user_accepted_fn_ != nullptr) {
798 self->user_accepted_fn_(goal_id);
799 }
800 }
801
802 ::rclcpp::Result install_callbacks() {
803 bool goal_set = (user_goal_fn_ != nullptr) || (user_goal_fn_ctx_ != nullptr);
804 bool cancel_set = (user_cancel_fn_ != nullptr) || (user_cancel_fn_ctx_ != nullptr);
805 bool accepted_set = (user_accepted_fn_ != nullptr) || (user_accepted_fn_ctx_ != nullptr);
806 nros_cpp_goal_callback_t gcb = goal_set ? &goal_trampoline : nullptr;
807 nros_cpp_cancel_callback_t ccb = cancel_set ? &cancel_trampoline : nullptr;
808 nros_cpp_ret_t ret = nros_cpp_action_server_set_callbacks(storage_, gcb, ccb, this);
809 if (ret != 0) return ::rclcpp::Result(ret);
810 // Issue 0796 — a SECOND install call rather than a fourth parameter on
811 // the first: `nros_cpp_action_server_set_callbacks` is declared in
812 // three places and called directly by C components, so growing it
813 // would have broken every one of them. Both calls pass the same
814 // `this`, which is the shared context slot the runtime keeps.
815 nros_cpp_accepted_callback_t acb = accepted_set ? &accepted_trampoline : nullptr;
816 return ::rclcpp::Result(nros_cpp_action_server_set_accepted_callback(storage_, acb, this));
817 }
818
819 alignas(8) uint8_t storage_[NROS_CPP_ACTION_SERVER_STORAGE_SIZE];
820 void* executor_; // Executor context needed for feedback/result operations
821 TypedGoalFn user_goal_fn_;
822 TypedGoalFnWithCtx user_goal_fn_ctx_;
823 void* user_goal_ctx_;
824 TypedCancelFn user_cancel_fn_;
825 TypedCancelFnWithCtx user_cancel_fn_ctx_;
826 void* user_cancel_ctx_;
827 TypedAcceptedFn user_accepted_fn_;
828 TypedAcceptedFnWithCtx user_accepted_fn_ctx_;
829 void* user_accepted_ctx_;
830 // phase-456 W3b — a `TypedVisitorFn user_visitor_fn_` sat here, written at
831 // the head of `for_each_active_goal` and cleared at its tail. The visitor
832 // travels in the FFI's own `void* ctx` now; see that function.
833 // Phase 87.6 put a `char action_name_[256]` here for a `get_action_name()`
834 // that was never written, and an earlier phase-417 W4.b wave deleted it as
835 // dead state. W4.b's second half writes the accessor, so it is back and it
836 // is read — see `get_action_name()` for why the FFI cannot answer instead.
837 char action_name_[::rclcpp_action::ACTION_NAME_MAX];
838 bool initialized_;
839};
840
841} // namespace rclcpp_action
842
843// Phase 84.G8: out-of-line definition of Node::create_action_server<A>().
844#include "rclcpp/node.hpp"
845
846namespace rclcpp {} // namespace rclcpp
847
848namespace rclcpp {
849template <typename A>
850Result Node::create_action_server(::rclcpp_action::Server<A>& out, const char* action_name,
851 const ::rclcpp::QoS& qos,
852 const ::rclcpp::ActionServerOptions& options) {
853 if (!initialized_) return Result(::rclcpp::ErrorCode::NotInitialized);
854 nros_cpp_qos_t ffi_qos = ::rclcpp::detail::qos_to_ffi(qos);
856 A::Goal::TYPE_HASH, ffi_qos, out.storage_);
857 if (ret != 0) return Result(ret);
858 // Register with executor — creates transport handles (3 queryables + 2 publishers).
859 // Deferred from create to avoid FreeRTOS QEMU deadlocks. Phase 87.6:
860 // names are passed at register-time (buffers live on the C++
861 // `rclcpp_action::Server<A>` class, not in the runtime struct).
862 // Phase 189.M3.3.c — `sched_context` binds the action's (arena-registered)
863 // goal-service handle to a scheduling context. UNSET ⇒ 0 (inherit, no-op).
864 uint8_t sched = (options.sched_context == ::rclcpp::SCHED_CONTEXT_UNSET)
865 ? 0u
866 : static_cast<uint8_t>(options.sched_context);
867 const nros_cpp_action_hashes_t hashes = ::rclcpp::detail::action_endpoint_hashes<A>();
868 ret = nros_cpp_action_server_register(out.storage_, executor_handle_, action_name, A::TYPE_NAME,
869 A::Goal::TYPE_HASH, &hashes, sched);
870 if (ret == 0) {
871 out.executor_ = executor_handle_;
872 // phase-417 W4.b — remember the name for `get_action_name()`. Truncating
873 // copy, as `Subscription`'s and the two polling tiers' do: a name longer
874 // than `rclcpp_action::ACTION_NAME_MAX` is not a reason to fail a create that the
875 // runtime already accepted.
876 ::rclcpp::detail::assign_entity_name(out.action_name_, action_name);
877 out.initialized_ = true;
878 }
879 return Result(ret);
880}
881} // namespace rclcpp
882
883namespace rclcpp {} // namespace rclcpp
884
885#endif // NROS_RCLCPP_ACTION_SERVER_HPP
Definition client.hpp:129
Definition result.hpp:216
Definition client.hpp:95
Definition server.hpp:340
void(*)(const uint8_t uuid[16], ::rclcpp_action::GoalStatus status) TypedVisitorFn
User-facing visitor signature for for_each_active_goal.
Definition server.hpp:362
~Server()
Definition server.hpp:680
::rclcpp::Result abort(const ::rclcpp_action::GoalUUID &goal_id, const ResultType &result)
abort taking a GoalUUID value.
Definition server.hpp:576
::rclcpp::Result complete_goal(const uint8_t goal_id[16], const ResultType &result)
Definition server.hpp:508
::rclcpp::Result abort(const uint8_t goal_id[16], const ResultType &result)
Definition server.hpp:554
::rclcpp::Result publish_feedback(const uint8_t goal_id[16], const FeedbackType &feedback)
Definition server.hpp:467
::rclcpp::Result complete_goal(const uint8_t goal_id[16], ::rclcpp_action::GoalStatus status, const ResultType &result)
Definition server.hpp:492
::rclcpp::Result set_goal_callback_with_ctx(TypedGoalFnWithCtx f, void *ctx)
Definition server.hpp:385
bool goal_exists(const ::rclcpp_action::GoalUUID &goal_id) const
goal_exists taking a GoalUUID value.
Definition server.hpp:659
::rclcpp::Result set_accepted_callback_with_ctx(TypedAcceptedFnWithCtx f, void *ctx)
Definition server.hpp:450
::rclcpp::Result set_cancel_callback(F f)
Definition server.hpp:396
typename A::Feedback FeedbackType
Definition server.hpp:344
::rclcpp::Result succeed(const ::rclcpp_action::GoalUUID &goal_id, const ResultType &result)
succeed taking a GoalUUID value.
Definition server.hpp:571
::rclcpp::Result complete_goal(const ::rclcpp_action::GoalUUID &goal_id, ::rclcpp_action::GoalStatus status, const ResultType &result)
complete_goal taking a GoalUUID value (phase-417 W4.b).
Definition server.hpp:519
::rclcpp::Result canceled(const uint8_t goal_id[16], const ResultType &result)
Definition server.hpp:566
const char * get_action_name() const
Definition server.hpp:643
Server(Server &&other)
Definition server.hpp:693
Server()
Definition server.hpp:741
::rclcpp::Result canceled(const ::rclcpp_action::GoalUUID &goal_id, const ResultType &result)
canceled taking a GoalUUID value.
Definition server.hpp:581
Server & operator=(Server &&other)
Definition server.hpp:709
::rclcpp::Result set_goal_callback(F f)
Definition server.hpp:370
::rclcpp::Result set_accepted_callback(F f)
Definition server.hpp:438
::rclcpp::Result publish_feedback(const ::rclcpp_action::GoalUUID &goal_id, const FeedbackType &feedback)
publish_feedback taking a GoalUUID value (phase-417 W4.b).
Definition server.hpp:513
bool goal_exists(const uint8_t goal_id[16]) const
Definition server.hpp:652
::rclcpp::Result set_cancel_callback_with_ctx(TypedCancelFnWithCtx f, void *ctx)
Definition server.hpp:410
typename A::Goal GoalType
Definition server.hpp:342
bool is_valid() const
Check if the action server is initialized and valid.
Definition server.hpp:664
::rclcpp::Result complete_goal(const ::rclcpp_action::GoalUUID &goal_id, const ResultType &result)
complete_goal taking a GoalUUID value (phase-417 W4.b).
Definition server.hpp:525
typename A::Result ResultType
Definition server.hpp:343
::rclcpp::Result for_each_active_goal(F f)
Definition server.hpp:606
::rclcpp::Result succeed(const uint8_t goal_id[16], const ResultType &result)
Definition server.hpp:546
Inline storage-size macros for opaque entity buffers.
int nros_cpp_ret_t
Definition future.hpp:21
nros_cpp_action_hashes_t action_endpoint_hashes()
Definition server.hpp:87
Definition node.hpp:199
constexpr int32_t to_ffi(GoalResponse r)
Definition server.hpp:234
CancelResponse
Definition server.hpp:224
GoalStatus
Definition server.hpp:262
static const size_t ACTION_NAME_MAX
Definition server.hpp:189
GoalResponse
Definition server.hpp:204
CancelReturnCode
Definition server.hpp:253
Definition rclcpp.hpp:75
@ Error
Generic failure not covered by a more specific code.
rclcpp::Node and global session helpers.
rclcpp::Result, rclcpp::ErrorCode, and the RCLCPP_TRY macro.
int32_t(* nros_cpp_goal_callback_t)(const uint8_t goal_id[16], const uint8_t *data, size_t len, void *ctx)
Definition server.hpp:39
nros_cpp_ret_t nros_cpp_action_server_set_callbacks(void *handle, nros_cpp_goal_callback_t goal_cb, nros_cpp_cancel_callback_t cancel_cb, void *ctx)
int32_t(* nros_cpp_cancel_callback_t)(const uint8_t goal_id[16], void *ctx)
Definition server.hpp:41
nros_cpp_ret_t nros_cpp_action_server_set_accepted_callback(void *handle, nros_cpp_accepted_callback_t accepted_cb, void *ctx)
void(* nros_cpp_accepted_callback_t)(const uint8_t goal_id[16], void *ctx)
Definition server.hpp:46
Definition qos.hpp:81
static nros_cpp_action_hashes_t get()
Definition server.hpp:70
Definition server.hpp:65
void type
Definition server.hpp:66
Definition server.hpp:124
bool operator!=(const GoalUUID &other) const
Definition server.hpp:160
bool operator==(const GoalUUID &other) const
Definition server.hpp:153
const uint8_t * data() const
Definition server.hpp:143
bool is_zero() const
True when every byte is zero — mirrors nros_core::GoalId::is_zero().
Definition server.hpp:146
GoalUUID()
The zero ("null") goal id — mirrors nros_core::GoalId::zero().
Definition server.hpp:132
uint8_t * data()
Pointer to the 16 bytes — what the raw-array overloads and the FFI take.
Definition server.hpp:142
GoalUUID(const uint8_t *src)
Copy the 16 bytes at src, which must point to at least that many.
Definition server.hpp:135
bool operator<(const GoalUUID &other) const
Definition server.hpp:165