Compare commits

..

56 Commits

Author SHA1 Message Date
Marco A. Gutierrez
86142c3aac 28.1.9
Signed-off-by: Marco A. Gutierrez <marcogg@marcogg.com>
2025-04-23 05:03:02 +00:00
Marco A. Gutierrez
379430b2ce Changelog.
Signed-off-by: Marco A. Gutierrez <marcogg@marcogg.com>
2025-04-23 05:02:13 +00:00
mergify[bot]
fe6aca3faf remove redundant typesupport check in serialization module (#2808) (#2815)
Signed-off-by: Tanishq Chaudhary <tanishqchaudhary101010@gmail.com>
(cherry picked from commit f78ed952b2)

Co-authored-by: Tanishq Chaudhary <tanishqchaudhary101010@gmail.com>
2025-04-15 09:38:01 +02:00
Janosch Machowinski
f3d66b892e fix(rclcpp_action): Fix sleep of expire thread in case of canceled timer (#2800)
This fixes a bug, that the expire action thread would not sleep as,
the sleep duration was not computed correctly.

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
2025-04-11 11:38:59 +02:00
Marco A. Gutierrez
3ca1e69c20 28.1.8
Signed-off-by: Marco A. Gutierrez <marcogg@marcogg.com>
2025-04-02 11:04:46 +00:00
Marco A. Gutierrez
405687cc5e Changelog.
Signed-off-by: Marco A. Gutierrez <marcogg@marcogg.com>
2025-04-02 11:04:17 +00:00
mergify[bot]
52d2bbfb8a Harden rclcpp_action::convert(). (#2786) (#2789)
* Harden rclcpp_action::convert().

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* update docstring.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
(cherry picked from commit ce86ef7e62)

Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-03-30 11:33:07 -07:00
mergify[bot]
b6acdc9ab6 should pull valid transition before trying to change the state. (#2774) (#2784)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
(cherry picked from commit 7b6ee8a2e7)

Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-03-28 15:39:41 +01:00
Michael Carroll
a982829f69 28.1.7 2025-03-26 16:27:46 +00:00
Michael Carroll
1aa7c7a969 Changelog.
Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>
2025-03-26 13:23:38 +00:00
Janosch Machowinski
04502128a4 fix(ClockConditionalVariable): Fixed potential crash on shutdown (#2762)
This commit deregisters the context shutdown callback on deletion of
the ClockConditionalVariable thus fixing a memory violation on shutdown.

Also adds tests for the ClockConditionalVariable.

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
2025-03-18 13:56:34 +01:00
mergify[bot]
6d586d17aa doc: Added warning to not instantiate Clock directly with RCL_ROS_TIME (#2768) (#2769)
Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Signed-off-by: Janosch Machowinski <jmachowinski@users.noreply.github.com>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
(cherry picked from commit 30e61c955d)

Co-authored-by: Janosch Machowinski <jmachowinski@users.noreply.github.com>
2025-03-14 17:25:02 -07:00
mergify[bot]
9c7e591e62 Use rmw_event_type_is_supported in test_qos_event (backport #2761) (#2766)
* Use rmw_event_type_is_supported in test_qos_event (#2761)

Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
(cherry picked from commit 9db7fa2ccb)
2025-03-12 21:42:45 +01:00
Jonas Otto
c31daa608d add NO_UNDEFINED_SYMBOLS to rclcpp_components_register_node cmake macro (#2746)
Signed-off-by: Jonas Otto <jonas.otto@ipa.fraunhofer.de>
Signed-off-by: Jonas Otto <jonas@jonasotto.com>
2025-03-07 22:29:37 +01:00
Janosch Machowinski
4c239d30a9 fix: Fixed expiring of goals if events executor is used (#2674)
* feat: Add ClockWaiter and ClockConditionalVariable

Added two new synchronization primitives to perform waits
using an rclcpp::Clock.

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

* fix: Fixed expiring of goals if events executor is used

This commit is only relevant if the events executor is used.

This commit starts a background thread, to create events
for the expire timer of the action. Without this the action
server will not expire old goal results leading to memory and
performance issues.

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

---------

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
2025-02-21 16:33:31 +01:00
mergify[bot]
d24a31738c Executor strong reference fix (#2745) (#2754)
https://github.com/ros2/rclcpp/issues/2678 reported that the executor
was holding strong references to entities during execution. This commit
adds a regression test for this.

* fix(Executor): Don't hold strong references to entities during spin

This fixes a bug, were dropping an entity during a callback would
not prevent further callbacks. Note, there might still be a race
in the case of the mutithreaded executor.

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
(cherry picked from commit 9c493c4615)

Co-authored-by: Janosch Machowinski <jmachowinski@users.noreply.github.com>
2025-02-21 16:31:41 +01:00
Janosch Machowinski
7dadf343b7 Double gc executor fix (#2753)
* fix(Executor): Don't add the notify_waitable two times to the waitset

Signed-off-by: Janosch Machowinski <j.machowinski@cellumation.com>

* test: Fix  TestExecutorNotifyWaitable wait test

The test was adding the same guard condition twice. This not allowed.

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

---------

Signed-off-by: Janosch Machowinski <j.machowinski@cellumation.com>
Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Janosch Machowinski <j.machowinski@cellumation.com>
2025-02-19 18:11:13 -06:00
mergify[bot]
1044236ade Fix typo in doc section for get_service_typesupport_handle (#2751) (#2752)
Signed-off-by: Barry Xu <barry.xu@sony.com>
(cherry picked from commit 06d400d795)

Co-authored-by: Barry Xu <barry.xu@sony.com>
2025-02-19 20:52:53 +01:00
mergify[bot]
abc76111dc Test case and fix for for https://github.com/ros2/rclcpp/issues/2652 (#2713) (#2740)
Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Signed-off-by: Francisco Martín Rico <fmrico@gmail.com>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Francisco Martín Rico <fmrico@gmail.com>
(cherry picked from commit 605251bd71)

Co-authored-by: Janosch Machowinski <jmachowinski@users.noreply.github.com>
2025-02-11 15:29:00 -08:00
mergify[bot]
2eaa2eb355 fix(timer): Delete node, after executor thread terminated (#2737) (#2738)
This fixes a potential race leading to a segfault. The segfault would
happen, if the tear down of the test would occur before the timer thread
stopped the spinning of the executor.

Also simplifies the test code, as the cancel of the executor is now in
the TearDown().

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
(cherry picked from commit f6b80abe4a)

Co-authored-by: Janosch Machowinski <jmachowinski@users.noreply.github.com>
2025-02-11 12:19:30 +01:00
mergify[bot]
9dd2c91d7d fix(Executor): Fixed entities not beeing executed after just beeing added (#2724) (#2729)
Fixes https://github.com/ros2/rclcpp/issues/2589

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
(cherry picked from commit e7afaa636a)

Co-authored-by: Janosch Machowinski <jmachowinski@users.noreply.github.com>
2025-01-28 12:06:34 -08:00
mergify[bot]
7c896265a6 Fix transient local IPC publish (#2708) (#2722)
* Fix transient local publish when inter and intra process communications are both present.

* Apply the fix to TypeAdapted signature

* Add an executor to intra_process_inter_process_mix_transient_local test case to enable inter process publishing test

Signed-off-by: Jeffery Hsu <jefferyyjhsu@gmail.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
(cherry picked from commit f5e08c2d0c)

Co-authored-by: Jeffery Hsu <jefferyyjhsu@gmail.com>
2025-01-07 09:11:33 +01:00
Marco A. Gutierrez
985e320de3 28.1.6
Signed-off-by: Marco A. Gutierrez <marcogg@marcogg.com>
2024-12-18 06:28:23 +00:00
Marco A. Gutierrez
eac2e8a7dd Changelog.
Signed-off-by: Marco A. Gutierrez <marcogg@marcogg.com>
2024-12-18 06:27:18 +00:00
mergify[bot]
cff2711aba apply actual QoS from rmw to the IPC publisher. (#2707) (#2712)
* apply actual QoS from rmw to the IPC publisher.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* address uncrustify warning.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
(cherry picked from commit 016cfeac99)

Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-12-16 17:27:51 -08:00
mergify[bot]
608e2f2e56 Adding in topic name to logging on IPC issues (#2706) (#2710)
* Adding in topic name to logging on IPC issues

Signed-off-by: Steve Macenski <stevenmacenski@gmail.com>

* Update test matching output logging

Signed-off-by: Steve Macenski <stevenmacenski@gmail.com>

* adding in single quotes

Signed-off-by: Steve Macenski <stevenmacenski@gmail.com>

---------

Signed-off-by: Steve Macenski <stevenmacenski@gmail.com>
(cherry picked from commit a13e16e2cb)

Co-authored-by: Steve Macenski <stevenmacenski@gmail.com>
2024-12-14 15:16:19 -08:00
Tomoya Fujita
bd695f4a3b enable testRaceConditionAddNode for rmw_connextdds. (#2698)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-12-04 12:45:09 -08:00
mergify[bot]
74162b19bf Re-enable executor test on rmw_connextdds. (#2693) (#2695)
It supports the events executor now, so re-enable the test.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
(cherry picked from commit d7245365ed)

Co-authored-by: Chris Lalancette <clalancette@gmail.com>
2024-12-04 08:32:48 -08:00
mergify[bot]
e217532817 Fix warnings on Windows. (backport #2692) (#2694)
* Fix warnings on Windows. (#2692)

For reasons I admit I do not understand, the deprecation
warnings for StaticSingleThreadedExecutor on Windows
happen when we construct a shared_ptr for it in the tests.
If we construct a regular object, then it is fine.  Luckily
this test does not require a shared_ptr, so just make it
a regular object here, which rixes the warning.

While we are in here, make all of the tests camel case to
be consistent.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
(cherry picked from commit 3310f9eaed)

# Conflicts:
#	rclcpp/test/rclcpp/executors/test_executors.cpp

* resolve backport conflict.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Co-authored-by: Chris Lalancette <clalancette@gmail.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-12-04 09:50:19 +01:00
mergify[bot]
a7b8ada6a7 Omnibus fixes for running tests with Connext. (backport #2684) (#2690)
* Omnibus fixes for running tests with Connext. (#2684)

* Omnibus fixes for running tests with Connext.

When running the tests with RTI Connext as the default
RMW, some of the tests are failing.  There are three
different failures fixed here:

1.  Setting the liveliness duration to a value smaller than
a microsecond causes Connext to throw an error.  Set it to
a millisecond.

2.  Using the SystemDefaultsQoS sets the QoS to KEEP_LAST 1.
Connext is somewhat slow in this regard, so it can be the case
that we are overwriting a previous service introspection event
with the next one.  Switch to the ServicesDefaultQoS in the test,
which ensures we will not lose events.

3.  Connext is slow to match publishers and subscriptions.  Thus,
when creating a subscription "on-the-fly", we should wait for the
publisher to match it before expecting the subscription to actually
receive data from it.

With these fixes in place, the test_client_common, test_generic_service,
test_service_introspection, and test_executors tests all pass for
me with rmw_connextdds.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>

* Fixes for executors.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>

* One more fix for services.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>

* More fixes for service_introspection.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>

* More fixes for introspection.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>

---------

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
(cherry picked from commit 9984197c29)

# Conflicts:
#	rclcpp/test/rclcpp/executors/test_executors.cpp
#	rclcpp/test/rclcpp/test_generic_service.cpp

* address backport merge conflicts.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Co-authored-by: Chris Lalancette <clalancette@gmail.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-12-03 15:04:57 -08:00
jmachowinski
df09c6e77d fix(Executor): Fix segfault if callback group is deleted during rmw_wait (#2682)
Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
2024-12-01 12:31:09 -08:00
mergify[bot]
06ae92ae96 Remove CODEOWNERS and the rolling-to-master job. (#2686) (#2687)
They are both legacy from times past, and are both
no longer serving their intended purposes.  Just remove them.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
(cherry picked from commit e64627004f)

Co-authored-by: Chris Lalancette <clalancette@gmail.com>
2024-11-27 10:45:36 +01:00
mergify[bot]
99b3803ce2 Fix NodeOptions assignment operator (#2656) (#2660)
* Fix NodeOptions assignment operator

Also copy the enable_logger_service_ member during the assignment operation

* Add more checks for NodeOptions copy test

* Set non default values by avoiding the copy-assignement

Signed-off-by: Romain DESILLE <r.desille@gmail.com>
Co-authored-by: Christophe Bedard <bedard.christophe@gmail.com>
(cherry picked from commit 9b654942f9)

Co-authored-by: Romain DESILLE <r.desille@gmail.com>
2024-11-07 09:47:55 -08:00
Cristóbal Arroyo
bbe2b99893 set QoS History KEEP_ALL explicitly for statistics publisher. (#2650) (#2657)
* set QoS History KEEP_ALL explicitly for statistics publisher.

* test_subscription_options adjustment.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-10-30 12:57:18 -04:00
Marco A. Gutierrez
09e5dd70f4 28.1.5 2024-09-19 17:15:53 +00:00
Marco A. Gutierrez
5551facd9b Changelog.
Signed-off-by: Marco A. Gutierrez <marcogg@marcogg.com>
2024-09-19 17:14:46 +00:00
Alberto Soragna
38ed9ed172 backport fix events-executor warm-up bug and add unit-tests (#2591) (#2628)
Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2024-09-17 13:38:52 +02:00
Marco A. Gutierrez
fad351ff85 28.1.4
Signed-off-by: Marco A. Gutierrez <marcogg@marcogg.com>
2024-09-06 19:00:36 +00:00
Marco A. Gutierrez
08c6cd9f9a Changelog.
Signed-off-by: Marco A. Gutierrez <marcogg@marcogg.com>
2024-09-06 18:59:53 +00:00
mergify[bot]
830a1f0212 Split test_executors.cpp even further. (#2572) (#2619)
That's because it is too large for Windows Debug to compile,
so split into smaller bits.

Even with this split, the file is too big; that's likely
because we are using TYPED_TEST here, which generates multiple
symbols per test case.  To deal with this, without further
breaking up the file, also add in the /bigobj flag when
compiling on Windows Debug.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
(cherry picked from commit c743c173e6)

Co-authored-by: Chris Lalancette <clalancette@gmail.com>
2024-09-06 10:28:31 -04:00
mergify[bot]
1b4485443d Correct node name in service test code (#2615) (#2616)
Signed-off-by: Barry Xu <barry.xu@sony.com>
(cherry picked from commit e846f56224)

Co-authored-by: Barry Xu <barry.xu@sony.com>
2024-09-03 09:14:43 +02:00
mergify[bot]
d73fc2a86a Release ownership of entities after spinning cancelled (backport #2556) (#2580)
* Release ownership of entities after spinning cancelled (#2556)

* Release ownership of entities after spinning cancelled

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Move release action to every exit point in different spin functions

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Move wait_result_.reset() before setting spinning to false

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Update test code

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Move test code to test_executors.cpp

Signed-off-by: Barry Xu <barry.xu@sony.com>

---------

Signed-off-by: Barry Xu <barry.xu@sony.com>
(cherry picked from commit 069a001893)

# Conflicts:
#	rclcpp/test/rclcpp/executors/test_executors.cpp

* Fix backport issue (#2581)

Signed-off-by: Barry Xu <barry.xu@sony.com>

---------

Signed-off-by: Barry Xu <barry.xu@sony.com>
Co-authored-by: Barry Xu <barry.xu@sony.com>
2024-07-18 12:43:49 -07:00
Marco A. Gutierrez
e083bf9b7d 28.1.3
Signed-off-by: Marco A. Gutierrez <marcogg@marcogg.com>
2024-06-27 10:35:14 +00:00
Marco A. Gutierrez
c3bc232eae Changelog.
Signed-off-by: Marco A. Gutierrez <marcogg@marcogg.com>
2024-06-27 10:28:12 +00:00
Tomoya Fujita
7f5b44ebe2 Revert "call shutdown in LifecycleNode dtor to avoid leaving the device in unknown state (2nd) (backport #2528) (#2542)" (#2558)
This reverts commit 8ab10aabc0.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-06-11 07:41:22 -07:00
mergify[bot]
8ab10aabc0 call shutdown in LifecycleNode dtor to avoid leaving the device in unknown state (2nd) (backport #2528) (#2542)
* call shutdown in LifecycleNode dtor to avoid leaving the device in unknown state (2nd) (#2528)

* Revert "Revert "call shutdown in LifecycleNode dtor to avoid leaving the device in un… (#2450)" (#2522)"

This reverts commit 42b0b5775b.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* lifecycle node dtor shutdown should be called only in primary state.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* adjust warning message if the node is still in transition state in dtor.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
(cherry picked from commit 3bc364a10b)

* LifecycleNode shutdown on dtor only with valid context. (#2545)

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-06-07 10:33:43 -07:00
mergify[bot]
119a7bcbac Add test creating two content filter topics with the same topic name (#2546) (#2549) (#2552)
Signed-off-by: Mario-DL <mariodominguez@eprosima.com>
Co-authored-by: Mario Domínguez López <116071334+Mario-DL@users.noreply.github.com>
(cherry picked from commit 7c096888ca)

Co-authored-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
2024-06-06 10:11:46 +02:00
mergify[bot]
0beba97156 rclcpp::shutdown should not be called before LifecycleNode dtor. (#2527) (#2540)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
(cherry picked from commit 22df1d593a)

Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-05-23 22:13:09 -07:00
Marco A. Gutierrez
c88a3602ab 28.1.2
Signed-off-by: Marco A. Gutierrez <marcogg@marcogg.com>
2024-05-13 21:21:56 +00:00
Marco A. Gutierrez
258b0a06bb Changelog.
Signed-off-by: Marco A. Gutierrez <marcogg@marcogg.com>
2024-05-13 21:20:28 +00:00
mergify[bot]
bf6a6733a1 add impl pointer for ExecutorOptions (#2523) (#2525)
* add impl pointer for ExecutorOptions

Signed-off-by: William Woodall <william@osrfoundation.org>
(cherry picked from commit 343b29b617)

Co-authored-by: William Woodall <william@osrfoundation.org>
2024-05-10 13:21:04 -04:00
mergify[bot]
4f17dee383 Revert "call shutdown in LifecycleNode dtor to avoid leaving the device in un… (#2450)" (#2522) (#2524)
This reverts commit 04ea0bb002.

(cherry picked from commit 42b0b5775b)

Co-authored-by: Chris Lalancette <clalancette@gmail.com>
2024-05-09 15:36:08 -04:00
mergify[bot]
2c23e3a73a Fixup Executor::spin_all() regression fix (#2517) (#2521)
* test(Executors): Added tests for busy waiting

Checks if executors are busy waiting while they should block
in spin_some or spin_all.

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

* fix: Reworked spinAll test

This test was strange. It looked like, it assumed that spin_all did
not return instantly. Also it was racy, as the thread could terminate
instantly.

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

* fix(Executor): Fixed spin_all not returning instantly is no work was available

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

* Update rclcpp/test/rclcpp/executors/test_executors.cpp

Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Signed-off-by: jmachowinski <jmachowinski@users.noreply.github.com>

* test(executors): Added test for busy waiting while calling spin

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

* fix(executor): Reset wait_result on every call to spin_some_impl

Before, the method would not recollect available work in case of
spin_some, spin_all. This would lead to the method behaving differently
than to what the documentation states.

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

* restore previous test logic for now

Signed-off-by: William Woodall <william@osrfoundation.org>

* refactor spin_some_impl's logic and improve busy wait tests

Signed-off-by: William Woodall <william@osrfoundation.org>

* added some more comments about the implementation

Signed-off-by: William Woodall <william@osrfoundation.org>

---------

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Signed-off-by: jmachowinski <jmachowinski@users.noreply.github.com>
Signed-off-by: William Woodall <william@osrfoundation.org>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: jmachowinski <jmachowinski@users.noreply.github.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
(cherry picked from commit f7185dc129)

Co-authored-by: William Woodall <william@osrfoundation.org>
2024-05-02 21:50:04 -07:00
Chris Lalancette
8934b5a0a9 28.1.1 2024-04-24 17:02:48 +00:00
Chris Lalancette
3407564a15 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-04-24 17:02:42 +00:00
mergify[bot]
8b3be2ad7e Revise the description of service configure_introspection() (#2511) (#2513)
Signed-off-by: Barry Xu <barry.xu@sony.com>
(cherry picked from commit 55939613a0)

Co-authored-by: Barry Xu <barry.xu@sony.com>
2024-04-23 22:57:31 +02:00
160 changed files with 3706 additions and 6731 deletions

View File

@@ -2,105 +2,133 @@
Changelog for package rclcpp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
29.3.0 (2024-12-20)
28.1.9 (2025-04-23)
-------------------
* Fix transient local IPC publish (`#2708 <https://github.com/ros2/rclcpp/issues/2708>`_)
* apply actual QoS from rmw to the IPC publisher. (`#2707 <https://github.com/ros2/rclcpp/issues/2707>`_)
* Adding in topic name to logging on IPC issues (`#2706 <https://github.com/ros2/rclcpp/issues/2706>`_)
* fix TestTimeSource.ROS_time_valid_attach_detach. (`#2700 <https://github.com/ros2/rclcpp/issues/2700>`_)
* Update docstring for `rclcpp::Node::now()` (`#2696 <https://github.com/ros2/rclcpp/issues/2696>`_)
* Re-enable executor test on rmw_connextdds. (`#2693 <https://github.com/ros2/rclcpp/issues/2693>`_)
* Fix warnings on Windows. (`#2692 <https://github.com/ros2/rclcpp/issues/2692>`_)
* Omnibus fixes for running tests with Connext. (`#2684 <https://github.com/ros2/rclcpp/issues/2684>`_)
* fix(Executor): Fix segfault if callback group is deleted during rmw_wait (`#2683 <https://github.com/ros2/rclcpp/issues/2683>`_)
* Contributors: Chris Lalancette, Jeffery Hsu, Patrick Roncagliolo, Steve Macenski, Tomoya Fujita, jmachowinski
* remove redundant typesupport check in serialization module (`#2808 <https://github.com/ros2/rclcpp/issues/2808>`_) (`#2815 <https://github.com/ros2/rclcpp/issues/2815>`_)
(cherry picked from commit f78ed952b27acc63ef8022d78cb816c309a9ca3d)
Co-authored-by: Tanishq Chaudhary <tanishqchaudhary101010@gmail.com>
* Contributors: mergify[bot]
29.2.0 (2024-11-25)
28.1.8 (2025-04-02)
-------------------
* accept custom allocator for LoanedMessage. (`#2672 <https://github.com/ros2/rclcpp/issues/2672>`_)
* Contributors: Tomoya Fujita
29.1.0 (2024-11-20)
28.1.7 (2025-03-26)
-------------------
* a couple of typo fixes in doc section for LoanedMessage. (`#2676 <https://github.com/ros2/rclcpp/issues/2676>`_)
* Make sure callback_end tracepoint is triggered in AnyServiceCallback (`#2670 <https://github.com/ros2/rclcpp/issues/2670>`_)
* Correct the incorrect comments in generic_client.hpp (`#2662 <https://github.com/ros2/rclcpp/issues/2662>`_)
* Fix NodeOptions assignment operator (`#2656 <https://github.com/ros2/rclcpp/issues/2656>`_)
* set QoS History KEEP_ALL explicitly for statistics publisher. (`#2650 <https://github.com/ros2/rclcpp/issues/2650>`_)
* Fix test_intra_process_manager.cpp with rmw_zenoh_cpp (`#2653 <https://github.com/ros2/rclcpp/issues/2653>`_)
* Fixed test_events_executors in zenoh (`#2643 <https://github.com/ros2/rclcpp/issues/2643>`_)
* rmw_fastrtps supports service event gid uniqueness test. (`#2638 <https://github.com/ros2/rclcpp/issues/2638>`_)
* print warning if event callback is not supported instead of passing exception. (`#2648 <https://github.com/ros2/rclcpp/issues/2648>`_)
* Implement callback support of async_send_request for service generic client (`#2614 <https://github.com/ros2/rclcpp/issues/2614>`_)
* Contributors: Alejandro Hernández Cordero, Barry Xu, Chris Lalancette, Christophe Bedard, Romain DESILLE, Tomoya Fujita
* fix(ClockConditionalVariable): Fixed potential crash on shutdown (`#2762 <https://github.com/ros2/rclcpp/issues/2762>`_)
* doc: Added warning to not instantiate Clock directly with RCL_ROS_TIME (`#2769 <https://github.com/ros2/rclcpp/issues/2769>`_)
* Backports: `#2768 <https://github.com/ros2/rclcpp/issues/2768>`_
* Use rmw_event_type_is_supported in test_qos_event (`#2766 <https://github.com/ros2/rclcpp/issues/2766>`_)
* Backports: `#2761 <https://github.com/ros2/rclcpp/issues/2761>`_
* fix: Fixed expiring of goals if events executor is used (`#2674 <https://github.com/ros2/rclcpp/issues/2674>`_)
* Executor strong reference fix (`#2754 <https://github.com/ros2/rclcpp/issues/2754>`_)
* Backports: `#2745 <https://github.com/ros2/rclcpp/issues/2745>`_
* Double gc executor fix (`#2753 <https://github.com/ros2/rclcpp/issues/2753>`_)
* Fix typo in doc section for get_service_typesupport_handle (`#2752 <https://github.com/ros2/rclcpp/issues/2752>`_)
* Backports: `#2751 <https://github.com/ros2/rclcpp/issues/2751>`_
* Test case and fix for for https://github.com/ros2/rclcpp/issues/2652 (`#2740 <https://github.com/ros2/rclcpp/issues/2740>`_)
* Backports: `#2713 <https://github.com/ros2/rclcpp/issues/2713>`_
* fix(timer): Delete node, after executor thread terminated (`#2738 <https://github.com/ros2/rclcpp/issues/2738>`_)
* Backports: `#2737 <https://github.com/ros2/rclcpp/issues/2737>`_
* fix(Executor): Fixed entities not beeing executed after just beeing added (`#2729 <https://github.com/ros2/rclcpp/issues/2729>`_)
* Backports: `#2737 <https://github.com/ros2/rclcpp/issues/2724>`_
* Fix transient local IPC publish (`#2722 <https://github.com/ros2/rclcpp/issues/2722>`_)
* Backports: `#2708 <https://github.com/ros2/rclcpp/issues/2708>`_
* Contributors: Janosch Machowinski, Jeffery Hsu, Tomoya Fujita, Francisco Martín Rico
29.0.0 (2024-10-03)
28.1.6 (2024-12-18)
-------------------
* Fixed test qos rmw zenoh (`#2639 <https://github.com/ros2/rclcpp/issues/2639>`_)
* verify client gid uniqueness for a single service event. (`#2636 <https://github.com/ros2/rclcpp/issues/2636>`_)
* Skip some tests in test_qos_event and run others with event types supported by rmw_zenoh (`#2626 <https://github.com/ros2/rclcpp/issues/2626>`_)
* Shutdown the context before context's destructor is invoked in tests (`#2633 <https://github.com/ros2/rclcpp/issues/2633>`_)
* Skip rmw zenoh content filtering tests (`#2627 <https://github.com/ros2/rclcpp/issues/2627>`_)
* Use InvalidServiceTypeError for unavailable service type in GenericClient (`#2629 <https://github.com/ros2/rclcpp/issues/2629>`_)
* Implement generic service (`#2617 <https://github.com/ros2/rclcpp/issues/2617>`_)
* fix events-executor warm-up bug and add unit-tests (`#2591 <https://github.com/ros2/rclcpp/issues/2591>`_)
* remove unnecessary gtest-skip in test_executors (`#2600 <https://github.com/ros2/rclcpp/issues/2600>`_)
* Correct node name in service test code (`#2615 <https://github.com/ros2/rclcpp/issues/2615>`_)
* Minor naming fixes for ParameterValue to_string() function (`#2609 <https://github.com/ros2/rclcpp/issues/2609>`_)
* Removed clang warnings (`#2605 <https://github.com/ros2/rclcpp/issues/2605>`_)
* Fix a couple of issues in the documentation. (`#2608 <https://github.com/ros2/rclcpp/issues/2608>`_)
* deprecate the static single threaded executor (`#2598 <https://github.com/ros2/rclcpp/issues/2598>`_)
* Fix name of ParameterEventHandler class in doc (`#2604 <https://github.com/ros2/rclcpp/issues/2604>`_)
* subscriber_statistics_collectors\_ should be protected by mutex. (`#2592 <https://github.com/ros2/rclcpp/issues/2592>`_)
* Fix bug in timers lifecycle for events executor (`#2586 <https://github.com/ros2/rclcpp/issues/2586>`_)
* fix rclcpp/test/rclcpp/CMakeLists.txt to check for the correct targets existance (`#2596 <https://github.com/ros2/rclcpp/issues/2596>`_)
* Shut down context during init if logging config fails (`#2594 <https://github.com/ros2/rclcpp/issues/2594>`_)
* Make more of the Waitable API abstract (`#2593 <https://github.com/ros2/rclcpp/issues/2593>`_)
* Contributors: Alberto Soragna, Alejandro Hernández Cordero, Alexis Pojomovsky, Barry Xu, Chris Lalancette, Christophe Bedard, Kang, Hsin-Yi, Tomoya Fujita
28.3.3 (2024-07-29)
-------------------
* Only compile the tests once. (`#2590 <https://github.com/ros2/rclcpp/issues/2590>`_)
* Contributors: Chris Lalancette
28.3.2 (2024-07-24)
-------------------
* Updated rcpputils path API (`#2579 <https://github.com/ros2/rclcpp/issues/2579>`_)
* Make the subscriber_triggered_to_receive_message test more reliable. (`#2584 <https://github.com/ros2/rclcpp/issues/2584>`_)
* Make the subscriber_triggered_to_receive_message test more reliable.
In the current code, inside of the timer we create the subscription
and the publisher, publish immediately, and expect the subscription
to get it immediately. But it may be the case that discovery
hasn't even happened between the publisher and the subscription
by the time the publish call happens.
To make this more reliable, create the subscription and publish *before*
we ever create and spin on the timer. This at least gives 100
milliseconds for discovery to happen. That may not be quite enough
to make this reliable on all platforms, but in my local testing this
helps a lot. Prior to this change I can make this fail one out of 10
times, and after the change I've run 100 times with no failures.
* Have the EventsExecutor use more common code (`#2570 <https://github.com/ros2/rclcpp/issues/2570>`_)
* move notify waitable setup to its own function
* move mutex lock to retrieve_entity utility
* use entities_need_rebuild\_ atomic bool in events-executors
* remove duplicated set_on_ready_callback for notify_waitable
* use mutex from base class rather than a new recursive mutex
* use current_collection\_ member in events-executor
* delay adding notify waitable to collection
* postpone clearing the current collection
* commonize notify waitable and collection
* commonize add/remove node/cbg methods
* fix linter errors
* apply actual QoS from rmw to the IPC publisher. (`#2707 <https://github.com/ros2/rclcpp/issues/2707>`_) (`#2712 <https://github.com/ros2/rclcpp/issues/2712>`_)
* apply actual QoS from rmw to the IPC publisher.
* address uncrustify warning.
---------
* Removed deprecated methods and classes (`#2575 <https://github.com/ros2/rclcpp/issues/2575>`_)
* Release ownership of entities after spinning cancelled (`#2556 <https://github.com/ros2/rclcpp/issues/2556>`_)
* Release ownership of entities after spinning cancelled
* Move release action to every exit point in different spin functions
* Move wait_result\_.reset() before setting spinning to false
* Update test code
* Move test code to test_executors.cpp
(cherry picked from commit 016cfeac99e4b67f58abdf247e57f05b85c09ec4)
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
* Adding in topic name to logging on IPC issues (`#2706 <https://github.com/ros2/rclcpp/issues/2706>`_) (`#2710 <https://github.com/ros2/rclcpp/issues/2710>`_)
* Adding in topic name to logging on IPC issues
* Update test matching output logging
* adding in single quotes
---------
* Split test_executors.cpp even further. (`#2572 <https://github.com/ros2/rclcpp/issues/2572>`_)
(cherry picked from commit a13e16e2cbaeacb14ff31272d01cbb21bd8ac037)
Co-authored-by: Steve Macenski <stevenmacenski@gmail.com>
* enable testRaceConditionAddNode for rmw_connextdds. (`#2698 <https://github.com/ros2/rclcpp/issues/2698>`_)
* Re-enable executor test on rmw_connextdds. (`#2693 <https://github.com/ros2/rclcpp/issues/2693>`_) (`#2695 <https://github.com/ros2/rclcpp/issues/2695>`_)
It supports the events executor now, so re-enable the test.
(cherry picked from commit d7245365ed867db9b309ed3efbfb0391bda09bd5)
Co-authored-by: Chris Lalancette <clalancette@gmail.com>
* Fix warnings on Windows. (backport `#2692 <https://github.com/ros2/rclcpp/issues/2692>`_) (`#2694 <https://github.com/ros2/rclcpp/issues/2694>`_)
* Fix warnings on Windows. (`#2692 <https://github.com/ros2/rclcpp/issues/2692>`_)
For reasons I admit I do not understand, the deprecation
warnings for StaticSingleThreadedExecutor on Windows
happen when we construct a shared_ptr for it in the tests.
If we construct a regular object, then it is fine. Luckily
this test does not require a shared_ptr, so just make it
a regular object here, which rixes the warning.
While we are in here, make all of the tests camel case to
be consistent.
(cherry picked from commit 3310f9eaed967e0c18d17bb2f82d2def838bb7a5)
# Conflicts:
# rclcpp/test/rclcpp/executors/test_executors.cpp
* resolve backport conflict.
---------
Co-authored-by: Chris Lalancette <clalancette@gmail.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
* Omnibus fixes for running tests with Connext. (backport `#2684 <https://github.com/ros2/rclcpp/issues/2684>`_) (`#2690 <https://github.com/ros2/rclcpp/issues/2690>`_)
* Omnibus fixes for running tests with Connext. (`#2684 <https://github.com/ros2/rclcpp/issues/2684>`_)
* Omnibus fixes for running tests with Connext.
When running the tests with RTI Connext as the default
RMW, some of the tests are failing. There are three
different failures fixed here:
1. Setting the liveliness duration to a value smaller than
a microsecond causes Connext to throw an error. Set it to
a millisecond.
2. Using the SystemDefaultsQoS sets the QoS to KEEP_LAST 1.
Connext is somewhat slow in this regard, so it can be the case
that we are overwriting a previous service introspection event
with the next one. Switch to the ServicesDefaultQoS in the test,
which ensures we will not lose events.
3. Connext is slow to match publishers and subscriptions. Thus,
when creating a subscription "on-the-fly", we should wait for the
publisher to match it before expecting the subscription to actually
receive data from it.
With these fixes in place, the test_client_common, test_generic_service,
test_service_introspection, and test_executors tests all pass for
me with rmw_connextdds.
* Fixes for executors.
* One more fix for services.
* More fixes for service_introspection.
* More fixes for introspection.
---------
(cherry picked from commit 9984197c292d6c5ae0e7661aaea245ffb0fea057)
# Conflicts:
# rclcpp/test/rclcpp/executors/test_executors.cpp
# rclcpp/test/rclcpp/test_generic_service.cpp
* address backport merge conflicts.
---------
Co-authored-by: Chris Lalancette <clalancette@gmail.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
* fix(Executor): Fix segfault if callback group is deleted during rmw_wait (`#2682 <https://github.com/ros2/rclcpp/issues/2682>`_)
* Fix NodeOptions assignment operator (`#2656 <https://github.com/ros2/rclcpp/issues/2656>`_) (`#2660 <https://github.com/ros2/rclcpp/issues/2660>`_)
* Fix NodeOptions assignment operator
Also copy the enable_logger_service\_ member during the assignment operation
* Add more checks for NodeOptions copy test
* Set non default values by avoiding the copy-assignement
Co-authored-by: Christophe Bedard <bedard.christophe@gmail.com>
(cherry picked from commit 9b654942f99f17850e0e95480958abdbb508bc00)
Co-authored-by: Romain DESILLE <r.desille@gmail.com>
* set QoS History KEEP_ALL explicitly for statistics publisher. (`#2650 <https://github.com/ros2/rclcpp/issues/2650>`_) (`#2657 <https://github.com/ros2/rclcpp/issues/2657>`_)
* set QoS History KEEP_ALL explicitly for statistics publisher.
* test_subscription_options adjustment.
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
* Contributors: Cristóbal Arroyo, Tomoya Fujita, jmachowinski, mergify[bot]
28.1.5 (2024-09-19)
-------------------
* backport fix events-executor warm-up bug and add unit-tests (`#2591 <https://github.com/ros2/rclcpp/issues/2591>`_) (`#2628 <https://github.com/ros2/rclcpp/issues/2628>`_)
* Contributors: Alberto Soragna
28.1.4 (2024-09-06)
-------------------
* Split test_executors.cpp even further. (`#2572 <https://github.com/ros2/rclcpp/issues/2572>`_) (`#2619 <https://github.com/ros2/rclcpp/issues/2619>`_)
That's because it is too large for Windows Debug to compile,
so split into smaller bits.
Even with this split, the file is too big; that's likely
@@ -108,32 +136,70 @@ Changelog for package rclcpp
symbols per test case. To deal with this, without further
breaking up the file, also add in the /bigobj flag when
compiling on Windows Debug.
* avoid adding notify waitable twice to events-executor collection (`#2564 <https://github.com/ros2/rclcpp/issues/2564>`_)
* avoid adding notify waitable twice to events-executor entities collection
* remove redundant mutex lock
(cherry picked from commit c743c173e68d92af872cf163e10721a8dbe51dd0)
Co-authored-by: Chris Lalancette <clalancette@gmail.com>
* Correct node name in service test code (`#2615 <https://github.com/ros2/rclcpp/issues/2615>`_) (`#2616 <https://github.com/ros2/rclcpp/issues/2616>`_)
(cherry picked from commit e846f56224a39b93f1c609e7ee03fff0662b7453)
Co-authored-by: Barry Xu <barry.xu@sony.com>
* Release ownership of entities after spinning cancelled (backport `#2556 <https://github.com/ros2/rclcpp/issues/2556>`_) (`#2580 <https://github.com/ros2/rclcpp/issues/2580>`_)
* Release ownership of entities after spinning cancelled (`#2556 <https://github.com/ros2/rclcpp/issues/2556>`_)
* Release ownership of entities after spinning cancelled
* Move release action to every exit point in different spin functions
* Move wait_result\_.reset() before setting spinning to false
* Update test code
* Move test code to test_executors.cpp
---------
* Contributors: Alberto Soragna, Alejandro Hernández Cordero, Barry Xu, Chris Lalancette
(cherry picked from commit 069a0018935b33a14632a1cdf4074984a1cf80fe)
# Conflicts:
# rclcpp/test/rclcpp/executors/test_executors.cpp
* Fix backport issue (`#2581 <https://github.com/ros2/rclcpp/issues/2581>`_)
---------
Co-authored-by: Barry Xu <barry.xu@sony.com>
* Contributors: mergify[bot]
28.3.1 (2024-06-25)
28.1.3 (2024-06-27)
-------------------
* Remove unnecessary msg includes in tests (`#2566 <https://github.com/ros2/rclcpp/issues/2566>`_)
* Fix copy-paste errors in function docs (`#2565 <https://github.com/ros2/rclcpp/issues/2565>`_)
* Fix typo in function doc (`#2563 <https://github.com/ros2/rclcpp/issues/2563>`_)
* Contributors: Christophe Bedard
* Add test creating two content filter topics with the same topic name (`#2546 <https://github.com/ros2/rclcpp/issues/2546>`_) (`#2549 <https://github.com/ros2/rclcpp/issues/2549>`_) (`#2552 <https://github.com/ros2/rclcpp/issues/2552>`_)
Co-authored-by: Mario Domínguez López <116071334+Mario-DL@users.noreply.github.com>
(cherry picked from commit 7c096888caf92aa7557e1d3efc5448b56d8ce81c)
Co-authored-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
* Contributors: mergify[bot]
28.3.0 (2024-06-17)
28.1.2 (2024-05-13)
-------------------
* Add test creating two content filter topics with the same topic name (`#2546 <https://github.com/ros2/rclcpp/issues/2546>`_) (`#2549 <https://github.com/ros2/rclcpp/issues/2549>`_)
* add impl pointer for ExecutorOptions (`#2523 <https://github.com/ros2/rclcpp/issues/2523>`_)
* Fixup Executor::spin_all() regression fix (`#2517 <https://github.com/ros2/rclcpp/issues/2517>`_)
* Add 'mimick' label to tests which use Mimick (`#2516 <https://github.com/ros2/rclcpp/issues/2516>`_)
* Contributors: Alejandro Hernández Cordero, Scott K Logan, William Woodall
* add impl pointer for ExecutorOptions (`#2523 <https://github.com/ros2/rclcpp/issues/2523>`_) (`#2525 <https://github.com/ros2/rclcpp/issues/2525>`_)
* add impl pointer for ExecutorOptions
(cherry picked from commit 343b29b617b163ad72b9fe3f6441dd4ed3d3af09)
Co-authored-by: William Woodall <william@osrfoundation.org>
* Fixup Executor::spin_all() regression fix (`#2517 <https://github.com/ros2/rclcpp/issues/2517>`_) (`#2521 <https://github.com/ros2/rclcpp/issues/2521>`_)
* test(Executors): Added tests for busy waiting
Checks if executors are busy waiting while they should block
in spin_some or spin_all.
* fix: Reworked spinAll test
This test was strange. It looked like, it assumed that spin_all did
not return instantly. Also it was racy, as the thread could terminate
instantly.
* fix(Executor): Fixed spin_all not returning instantly is no work was available
* Update rclcpp/test/rclcpp/executors/test_executors.cpp
* test(executors): Added test for busy waiting while calling spin
* fix(executor): Reset wait_result on every call to spin_some_impl
Before, the method would not recollect available work in case of
spin_some, spin_all. This would lead to the method behaving differently
than to what the documentation states.
* restore previous test logic for now
* refactor spin_some_impl's logic and improve busy wait tests
* added some more comments about the implementation
---------
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: jmachowinski <jmachowinski@users.noreply.github.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Co-authored-by: William Woodall <william@osrfoundation.org>
* Contributors: mergify[bot]
28.2.0 (2024-04-26)
28.1.1 (2024-04-24)
-------------------
* Check for negative time in rclcpp::Time(int64_t nanoseconds, ...) constructor (`#2510 <https://github.com/ros2/rclcpp/issues/2510>`_)
* Revise the description of service configure_introspection() (`#2511 <https://github.com/ros2/rclcpp/issues/2511>`_)
* Contributors: Barry Xu, Sharmin Ramli
* Revise the description of service configure_introspection() (`#2511 <https://github.com/ros2/rclcpp/issues/2511>`_) (`#2513 <https://github.com/ros2/rclcpp/issues/2513>`_)
* Contributors: mergify[bot]
28.1.0 (2024-04-16)
-------------------

View File

@@ -77,7 +77,6 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/future_return_code.cpp
src/rclcpp/generic_client.cpp
src/rclcpp/generic_publisher.cpp
src/rclcpp/generic_service.cpp
src/rclcpp/generic_subscription.cpp
src/rclcpp/graph_listener.cpp
src/rclcpp/guard_condition.cpp
@@ -113,7 +112,6 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/qos.cpp
src/rclcpp/event_handler.cpp
src/rclcpp/qos_overriding_options.cpp
src/rclcpp/dynamic_subscription.cpp
src/rclcpp/rate.cpp
src/rclcpp/serialization.cpp
src/rclcpp/serialized_message.cpp

View File

@@ -165,13 +165,11 @@ public:
if (std::holds_alternative<SharedPtrDeferResponseCallback>(callback_)) {
const auto & cb = std::get<SharedPtrDeferResponseCallback>(callback_);
cb(request_header, std::move(request));
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
return nullptr;
}
if (std::holds_alternative<SharedPtrDeferResponseCallbackWithServiceHandle>(callback_)) {
const auto & cb = std::get<SharedPtrDeferResponseCallbackWithServiceHandle>(callback_);
cb(service_handle, request_header, std::move(request));
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
return nullptr;
}
// auto response = allocate_shared<typename ServiceT::Response, Allocator>();

View File

@@ -59,6 +59,46 @@ class CallbackGroup
public:
RCLCPP_SMART_PTR_DEFINITIONS(CallbackGroup)
/// Constructor for CallbackGroup.
/**
* Callback Groups have a type, either 'Mutually Exclusive' or 'Reentrant'
* and when creating one the type must be specified.
*
* Callbacks in Reentrant Callback Groups must be able to:
* - run at the same time as themselves (reentrant)
* - run at the same time as other callbacks in their group
* - run at the same time as other callbacks in other groups
*
* Callbacks in Mutually Exclusive Callback Groups:
* - will not be run multiple times simultaneously (non-reentrant)
* - will not be run at the same time as other callbacks in their group
* - but must run at the same time as callbacks in other groups
*
* Additionally, callback groups have a property which determines whether or
* not they are added to an executor with their associated node automatically.
* When creating a callback group the automatically_add_to_executor_with_node
* argument determines this behavior, and if true it will cause the newly
* created callback group to be added to an executor with the node when the
* Executor::add_node method is used.
* If false, this callback group will not be added automatically and would
* have to be added to an executor manually using the
* Executor::add_callback_group method.
*
* Whether the node was added to the executor before creating the callback
* group, or after, is irrelevant; the callback group will be automatically
* added to the executor in either case.
*
* \param[in] group_type The type of the callback group.
* \param[in] automatically_add_to_executor_with_node A boolean that
* determines whether a callback group is automatically added to an executor
* with the node with which it is associated.
*/
[[deprecated("Use CallbackGroup constructor with context function argument")]]
RCLCPP_PUBLIC
explicit CallbackGroup(
CallbackGroupType group_type,
bool automatically_add_to_executor_with_node = true);
/// Constructor for CallbackGroup.
/**
* Callback Groups have a type, either 'Mutually Exclusive' or 'Reentrant'

View File

@@ -70,6 +70,14 @@ struct FutureAndRequestId
/// Allow implicit conversions to `std::future` by reference.
operator FutureT &() {return this->future;}
/// Deprecated, use the `future` member variable instead.
/**
* Allow implicit conversions to `std::future` by value.
* \deprecated
*/
[[deprecated("FutureAndRequestId: use .future instead of an implicit conversion")]]
operator FutureT() {return this->future;}
// delegate future like methods in the std::future impl_
/// See std::future::get().
@@ -428,6 +436,15 @@ public:
{
using detail::FutureAndRequestId<std::future<SharedResponse>>::FutureAndRequestId;
/// Deprecated, use `.future.share()` instead.
/**
* Allow implicit conversions to `std::shared_future` by value.
* \deprecated
*/
[[deprecated(
"FutureAndRequestId: use .future.share() instead of an implicit conversion")]]
operator SharedFuture() {return this->future.share();}
// delegate future like methods in the std::future impl_
/// See std::future::share().
@@ -473,7 +490,7 @@ public:
* \param[in] node_base NodeBaseInterface pointer that is used in part of the setup.
* \param[in] node_graph The node graph interface of the corresponding node.
* \param[in] service_name Name of the topic to publish to.
* \param[in] client_options options for the client.
* \param[in] client_options options for the subscription.
*/
Client(
rclcpp::node_interfaces::NodeBaseInterface * node_base,

View File

@@ -60,6 +60,13 @@ public:
/**
* Initializes the clock instance with the given clock_type.
*
* WARNING Don't instantiate a clock using RCL_ROS_TIME directly,
* unless you really know what you are doing. By default no TimeSource
* is attached to a new clock. This will lead to the unexpected behavior,
* that your RCL_ROS_TIME will run always on system time. If you want
* a RCL_ROS_TIME use Node::get_clock(), or make sure to attach a
* TimeSource yourself.
*
* \param clock_type type of the clock.
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw.
*/
@@ -217,13 +224,13 @@ public:
std::mutex &
get_clock_mutex() noexcept;
/// Add a callback to invoke if the jump threshold is exceeded.
// Add a callback to invoke if the jump threshold is exceeded.
/**
* These callback functions must remain valid as long as the
* returned shared pointer is valid.
*
* Function will register callbacks to the callback queue. On time jump all
* callbacks will be executed whose threshold is greater than the time jump;
* callbacks will be executed whose threshold is greater then the time jump;
* The logic will first call selected pre_callbacks and then all selected
* post_callbacks.
*
@@ -232,7 +239,7 @@ public:
* \param pre_callback Must be non-throwing
* \param post_callback Must be non-throwing.
* \param threshold Callbacks will be triggered if the time jump is greater
* than the threshold.
* then the threshold.
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw.
* \throws std::bad_alloc if the allocation of the JumpHandler fails.
* \warning the instance of the clock must remain valid as long as any created
@@ -260,6 +267,117 @@ private:
std::shared_ptr<Impl> impl_;
};
/**
* A synchronization primitive, equal to std::conditional_variable,
* that works with the rclcpp::Clock.
*
* For more information on the API see https://en.cppreference.com/w/cpp/thread/condition_variable.
*
* Note, this class does not handle shutdowns, if you want to
* haven them handles as well, use ClockConditionalVariable.
*/
class ClockWaiter
{
private:
class ClockWaiterImpl;
std::unique_ptr<ClockWaiterImpl> impl_;
public:
RCLCPP_SMART_PTR_DEFINITIONS(ClockWaiter)
RCLCPP_PUBLIC
explicit ClockWaiter(const rclcpp::Clock::SharedPtr & clock);
RCLCPP_PUBLIC
~ClockWaiter();
/**
* Calling this function will block the current thread, until abs_time is reached,
* or pred returns true.
* @param lock A locked lock. The lock must be locked at call time, or this method will throw.
* The lock will be atomically released and this thread will blocked.
* @param abs_time The time until which this thread shall be blocked.
* @param pred may be called in cased of spurious wakeups, but must be called every time
* notify_one() was called. During the call to pred, the given lock will be locked.
* This method will return, if pred returns true.
*/
RCLCPP_PUBLIC
bool
wait_until(
std::unique_lock<std::mutex> & lock,
const rclcpp::Time & abs_time, const std::function<bool ()> & pred);
/**
* Notify the blocked thread, that it should reevaluate the wakeup condition.
* The given pred function in wait_until will be reevaluated and wait_until
* will return if it evaluates to true.
*/
RCLCPP_PUBLIC
void
notify_one();
};
/**
* A synchronization primitive, similar to std::conditional_variable,
* that works with the rclcpp::Clock.
*
* For more information on the API see https://en.cppreference.com/w/cpp/thread/condition_variable.
*
* This primitive will wake up if the context was shut down.
*/
class ClockConditionalVariable
{
class Impl;
std::unique_ptr<Impl> impl_;
public:
RCLCPP_SMART_PTR_DEFINITIONS(ClockConditionalVariable)
RCLCPP_PUBLIC
ClockConditionalVariable(
const rclcpp::Clock::SharedPtr & clock,
rclcpp::Context::SharedPtr context = rclcpp::contexts::get_global_default_context());
RCLCPP_PUBLIC
~ClockConditionalVariable();
/**
* Calling this function will block the current thread, until abs_time is reached,
* or pred returns true.
* @param lock A locked lock. The lock must be locked at call time, or this method will throw.
* The lock will be atomically released and this thread will blocked.
* The given lock must be created using the mutex returned my mutex().
* @param abs_time The time until which this thread shall be blocked.
* @param pred may be called in cased of spurious wakeups, but must be called every time
* notify_one() was called. During the call to pred, the given lock will be locked.
* This method will return, if pred returns true.
*
* @return true if until was reached.
*/
RCLCPP_PUBLIC
bool
wait_until(
std::unique_lock<std::mutex> & lock, rclcpp::Time until,
const std::function<bool ()> & pred);
/**
* Notify the blocked thread, that is should reevaluate the wakeup condition.
* E.g. the given pred function in wait_until shall be reevaluated.
*/
RCLCPP_PUBLIC
void
notify_one();
/**
* Returns the internal mutex. In order to be race free with the context shutdown,
* this mutex must be used for the wait_until call.
*/
RCLCPP_PUBLIC
std::mutex &
mutex();
};
} // namespace rclcpp
#endif // RCLCPP__CLOCK_HPP_

View File

@@ -47,9 +47,28 @@ create_client(
const std::string & service_name,
const rclcpp::QoS & qos = rclcpp::ServicesQoS(),
rclcpp::CallbackGroup::SharedPtr group = nullptr)
{
return create_client<ServiceT>(
node_base, node_graph, node_services,
service_name,
qos.get_rmw_qos_profile(),
group);
}
/// Create a service client with a given type.
/// \internal
template<typename ServiceT>
typename rclcpp::Client<ServiceT>::SharedPtr
create_client(
std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
std::shared_ptr<node_interfaces::NodeGraphInterface> node_graph,
std::shared_ptr<node_interfaces::NodeServicesInterface> node_services,
const std::string & service_name,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group)
{
rcl_client_options_t options = rcl_client_get_default_options();
options.qos = qos.get_rmw_qos_profile();
options.qos = qos_profile;
auto cli = rclcpp::Client<ServiceT>::make_shared(
node_base.get(),
@@ -61,6 +80,7 @@ create_client(
node_services->add_client(cli_base_ptr, group);
return cli;
}
} // namespace rclcpp
#endif // RCLCPP__CREATE_CLIENT_HPP_

View File

@@ -1,102 +0,0 @@
// Copyright 2024 Sony Group Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__CREATE_GENERIC_SERVICE_HPP_
#define RCLCPP__CREATE_GENERIC_SERVICE_HPP_
#include <memory>
#include <string>
#include <utility>
#include "rclcpp/generic_service.hpp"
#include "rclcpp/node_interfaces/get_node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/get_node_services_interface.hpp"
#include "rclcpp/node_interfaces/node_services_interface.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rmw/rmw.h"
namespace rclcpp
{
/// Create a generic service with a given type.
/**
* \param[in] node_base NodeBaseInterface implementation of the node on which
* to create the generic service.
* \param[in] node_services NodeServicesInterface implementation of the node on
* which to create the service.
* \param[in] service_name The name on which the service is accessible.
* \param[in] service_type The name of service type, e.g. "std_srvs/srv/SetBool".
* \param[in] callback The callback to call when the service gets a request.
* \param[in] qos Quality of service profile for the service.
* \param[in] group Callback group to handle the reply to service calls.
* \return Shared pointer to the created service.
*/
template<typename CallbackT>
typename rclcpp::GenericService::SharedPtr
create_generic_service(
std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
std::shared_ptr<node_interfaces::NodeServicesInterface> node_services,
const std::string & service_name,
const std::string & service_type,
CallbackT && callback,
const rclcpp::QoS & qos,
rclcpp::CallbackGroup::SharedPtr group)
{
rclcpp::GenericServiceCallback any_service_callback;
any_service_callback.set(std::forward<CallbackT>(callback));
rcl_service_options_t service_options = rcl_service_get_default_options();
service_options.qos = qos.get_rmw_qos_profile();
auto serv = GenericService::make_shared(
node_base->get_shared_rcl_node_handle(),
service_name, service_type, any_service_callback, service_options);
auto serv_base_ptr = std::dynamic_pointer_cast<ServiceBase>(serv);
node_services->add_service(serv_base_ptr, group);
return serv;
}
/// Create a generic service with a given type.
/**
* The NodeT type needs to have NodeBaseInterface implementation and NodeServicesInterface
* implementation of the node which to create the generic service.
*
* \param[in] node The node on which to create the generic service.
* \param[in] service_name The name on which the service is accessible.
* \param[in] service_type The name of service type, e.g. "std_srvs/srv/SetBool".
* \param[in] callback The callback to call when the service gets a request.
* \param[in] qos Quality of service profile for the service.
* \param[in] group Callback group to handle the reply to service calls.
* \return Shared pointer to the created service.
*/
template<typename NodeT, typename CallbackT>
typename rclcpp::GenericService::SharedPtr
create_generic_service(
NodeT node,
const std::string & service_name,
const std::string & service_type,
CallbackT && callback,
const rclcpp::QoS & qos,
rclcpp::CallbackGroup::SharedPtr group)
{
return create_generic_service<CallbackT>(
rclcpp::node_interfaces::get_node_base_interface(node),
rclcpp::node_interfaces::get_node_services_interface(node),
service_name,
service_type,
std::forward<CallbackT>(callback), qos.get_rmw_qos_profile(), group);
}
} // namespace rclcpp
#endif // RCLCPP__CREATE_GENERIC_SERVICE_HPP_

View File

@@ -1,175 +0,0 @@
// Copyright 2022 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__DYNAMIC_SUBSCRIPTION_HPP_
#define RCLCPP__DYNAMIC_SUBSCRIPTION_HPP_
#include <rosidl_dynamic_typesupport/identifier.h>
#include <functional>
#include <memory>
#include <string>
#include "rcpputils/shared_library.hpp"
#include "rclcpp/callback_group.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_message_type_support.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/serialized_message.hpp"
#include "rclcpp/subscription_base.hpp"
#include "rclcpp/typesupport_helpers.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
/// %Subscription for messages whose type descriptions are obtained at runtime.
/**
* Since the type is not known at compile time, this is not a template, and the dynamic library
* containing type support information has to be identified and loaded based on the type name.
*
* NOTE(methylDragon): No considerations for intra-process handling are made.
*/
class DynamicSubscription : public rclcpp::SubscriptionBase
{
public:
// cppcheck-suppress unknownMacro
RCLCPP_SMART_PTR_DEFINITIONS(DynamicSubscription)
template<typename AllocatorT = std::allocator<void>>
DynamicSubscription(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
rclcpp::dynamic_typesupport::DynamicMessageTypeSupport::SharedPtr type_support,
const std::string & topic_name,
const rclcpp::QoS & qos,
std::function<void(
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr,
const rosidl_runtime_c__type_description__TypeDescription &
)> callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options)
: SubscriptionBase(
node_base,
type_support->get_const_rosidl_message_type_support(),
topic_name,
options.to_rcl_subscription_options(
qos),
options.event_callbacks,
options.use_default_callbacks,
DeliveredMessageKind::DYNAMIC_MESSAGE),
ts_(type_support),
callback_(callback),
serialization_support_(nullptr),
dynamic_message_(nullptr),
dynamic_message_type_(nullptr)
{
if (!type_support) {
throw std::runtime_error("DynamicMessageTypeSupport cannot be nullptr!");
}
if (type_support->get_const_rosidl_message_type_support().typesupport_identifier !=
rosidl_get_dynamic_typesupport_identifier())
{
throw std::runtime_error(
"DynamicSubscription must use dynamic type introspection type support!");
}
serialization_support_ = type_support->get_shared_dynamic_serialization_support();
dynamic_message_type_ = type_support->get_shared_dynamic_message_type()->clone_shared();
dynamic_message_ = type_support->get_shared_dynamic_message()->clone_shared();
}
// TODO(methylDragon):
/// Deferred type description constructor, only usable if the middleware implementation supports
/// type discovery
RCLCPP_PUBLIC
virtual ~DynamicSubscription() = default;
// Same as create_serialized_message() as the subscription is to serialized_messages only
RCLCPP_PUBLIC
std::shared_ptr<void> create_message() override;
RCLCPP_PUBLIC
std::shared_ptr<rclcpp::SerializedMessage> create_serialized_message() override;
/// Cast the message to a rclcpp::SerializedMessage and call the callback.
RCLCPP_PUBLIC
void handle_message(
std::shared_ptr<void> & message, const rclcpp::MessageInfo & message_info) override;
/// Handle dispatching rclcpp::SerializedMessage to user callback.
RCLCPP_PUBLIC
void
handle_serialized_message(
const std::shared_ptr<rclcpp::SerializedMessage> & serialized_message,
const rclcpp::MessageInfo & message_info) override;
/// This function is currently not implemented.
RCLCPP_PUBLIC
void handle_loaned_message(
void * loaned_message, const rclcpp::MessageInfo & message_info) override;
// Same as return_serialized_message() as the subscription is to serialized_messages only
RCLCPP_PUBLIC
void return_message(std::shared_ptr<void> & message) override;
RCLCPP_PUBLIC
void return_serialized_message(std::shared_ptr<rclcpp::SerializedMessage> & message) override;
// DYNAMIC TYPE ==================================================================================
// TODO(methylDragon): Reorder later
RCLCPP_PUBLIC
rclcpp::dynamic_typesupport::DynamicMessageType::SharedPtr
get_shared_dynamic_message_type() override;
RCLCPP_PUBLIC
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr get_shared_dynamic_message() override;
RCLCPP_PUBLIC
rclcpp::dynamic_typesupport::DynamicSerializationSupport::SharedPtr
get_shared_dynamic_serialization_support() override;
RCLCPP_PUBLIC
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr create_dynamic_message() override;
RCLCPP_PUBLIC
void return_dynamic_message(
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message) override;
RCLCPP_PUBLIC
void handle_dynamic_message(
const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
const rclcpp::MessageInfo & message_info) override;
private:
RCLCPP_DISABLE_COPY(DynamicSubscription)
rclcpp::dynamic_typesupport::DynamicMessageTypeSupport::SharedPtr ts_;
std::function<void(
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr,
const rosidl_runtime_c__type_description__TypeDescription &
)> callback_;
rclcpp::dynamic_typesupport::DynamicSerializationSupport::SharedPtr serialization_support_;
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr dynamic_message_;
rclcpp::dynamic_typesupport::DynamicMessageType::SharedPtr dynamic_message_type_;
};
} // namespace rclcpp
#endif // RCLCPP__DYNAMIC_SUBSCRIPTION_HPP_

View File

@@ -1,327 +0,0 @@
// Copyright 2023 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_IMPL_HPP_
#define RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_IMPL_HPP_
#include <rosidl_dynamic_typesupport/types.h>
#include <rosidl_dynamic_typesupport/api/dynamic_data.h>
#include <cstdint>
#include <cstddef>
#include <memory>
#include <string>
#include "rclcpp/exceptions.hpp"
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_HPP_
#include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
#endif
#define __DYNAMIC_MESSAGE_GET_VALUE_BY_ID_FN(ValueT, FunctionT) \
template<> \
ValueT \
DynamicMessage::get_value<ValueT>(rosidl_dynamic_typesupport_member_id_t id) \
{ \
ValueT out; \
rosidl_dynamic_typesupport_dynamic_data_get_ ## FunctionT ## _value( \
&rosidl_dynamic_data_, id, &out); \
return out; \
}
#define __DYNAMIC_MESSAGE_GET_VALUE_BY_NAME_FN(ValueT, FunctionT) \
template<> \
ValueT \
DynamicMessage::get_value<ValueT>(const std::string & name) \
{ \
return get_value<ValueT>(get_member_id(name)); \
}
#define __DYNAMIC_MESSAGE_SET_VALUE_BY_ID_FN(ValueT, FunctionT) \
template<> \
void \
DynamicMessage::set_value<ValueT>(rosidl_dynamic_typesupport_member_id_t id, ValueT value) \
{ \
rosidl_dynamic_typesupport_dynamic_data_set_ ## FunctionT ## _value( \
&rosidl_dynamic_data_, id, value); \
}
#define __DYNAMIC_MESSAGE_SET_VALUE_BY_NAME_FN(ValueT, FunctionT) \
template<> \
void \
DynamicMessage::set_value<ValueT>(const std::string & name, ValueT value) \
{ \
set_value<ValueT>(get_member_id(name), value); \
}
#define __DYNAMIC_MESSAGE_INSERT_VALUE(ValueT, FunctionT) \
template<> \
rosidl_dynamic_typesupport_member_id_t \
DynamicMessage::insert_value<ValueT>(ValueT value) \
{ \
rosidl_dynamic_typesupport_member_id_t out; \
rosidl_dynamic_typesupport_dynamic_data_insert_ ## FunctionT ## _value( \
&rosidl_dynamic_data_, value, &out); \
return out; \
}
#define DYNAMIC_MESSAGE_DEFINITIONS(ValueT, FunctionT) \
__DYNAMIC_MESSAGE_GET_VALUE_BY_ID_FN(ValueT, FunctionT) \
__DYNAMIC_MESSAGE_GET_VALUE_BY_NAME_FN(ValueT, FunctionT) \
__DYNAMIC_MESSAGE_SET_VALUE_BY_ID_FN(ValueT, FunctionT) \
__DYNAMIC_MESSAGE_SET_VALUE_BY_NAME_FN(ValueT, FunctionT) \
__DYNAMIC_MESSAGE_INSERT_VALUE(ValueT, FunctionT)
namespace rclcpp
{
namespace dynamic_typesupport
{
/**
* Since we're in a ROS layer, these should support all ROS interface C++ types as found in:
* https://docs.ros.org/en/rolling/Concepts/About-ROS-Interfaces.html
*
* Explicitly:
* - Basic types: bool, byte, char
* - Float types: float, double
* - Int types: int8_t, int16_t, int32_t, int64_t
* - Unsigned int types: uint8_t, uint16_t, uint32_t, uint64_t
* - String types: std::string, std::u16string
*/
DYNAMIC_MESSAGE_DEFINITIONS(bool, bool);
// DYNAMIC_MESSAGE_DEFINITIONS(std::byte, byte);
DYNAMIC_MESSAGE_DEFINITIONS(char, char);
DYNAMIC_MESSAGE_DEFINITIONS(float, float32);
DYNAMIC_MESSAGE_DEFINITIONS(double, float64);
DYNAMIC_MESSAGE_DEFINITIONS(int8_t, int8);
DYNAMIC_MESSAGE_DEFINITIONS(int16_t, int16);
DYNAMIC_MESSAGE_DEFINITIONS(int32_t, int32);
DYNAMIC_MESSAGE_DEFINITIONS(int64_t, int64);
DYNAMIC_MESSAGE_DEFINITIONS(uint8_t, uint8);
DYNAMIC_MESSAGE_DEFINITIONS(uint16_t, uint16);
DYNAMIC_MESSAGE_DEFINITIONS(uint32_t, uint32);
DYNAMIC_MESSAGE_DEFINITIONS(uint64_t, uint64);
// DYNAMIC_MESSAGE_DEFINITIONS(std::string, std::string);
// DYNAMIC_MESSAGE_DEFINITIONS(std::u16string, std::u16string);
// Byte and String getters have a different implementation and are defined below
// BYTE ============================================================================================
template<>
std::byte
DynamicMessage::get_value<std::byte>(rosidl_dynamic_typesupport_member_id_t id)
{
unsigned char out;
rosidl_dynamic_typesupport_dynamic_data_get_byte_value(&get_rosidl_dynamic_data(), id, &out);
return static_cast<std::byte>(out);
}
template<>
std::byte
DynamicMessage::get_value<std::byte>(const std::string & name)
{
return get_value<std::byte>(get_member_id(name));
}
template<>
void
DynamicMessage::set_value<std::byte>(
rosidl_dynamic_typesupport_member_id_t id, const std::byte value)
{
rosidl_dynamic_typesupport_dynamic_data_set_byte_value(
&rosidl_dynamic_data_, id, static_cast<unsigned char>(value));
}
template<>
void
DynamicMessage::set_value<std::byte>(const std::string & name, const std::byte value)
{
set_value<std::byte>(get_member_id(name), value);
}
template<>
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::insert_value<std::byte>(const std::byte value)
{
rosidl_dynamic_typesupport_member_id_t out;
rosidl_dynamic_typesupport_dynamic_data_insert_byte_value(
&rosidl_dynamic_data_, static_cast<unsigned char>(value), &out);
return out;
}
// STRINGS =========================================================================================
template<>
std::string
DynamicMessage::get_value<std::string>(rosidl_dynamic_typesupport_member_id_t id)
{
size_t buf_length;
char * buf = nullptr;
rosidl_dynamic_typesupport_dynamic_data_get_string_value(
&get_rosidl_dynamic_data(), id, &buf, &buf_length);
auto out = std::string(buf, buf_length);
delete buf;
return out;
}
template<>
std::u16string
DynamicMessage::get_value<std::u16string>(rosidl_dynamic_typesupport_member_id_t id)
{
size_t buf_length;
char16_t * buf = nullptr;
rosidl_dynamic_typesupport_dynamic_data_get_wstring_value(
&get_rosidl_dynamic_data(), id, &buf, &buf_length);
auto out = std::u16string(buf, buf_length);
delete buf;
return out;
}
template<>
std::string
DynamicMessage::get_value<std::string>(const std::string & name)
{
return get_value<std::string>(get_member_id(name));
}
template<>
std::u16string
DynamicMessage::get_value<std::u16string>(const std::string & name)
{
return get_value<std::u16string>(get_member_id(name));
}
template<>
void
DynamicMessage::set_value<std::string>(
rosidl_dynamic_typesupport_member_id_t id, const std::string value)
{
rosidl_dynamic_typesupport_dynamic_data_set_string_value(
&rosidl_dynamic_data_, id, value.c_str(), value.size());
}
template<>
void
DynamicMessage::set_value<std::u16string>(
rosidl_dynamic_typesupport_member_id_t id, const std::u16string value)
{
rosidl_dynamic_typesupport_dynamic_data_set_wstring_value(
&rosidl_dynamic_data_, id, value.c_str(), value.size());
}
template<>
void
DynamicMessage::set_value<std::string>(const std::string & name, const std::string value)
{
set_value<std::string>(get_member_id(name), value);
}
template<>
void
DynamicMessage::set_value<std::u16string>(const std::string & name, const std::u16string value)
{
set_value<std::u16string>(get_member_id(name), value);
}
template<>
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::insert_value<std::string>(const std::string value)
{
rosidl_dynamic_typesupport_member_id_t out;
rosidl_dynamic_typesupport_dynamic_data_insert_string_value(
&rosidl_dynamic_data_, value.c_str(), value.size(), &out);
return out;
}
template<>
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::insert_value<std::u16string>(const std::u16string value)
{
rosidl_dynamic_typesupport_member_id_t out;
rosidl_dynamic_typesupport_dynamic_data_insert_wstring_value(
&rosidl_dynamic_data_, value.c_str(), value.size(), &out);
return out;
}
// THROW FOR UNSUPPORTED TYPES =====================================================================
template<typename ValueT>
ValueT
DynamicMessage::get_value(rosidl_dynamic_typesupport_member_id_t id)
{
throw rclcpp::exceptions::UnimplementedError("get_value is not implemented for input type");
}
template<typename ValueT>
ValueT
DynamicMessage::get_value(const std::string & name)
{
throw rclcpp::exceptions::UnimplementedError("get_value is not implemented for input type");
}
template<typename ValueT>
void
DynamicMessage::set_value(
rosidl_dynamic_typesupport_member_id_t id, ValueT value)
{
throw rclcpp::exceptions::UnimplementedError("set_value is not implemented for input type");
}
template<typename ValueT>
void
DynamicMessage::set_value(const std::string & name, ValueT value)
{
throw rclcpp::exceptions::UnimplementedError("set_value is not implemented for input type");
}
template<typename ValueT>
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::insert_value(ValueT value)
{
throw rclcpp::exceptions::UnimplementedError("insert_value is not implemented for input type");
}
} // namespace dynamic_typesupport
} // namespace rclcpp
#undef __DYNAMIC_MESSAGE_GET_VALUE_BY_ID_FN
#undef __DYNAMIC_MESSAGE_GET_VALUE_BY_NAME_FN
#undef __DYNAMIC_MESSAGE_SET_VALUE_BY_ID_FN
#undef __DYNAMIC_MESSAGE_SET_VALUE_BY_NAME_FN
#undef __DYNAMIC_MESSAGE_INSERT_VALUE
#undef DYNAMIC_MESSAGE_DEFINITIONS
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_IMPL_HPP_

View File

@@ -1,189 +0,0 @@
// Copyright 2023 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_TYPE_BUILDER_IMPL_HPP_
#define RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_TYPE_BUILDER_IMPL_HPP_
#include <rosidl_dynamic_typesupport/types.h>
#include <rosidl_dynamic_typesupport/api/dynamic_type.h>
#include <cstdint>
#include <cstddef>
#include <memory>
#include <string>
#include "rclcpp/exceptions.hpp"
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_BUILDER_HPP_
#include "rclcpp/dynamic_typesupport/dynamic_message_type_builder.hpp"
#endif
#define __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_MEMBER_FN(MemberT, FunctionT) \
template<> \
void \
DynamicMessageTypeBuilder::add_member<MemberT>( \
rosidl_dynamic_typesupport_member_id_t id, \
const std::string & name, \
const std::string & default_value) \
{ \
rosidl_dynamic_typesupport_dynamic_type_builder_add_ ## FunctionT ## _member( \
&rosidl_dynamic_type_builder_, \
id, name.c_str(), name.size(), default_value.c_str(), default_value.size()); \
}
#define __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_ARRAY_MEMBER_FN(MemberT, FunctionT) \
template<> \
void \
DynamicMessageTypeBuilder::add_array_member<MemberT>( \
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, \
size_t array_length, \
const std::string & default_value) \
{ \
rosidl_dynamic_typesupport_dynamic_type_builder_add_ ## FunctionT ## _array_member( \
&rosidl_dynamic_type_builder_, \
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(), \
array_length); \
}
#define __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_UNBOUNDED_SEQUENCE_MEMBER_FN(MemberT, FunctionT) \
template<> \
void \
DynamicMessageTypeBuilder::add_unbounded_sequence_member<MemberT>( \
rosidl_dynamic_typesupport_member_id_t id, \
const std::string & name, \
const std::string & default_value) \
{ \
rosidl_dynamic_typesupport_dynamic_type_builder_add_ ## FunctionT ## \
_unbounded_sequence_member( \
&rosidl_dynamic_type_builder_, \
id, name.c_str(), name.size(), default_value.c_str(), default_value.size()); \
}
#define __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_BOUNDED_SEQUENCE_MEMBER_FN(MemberT, FunctionT) \
template<> \
void \
DynamicMessageTypeBuilder::add_bounded_sequence_member<MemberT>( \
rosidl_dynamic_typesupport_member_id_t id, \
const std::string & name, \
size_t sequence_bound, \
const std::string & default_value) \
{ \
rosidl_dynamic_typesupport_dynamic_type_builder_add_ ## FunctionT ## _bounded_sequence_member( \
&rosidl_dynamic_type_builder_, \
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(), \
sequence_bound); \
}
#define DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(MemberT, FunctionT) \
__DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_MEMBER_FN(MemberT, FunctionT) \
__DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_ARRAY_MEMBER_FN(MemberT, FunctionT) \
__DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_UNBOUNDED_SEQUENCE_MEMBER_FN(MemberT, FunctionT) \
__DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_BOUNDED_SEQUENCE_MEMBER_FN(MemberT, FunctionT) \
namespace rclcpp
{
namespace dynamic_typesupport
{
/**
* Since we're in a ROS layer, these should support all ROS interface C++ types as found in:
* https://docs.ros.org/en/rolling/Concepts/About-ROS-Interfaces.html
*
* Explicitly:
* - Basic types: bool, byte, char
* - Float types: float, double
* - Int types: int8_t, int16_t, int32_t, int64_t
* - Unsigned int types: uint8_t, uint16_t, uint32_t, uint64_t
* - String types: std::string, std::u16string
*/
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(bool, bool);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(std::byte, byte);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(char, char);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(float, float32);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(double, float64);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(int8_t, int8);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(int16_t, int16);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(int32_t, int32);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(int64_t, int64);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(uint8_t, uint8);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(uint16_t, uint16);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(uint32_t, uint32);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(uint64_t, uint64);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(std::string, string);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(std::u16string, wstring);
// THROW FOR UNSUPPORTED TYPES =====================================================================
template<typename MemberT>
void
DynamicMessageTypeBuilder::add_member(
rosidl_dynamic_typesupport_member_id_t id,
const std::string & name,
const std::string & default_value)
{
throw rclcpp::exceptions::UnimplementedError(
"add_member is not implemented for input type");
}
template<typename MemberT>
void
DynamicMessageTypeBuilder::add_array_member(
rosidl_dynamic_typesupport_member_id_t id,
const std::string & name,
size_t array_length, const std::string & default_value)
{
throw rclcpp::exceptions::UnimplementedError(
"add_array_member is not implemented for input type");
}
template<typename MemberT>
void
DynamicMessageTypeBuilder::add_unbounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id,
const std::string & name,
const std::string & default_value)
{
throw rclcpp::exceptions::UnimplementedError(
"add_unbounded_sequence_member is not implemented for input type");
}
template<typename MemberT>
void
DynamicMessageTypeBuilder::add_bounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id,
const std::string & name,
size_t sequence_bound,
const std::string & default_value)
{
throw rclcpp::exceptions::UnimplementedError(
"add_bounded_sequence_member is not implemented for input type");
}
} // namespace dynamic_typesupport
} // namespace rclcpp
#undef __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_MEMBER_FN
#undef __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_ARRAY_MEMBER_FN
#undef __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_UNBOUNDED_SEQUENCE_MEMBER_FN
#undef __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_BOUNDED_SEQUENCE_MEMBER_FN
#undef DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_TYPE_BUILDER_IMPL_HPP_

View File

@@ -32,372 +32,16 @@ namespace rclcpp
namespace dynamic_typesupport
{
class DynamicMessageType;
class DynamicMessageTypeBuilder;
/// Utility wrapper class for rosidl_dynamic_typesupport_dynamic_data_t
/**
* This class:
* - Exposes getter methods for the struct
* - Exposes the underlying serialization support API
*
* Ownership:
* - This class borrows the rosidl_dynamic_typesupport_serialization_support_t stored in the passed
* DynamicSerializationSupport. So it cannot outlive the DynamicSerializationSupport.
* - The DynamicSerializationSupport's rosidl_dynamic_typesupport_serialization_support_t pointer
* must point to the same location in memory as the stored raw pointer!
*
* Note: This class is meant to map to the lower level rosidl_dynamic_typesupport_dynamic_data_t,
* even though rosidl_dynamic_typesupport_dynamic_data_t is equivalent to
* rosidl_dynamic_typesupport_dynamic_data_t, exposing the fundamental methods available to
* rosidl_dynamic_typesupport_dynamic_data_t, allowing the user to access the data's fields.
*/
/// STUBBED OUT
class DynamicMessage : public std::enable_shared_from_this<DynamicMessage>
{
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicMessage)
// CONSTRUCTION ==================================================================================
// Most constructors require a passed in DynamicSerializationSupport::SharedPtr, to extend the
// lifetime of the serialization support (if the constructor cannot otherwise get it from args).
//
// In cases where a dynamic data pointer is passed, the serialization support composed by
// the data should be the exact same object managed by the DynamicSerializationSupport,
// otherwise the lifetime management will not work properly.
/// Construct a new DynamicMessage with the provided dynamic type builder, using its allocator
RCLCPP_PUBLIC
explicit DynamicMessage(std::shared_ptr<DynamicMessageTypeBuilder> dynamic_type_builder);
/// Construct a new DynamicMessage with the provided dynamic type builder and allocator
RCLCPP_PUBLIC
DynamicMessage(
std::shared_ptr<DynamicMessageTypeBuilder> dynamic_type_builder,
rcl_allocator_t allocator);
/// Construct a new DynamicMessage with the provided dynamic type, using its allocator
RCLCPP_PUBLIC
explicit DynamicMessage(std::shared_ptr<DynamicMessageType> dynamic_type);
/// Construct a new DynamicMessage with the provided dynamic type and allocator
RCLCPP_PUBLIC
DynamicMessage(
std::shared_ptr<DynamicMessageType> dynamic_type,
rcl_allocator_t allocator);
/// Assume ownership of struct
RCLCPP_PUBLIC
DynamicMessage(
DynamicSerializationSupport::SharedPtr serialization_support,
rosidl_dynamic_typesupport_dynamic_data_t && rosidl_dynamic_data);
/// Loaning constructor
/// Must only be called with a rosidl dynaimc data object obtained from loaning!
// NOTE(methylDragon): I'd put this in protected, but I need this exposed to
// enable_shared_from_this...
RCLCPP_PUBLIC
DynamicMessage(
DynamicMessage::SharedPtr parent_data,
rosidl_dynamic_typesupport_dynamic_data_t && rosidl_loaned_data);
// NOTE(methylDragon): Deliberately no constructor from description to nudge users towards using
// construction from dynamic type/builder, which is more efficient
/// Move constructor
RCLCPP_PUBLIC
DynamicMessage(DynamicMessage && other) noexcept;
/// Move assignment
RCLCPP_PUBLIC
DynamicMessage & operator=(DynamicMessage && other) noexcept;
RCLCPP_PUBLIC
virtual ~DynamicMessage();
// GETTERS =======================================================================================
RCLCPP_PUBLIC
const std::string
get_serialization_library_identifier() const;
RCLCPP_PUBLIC
const std::string
get_name() const;
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_dynamic_data_t &
get_rosidl_dynamic_data();
RCLCPP_PUBLIC
const rosidl_dynamic_typesupport_dynamic_data_t &
get_rosidl_dynamic_data() const;
RCLCPP_PUBLIC
DynamicSerializationSupport::SharedPtr
get_shared_dynamic_serialization_support();
RCLCPP_PUBLIC
DynamicSerializationSupport::ConstSharedPtr
get_shared_dynamic_serialization_support() const;
RCLCPP_PUBLIC
size_t
get_item_count() const;
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_member_id_t
get_member_id(size_t index) const;
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_member_id_t
get_member_id(const std::string & name) const;
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_member_id_t
get_array_index(size_t index) const;
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_member_id_t
get_array_index(const std::string & name) const;
// METHODS =======================================================================================
RCLCPP_PUBLIC
DynamicMessage
clone(rcl_allocator_t allocator = rcl_get_default_allocator());
RCLCPP_PUBLIC
DynamicMessage::SharedPtr
clone_shared(rcl_allocator_t allocator = rcl_get_default_allocator());
RCLCPP_PUBLIC
DynamicMessage
init_from_type(
DynamicMessageType & type, rcl_allocator_t allocator = rcl_get_default_allocator()) const;
RCLCPP_PUBLIC
DynamicMessage::SharedPtr
init_from_type_shared(
DynamicMessageType & type, rcl_allocator_t allocator = rcl_get_default_allocator()) const;
RCLCPP_PUBLIC
bool
equals(const DynamicMessage & other) const;
RCLCPP_PUBLIC
DynamicMessage::SharedPtr
loan_value(
rosidl_dynamic_typesupport_member_id_t id,
rcl_allocator_t allocator = rcl_get_default_allocator());
RCLCPP_PUBLIC
DynamicMessage::SharedPtr
loan_value(
const std::string & name,
rcl_allocator_t allocator = rcl_get_default_allocator());
RCLCPP_PUBLIC
void
clear_all_values();
RCLCPP_PUBLIC
void
clear_nonkey_values();
RCLCPP_PUBLIC
void
clear_value(rosidl_dynamic_typesupport_member_id_t id);
RCLCPP_PUBLIC
void
clear_value(const std::string & name);
RCLCPP_PUBLIC
void
clear_sequence();
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_member_id_t
insert_sequence_data();
RCLCPP_PUBLIC
void
remove_sequence_data(rosidl_dynamic_typesupport_member_id_t index);
RCLCPP_PUBLIC
bool
serialize(rcl_serialized_message_t & buffer);
RCLCPP_PUBLIC
bool
deserialize(rcl_serialized_message_t & buffer);
// MEMBER ACCESS TEMPLATES =======================================================================
/**
* Since we're in a ROS layer, these should support all ROS interface C++ types as found in:
* https://docs.ros.org/en/rolling/Concepts/About-ROS-Interfaces.html
*
* Explicitly:
* - Basic types: bool, byte, char
* - Float types: float, double
* - Int types: int8_t, int16_t, int32_t, int64_t
* - Unsigned int types: uint8_t, uint16_t, uint32_t, uint64_t
* - String types: std::string, std::u16string
*/
template<typename ValueT>
ValueT
get_value(rosidl_dynamic_typesupport_member_id_t id);
template<typename ValueT>
ValueT
get_value(const std::string & name);
template<typename ValueT>
void
set_value(rosidl_dynamic_typesupport_member_id_t id, ValueT value);
template<typename ValueT>
void
set_value(const std::string & name, ValueT value);
template<typename ValueT>
rosidl_dynamic_typesupport_member_id_t
insert_value(ValueT value);
// FIXED STRING MEMBER ACCESS ====================================================================
RCLCPP_PUBLIC
const std::string
get_fixed_string_value(rosidl_dynamic_typesupport_member_id_t id, size_t string_length);
RCLCPP_PUBLIC
const std::string
get_fixed_string_value(const std::string & name, size_t string_length);
RCLCPP_PUBLIC
const std::u16string
get_fixed_wstring_value(rosidl_dynamic_typesupport_member_id_t id, size_t wstring_length);
RCLCPP_PUBLIC
const std::u16string
get_fixed_wstring_value(const std::string & name, size_t wstring_length);
RCLCPP_PUBLIC
void
set_fixed_string_value(
rosidl_dynamic_typesupport_member_id_t id, const std::string value, size_t string_length);
RCLCPP_PUBLIC
void
set_fixed_string_value(const std::string & name, const std::string value, size_t string_length);
RCLCPP_PUBLIC
void
set_fixed_wstring_value(
rosidl_dynamic_typesupport_member_id_t id, const std::u16string value, size_t wstring_length);
RCLCPP_PUBLIC
void
set_fixed_wstring_value(
const std::string & name, const std::u16string value, size_t wstring_length);
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_member_id_t
insert_fixed_string_value(const std::string value, size_t string_length);
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_member_id_t
insert_fixed_wstring_value(const std::u16string value, size_t wstring_length);
// BOUNDED STRING MEMBER ACCESS ==================================================================
RCLCPP_PUBLIC
const std::string
get_bounded_string_value(rosidl_dynamic_typesupport_member_id_t id, size_t string_bound);
RCLCPP_PUBLIC
const std::string
get_bounded_string_value(const std::string & name, size_t string_bound);
RCLCPP_PUBLIC
const std::u16string
get_bounded_wstring_value(rosidl_dynamic_typesupport_member_id_t id, size_t wstring_bound);
RCLCPP_PUBLIC
const std::u16string
get_bounded_wstring_value(const std::string & name, size_t wstring_bound);
RCLCPP_PUBLIC
void
set_bounded_string_value(
rosidl_dynamic_typesupport_member_id_t id, const std::string value, size_t string_bound);
RCLCPP_PUBLIC
void
set_bounded_string_value(const std::string & name, const std::string value, size_t string_bound);
RCLCPP_PUBLIC
void
set_bounded_wstring_value(
rosidl_dynamic_typesupport_member_id_t id, const std::u16string value, size_t wstring_bound);
RCLCPP_PUBLIC
void
set_bounded_wstring_value(
const std::string & name, const std::u16string value, size_t wstring_bound);
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_member_id_t
insert_bounded_string_value(const std::string value, size_t string_bound);
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_member_id_t
insert_bounded_wstring_value(const std::u16string value, size_t wstring_bound);
// NESTED MEMBER ACCESS ==========================================================================
RCLCPP_PUBLIC
DynamicMessage
get_nested_data(
rosidl_dynamic_typesupport_member_id_t id,
rcl_allocator_t allocator = rcl_get_default_allocator());
RCLCPP_PUBLIC
DynamicMessage
get_nested_data(
const std::string & name,
rcl_allocator_t allocator = rcl_get_default_allocator());
RCLCPP_PUBLIC
DynamicMessage::SharedPtr
get_nested_data_shared(
rosidl_dynamic_typesupport_member_id_t id,
rcl_allocator_t allocator = rcl_get_default_allocator());
RCLCPP_PUBLIC
DynamicMessage::SharedPtr
get_nested_data_shared(
const std::string & name,
rcl_allocator_t allocator = rcl_get_default_allocator());
RCLCPP_PUBLIC
void
set_nested_data(rosidl_dynamic_typesupport_member_id_t id, DynamicMessage & value);
RCLCPP_PUBLIC
void
set_nested_data(const std::string & name, DynamicMessage & value);
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_member_id_t
insert_nested_data_copy(const DynamicMessage & value);
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_member_id_t
insert_nested_data(DynamicMessage & value);
protected:
// NOTE(methylDragon):
// This is just here to extend the lifetime of the serialization support
@@ -418,12 +62,6 @@ private:
RCLCPP_PUBLIC
DynamicMessage();
RCLCPP_PUBLIC
bool
match_serialization_support_(
const DynamicSerializationSupport & serialization_support,
const rosidl_dynamic_typesupport_dynamic_data_t & dynamic_data);
};
} // namespace dynamic_typesupport

View File

@@ -30,143 +30,16 @@ namespace rclcpp
namespace dynamic_typesupport
{
class DynamicMessage;
class DynamicMessageTypeBuilder;
/// Utility wrapper class for `rosidl_dynamic_typesupport_dynamic_type_t`
/**
* This class:
* - Exposes getter methods for the struct
* - Exposes the underlying serialization support API
*
* Ownership:
* - This class borrows the `rosidl_dynamic_typesupport_serialization_support_t` stored in the
* passed `DynamicSerializationSupport`.
* So it cannot outlive the `DynamicSerializationSupport`.
* - The `DynamicSerializationSupport`'s `rosidl_dynamic_typesupport_serialization_support_t`
* pointer must point to the same location in memory as the stored raw pointer!
*
* This class is meant to map to the lower level `rosidl_dynamic_typesupport_dynamic_type_t`,
* which can be constructed via `DynamicMessageTypeBuilder`, which maps to
* `rosidl_dynamic_typesupport_dynamic_type_builder_t`.
*
* The usual method of obtaining a `DynamicMessageType` is through construction of
* `rosidl_message_type_support_t` via `rcl_dynamic_message_type_support_handle_create()`, then
* taking ownership of its contents. But `DynamicMessageTypeBuilder` can also be used to obtain
* `DynamicMessageType` by constructing it bottom-up instead, since it exposes the lower_level
* rosidl methods.
*/
/// STUBBED OUT
class DynamicMessageType : public std::enable_shared_from_this<DynamicMessageType>
{
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicMessageType)
// CONSTRUCTION ==================================================================================
// Most constructors require a passed in `DynamicSerializationSupport::SharedPtr`, to extend the
// lifetime of the serialization support (if the constructor cannot otherwise get it from args).
//
// In cases where a dynamic type pointer is passed, the serialization support composed by
// the type should be the exact same object managed by the `DynamicSerializationSupport`,
// otherwise the lifetime management will not work properly.
/// Construct a new `DynamicMessageType` with the provided dynamic type builder,
/// using its allocator
RCLCPP_PUBLIC
explicit DynamicMessageType(std::shared_ptr<DynamicMessageTypeBuilder> dynamic_type_builder);
/// Construct a new `DynamicMessageType` with the provided dynamic type builder and allocator
RCLCPP_PUBLIC
DynamicMessageType(
std::shared_ptr<DynamicMessageTypeBuilder> dynamic_type_builder,
rcl_allocator_t allocator);
/// Assume ownership of struct
RCLCPP_PUBLIC
DynamicMessageType(
DynamicSerializationSupport::SharedPtr serialization_support,
rosidl_dynamic_typesupport_dynamic_type_t && rosidl_dynamic_type);
/// From description
RCLCPP_PUBLIC
DynamicMessageType(
DynamicSerializationSupport::SharedPtr serialization_support,
const rosidl_runtime_c__type_description__TypeDescription & description,
rcl_allocator_t allocator = rcl_get_default_allocator());
/// Move constructor
RCLCPP_PUBLIC
DynamicMessageType(DynamicMessageType && other) noexcept;
/// Move assignment
RCLCPP_PUBLIC
DynamicMessageType & operator=(DynamicMessageType && other) noexcept;
RCLCPP_PUBLIC
virtual ~DynamicMessageType();
/// Swaps the serialization support if `serialization_support` is populated
/**
* The user can call this with another description to reconfigure the type without changing the
* serialization support
*/
RCLCPP_PUBLIC
void
init_from_description(
const rosidl_runtime_c__type_description__TypeDescription & description,
rcl_allocator_t allocator = rcl_get_default_allocator(),
DynamicSerializationSupport::SharedPtr serialization_support = nullptr);
// GETTERS =======================================================================================
RCLCPP_PUBLIC
const std::string
get_serialization_library_identifier() const;
RCLCPP_PUBLIC
const std::string
get_name() const;
RCLCPP_PUBLIC
size_t
get_member_count() const;
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_dynamic_type_t &
get_rosidl_dynamic_type();
RCLCPP_PUBLIC
const rosidl_dynamic_typesupport_dynamic_type_t &
get_rosidl_dynamic_type() const;
RCLCPP_PUBLIC
DynamicSerializationSupport::SharedPtr
get_shared_dynamic_serialization_support();
RCLCPP_PUBLIC
DynamicSerializationSupport::ConstSharedPtr
get_shared_dynamic_serialization_support() const;
// METHODS =======================================================================================
RCLCPP_PUBLIC
DynamicMessageType
clone(rcl_allocator_t allocator = rcl_get_default_allocator());
RCLCPP_PUBLIC
DynamicMessageType::SharedPtr
clone_shared(rcl_allocator_t allocator = rcl_get_default_allocator());
RCLCPP_PUBLIC
bool
equals(const DynamicMessageType & other) const;
RCLCPP_PUBLIC
DynamicMessage
build_dynamic_message(rcl_allocator_t allocator = rcl_get_default_allocator());
RCLCPP_PUBLIC
std::shared_ptr<DynamicMessage>
build_dynamic_message_shared(rcl_allocator_t allocator = rcl_get_default_allocator());
protected:
// NOTE(methylDragon):
// This is just here to extend the lifetime of the serialization support
@@ -183,12 +56,6 @@ private:
RCLCPP_PUBLIC
DynamicMessageType();
RCLCPP_PUBLIC
bool
match_serialization_support_(
const DynamicSerializationSupport & serialization_support,
const rosidl_dynamic_typesupport_dynamic_type_t & rosidl_dynamic_type);
};
} // namespace dynamic_typesupport

View File

@@ -30,347 +30,16 @@ namespace rclcpp
namespace dynamic_typesupport
{
class DynamicMessage;
class DynamicMessageType;
/// Utility wrapper class for `rosidl_dynamic_typesupport_dynamic_type_builder_t *`
/**
* This class:
* - Manages the lifetime of the raw pointer.
* - Exposes getter methods to get the raw pointer and shared pointers
* - Exposes the underlying serialization support API
*
* Ownership:
* - This class borrows the rosidl_dynamic_typesupport_serialization_support_t stored in the passed
* `DynamicSerializationSupport`.
* So it cannot outlive the `DynamicSerializationSupport`.
* - The `DynamicSerializationSupport`'s `rosidl_dynamic_typesupport_serialization_support_t`
* pointer must point to the same location in memory as the stored raw pointer!
*
* This class is meant to map to rosidl_dynamic_typesupport_dynamic_type_builder_t, facilitating the
* construction of dynamic types bottom-up in the C++ layer.
*
* The usual method of obtaining a `DynamicMessageType` is through construction of
* `rosidl_message_type_support_t` via `rcl_dynamic_message_type_support_handle_create()`, then
* taking ownership of its contents.
* But `DynamicMessageTypeBuilder` can also be used to obtain `DynamicMessageType` by constructing
* it bottom-up instead, since it exposes the lower_level rosidl methods.
*/
/// STUBBED OUT
class DynamicMessageTypeBuilder : public std::enable_shared_from_this<DynamicMessageTypeBuilder>
{
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicMessageTypeBuilder)
// CONSTRUCTION ==================================================================================
// All constructors require a passed in `DynamicSerializationSupport::SharedPtr`, to extend the
// lifetime of the serialization support.
//
// In cases where a dynamic type builder pointer is passed, the serialization support composed by
// the builder should be the exact same object managed by the `DynamicSerializationSupport`,
// otherwise the lifetime management will not work properly.
/// Construct a new `DynamicMessageTypeBuilder` with the provided serialization support using its
/// allocator
RCLCPP_PUBLIC
DynamicMessageTypeBuilder(
DynamicSerializationSupport::SharedPtr serialization_support,
const std::string & name);
/// Construct a new `DynamicMessageTypeBuilder` with the provided serialization support and
/// allocator
RCLCPP_PUBLIC
DynamicMessageTypeBuilder(
DynamicSerializationSupport::SharedPtr serialization_support,
const std::string & name,
rcl_allocator_t allocator);
/// Assume ownership of struct
RCLCPP_PUBLIC
DynamicMessageTypeBuilder(
DynamicSerializationSupport::SharedPtr serialization_support,
rosidl_dynamic_typesupport_dynamic_type_builder_t && dynamic_type_builder);
/// From description
RCLCPP_PUBLIC
DynamicMessageTypeBuilder(
DynamicSerializationSupport::SharedPtr serialization_support,
const rosidl_runtime_c__type_description__TypeDescription & description,
rcl_allocator_t allocator = rcl_get_default_allocator());
/// Move constructor
RCLCPP_PUBLIC
DynamicMessageTypeBuilder(DynamicMessageTypeBuilder && other) noexcept;
/// Move assignment
RCLCPP_PUBLIC
DynamicMessageTypeBuilder & operator=(DynamicMessageTypeBuilder && other) noexcept;
RCLCPP_PUBLIC
virtual ~DynamicMessageTypeBuilder();
/// Swaps the serialization support if serialization_support is populated
/**
* The user can call this with another description to reconfigure the type without changing the
* serialization support
*/
RCLCPP_PUBLIC
void
init_from_description(
const rosidl_runtime_c__type_description__TypeDescription & description,
rcl_allocator_t allocator = rcl_get_default_allocator(),
DynamicSerializationSupport::SharedPtr serialization_support = nullptr);
// GETTERS =======================================================================================
RCLCPP_PUBLIC
const std::string
get_serialization_library_identifier() const;
RCLCPP_PUBLIC
const std::string
get_name() const;
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_dynamic_type_builder_t &
get_rosidl_dynamic_type_builder();
RCLCPP_PUBLIC
const rosidl_dynamic_typesupport_dynamic_type_builder_t &
get_rosidl_dynamic_type_builder() const;
RCLCPP_PUBLIC
DynamicSerializationSupport::SharedPtr
get_shared_dynamic_serialization_support();
RCLCPP_PUBLIC
DynamicSerializationSupport::ConstSharedPtr
get_shared_dynamic_serialization_support() const;
// METHODS =======================================================================================
RCLCPP_PUBLIC
void
set_name(const std::string & name);
RCLCPP_PUBLIC
DynamicMessageTypeBuilder
clone(rcl_allocator_t allocator = rcl_get_default_allocator());
RCLCPP_PUBLIC
DynamicMessageTypeBuilder::SharedPtr
clone_shared(rcl_allocator_t allocator = rcl_get_default_allocator());
RCLCPP_PUBLIC
void
clear(rcl_allocator_t allocator = rcl_get_default_allocator());
RCLCPP_PUBLIC
DynamicMessage
build_dynamic_message(rcl_allocator_t allocator = rcl_get_default_allocator());
RCLCPP_PUBLIC
DynamicMessage::SharedPtr
build_dynamic_message_shared(rcl_allocator_t allocator = rcl_get_default_allocator());
RCLCPP_PUBLIC
DynamicMessageType
build_dynamic_message_type(rcl_allocator_t allocator = rcl_get_default_allocator());
RCLCPP_PUBLIC
DynamicMessageType::SharedPtr
build_dynamic_message_type_shared(rcl_allocator_t allocator = rcl_get_default_allocator());
// ADD MEMBERS TEMPLATES =========================================================================
/**
* Since we're in a ROS layer, these should support all ROS interface C++ types as found in:
* https://docs.ros.org/en/rolling/Concepts/About-ROS-Interfaces.html
*
* Explicitly:
* - Basic types: bool, byte, char
* - Float types: float, double
* - Int types: int8_t, int16_t, int32_t, int64_t
* - Unsigned int types: uint8_t, uint16_t, uint32_t, uint64_t
* - String types: std::string, std::u16string
*/
template<typename MemberT>
void
add_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
const std::string & default_value = "");
template<typename MemberT>
void
add_array_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t array_length,
const std::string & default_value = "");
template<typename MemberT>
void
add_unbounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
const std::string & default_value = "");
template<typename MemberT>
void
add_bounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t sequence_bound,
const std::string & default_value = "");
// ADD FIXED STRING MEMBERS ======================================================================
RCLCPP_PUBLIC
void
add_fixed_string_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_length,
const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_fixed_wstring_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_length,
const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_fixed_string_array_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t string_length, size_t array_length, const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_fixed_wstring_array_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t wstring_length, size_t array_length, const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_fixed_string_unbounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_length,
const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_fixed_wstring_unbounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_length,
const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_fixed_string_bounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t string_length, size_t sequence_bound, const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_fixed_wstring_bounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t wstring_length, size_t sequence_bound, const std::string & default_value = "");
// ADD BOUNDED STRING MEMBERS ====================================================================
RCLCPP_PUBLIC
void
add_bounded_string_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_bound,
const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_bounded_wstring_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_bound,
const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_bounded_string_array_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t string_bound, size_t array_length, const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_bounded_wstring_array_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t wstring_bound, size_t array_length, const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_bounded_string_unbounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_bound,
const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_bounded_wstring_unbounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_bound,
const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_bounded_string_bounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t string_bound, size_t sequence_bound, const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_bounded_wstring_bounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t wstring_bound, size_t sequence_bound, const std::string & default_value = "");
// ADD NESTED MEMBERS ============================================================================
RCLCPP_PUBLIC
void
add_complex_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageType & nested_type, const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_complex_array_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageType & nested_type, size_t array_length, const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_complex_unbounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageType & nested_type, const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_complex_bounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageType & nested_type, size_t sequence_bound,
const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_complex_member_builder(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageTypeBuilder & nested_type_builder, const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_complex_array_member_builder(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageTypeBuilder & nested_type_builder, size_t array_length,
const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_complex_unbounded_sequence_member_builder(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageTypeBuilder & nested_type_builder, const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_complex_bounded_sequence_member_builder(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageTypeBuilder & nested_type_builder, size_t sequence_bound,
const std::string & default_value = "");
protected:
// NOTE(methylDragon):
// This is just here to extend the lifetime of the serialization support
@@ -387,19 +56,6 @@ private:
RCLCPP_PUBLIC
DynamicMessageTypeBuilder();
RCLCPP_PUBLIC
void
init_from_serialization_support_(
DynamicSerializationSupport::SharedPtr serialization_support,
const std::string & name,
rcl_allocator_t allocator);
RCLCPP_PUBLIC
bool
match_serialization_support_(
const DynamicSerializationSupport & serialization_support,
const rosidl_dynamic_typesupport_dynamic_type_builder_t & dynamic_type_builder);
};
} // namespace dynamic_typesupport

View File

@@ -38,115 +38,16 @@ namespace dynamic_typesupport
{
/// Utility wrapper class for `rosidl_message_type_support_t` containing managed
/// instances of the typesupport handle impl.
/**
*
* NOTE: This class is the recommended way to obtain the dynamic message type
* support struct, instead of `rcl_dynamic_message_type_support_handle_init()`,
* because this class will manage the lifetimes for you.
*
* Do NOT call rcl_dynamic_message_type_support_handle_fini
*
* This class:
* - Exposes getter methods for the struct
* - Stores shared pointers to wrapper classes that expose the underlying
* serialization support API
*
* Ownership:
* - This class, similarly to the `rosidl_dynamic_typesupport_serialization_support_t`, must outlive
* all downstream usages of the serialization support.
*/
/// STUBBED OUT
class DynamicMessageTypeSupport : public std::enable_shared_from_this<DynamicMessageTypeSupport>
{
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicMessageTypeSupport)
// CONSTRUCTION ==================================================================================
/// From description
/// Does NOT take ownership of the description (copies instead.)
/// Constructs type support top-down (calling `rcl_dynamic_message_type_support_handle_create()`)
RCLCPP_PUBLIC
DynamicMessageTypeSupport(
const rosidl_runtime_c__type_description__TypeDescription & description,
const std::string & serialization_library_name = "",
rcl_allocator_t allocator = rcl_get_default_allocator());
/// From description, for provided serialization support
/// Does NOT take ownership of the description (copies instead.)
/// Constructs type support top-down (calling `rosidl_dynamic_message_type_support_handle_init()`)
RCLCPP_PUBLIC
DynamicMessageTypeSupport(
DynamicSerializationSupport::SharedPtr serialization_support,
const rosidl_runtime_c__type_description__TypeDescription & description,
rcl_allocator_t allocator = rcl_get_default_allocator());
/// Assume ownership of managed types
/// Does NOT take ownership of the description (copies instead.)
///
/// The serialization support used to construct all managed SharedPtrs must match.
/// The structure of the provided `description` must match the `dynamic_message_type`
/// The structure of the provided `dynamic_message_type` must match the `dynamic_message
///
/// In this case, the user would have constructed the type support bototm-up (by creating the
/// respective dynamic members.)
RCLCPP_PUBLIC
DynamicMessageTypeSupport(
DynamicSerializationSupport::SharedPtr serialization_support,
DynamicMessageType::SharedPtr dynamic_message_type,
DynamicMessage::SharedPtr dynamic_message,
const rosidl_runtime_c__type_description__TypeDescription & description,
rcl_allocator_t allocator = rcl_get_default_allocator());
RCLCPP_PUBLIC
virtual ~DynamicMessageTypeSupport();
// GETTERS =======================================================================================
RCLCPP_PUBLIC
const std::string
get_serialization_library_identifier() const;
RCLCPP_PUBLIC
const rosidl_message_type_support_t &
get_const_rosidl_message_type_support();
RCLCPP_PUBLIC
const rosidl_message_type_support_t &
get_const_rosidl_message_type_support() const;
RCLCPP_PUBLIC
const rosidl_runtime_c__type_description__TypeDescription &
get_rosidl_runtime_c_type_description() const;
RCLCPP_PUBLIC
DynamicSerializationSupport::SharedPtr
get_shared_dynamic_serialization_support();
RCLCPP_PUBLIC
DynamicSerializationSupport::ConstSharedPtr
get_shared_dynamic_serialization_support() const;
RCLCPP_PUBLIC
DynamicMessageType::SharedPtr
get_shared_dynamic_message_type();
RCLCPP_PUBLIC
DynamicMessageType::ConstSharedPtr
get_shared_dynamic_message_type() const;
RCLCPP_PUBLIC
DynamicMessage::SharedPtr
get_shared_dynamic_message();
RCLCPP_PUBLIC
DynamicMessage::ConstSharedPtr
get_shared_dynamic_message() const;
protected:
RCLCPP_PUBLIC
rosidl_message_type_support_t &
get_rosidl_message_type_support();
DynamicSerializationSupport::SharedPtr serialization_support_;
DynamicMessageType::SharedPtr dynamic_message_type_;
DynamicMessage::SharedPtr dynamic_message_;

View File

@@ -31,60 +31,22 @@ namespace dynamic_typesupport
{
/// Utility wrapper class for rosidl_dynamic_typesupport_serialization_support_t
/**
* This class:
* - Exposes getter methods for the struct
* - Exposes the underlying serialization support API
*
* Ownership:
* - This class, similarly to the rosidl_dynamic_typesupport_serialization_support_t, must outlive
* all downstream usages of the serialization support.
*/
class DynamicSerializationSupport : public std::enable_shared_from_this<DynamicSerializationSupport>
{
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicSerializationSupport)
// CONSTRUCTION ==================================================================================
RCLCPP_PUBLIC
explicit DynamicSerializationSupport(rcl_allocator_t allocator = rcl_get_default_allocator());
/// Get the rmw middleware implementation specific serialization support (configured by name)
RCLCPP_PUBLIC
DynamicSerializationSupport(
const std::string & serialization_library_name,
rcl_allocator_t allocator = rcl_get_default_allocator());
/// Assume ownership of struct
RCLCPP_PUBLIC
explicit DynamicSerializationSupport(
rosidl_dynamic_typesupport_serialization_support_t && rosidl_serialization_support);
/// Move constructor
RCLCPP_PUBLIC
DynamicSerializationSupport(DynamicSerializationSupport && other) noexcept;
/// Move assignment
RCLCPP_PUBLIC
DynamicSerializationSupport & operator=(DynamicSerializationSupport && other) noexcept;
RCLCPP_PUBLIC
virtual ~DynamicSerializationSupport();
// GETTERS =======================================================================================
RCLCPP_PUBLIC
const std::string
get_serialization_library_identifier() const;
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_serialization_support_t &
get_rosidl_serialization_support();
RCLCPP_PUBLIC
const rosidl_dynamic_typesupport_serialization_support_t &
get_rosidl_serialization_support() const;
protected:
rosidl_dynamic_typesupport_serialization_support_t rosidl_serialization_support_;

View File

@@ -233,6 +233,8 @@ protected:
size_t wait_set_event_index_;
};
using QOSEventHandlerBase [[deprecated("Use rclcpp::EventHandlerBase")]] = EventHandlerBase;
template<typename EventCallbackT, typename ParentHandleT>
class EventHandler : public EventHandlerBase
{
@@ -309,6 +311,11 @@ private:
ParentHandleT parent_handle_;
EventCallbackT event_callback_;
};
template<typename EventCallbackT, typename ParentHandleT>
using QOSEventHandler [[deprecated("Use rclcpp::EventHandler")]] = EventHandler<EventCallbackT,
ParentHandleT>;
} // namespace rclcpp
#endif // RCLCPP__EVENT_HANDLER_HPP_

View File

@@ -100,15 +100,6 @@ public:
{}
};
class InvalidServiceTypeError : public std::runtime_error
{
public:
InvalidServiceTypeError()
: std::runtime_error("Service type is invalid.") {}
explicit InvalidServiceTypeError(const std::string & msg)
: std::runtime_error(msg) {}
};
class UnimplementedError : public std::runtime_error
{
public:

View File

@@ -541,9 +541,8 @@ protected:
*
* \param[in] notify if true will execute a trigger that will wake up a waiting executor
*/
RCLCPP_PUBLIC
virtual void
handle_updated_entities(bool notify);
void
trigger_entity_recollect(bool notify);
/// Spinning state, used to prevent multi threaded calls to spin and to cancel blocking spins.
std::atomic_bool spinning;

View File

@@ -122,14 +122,6 @@ public:
void
clear_on_ready_callback() override;
/// Set a new callback to be called whenever this waitable is executed.
/**
* \param[in] on_execute_callback The new callback
*/
RCLCPP_PUBLIC
void
set_execute_callback(std::function<void(void)> on_execute_callback);
/// Remove a guard condition from being waited on.
/**
* \param[in] weak_guard_condition The guard condition to remove.
@@ -150,10 +142,7 @@ private:
/// Callback to run when waitable executes
std::function<void(void)> execute_callback_;
/// Mutex to procetect the guard conditions
std::mutex guard_condition_mutex_;
/// Mutex to protect the execute callback
std::mutex execute_mutex_;
std::function<void(size_t)> on_ready_callback_;

View File

@@ -31,15 +31,9 @@ namespace executors
/// Static executor implementation
/**
* This executor is a static version of the original single threaded executor.
* It contains some performance optimization to avoid unnecessary reconstructions of
* the executable list for every iteration.
* It's static because it doesn't reconstruct the executable list for every iteration.
* All nodes, callbackgroups, timers, subscriptions etc. are created before
* spin() is called, and modified only when an entity is added/removed to/from a node.
* This executor is deprecated because these performance improvements have now been
* applied to all other executors.
* This executor is also considered unstable due to known bugs.
* See the unit-tests that are only applied to `StandardExecutors` for information
* on the known limitations.
*
* To run this executor instead of SingleThreadedExecutor replace:
* rclcpp::executors::SingleThreadedExecutor exec;
@@ -50,8 +44,7 @@ namespace executors
* exec.spin();
* exec.remove_node(node);
*/
class [[deprecated("Use rclcpp::executors::SingleThreadedExecutor")]] StaticSingleThreadedExecutor
: public rclcpp::Executor
class StaticSingleThreadedExecutor : public rclcpp::Executor
{
public:
RCLCPP_SMART_PTR_DEFINITIONS(StaticSingleThreadedExecutor)

View File

@@ -59,6 +59,8 @@ namespace executors
*/
class EventsExecutor : public rclcpp::Executor
{
friend class EventsExecutorEntitiesCollector;
public:
RCLCPP_SMART_PTR_DEFINITIONS(EventsExecutor)
@@ -70,7 +72,7 @@ public:
* \param[in] options Options used to configure the executor.
*/
RCLCPP_PUBLIC
EventsExecutor(
explicit EventsExecutor(
rclcpp::experimental::executors::EventsQueue::UniquePtr events_queue = std::make_unique<
rclcpp::experimental::executors::SimpleEventsQueue>(),
bool execute_timers_separate_thread = false,
@@ -126,6 +128,87 @@ public:
void
spin_all(std::chrono::nanoseconds max_duration) override;
/// Add a node to the executor.
/**
* \sa rclcpp::Executor::add_node
*/
RCLCPP_PUBLIC
void
add_node(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
bool notify = true) override;
/// Convenience function which takes Node and forwards NodeBaseInterface.
/**
* \sa rclcpp::EventsExecutor::add_node
*/
RCLCPP_PUBLIC
void
add_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify = true) override;
/// Remove a node from the executor.
/**
* \sa rclcpp::Executor::remove_node
*/
RCLCPP_PUBLIC
void
remove_node(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
bool notify = true) override;
/// Convenience function which takes Node and forwards NodeBaseInterface.
/**
* \sa rclcpp::Executor::remove_node
*/
RCLCPP_PUBLIC
void
remove_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify = true) override;
/// Add a callback group to an executor.
/**
* \sa rclcpp::Executor::add_callback_group
*/
RCLCPP_PUBLIC
void
add_callback_group(
rclcpp::CallbackGroup::SharedPtr group_ptr,
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
bool notify = true) override;
/// Remove callback group from the executor
/**
* \sa rclcpp::Executor::remove_callback_group
*/
RCLCPP_PUBLIC
void
remove_callback_group(
rclcpp::CallbackGroup::SharedPtr group_ptr,
bool notify = true) override;
/// Get callback groups that belong to executor.
/**
* \sa rclcpp::Executor::get_all_callback_groups()
*/
RCLCPP_PUBLIC
std::vector<rclcpp::CallbackGroup::WeakPtr>
get_all_callback_groups() override;
/// Get callback groups that belong to executor.
/**
* \sa rclcpp::Executor::get_manually_added_callback_groups()
*/
RCLCPP_PUBLIC
std::vector<rclcpp::CallbackGroup::WeakPtr>
get_manually_added_callback_groups() override;
/// Get callback groups that belong to executor.
/**
* \sa rclcpp::Executor::get_automatically_added_callback_groups_from_nodes()
*/
RCLCPP_PUBLIC
std::vector<rclcpp::CallbackGroup::WeakPtr>
get_automatically_added_callback_groups_from_nodes() override;
protected:
/// Internal implementation of spin_once
RCLCPP_PUBLIC
@@ -137,11 +220,6 @@ protected:
void
spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive);
/// Collect entities from callback groups and refresh the current collection with them
RCLCPP_PUBLIC
void
handle_updated_entities(bool notify) override;
private:
RCLCPP_DISABLE_COPY(EventsExecutor)
@@ -149,9 +227,9 @@ private:
void
execute_event(const ExecutorEvent & event);
/// Rebuilds the executor's notify waitable, as we can't use the one built in the base class
/// Collect entities from callback groups and refresh the current collection with them
void
setup_notify_waitable();
refresh_current_collection_from_callback_groups();
/// Refresh the current collection using the provided new_collection
void
@@ -175,11 +253,6 @@ private:
typename CollectionType::EntitySharedPtr
retrieve_entity(typename CollectionType::Key entity_id, CollectionType & collection)
{
// Note: we lock the mutex because we assume that you are trying to get an element from the
// current collection... If there will be a use-case to retrieve elements also from other
// collections, we can move the mutex back to the calling codes.
std::lock_guard<std::mutex> guard(mutex_);
// Check if the entity_id is in the collection
auto it = collection.find(entity_id);
if (it == collection.end()) {
@@ -200,6 +273,16 @@ private:
/// Queue where entities can push events
rclcpp::experimental::executors::EventsQueue::UniquePtr events_queue_;
std::shared_ptr<rclcpp::executors::ExecutorEntitiesCollector> entities_collector_;
std::shared_ptr<rclcpp::executors::ExecutorNotifyWaitable> notify_waitable_;
/// Mutex to protect the current_entities_collection_
std::recursive_mutex collection_mutex_;
std::shared_ptr<rclcpp::executors::ExecutorEntitiesCollection> current_entities_collection_;
/// Flag used to reduce the number of unnecessary waitable events
std::atomic<bool> notify_waitable_event_pushed_ {false};
/// Timers manager used to track and/or execute associated timers
std::shared_ptr<rclcpp::experimental::TimersManager> timers_manager_;
};

View File

@@ -19,7 +19,6 @@
#include <memory>
#include <future>
#include <string>
#include <tuple>
#include <vector>
#include <utility>
@@ -36,8 +35,8 @@ namespace rclcpp
class GenericClient : public ClientBase
{
public:
using Request = void *; // Deserialized data pointer of request message
using Response = void *; // Deserialized data pointer of response message
using Request = void *; // Serialized data pointer of request message
using Response = void *; // Serialized data pointer of response message
using SharedResponse = std::shared_ptr<void>;
@@ -47,8 +46,6 @@ public:
using Future = std::future<SharedResponse>;
using SharedFuture = std::shared_future<SharedResponse>;
using CallbackType = std::function<void (SharedFuture)>;
RCLCPP_SMART_PTR_DEFINITIONS(GenericClient)
/// A convenient GenericClient::Future and request id pair.
@@ -79,20 +76,6 @@ public:
~FutureAndRequestId() = default;
};
/// A convenient GenericClient::SharedFuture and request id pair.
/**
* Public members:
* - future: a std::shared_future<SharedResponse>.
* - request_id: the request id associated with the future.
*
* All the other methods are equivalent to the ones std::shared_future provides.
*/
struct SharedFutureAndRequestId
: detail::FutureAndRequestId<std::shared_future<SharedResponse>>
{
using detail::FutureAndRequestId<std::shared_future<SharedResponse>>::FutureAndRequestId;
};
GenericClient(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph,
@@ -123,16 +106,16 @@ public:
* If the future never completes,
* e.g. the call to Executor::spin_until_future_complete() times out,
* GenericClient::remove_pending_request() must be called to clean the client internal state.
* Not doing so will make the `GenericClient` instance to use more memory each time a response is
* not received from the service server.
* Not doing so will make the `Client` instance to use more memory each time a response is not
* received from the service server.
*
* ```cpp
* auto future = generic_client->async_send_request(my_request);
* auto future = client->async_send_request(my_request);
* if (
* rclcpp::FutureReturnCode::TIMEOUT ==
* executor->spin_until_future_complete(future, timeout))
* {
* generic_client->remove_pending_request(future);
* client->remove_pending_request(future);
* // handle timeout
* } else {
* handle_response(future.get());
@@ -146,45 +129,6 @@ public:
FutureAndRequestId
async_send_request(const Request request);
/// Send a request to the service server and schedule a callback in the executor.
/**
* Similar to the previous overload, but a callback will automatically be called when a response
* is received.
*
* If the callback is never called, because we never got a reply for the service server,
* remove_pending_request() has to be called with the returned request id or
* prune_pending_requests().
* Not doing so will make the `GenericClient` instance use more memory each time a response is not
* received from the service server.
* In this case, it's convenient to setup a timer to cleanup the pending requests.
*
* \param[in] request request to be send.
* \param[in] cb callback that will be called when we get a response for this request.
* \return the request id representing the request just sent.
*/
template<
typename CallbackT,
typename std::enable_if<
rclcpp::function_traits::same_arguments<
CallbackT,
CallbackType
>::value
>::type * = nullptr
>
SharedFutureAndRequestId
async_send_request(const Request request, CallbackT && cb)
{
Promise promise;
auto shared_future = promise.get_future().share();
auto req_id = async_send_request_impl(
request,
std::make_tuple(
CallbackType{std::forward<CallbackT>(cb)},
shared_future,
std::move(promise)));
return SharedFutureAndRequestId{std::move(shared_future), req_id};
}
/// Clean all pending requests older than a time_point.
/**
* \param[in] time_point Requests that were sent before this point are going to be removed.
@@ -205,52 +149,15 @@ public:
pruned_requests);
}
/// Clean all pending requests.
/**
* \return number of pending requests that were removed.
*/
RCLCPP_PUBLIC
size_t
prune_pending_requests();
/// Cleanup a pending request.
/**
* This notifies the client that we have waited long enough for a response from the server
* to come, we have given up and we are not waiting for a response anymore.
*
* Not calling this will make the client start using more memory for each request
* that never got a reply from the server.
*
* \param[in] request_id request id returned by async_send_request().
* \return true when a pending request was removed, false if not (e.g. a response was received).
*/
RCLCPP_PUBLIC
bool
remove_pending_request(
int64_t request_id);
/// Cleanup a pending request.
/**
* Convenient overload, same as:
*
* `GenericClient::remove_pending_request(this, future.request_id)`.
*/
RCLCPP_PUBLIC
bool
remove_pending_request(
const FutureAndRequestId & future);
/// Cleanup a pending request.
/**
* Convenient overload, same as:
*
* `GenericClient::remove_pending_request(this, future.request_id)`.
*/
RCLCPP_PUBLIC
bool
remove_pending_request(
const SharedFutureAndRequestId & future);
/// Take the next response for this client.
/**
* \sa ClientBase::take_type_erased_response().
@@ -272,12 +179,9 @@ public:
}
protected:
using CallbackTypeValueVariant = std::tuple<CallbackType, SharedFuture, Promise>;
using CallbackInfoVariant = std::variant<
std::promise<SharedResponse>,
CallbackTypeValueVariant>; // Use variant for extension
std::promise<SharedResponse>>; // Use variant for extension
RCLCPP_PUBLIC
int64_t
async_send_request_impl(
const Request request,

View File

@@ -1,308 +0,0 @@
// Copyright 2024 Sony Group Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__GENERIC_SERVICE_HPP_
#define RCLCPP__GENERIC_SERVICE_HPP_
#include <cstdlib>
#include <functional>
#include <memory>
#include <string>
#include <type_traits>
#include <utility>
#include <variant>
#include "rclcpp/typesupport_helpers.hpp"
#include "rosidl_runtime_c/service_type_support_struct.h"
#include "rosidl_typesupport_introspection_cpp/identifier.hpp"
#include "rosidl_typesupport_introspection_cpp/service_introspection.hpp"
#include "service.hpp"
namespace rclcpp
{
class GenericService;
class GenericServiceCallback
{
public:
using SharedRequest = std::shared_ptr<void>;
using SharedResponse = std::shared_ptr<void>;
GenericServiceCallback()
: callback_(std::monostate{})
{}
template<
typename CallbackT,
typename std::enable_if_t<!detail::can_be_nullptr<CallbackT>::value, int> = 0>
void
set(CallbackT && callback)
{
// Workaround Windows issue with std::bind
if constexpr (
rclcpp::function_traits::same_arguments<
CallbackT,
SharedPtrCallback
>::value)
{
callback_.template emplace<SharedPtrCallback>(callback);
} else if constexpr ( // NOLINT, can't satisfy both cpplint and uncrustify
rclcpp::function_traits::same_arguments<
CallbackT,
SharedPtrWithRequestHeaderCallback
>::value)
{
callback_.template emplace<SharedPtrWithRequestHeaderCallback>(callback);
} else if constexpr ( // NOLINT
rclcpp::function_traits::same_arguments<
CallbackT,
SharedPtrDeferResponseCallback
>::value)
{
callback_.template emplace<SharedPtrDeferResponseCallback>(callback);
} else if constexpr ( // NOLINT
rclcpp::function_traits::same_arguments<
CallbackT,
SharedPtrDeferResponseCallbackWithServiceHandle
>::value)
{
callback_.template emplace<SharedPtrDeferResponseCallbackWithServiceHandle>(callback);
} else {
// the else clause is not needed, but anyways we should only be doing this instead
// of all the above workaround ...
callback_ = std::forward<CallbackT>(callback);
}
}
template<
typename CallbackT,
typename std::enable_if_t<detail::can_be_nullptr<CallbackT>::value, int> = 0>
void
set(CallbackT && callback)
{
if (!callback) {
throw std::invalid_argument("AnyServiceCallback::set(): callback cannot be nullptr");
}
// Workaround Windows issue with std::bind
if constexpr (
rclcpp::function_traits::same_arguments<
CallbackT,
SharedPtrCallback
>::value)
{
callback_.template emplace<SharedPtrCallback>(callback);
} else if constexpr ( // NOLINT
rclcpp::function_traits::same_arguments<
CallbackT,
SharedPtrWithRequestHeaderCallback
>::value)
{
callback_.template emplace<SharedPtrWithRequestHeaderCallback>(callback);
} else if constexpr ( // NOLINT
rclcpp::function_traits::same_arguments<
CallbackT,
SharedPtrDeferResponseCallback
>::value)
{
callback_.template emplace<SharedPtrDeferResponseCallback>(callback);
} else if constexpr ( // NOLINT
rclcpp::function_traits::same_arguments<
CallbackT,
SharedPtrDeferResponseCallbackWithServiceHandle
>::value)
{
callback_.template emplace<SharedPtrDeferResponseCallbackWithServiceHandle>(callback);
} else {
// the else clause is not needed, but anyways we should only be doing this instead
// of all the above workaround ...
callback_ = std::forward<CallbackT>(callback);
}
}
SharedResponse
dispatch(
const std::shared_ptr<rclcpp::GenericService> & service_handle,
const std::shared_ptr<rmw_request_id_t> & request_header,
SharedRequest request,
SharedRequest response)
{
TRACETOOLS_TRACEPOINT(callback_start, static_cast<const void *>(this), false);
if (std::holds_alternative<std::monostate>(callback_)) {
// TODO(ivanpauno): Remove the set method, and force the users of this class
// to pass a callback at construnciton.
throw std::runtime_error{"unexpected request without any callback set"};
}
if (std::holds_alternative<SharedPtrDeferResponseCallback>(callback_)) {
const auto & cb = std::get<SharedPtrDeferResponseCallback>(callback_);
cb(request_header, std::move(request));
return nullptr;
}
if (std::holds_alternative<SharedPtrDeferResponseCallbackWithServiceHandle>(callback_)) {
const auto & cb = std::get<SharedPtrDeferResponseCallbackWithServiceHandle>(callback_);
cb(service_handle, request_header, std::move(request));
return nullptr;
}
if (std::holds_alternative<SharedPtrCallback>(callback_)) {
(void)request_header;
const auto & cb = std::get<SharedPtrCallback>(callback_);
cb(std::move(request), std::move(response));
} else if (std::holds_alternative<SharedPtrWithRequestHeaderCallback>(callback_)) {
const auto & cb = std::get<SharedPtrWithRequestHeaderCallback>(callback_);
cb(request_header, std::move(request), std::move(response));
}
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
return response;
}
void register_callback_for_tracing()
{
#ifndef TRACETOOLS_DISABLED
std::visit(
[this](auto && arg) {
if (TRACETOOLS_TRACEPOINT_ENABLED(rclcpp_callback_register)) {
char * symbol = tracetools::get_symbol(arg);
TRACETOOLS_DO_TRACEPOINT(
rclcpp_callback_register,
static_cast<const void *>(this),
symbol);
std::free(symbol);
}
}, callback_);
#endif // TRACETOOLS_DISABLED
}
private:
using SharedPtrCallback = std::function<void (SharedRequest, SharedResponse)>;
using SharedPtrWithRequestHeaderCallback = std::function<
void (
std::shared_ptr<rmw_request_id_t>,
SharedRequest,
SharedResponse
)>;
using SharedPtrDeferResponseCallback = std::function<
void (
std::shared_ptr<rmw_request_id_t>,
SharedRequest
)>;
using SharedPtrDeferResponseCallbackWithServiceHandle = std::function<
void (
std::shared_ptr<rclcpp::GenericService>,
std::shared_ptr<rmw_request_id_t>,
SharedRequest
)>;
std::variant<
std::monostate,
SharedPtrCallback,
SharedPtrWithRequestHeaderCallback,
SharedPtrDeferResponseCallback,
SharedPtrDeferResponseCallbackWithServiceHandle> callback_;
};
class GenericService
: public ServiceBase,
public std::enable_shared_from_this<GenericService>
{
public:
using Request = void *; // Serialized/Deserialized data pointer of request message
using Response = void *; // Serialized/Deserialized data pointer of response message
using SharedRequest = std::shared_ptr<void>;
using SharedResponse = std::shared_ptr<void>;
using CallbackType = std::function<void (const SharedRequest, SharedResponse)>;
using CallbackWithHeaderType =
std::function<void (const std::shared_ptr<rmw_request_id_t>,
const SharedRequest,
SharedResponse)>;
RCLCPP_SMART_PTR_DEFINITIONS(GenericService)
/// Default constructor.
/**
* The constructor for a Service is almost never called directly.
* Instead, services should be instantiated through the function
* rclcpp::create_service().
*
* \param[in] node_handle NodeBaseInterface pointer that is used in part of the setup.
* \param[in] service_name Name of the topic to publish to.
* \param[in] service_type The name of service type, e.g. "std_srvs/srv/SetBool".
* \param[in] any_callback User defined callback to call when a client request is received.
* \param[in] service_options options for the service.
*/
RCLCPP_PUBLIC
GenericService(
std::shared_ptr<rcl_node_t> node_handle,
const std::string & service_name,
const std::string & service_type,
GenericServiceCallback any_callback,
rcl_service_options_t & service_options);
GenericService() = delete;
RCLCPP_PUBLIC
virtual ~GenericService() {}
/// Take the next request from the service.
/**
* \sa ServiceBase::take_type_erased_request().
*
* \param[out] request_out The reference to a service deserialized request object
* into which the middleware will copy the taken request.
* \param[out] request_id_out The output id for the request which can be used
* to associate response with this request in the future.
* \returns true if the request was taken, otherwise false.
* \throws rclcpp::exceptions::RCLError based exceptions if the underlying
* rcl calls fail.
*/
RCLCPP_PUBLIC
bool
take_request(SharedRequest request_out, rmw_request_id_t & request_id_out);
RCLCPP_PUBLIC
std::shared_ptr<void>
create_request() override;
RCLCPP_PUBLIC
std::shared_ptr<void>
create_response();
RCLCPP_PUBLIC
std::shared_ptr<rmw_request_id_t>
create_request_header() override;
RCLCPP_PUBLIC
void
handle_request(
std::shared_ptr<rmw_request_id_t> request_header,
std::shared_ptr<void> request) override;
RCLCPP_PUBLIC
void
send_response(rmw_request_id_t & req_id, SharedResponse & response);
private:
RCLCPP_DISABLE_COPY(GenericService)
GenericServiceCallback any_callback_;
std::shared_ptr<rcpputils::SharedLibrary> ts_lib_;
const rosidl_typesupport_introspection_cpp::MessageMembers * request_members_;
const rosidl_typesupport_introspection_cpp::MessageMembers * response_members_;
};
} // namespace rclcpp
#endif // RCLCPP__GENERIC_SERVICE_HPP_

View File

@@ -31,20 +31,21 @@ namespace rclcpp
template<typename MessageT, typename AllocatorT = std::allocator<void>>
class LoanedMessage
{
public:
using MessageAllocatorTraits = rclcpp::allocator::AllocRebind<MessageT, AllocatorT>;
using MessageAllocator = typename MessageAllocatorTraits::allocator_type;
public:
/// Constructor of the LoanedMessage class.
/**
* The constructor of this class allocates memory for a given message type
* and associates this with a given publisher.
*
* The underlying middleware is queried to determine whether it is able to allocate the
* appropriate memory for this message type or not.
* In the case that the middleware cannot loan messages, the passed in allocator instance
* is used to allocate the message within the scope of this class.
* Otherwise, the allocator is ignored and the allocation is solely performed
* Given the publisher instance, a case differentiation is being performaned
* which decides whether the underlying middleware is able to allocate the appropriate
* memory for this message type or not.
* In the case that the middleware can not loan messages, the passed in allocator instance
* is being used to allocate the message within the scope of this class.
* Otherwise, the allocator is being ignored and the allocation is solely performaned
* in the underlying middleware with its appropriate allocation strategy.
* The need for this arises as the user code can be written explicitly targeting a middleware
* capable of loaning messages.
@@ -52,12 +53,12 @@ public:
* a middleware which doesn't support message loaning in which case the allocator will be used.
*
* \param[in] pub rclcpp::Publisher instance to which the memory belongs
* \param[in] allocator Allocator instance in case middleware cannot allocate messages
* \param[in] allocator Allocator instance in case middleware can not allocate messages
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw.
*/
LoanedMessage(
const rclcpp::PublisherBase & pub,
MessageAllocator allocator)
std::allocator<MessageT> allocator)
: pub_(pub),
message_(nullptr),
message_allocator_(std::move(allocator))
@@ -81,6 +82,36 @@ public:
}
}
/// Constructor of the LoanedMessage class.
/**
* The constructor of this class allocates memory for a given message type
* and associates this with a given publisher.
*
* Given the publisher instance, a case differentiation is being performaned
* which decides whether the underlying middleware is able to allocate the appropriate
* memory for this message type or not.
* In the case that the middleware can not loan messages, the passed in allocator instance
* is being used to allocate the message within the scope of this class.
* Otherwise, the allocator is being ignored and the allocation is solely performaned
* in the underlying middleware with its appropriate allocation strategy.
* The need for this arises as the user code can be written explicitly targeting a middleware
* capable of loaning messages.
* However, this user code is ought to be usable even when dynamically linked against
* a middleware which doesn't support message loaning in which case the allocator will be used.
*
* \param[in] pub rclcpp::Publisher instance to which the memory belongs
* \param[in] allocator Allocator instance in case middleware can not allocate messages
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw.
*/
[[
deprecated("used the LoanedMessage constructor that does not use a shared_ptr to the allocator")
]]
LoanedMessage(
const rclcpp::PublisherBase * pub,
std::shared_ptr<std::allocator<MessageT>> allocator)
: LoanedMessage(*pub, *allocator)
{}
/// Move semantic for RVO
LoanedMessage(LoanedMessage<MessageT> && other)
: pub_(std::move(other.pub_)),

View File

@@ -15,7 +15,6 @@
#ifndef RCLCPP__LOGGER_HPP_
#define RCLCPP__LOGGER_HPP_
#include <filesystem>
#include <memory>
#include <string>
#include <utility>
@@ -78,14 +77,6 @@ RCLCPP_PUBLIC
Logger
get_node_logger(const rcl_node_t * node);
// TODO(ahcorde): Remove deprecated class on the next release (in Rolling after Kilted).
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
/// Get the current logging directory.
/**
* For more details of how the logging directory is determined,
@@ -94,30 +85,10 @@ get_node_logger(const rcl_node_t * node);
* \returns the logging directory being used.
* \throws rclcpp::exceptions::RCLError if an unexpected error occurs.
*/
[[deprecated("use rclcpp::get_log_directory instead of rclcpp::get_logging_directory")]]
RCLCPP_PUBLIC
rcpputils::fs::path
get_logging_directory();
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
/// Get the current logging directory.
/**
* For more details of how the logging directory is determined,
* see rcl_logging_get_logging_directory().
*
* \returns the logging directory being used.
* \throws rclcpp::exceptions::RCLError if an unexpected error occurs.
*/
RCLCPP_PUBLIC
std::filesystem::path
get_log_directory();
class Logger
{
public:

View File

@@ -44,7 +44,6 @@
#include "rclcpp/event.hpp"
#include "rclcpp/generic_client.hpp"
#include "rclcpp/generic_publisher.hpp"
#include "rclcpp/generic_service.hpp"
#include "rclcpp/generic_subscription.hpp"
#include "rclcpp/logger.hpp"
#include "rclcpp/macros.hpp"
@@ -258,6 +257,22 @@ public:
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Create and return a Client.
/**
* \param[in] service_name The topic to service on.
* \param[in] qos_profile rmw_qos_profile_t Quality of service profile for client.
* \param[in] group Callback group to call the service.
* \return Shared pointer to the created client.
* \deprecated use rclcpp::QoS instead of rmw_qos_profile_t
*/
template<typename ServiceT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
typename rclcpp::Client<ServiceT>::SharedPtr
create_client(
const std::string & service_name,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Create and return a Client.
/**
* \param[in] service_name The name on which the service is accessible.
@@ -272,6 +287,24 @@ public:
const rclcpp::QoS & qos = rclcpp::ServicesQoS(),
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Create and return a Service.
/**
* \param[in] service_name The topic to service on.
* \param[in] callback User-defined callback function.
* \param[in] qos_profile rmw_qos_profile_t Quality of service profile for client.
* \param[in] group Callback group to call the service.
* \return Shared pointer to the created service.
* \deprecated use rclcpp::QoS instead of rmw_qos_profile_t
*/
template<typename ServiceT, typename CallbackT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
typename rclcpp::Service<ServiceT>::SharedPtr
create_service(
const std::string & service_name,
CallbackT && callback,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Create and return a Service.
/**
* \param[in] service_name The topic to service on.
@@ -304,24 +337,6 @@ public:
const rclcpp::QoS & qos = rclcpp::ServicesQoS(),
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Create and return a GenericService.
/**
* \param[in] service_name The topic to service on.
* \param[in] service_type The name of service type, e.g. "std_srvs/srv/SetBool"
* \param[in] callback User-defined callback function.
* \param[in] qos Quality of service profile for the service.
* \param[in] group Callback group to call the service.
* \return Shared pointer to the created service.
*/
template<typename CallbackT>
typename rclcpp::GenericService::SharedPtr
create_generic_service(
const std::string & service_name,
const std::string & service_type,
CallbackT && callback,
const rclcpp::QoS & qos = rclcpp::ServicesQoS(),
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Create and return a GenericPublisher.
/**
* The returned pointer will never be empty, but this function can throw various exceptions, for
@@ -1000,6 +1015,8 @@ public:
rclcpp::node_interfaces::OnSetParametersCallbackHandle;
using OnSetParametersCallbackType =
rclcpp::node_interfaces::NodeParametersInterface::OnSetParametersCallbackType;
using OnParametersSetCallbackType [[deprecated("use OnSetParametersCallbackType instead")]] =
OnSetParametersCallbackType;
using PostSetParametersCallbackHandle =
rclcpp::node_interfaces::PostSetParametersCallbackHandle;
@@ -1430,7 +1447,7 @@ public:
rclcpp::Clock::ConstSharedPtr
get_clock() const;
/// Returns current time from the node clock.
/// Returns current time from the time source specified by clock_type.
/**
* \sa rclcpp::Clock::now
*/

View File

@@ -40,7 +40,6 @@
#include "rclcpp/create_generic_subscription.hpp"
#include "rclcpp/create_publisher.hpp"
#include "rclcpp/create_service.hpp"
#include "rclcpp/create_generic_service.hpp"
#include "rclcpp/create_subscription.hpp"
#include "rclcpp/create_timer.hpp"
#include "rclcpp/detail/resolve_enable_topic_statistics.hpp"
@@ -155,6 +154,22 @@ Node::create_client(
group);
}
template<typename ServiceT>
typename Client<ServiceT>::SharedPtr
Node::create_client(
const std::string & service_name,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group)
{
return rclcpp::create_client<ServiceT>(
node_base_,
node_graph_,
node_services_,
extend_name_with_sub_namespace(service_name, this->get_sub_namespace()),
qos_profile,
group);
}
template<typename ServiceT, typename CallbackT>
typename rclcpp::Service<ServiceT>::SharedPtr
Node::create_service(
@@ -172,22 +187,20 @@ Node::create_service(
group);
}
template<typename CallbackT>
typename rclcpp::GenericService::SharedPtr
Node::create_generic_service(
template<typename ServiceT, typename CallbackT>
typename rclcpp::Service<ServiceT>::SharedPtr
Node::create_service(
const std::string & service_name,
const std::string & service_type,
CallbackT && callback,
const rclcpp::QoS & qos,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group)
{
return rclcpp::create_generic_service<CallbackT>(
return rclcpp::create_service<ServiceT, CallbackT>(
node_base_,
node_services_,
extend_name_with_sub_namespace(service_name, this->get_sub_namespace()),
service_type,
std::forward<CallbackT>(callback),
qos,
qos_profile,
group);
}

View File

@@ -52,6 +52,8 @@ struct OnSetParametersCallbackHandle
std::function<
rcl_interfaces::msg::SetParametersResult(
const std::vector<rclcpp::Parameter> &)>;
using OnParametersSetCallbackType [[deprecated("use OnSetParametersCallbackType instead")]] =
OnSetParametersCallbackType;
OnSetParametersCallbackType callback;
};

View File

@@ -52,6 +52,37 @@ class AsyncParametersClient
public:
RCLCPP_SMART_PTR_DEFINITIONS(AsyncParametersClient)
/// Create an async parameters client.
/**
* \param[in] node_base_interface The node base interface of the corresponding node.
* \param[in] node_topics_interface Node topic base interface.
* \param[in] node_graph_interface The node graph interface of the corresponding node.
* \param[in] node_services_interface Node service interface.
* \param[in] remote_node_name Name of the remote node
* \param[in] qos_profile The rmw qos profile to use to subscribe
* \param[in] group (optional) The async parameter client will be added to this callback group.
* \deprecated use rclcpp::QoS instead of rmw_qos_profile_t
*/
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
RCLCPP_PUBLIC
AsyncParametersClient(
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_interface,
const rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics_interface,
const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_interface,
const rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_interface,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group = nullptr)
: AsyncParametersClient(
node_base_interface,
node_topics_interface,
node_graph_interface,
node_services_interface,
remote_node_name,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)),
group)
{}
/// Create an async parameters client.
/**
* \param[in] node_base_interface The node base interface of the corresponding node.
@@ -72,6 +103,31 @@ public:
const rclcpp::QoS & qos_profile = rclcpp::ParametersQoS(),
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Constructor
/**
* \param[in] node The async parameters client will be added to this node.
* \param[in] remote_node_name name of the remote node
* \param[in] qos_profile The rmw qos profile to use to subscribe
* \param[in] group (optional) The async parameter client will be added to this callback group.
* \deprecated use rclcpp::QoS instead of rmw_qos_profile_t
*/
template<typename NodeT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
AsyncParametersClient(
const std::shared_ptr<NodeT> node,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group = nullptr)
: AsyncParametersClient(
node->get_node_base_interface(),
node->get_node_topics_interface(),
node->get_node_graph_interface(),
node->get_node_services_interface(),
remote_node_name,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)),
group)
{}
/**
* \param[in] node The async parameters client will be added to this node.
* \param[in] remote_node_name (optional) name of the remote node
@@ -94,6 +150,31 @@ public:
group)
{}
/// Constructor
/**
* \param[in] node The async parameters client will be added to this node.
* \param[in] remote_node_name Name of the remote node
* \param[in] qos_profile The rmw qos profile to use to subscribe
* \param[in] group (optional) The async parameter client will be added to this callback group.
* \deprecated use rclcpp::QoS instead of rmw_qos_profile_t
*/
template<typename NodeT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
AsyncParametersClient(
NodeT * node,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group = nullptr)
: AsyncParametersClient(
node->get_node_base_interface(),
node->get_node_topics_interface(),
node->get_node_graph_interface(),
node->get_node_services_interface(),
remote_node_name,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)),
group)
{}
/**
* \param[in] node The async parameters client will be added to this node.
* \param[in] remote_node_name (optional) name of the remote node
@@ -302,6 +383,19 @@ class SyncParametersClient
public:
RCLCPP_SMART_PTR_DEFINITIONS(SyncParametersClient)
template<typename NodeT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
SyncParametersClient(
std::shared_ptr<NodeT> node,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile)
: SyncParametersClient(
std::make_shared<rclcpp::executors::SingleThreadedExecutor>(),
node,
remote_node_name,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)))
{}
template<typename NodeT>
explicit SyncParametersClient(
std::shared_ptr<NodeT> node,
@@ -314,6 +408,23 @@ public:
qos_profile)
{}
template<typename NodeT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
SyncParametersClient(
rclcpp::Executor::SharedPtr executor,
std::shared_ptr<NodeT> node,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile)
: SyncParametersClient(
executor,
node->get_node_base_interface(),
node->get_node_topics_interface(),
node->get_node_graph_interface(),
node->get_node_services_interface(),
remote_node_name,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)))
{}
template<typename NodeT>
SyncParametersClient(
rclcpp::Executor::SharedPtr executor,
@@ -330,6 +441,19 @@ public:
qos_profile)
{}
template<typename NodeT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
SyncParametersClient(
NodeT * node,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile)
: SyncParametersClient(
std::make_shared<rclcpp::executors::SingleThreadedExecutor>(),
node,
remote_node_name,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)))
{}
template<typename NodeT>
explicit SyncParametersClient(
NodeT * node,
@@ -342,6 +466,23 @@ public:
qos_profile)
{}
template<typename NodeT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
SyncParametersClient(
rclcpp::Executor::SharedPtr executor,
NodeT * node,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile)
: SyncParametersClient(
executor,
node->get_node_base_interface(),
node->get_node_topics_interface(),
node->get_node_graph_interface(),
node->get_node_services_interface(),
remote_node_name,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)))
{}
template<typename NodeT>
SyncParametersClient(
rclcpp::Executor::SharedPtr executor,
@@ -358,6 +499,28 @@ public:
qos_profile)
{}
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
RCLCPP_PUBLIC
SyncParametersClient(
rclcpp::Executor::SharedPtr executor,
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_interface,
const rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics_interface,
const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_interface,
const rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_interface,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile)
: executor_(executor), node_base_interface_(node_base_interface)
{
async_parameters_client_ =
std::make_shared<AsyncParametersClient>(
node_base_interface,
node_topics_interface,
node_graph_interface,
node_services_interface,
remote_node_name,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)));
}
RCLCPP_PUBLIC
SyncParametersClient(
rclcpp::Executor::SharedPtr executor,

View File

@@ -67,23 +67,19 @@ struct ParameterEventCallbackHandle
* The first step is to instantiate a ParameterEventHandler, providing a ROS node to use
* to create any required subscriptions:
*
* ```cpp
* auto param_handler = std::make_shared<rclcpp::ParameterEventHandler>(node);
* ```
* auto param_handler = std::make_shared<rclcpp::ParameterEventHandler>(node);
*
* Next, you can supply a callback to the add_parameter_callback method, as follows:
*
* ```cpp
* auto cb1 = [&node](const rclcpp::Parameter & p) {
* RCLCPP_INFO(
* node->get_logger(),
* "cb1: Received an update to parameter \"%s\" of type %s: \"%ld\"",
* p.get_name().c_str(),
* p.get_type_name().c_str(),
* p.as_int());
* };
* auto handle1 = param_handler->add_parameter_callback("an_int_param", cb1);
* ```
* auto cb1 = [&node](const rclcpp::Parameter & p) {
* RCLCPP_INFO(
* node->get_logger(),
* "cb1: Received an update to parameter \"%s\" of type %s: \"%ld\"",
* p.get_name().c_str(),
* p.get_type_name().c_str(),
* p.as_int());
* };
* auto handle1 = param_handler->add_parameter_callback("an_int_param", cb1);
*
* In this case, we didn't supply a node name (the third, optional, parameter) so the
* default will be to monitor for changes to the "an_int_param" parameter associated with
@@ -96,18 +92,16 @@ struct ParameterEventCallbackHandle
* You may also monitor for changes to parameters in other nodes by supplying the node
* name to add_parameter_callback:
*
* ```cpp
* auto cb2 = [&node](const rclcpp::Parameter & p) {
* RCLCPP_INFO(
* node->get_logger(),
* "cb2: Received an update to parameter \"%s\" of type: %s: \"%s\"",
* p.get_name().c_str(),
* p.get_type_name().c_str(),
* p.as_string().c_str());
* };
* auto handle2 = param_handler->add_parameter_callback(
* "some_remote_param_name", cb2, "some_remote_node_name");
* ```
* auto cb2 = [&node](const rclcpp::Parameter & p) {
* RCLCPP_INFO(
* node->get_logger(),
* "cb2: Received an update to parameter \"%s\" of type: %s: \"%s\"",
* p.get_name().c_str(),
* p.get_type_name().c_str(),
* p.as_string().c_str());
* };
* auto handle2 = param_handler->add_parameter_callback(
* "some_remote_param_name", cb2, "some_remote_node_name");
*
* In this case, the callback will be invoked whenever "some_remote_param_name" changes
* on remote node "some_remote_node_name".
@@ -115,9 +109,7 @@ struct ParameterEventCallbackHandle
* To remove a parameter callback, reset the callback handle smart pointer or call
* remove_parameter_callback, passing the handle returned from add_parameter_callback:
*
* ```cpp
* param_handler->remove_parameter_callback(handle2);
* ```
* param_handler->remove_parameter_callback(handle2);
*
* You can also monitor for *all* parameter changes, using add_parameter_event_callback.
* In this case, the callback will be invoked whenever any parameter changes in the system.
@@ -125,42 +117,40 @@ struct ParameterEventCallbackHandle
* is convenient to use a regular expression on the node names or namespaces of interest.
* For example:
*
* ```cpp
* auto cb3 =
* [fqn, remote_param_name, &node](const rcl_interfaces::msg::ParameterEvent & event) {
* // Look for any updates to parameters in "/a_namespace" as well as any parameter changes
* // to our own node ("this_node")
* std::regex re("(/a_namespace/.*)|(/this_node)");
* if (regex_match(event.node, re)) {
* // Now that we know the event matches the regular expression we scanned for, we can
* // use 'get_parameter_from_event' to get a specific parameter name that we're looking for
* rclcpp::Parameter p;
* if (rclcpp::ParameterEventHandler::get_parameter_from_event(
* event, p, remote_param_name, fqn))
* {
* RCLCPP_INFO(
* node->get_logger(),
* "cb3: Received an update to parameter \"%s\" of type: %s: \"%s\"",
* p.get_name().c_str(),
* p.get_type_name().c_str(),
* p.as_string().c_str());
* }
* auto cb3 =
* [fqn, remote_param_name, &node](const rcl_interfaces::msg::ParameterEvent & event) {
* // Look for any updates to parameters in "/a_namespace" as well as any parameter changes
* // to our own node ("this_node")
* std::regex re("(/a_namespace/.*)|(/this_node)");
* if (regex_match(event.node, re)) {
* // Now that we know the event matches the regular expression we scanned for, we can
* // use 'get_parameter_from_event' to get a specific parameter name that we're looking for
* rclcpp::Parameter p;
* if (rclcpp::ParameterEventsSubscriber::get_parameter_from_event(
* event, p, remote_param_name, fqn))
* {
* RCLCPP_INFO(
* node->get_logger(),
* "cb3: Received an update to parameter \"%s\" of type: %s: \"%s\"",
* p.get_name().c_str(),
* p.get_type_name().c_str(),
* p.as_string().c_str());
* }
*
* // You can also use 'get_parameter*s*_from_event' to enumerate all changes that came
* // in on this event
* auto params = rclcpp::ParameterEventHandler::get_parameters_from_event(event);
* for (auto & p : params) {
* RCLCPP_INFO(
* node->get_logger(),
* "cb3: Received an update to parameter \"%s\" of type: %s: \"%s\"",
* p.get_name().c_str(),
* p.get_type_name().c_str(),
* p.value_to_string().c_str());
* // You can also use 'get_parameter*s*_from_event' to enumerate all changes that came
* // in on this event
* auto params = rclcpp::ParameterEventsSubscriber::get_parameters_from_event(event);
* for (auto & p : params) {
* RCLCPP_INFO(
* node->get_logger(),
* "cb3: Received an update to parameter \"%s\" of type: %s: \"%s\"",
* p.get_name().c_str(),
* p.get_type_name().c_str(),
* p.value_to_string().c_str());
* }
* }
* }
* };
* auto handle3 = param_handler->add_parameter_event_callback(cb3);
* ```
* };
* auto handle3 = param_handler->add_parameter_event_callback(cb3);
*
* For both parameter callbacks and parameter event callbacks, when multiple callbacks are added,
* the callbacks are invoked last-in, first-called order (LIFO).
@@ -170,9 +160,7 @@ struct ParameterEventCallbackHandle
*
* To remove a parameter event callback, reset the callback smart pointer or use:
*
* ```cpp
* param_handler->remove_event_parameter_callback(handle3);
* ```
* param_handler->remove_event_parameter_callback(handle3);
*/
class ParameterEventHandler
{

View File

@@ -40,6 +40,20 @@ class ParameterService
public:
RCLCPP_SMART_PTR_DEFINITIONS(ParameterService)
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
RCLCPP_PUBLIC
ParameterService(
const std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
const std::shared_ptr<node_interfaces::NodeServicesInterface> node_services,
rclcpp::node_interfaces::NodeParametersInterface * node_params,
const rmw_qos_profile_t & qos_profile)
: ParameterService(
node_base,
node_services,
node_params,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)))
{}
RCLCPP_PUBLIC
ParameterService(
const std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,

View File

@@ -359,7 +359,7 @@ private:
/// Return the value of a parameter as a string
RCLCPP_PUBLIC
std::string
to_string(const ParameterValue & value);
to_string(const ParameterValue & type);
} // namespace rclcpp

View File

@@ -96,6 +96,22 @@ public:
using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
using MessageAllocatorTraits
[[deprecated("use PublishedTypeAllocatorTraits")]] =
PublishedTypeAllocatorTraits;
using MessageAllocator
[[deprecated("use PublishedTypeAllocator")]] =
PublishedTypeAllocator;
using MessageDeleter
[[deprecated("use PublishedTypeDeleter")]] =
PublishedTypeDeleter;
using MessageUniquePtr
[[deprecated("use std::unique_ptr<PublishedType, PublishedTypeDeleter>")]] =
std::unique_ptr<PublishedType, PublishedTypeDeleter>;
using MessageSharedPtr
[[deprecated("use std::shared_ptr<const PublishedType>")]] =
std::shared_ptr<const PublishedType>;
using BufferSharedPtr = typename rclcpp::experimental::buffers::IntraProcessBuffer<
ROSMessageType,
ROSMessageTypeAllocator,
@@ -112,8 +128,8 @@ public:
*
* \param[in] node_base NodeBaseInterface pointer that is used in part of the setup.
* \param[in] topic Name of the topic to publish to.
* \param[in] qos QoS profile for the publisher.
* \param[in] options Options for the publisher.
* \param[in] qos QoS profile for Subcription.
* \param[in] options Options for the subscription.
*/
Publisher(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
@@ -190,7 +206,7 @@ public:
* the loaned message will be directly allocated in the middleware.
* If not, the message allocator of this rclcpp::Publisher instance is being used.
*
* With a call to `publish` the LoanedMessage instance is being returned to the middleware
* With a call to \sa `publish` the LoanedMessage instance is being returned to the middleware
* or free'd accordingly to the allocator.
* If the message is not being published but processed differently, the destructor of this
* class will either return the message to the middleware or deallocate it via the internal
@@ -417,6 +433,13 @@ public:
}
}
[[deprecated("use get_published_type_allocator() or get_ros_message_type_allocator() instead")]]
std::shared_ptr<PublishedTypeAllocator>
get_allocator() const
{
return std::make_shared<PublishedTypeAllocator>(published_type_allocator_);
}
PublishedTypeAllocator
get_published_type_allocator() const
{

View File

@@ -39,6 +39,10 @@ public:
RCLCPP_PUBLIC
virtual bool sleep() = 0;
[[deprecated("use get_type() instead")]]
RCLCPP_PUBLIC
virtual bool is_steady() const = 0;
RCLCPP_PUBLIC
virtual rcl_clock_type_t get_type() const = 0;
@@ -50,6 +54,82 @@ using std::chrono::duration;
using std::chrono::duration_cast;
using std::chrono::nanoseconds;
template<class Clock = std::chrono::high_resolution_clock>
class [[deprecated("use rclcpp::Rate class instead of GenericRate")]] GenericRate : public RateBase
{
public:
RCLCPP_SMART_PTR_DEFINITIONS(GenericRate)
explicit GenericRate(double rate)
: period_(duration_cast<nanoseconds>(duration<double>(1.0 / rate))), last_interval_(Clock::now())
{}
explicit GenericRate(std::chrono::nanoseconds period)
: period_(period), last_interval_(Clock::now())
{}
virtual bool
sleep()
{
// Time coming into sleep
auto now = Clock::now();
// Time of next interval
auto next_interval = last_interval_ + period_;
// Detect backwards time flow
if (now < last_interval_) {
// Best thing to do is to set the next_interval to now + period
next_interval = now + period_;
}
// Calculate the time to sleep
auto time_to_sleep = next_interval - now;
// Update the interval
last_interval_ += period_;
// If the time_to_sleep is negative or zero, don't sleep
if (time_to_sleep <= std::chrono::seconds(0)) {
// If an entire cycle was missed then reset next interval.
// This might happen if the loop took more than a cycle.
// Or if time jumps forward.
if (now > next_interval + period_) {
last_interval_ = now + period_;
}
// Either way do not sleep and return false
return false;
}
// Sleep (will get interrupted by ctrl-c, may not sleep full time)
rclcpp::sleep_for(time_to_sleep);
return true;
}
[[deprecated("use get_type() instead")]]
virtual bool
is_steady() const
{
return Clock::is_steady;
}
virtual rcl_clock_type_t get_type() const
{
return Clock::is_steady ? RCL_STEADY_TIME : RCL_SYSTEM_TIME;
}
virtual void
reset()
{
last_interval_ = Clock::now();
}
std::chrono::nanoseconds period() const
{
return period_;
}
private:
RCLCPP_DISABLE_COPY(GenericRate)
std::chrono::nanoseconds period_;
using ClockDurationNano = std::chrono::duration<typename Clock::rep, std::nano>;
std::chrono::time_point<Clock, ClockDurationNano> last_interval_;
};
class Rate : public RateBase
{
public:
@@ -69,6 +149,11 @@ public:
virtual bool
sleep();
[[deprecated("use get_type() instead")]]
RCLCPP_PUBLIC
virtual bool
is_steady() const;
RCLCPP_PUBLIC
virtual rcl_clock_type_t
get_type() const;

View File

@@ -133,9 +133,6 @@
* - Dynamic typesupport
* - rclcpp::dynamic_typesupport::DynamicMessageTypeSupport
* - rclcpp/dynamic_typesupport/dynamic_message_type_support.hpp
* - Dynamic subscription
* - rclcpp::DynamicSubscription
* - rclcpp/dynamic_subscription.hpp
* - Generic publisher
* - rclcpp::Node::create_generic_publisher()
* - rclcpp::GenericPublisher
@@ -187,6 +184,4 @@
#include "rclcpp/waitable.hpp"
#include "rclcpp/wait_set.hpp"
#include "rclcpp/dynamic_subscription.hpp"
#endif // RCLCPP__RCLCPP_HPP_

View File

@@ -307,7 +307,7 @@ public:
* \param[in] node_handle NodeBaseInterface pointer that is used in part of the setup.
* \param[in] service_name Name of the topic to publish to.
* \param[in] any_callback User defined callback to call when a client request is received.
* \param[in] service_options options for the service.
* \param[in] service_options options for the subscription.
*/
Service(
std::shared_ptr<rcl_node_t> node_handle,

View File

@@ -90,6 +90,18 @@ public:
using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
using MessageAllocatorTraits [[deprecated("use ROSMessageTypeAllocatorTraits")]] =
ROSMessageTypeAllocatorTraits;
using MessageAllocator [[deprecated("use ROSMessageTypeAllocator")]] =
ROSMessageTypeAllocator;
using MessageDeleter [[deprecated("use ROSMessageTypeDeleter")]] =
ROSMessageTypeDeleter;
using ConstMessageSharedPtr [[deprecated]] = std::shared_ptr<const ROSMessageType>;
using MessageUniquePtr
[[deprecated("use std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter> instead")]] =
std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>;
private:
using SubscriptionTopicStatisticsSharedPtr =
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics>;

View File

@@ -644,10 +644,6 @@ protected:
rclcpp::node_interfaces::NodeBaseInterface * const node_base_;
// TODO(methylDragon): Remove if we don't need this
// rclcpp::node_interfaces::NodeGraphInterface * const node_graph_;
// rclcpp::node_interfaces::NodeServicesInterface * const node_services_;
std::shared_ptr<rcl_node_t> node_handle_;
std::recursive_mutex callback_mutex_;

View File

@@ -49,7 +49,6 @@ public:
/**
* \param nanoseconds since time epoch
* \param clock_type clock type
* \throws std::runtime_error if nanoseconds are negative
*/
RCLCPP_PUBLIC
explicit Time(int64_t nanoseconds = 0, rcl_clock_type_t clock_type = RCL_SYSTEM_TIME);

View File

@@ -172,11 +172,12 @@ private:
{
auto received_message_age = std::make_unique<ReceivedMessageAge>();
received_message_age->Start();
subscriber_statistics_collectors_.emplace_back(std::move(received_message_age));
auto received_message_period = std::make_unique<ReceivedMessagePeriod>();
received_message_period->Start();
{
std::lock_guard<std::mutex> lock(mutex_);
subscriber_statistics_collectors_.emplace_back(std::move(received_message_age));
subscriber_statistics_collectors_.emplace_back(std::move(received_message_period));
}

View File

@@ -38,6 +38,25 @@ RCLCPP_PUBLIC
std::shared_ptr<rcpputils::SharedLibrary>
get_typesupport_library(const std::string & type, const std::string & typesupport_identifier);
/// Extract the type support handle from the library.
/**
* The library needs to match the topic type. The shared library must stay loaded for the lifetime of the result.
*
* \deprecated Use get_message_typesupport_handle() instead
*
* \param[in] type The topic type, e.g. "std_msgs/msg/String"
* \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
* \param[in] library The shared type support library
* \return A type support handle
*/
[[deprecated("Use `get_message_typesupport_handle` instead")]]
RCLCPP_PUBLIC
const rosidl_message_type_support_t *
get_typesupport_handle(
const std::string & type,
const std::string & typesupport_identifier,
rcpputils::SharedLibrary & library);
/// Extract the message type support handle from the library.
/**
* The library needs to match the topic type. The shared library must stay loaded for the lifetime of the result.
@@ -57,7 +76,7 @@ get_message_typesupport_handle(
/// Extract the service type support handle from the library.
/**
* The library needs to match the topic type. The shared library must stay loaded for the lifetime of the result.
* The library needs to match the service type. The shared library must stay loaded for the lifetime of the result.
*
* \param[in] type The service type, e.g. "std_srvs/srv/Empty"
* \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"

View File

@@ -176,7 +176,9 @@ public:
for (; ii < wait_set.size_of_timers(); ++ii) {
if (rcl_wait_set.timers[ii] != nullptr) {
ret = wait_set.timers(ii);
break;
if (ret) {
break;
}
}
}
}
@@ -217,7 +219,9 @@ public:
if (rcl_wait_set.subscriptions[ii] != nullptr) {
ret = wait_set.subscriptions(ii);
rcl_wait_set.subscriptions[ii] = nullptr;
break;
if (ret) {
break;
}
}
}
}
@@ -237,7 +241,9 @@ public:
if (rcl_wait_set.services[ii] != nullptr) {
ret = wait_set.services(ii);
rcl_wait_set.services[ii] = nullptr;
break;
if (ret) {
break;
}
}
}
}
@@ -257,7 +263,9 @@ public:
if (rcl_wait_set.clients[ii] != nullptr) {
ret = wait_set.clients(ii);
rcl_wait_set.clients[ii] = nullptr;
break;
if (ret) {
break;
}
}
}
}

View File

@@ -216,6 +216,11 @@ public:
shared_waitables_
);
if (this->needs_pruning_) {
this->storage_prune_deleted_entities();
this->needs_pruning_ = false;
}
this->storage_release_ownerships();
}
@@ -455,59 +460,60 @@ public:
size_t size_of_subscriptions() const
{
return shared_subscriptions_.size();
return subscriptions_.size();
}
size_t size_of_timers() const
{
return shared_timers_.size();
return timers_.size();
}
size_t size_of_clients() const
{
return shared_clients_.size();
return clients_.size();
}
size_t size_of_services() const
{
return shared_services_.size();
return services_.size();
}
size_t size_of_waitables() const
{
return shared_waitables_.size();
return waitables_.size();
}
std::shared_ptr<rclcpp::SubscriptionBase>
subscriptions(size_t ii) const
{
return shared_subscriptions_[ii].subscription;
return subscriptions_[ii].lock();
}
std::shared_ptr<rclcpp::TimerBase>
timers(size_t ii) const
{
return shared_timers_[ii];
return timers_[ii].lock();
}
std::shared_ptr<rclcpp::ClientBase>
clients(size_t ii) const
{
return shared_clients_[ii];
return clients_[ii].lock();
}
std::shared_ptr<rclcpp::ServiceBase>
services(size_t ii) const
{
return shared_services_[ii];
return services_[ii].lock();
}
std::shared_ptr<rclcpp::Waitable>
waitables(size_t ii) const
{
return shared_waitables_[ii].waitable;
return waitables_[ii].lock();
}
private:
size_t ownership_reference_counter_ = 0;
SequenceOfWeakSubscriptions subscriptions_;

View File

@@ -160,6 +160,15 @@ public:
services_,
waitables_
);
if(this->needs_pruning_) {
// we need to throw here, as the indexing of the rcl_waitset is broken,
// in case of invalid entries
throw std::runtime_error(
"StaticStorage::storage_rebuild_rcl_wait_set(): entity weak_ptr "
"unexpectedly expired in static entity storage");
}
}
// storage_add_subscription() explicitly not declared here

View File

@@ -734,8 +734,6 @@ private:
wait_result_dirty_ = false;
// this method comes from the SynchronizationPolicy
this->sync_wait_result_acquire();
// this method comes from the StoragePolicy
this->storage_acquire_ownerships();
}
/// Called by the WaitResult's destructor to release resources.
@@ -752,8 +750,6 @@ private:
}
wait_result_holding_ = false;
wait_result_dirty_ = false;
// this method comes from the StoragePolicy
this->storage_release_ownerships();
// this method comes from the SynchronizationPolicy
this->sync_wait_result_release();
}

View File

@@ -101,6 +101,23 @@ public:
size_t
get_number_of_ready_guard_conditions();
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Woverloaded-virtual"
#endif
/// Deprecated.
/**
* \sa add_to_wait_set(rcl_wait_set_t &)
*/
[[deprecated("Use add_to_wait_set(rcl_wait_set_t & wait_set) signature")]]
RCLCPP_PUBLIC
virtual
void
add_to_wait_set(rcl_wait_set_t * wait_set);
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
/// Add the Waitable to a wait set.
/**
* \param[in] wait_set A handle to the wait set to add the Waitable to.
@@ -109,7 +126,24 @@ public:
RCLCPP_PUBLIC
virtual
void
add_to_wait_set(rcl_wait_set_t & wait_set) = 0;
add_to_wait_set(rcl_wait_set_t & wait_set);
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Woverloaded-virtual"
#endif
/// Deprecated.
/**
* \sa is_ready(const rcl_wait_set_t &)
*/
[[deprecated("Use is_ready(const rcl_wait_set_t & wait_set) signature")]]
RCLCPP_PUBLIC
virtual
bool
is_ready(rcl_wait_set_t * wait_set);
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
/// Check if the Waitable is ready.
/**
@@ -124,7 +158,7 @@ public:
RCLCPP_PUBLIC
virtual
bool
is_ready(const rcl_wait_set_t & wait_set) = 0;
is_ready(const rcl_wait_set_t & wait_set);
/// Take the data so that it can be consumed with `execute`.
/**
@@ -176,7 +210,24 @@ public:
RCLCPP_PUBLIC
virtual
std::shared_ptr<void>
take_data_by_entity_id(size_t id) = 0;
take_data_by_entity_id(size_t id);
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Woverloaded-virtual"
#endif
/// Deprecated.
/**
* \sa execute(const std::shared_ptr<void> &)
*/
[[deprecated("Use execute(const std::shared_ptr<void> & data) signature")]]
RCLCPP_PUBLIC
virtual
void
execute(std::shared_ptr<void> & data);
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
/// Execute data that is passed in.
/**
@@ -203,7 +254,7 @@ public:
RCLCPP_PUBLIC
virtual
void
execute(const std::shared_ptr<void> & data) = 0;
execute(const std::shared_ptr<void> & data);
/// Exchange the "in use by wait set" state for this timer.
/**
@@ -246,7 +297,7 @@ public:
RCLCPP_PUBLIC
virtual
void
set_on_ready_callback(std::function<void(size_t, int)> callback) = 0;
set_on_ready_callback(std::function<void(size_t, int)> callback);
/// Unset any callback registered via set_on_ready_callback.
/**
@@ -256,7 +307,7 @@ public:
RCLCPP_PUBLIC
virtual
void
clear_on_ready_callback() = 0;
clear_on_ready_callback();
private:
std::atomic<bool> in_use_by_wait_set_{false};

View File

@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>rclcpp</name>
<version>29.3.0</version>
<version>28.1.9</version>
<description>The ROS client library in C++.</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>

View File

@@ -118,7 +118,7 @@ Clock::sleep_until(
});
// No longer need the shutdown callback when this function exits
auto callback_remover = rcpputils::scope_exit(
[context, &shutdown_cb_handle]() {
[&context, &shutdown_cb_handle]() {
context->remove_on_shutdown_callback(shutdown_cb_handle);
});
@@ -367,4 +367,245 @@ Clock::create_jump_callback(
// *INDENT-ON*
}
class ClockWaiter::ClockWaiterImpl
{
private:
std::condition_variable cv_;
rclcpp::Clock::SharedPtr clock_;
bool time_source_changed_ = false;
std::function<void(const rcl_time_jump_t &)> post_time_jump_callback;
bool
wait_until_system_time(
std::unique_lock<std::mutex> & lock,
const rclcpp::Time & abs_time, const std::function<bool ()> & pred)
{
auto system_time = std::chrono::system_clock::time_point(
// Cast because system clock resolution is too big for nanoseconds on some systems
std::chrono::duration_cast<std::chrono::system_clock::duration>(
std::chrono::nanoseconds(abs_time.nanoseconds())));
return cv_.wait_until(lock, system_time, pred);
}
bool
wait_until_steady_time(
std::unique_lock<std::mutex> & lock,
const rclcpp::Time & abs_time, const std::function<bool ()> & pred)
{
// Synchronize because RCL steady clock epoch might differ from chrono::steady_clock epoch
const rclcpp::Time rcl_entry = clock_->now();
const std::chrono::steady_clock::time_point chrono_entry = std::chrono::steady_clock::now();
const rclcpp::Duration delta_t = abs_time - rcl_entry;
const std::chrono::steady_clock::time_point chrono_until =
chrono_entry + std::chrono::nanoseconds(delta_t.nanoseconds());
return cv_.wait_until(lock, chrono_until, pred);
}
bool
wait_until_ros_time(
std::unique_lock<std::mutex> & lock,
const rclcpp::Time & abs_time, const std::function<bool ()> & pred)
{
// Install jump handler for any amount of time change, for two purposes:
// - if ROS time is active, check if time reached on each new clock sample
// - Trigger via on_clock_change to detect if time source changes, to invalidate sleep
rcl_jump_threshold_t threshold;
threshold.on_clock_change = true;
// 0 is disable, so -1 and 1 are smallest possible time changes
threshold.min_backward.nanoseconds = -1;
threshold.min_forward.nanoseconds = 1;
time_source_changed_ = false;
post_time_jump_callback = [this, &lock] (const rcl_time_jump_t & jump)
{
if (jump.clock_change != RCL_ROS_TIME_NO_CHANGE) {
std::lock_guard<std::mutex> lk(*lock.mutex());
time_source_changed_ = true;
}
cv_.notify_one();
};
// Note this is a trade-off. Adding the callback for every call
// is expensive for high frequency calls. For low frequency waits
// its more overhead to have the callback being called all the time.
// As we expect the use case to be low frequency calls to wait_until
// with relative big pauses between the calls, we install it on demand.
auto clock_handler = clock_->create_jump_callback(
nullptr,
post_time_jump_callback,
threshold);
if (!clock_->ros_time_is_active()) {
auto system_time = std::chrono::system_clock::time_point(
// Cast because system clock resolution is too big for nanoseconds on some systems
std::chrono::duration_cast<std::chrono::system_clock::duration>(
std::chrono::nanoseconds(abs_time.nanoseconds())));
return cv_.wait_until(lock, system_time, [this, &pred] () {
return time_source_changed_ || pred();
});
}
// RCL_ROS_TIME with ros_time_is_active.
// Just wait without "until" because installed
// jump callbacks wake the cv on every new sample.
cv_.wait(lock, [this, &pred, &abs_time] () {
return clock_->now() >= abs_time || time_source_changed_ || pred();
});
return clock_->now() < abs_time;
}
public:
explicit ClockWaiterImpl(const rclcpp::Clock::SharedPtr & clock)
:clock_(clock)
{
}
bool
wait_until(
std::unique_lock<std::mutex> & lock,
const rclcpp::Time & abs_time, const std::function<bool ()> & pred)
{
switch(clock_->get_clock_type()) {
case RCL_CLOCK_UNINITIALIZED:
throw std::runtime_error("Error, wait on uninitialized clock called");
case RCL_ROS_TIME:
return wait_until_ros_time(lock, abs_time, pred);
break;
case RCL_STEADY_TIME:
return wait_until_steady_time(lock, abs_time, pred);
break;
case RCL_SYSTEM_TIME:
return wait_until_system_time(lock, abs_time, pred);
break;
}
return false;
}
void
notify_one()
{
cv_.notify_one();
}
};
ClockWaiter::ClockWaiter(const rclcpp::Clock::SharedPtr & clock)
:impl_(std::make_unique<ClockWaiterImpl>(clock))
{
}
ClockWaiter::~ClockWaiter() = default;
bool
ClockWaiter::wait_until(
std::unique_lock<std::mutex> & lock,
const rclcpp::Time & abs_time, const std::function<bool ()> & pred)
{
return impl_->wait_until(lock, abs_time, pred);
}
void
ClockWaiter::notify_one()
{
impl_->notify_one();
}
class ClockConditionalVariable::Impl
{
std::mutex pred_mutex_;
bool shutdown_ = false;
rclcpp::Context::SharedPtr context_;
rclcpp::OnShutdownCallbackHandle shutdown_cb_handle_;
ClockWaiter::UniquePtr clock_;
public:
Impl(const rclcpp::Clock::SharedPtr & clock, rclcpp::Context::SharedPtr context)
:context_(context),
clock_(std::make_unique<ClockWaiter>(clock))
{
if (!context_ || !context_->is_valid()) {
throw std::runtime_error("context cannot be slept with because it's invalid");
}
// Wake this thread if the context is shutdown
shutdown_cb_handle_ = context_->add_on_shutdown_callback(
[this]() {
{
std::unique_lock lock(pred_mutex_);
shutdown_ = true;
}
clock_->notify_one();
});
}
~Impl()
{
context_->remove_on_shutdown_callback(shutdown_cb_handle_);
}
bool
wait_until(
std::unique_lock<std::mutex> & lock, rclcpp::Time until,
const std::function<bool ()> & pred)
{
if(lock.mutex() != &pred_mutex_) {
throw std::runtime_error(
"ClockConditionalVariable::wait_until: Internal error, given lock does not use"
" mutex returned by this->mutex()");
}
clock_->wait_until(lock, until, [this, &pred] () -> bool {
return shutdown_ || pred();
});
return true;
}
void
notify_one()
{
clock_->notify_one();
}
std::mutex &
mutex()
{
return pred_mutex_;
}
};
ClockConditionalVariable::ClockConditionalVariable(
const rclcpp::Clock::SharedPtr & clock,
rclcpp::Context::SharedPtr context)
:impl_(std::make_unique<Impl>(clock, context))
{
}
ClockConditionalVariable::~ClockConditionalVariable() = default;
void
ClockConditionalVariable::notify_one()
{
impl_->notify_one();
}
bool
ClockConditionalVariable::wait_until(
std::unique_lock<std::mutex> & lock, rclcpp::Time until,
const std::function<bool ()> & pred)
{
return impl_->wait_until(lock, until, pred);
}
std::mutex &
ClockConditionalVariable::mutex()
{
return impl_->mutex();
}
} // namespace rclcpp

View File

@@ -212,27 +212,28 @@ Context::init(
}
rcl_context_.reset(context, __delete_context);
try {
if (init_options.auto_initialize_logging()) {
logging_mutex_ = get_global_logging_mutex();
std::lock_guard<std::recursive_mutex> guard(*logging_mutex_);
size_t & count = get_logging_reference_count();
if (0u == count) {
ret = rcl_logging_configure_with_output_handler(
&rcl_context_->global_arguments,
rcl_init_options_get_allocator(init_options.get_rcl_init_options()),
rclcpp_logging_output_handler);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to configure logging");
}
} else {
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"logging was initialized more than once");
if (init_options.auto_initialize_logging()) {
logging_mutex_ = get_global_logging_mutex();
std::lock_guard<std::recursive_mutex> guard(*logging_mutex_);
size_t & count = get_logging_reference_count();
if (0u == count) {
ret = rcl_logging_configure_with_output_handler(
&rcl_context_->global_arguments,
rcl_init_options_get_allocator(init_options.get_rcl_init_options()),
rclcpp_logging_output_handler);
if (RCL_RET_OK != ret) {
rcl_context_.reset();
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to configure logging");
}
++count;
} else {
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"logging was initialized more than once");
}
++count;
}
try {
std::vector<std::string> unparsed_ros_arguments = detail::get_unparsed_ros_arguments(
argc, argv, &(rcl_context_->global_arguments), rcl_get_default_allocator());
if (!unparsed_ros_arguments.empty()) {

View File

@@ -1,49 +0,0 @@
// Copyright 2024 Sony Group Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string>
#include <memory>
#include "rclcpp/create_generic_service.hpp"
#include "rclcpp/generic_service.hpp"
namespace rclcpp
{
rclcpp::GenericService::SharedPtr
create_generic_service(
std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
std::shared_ptr<node_interfaces::NodeGraphInterface> node_graph,
std::shared_ptr<node_interfaces::NodeServicesInterface> node_services,
const std::string & service_name,
const std::string & service_type,
GenericServiceCallback any_callback,
const rclcpp::QoS & qos,
rclcpp::CallbackGroup::SharedPtr group)
{
rcl_service_options_t options = rcl_service_get_default_options();
options.qos = qos.get_rmw_qos_profile();
auto srv = rclcpp::GenericService::make_shared(
node_base.get(),
node_graph,
service_name,
service_type,
any_callback,
options);
auto srv_base_ptr = std::dynamic_pointer_cast<rclcpp::ServiceBase>(srv);
node_services->add_service(srv_base_ptr, group);
return srv;
}
} // namespace rclcpp

View File

@@ -1,113 +0,0 @@
// Copyright 2022 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "rclcpp/dynamic_subscription.hpp"
#include <memory>
#include <string>
#include "rcl/subscription.h"
#include "rclcpp/exceptions.hpp"
namespace rclcpp
{
std::shared_ptr<void> DynamicSubscription::create_message()
{
return create_serialized_message();
}
std::shared_ptr<rclcpp::SerializedMessage> DynamicSubscription::create_serialized_message()
{
return std::make_shared<rclcpp::SerializedMessage>(0);
}
void DynamicSubscription::handle_message(std::shared_ptr<void> &, const rclcpp::MessageInfo &)
{
throw rclcpp::exceptions::UnimplementedError(
"handle_message is not implemented for DynamicSubscription");
}
void DynamicSubscription::handle_serialized_message(
const std::shared_ptr<rclcpp::SerializedMessage> &, const rclcpp::MessageInfo &)
{
throw rclcpp::exceptions::UnimplementedError(
"handle_serialized_message is not implemented for DynamicSubscription");
}
void DynamicSubscription::handle_loaned_message(void *, const rclcpp::MessageInfo &)
{
throw rclcpp::exceptions::UnimplementedError(
"handle_loaned_message is not implemented for DynamicSubscription");
}
void DynamicSubscription::return_message(std::shared_ptr<void> & message)
{
auto typed_message = std::static_pointer_cast<rclcpp::SerializedMessage>(message);
return_serialized_message(typed_message);
}
void DynamicSubscription::return_serialized_message(
std::shared_ptr<rclcpp::SerializedMessage> & message)
{
message.reset();
}
// DYNAMIC TYPE ====================================================================================
// TODO(methylDragon): Re-order later
// Does not clone
rclcpp::dynamic_typesupport::DynamicMessageType::SharedPtr
DynamicSubscription::get_shared_dynamic_message_type()
{
return dynamic_message_type_;
}
// Does not clone
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr
DynamicSubscription::get_shared_dynamic_message()
{
return dynamic_message_;
}
rclcpp::dynamic_typesupport::DynamicSerializationSupport::SharedPtr
DynamicSubscription::get_shared_dynamic_serialization_support()
{
return serialization_support_;
}
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr
DynamicSubscription::create_dynamic_message()
{
return dynamic_message_->init_from_type_shared(*dynamic_message_type_);
}
void
DynamicSubscription::return_dynamic_message(
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message)
{
message.reset();
}
void DynamicSubscription::handle_dynamic_message(
const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
const rclcpp::MessageInfo & message_info)
{
(void) message_info;
callback_(message, ts_->get_rosidl_runtime_c_type_description());
}
} // namespace rclcpp

View File

@@ -36,734 +36,5 @@ using rclcpp::dynamic_typesupport::DynamicMessageType;
using rclcpp::dynamic_typesupport::DynamicMessageTypeBuilder;
using rclcpp::dynamic_typesupport::DynamicSerializationSupport;
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_IMPL_HPP_
// Template specialization implementations
#include "rclcpp/dynamic_typesupport/detail/dynamic_message_impl.hpp"
#endif
// CONSTRUCTION ==================================================================================
DynamicMessage::DynamicMessage(const DynamicMessageTypeBuilder::SharedPtr dynamic_type_builder)
: DynamicMessage::DynamicMessage(
dynamic_type_builder, dynamic_type_builder->get_rosidl_dynamic_type_builder().allocator) {}
DynamicMessage::DynamicMessage(
const DynamicMessageTypeBuilder::SharedPtr dynamic_type_builder,
rcl_allocator_t allocator)
: serialization_support_(dynamic_type_builder->get_shared_dynamic_serialization_support()),
rosidl_dynamic_data_(rosidl_dynamic_typesupport_get_zero_initialized_dynamic_data()),
is_loaned_(false),
parent_data_(nullptr)
{
if (!serialization_support_) {
throw std::runtime_error("dynamic message could not bind serialization support!");
}
if (!dynamic_type_builder) {
throw std::runtime_error("dynamic message type builder cannot be nullptr!");
}
rosidl_dynamic_typesupport_dynamic_type_builder_t rosidl_dynamic_type_builder =
dynamic_type_builder->get_rosidl_dynamic_type_builder();
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_init_from_dynamic_type_builder(
&rosidl_dynamic_type_builder, &allocator, &get_rosidl_dynamic_data());
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error("could not init new dynamic data object from dynamic type builder");
}
}
DynamicMessage::DynamicMessage(const DynamicMessageType::SharedPtr dynamic_type)
: DynamicMessage::DynamicMessage(
dynamic_type, dynamic_type->get_rosidl_dynamic_type().allocator) {}
DynamicMessage::DynamicMessage(
const DynamicMessageType::SharedPtr dynamic_type,
rcl_allocator_t allocator)
: serialization_support_(dynamic_type->get_shared_dynamic_serialization_support()),
rosidl_dynamic_data_(rosidl_dynamic_typesupport_get_zero_initialized_dynamic_data()),
is_loaned_(false),
parent_data_(nullptr)
{
if (!serialization_support_) {
throw std::runtime_error("dynamic type could not bind serialization support!");
}
if (!dynamic_type) {
throw std::runtime_error("dynamic message type cannot be nullptr!");
}
rosidl_dynamic_typesupport_dynamic_type_t rosidl_dynamic_type =
dynamic_type->get_rosidl_dynamic_type();
rosidl_dynamic_typesupport_dynamic_data_t rosidl_dynamic_data =
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_data();
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_init_from_dynamic_type(
&rosidl_dynamic_type, &allocator, &rosidl_dynamic_data);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error(
std::string("could not init new dynamic data object from dynamic type") +
rcl_get_error_string().str);
}
}
DynamicMessage::DynamicMessage(
DynamicSerializationSupport::SharedPtr serialization_support,
rosidl_dynamic_typesupport_dynamic_data_t && rosidl_dynamic_data)
: serialization_support_(serialization_support),
rosidl_dynamic_data_(std::move(rosidl_dynamic_data)),
is_loaned_(false),
parent_data_(nullptr)
{
if (serialization_support) {
if (!match_serialization_support_(*serialization_support, rosidl_dynamic_data)) {
throw std::runtime_error(
"serialization support library identifier does not match dynamic data's!");
}
}
}
DynamicMessage::DynamicMessage(
DynamicMessage::SharedPtr parent_data,
rosidl_dynamic_typesupport_dynamic_data_t && rosidl_loaned_data)
: serialization_support_(parent_data->get_shared_dynamic_serialization_support()),
rosidl_dynamic_data_(std::move(rosidl_loaned_data)),
is_loaned_(true),
parent_data_(nullptr)
{
if (!parent_data) {
throw std::runtime_error("parent dynamic data cannot be nullptr!");
}
if (serialization_support_) {
if (!match_serialization_support_(*serialization_support_, rosidl_loaned_data)) {
throw std::runtime_error(
"serialization support library identifier does not match loaned dynamic data's!");
}
}
parent_data_ = parent_data;
}
DynamicMessage::DynamicMessage(DynamicMessage && other) noexcept
: serialization_support_(std::exchange(other.serialization_support_, nullptr)),
rosidl_dynamic_data_(std::exchange(
other.rosidl_dynamic_data_,
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_data())),
is_loaned_(other.is_loaned_),
parent_data_(std::exchange(other.parent_data_, nullptr))
{}
DynamicMessage &
DynamicMessage::operator=(DynamicMessage && other) noexcept
{
std::swap(serialization_support_, other.serialization_support_);
std::swap(rosidl_dynamic_data_, other.rosidl_dynamic_data_);
is_loaned_ = other.is_loaned_;
std::swap(parent_data_, other.parent_data_);
return *this;
}
DynamicMessage::~DynamicMessage()
{
if (!is_loaned_) {
if (rosidl_dynamic_typesupport_dynamic_data_fini(&get_rosidl_dynamic_data()) !=
RCUTILS_RET_OK)
{
RCUTILS_LOG_ERROR("could not fini rosidl dynamic data");
}
return;
}
// Loaned case
if (!parent_data_) {
RCUTILS_LOG_ERROR("dynamic data is loaned, but parent is missing!!");
} else {
rosidl_dynamic_typesupport_dynamic_data_return_loaned_value(
&parent_data_->get_rosidl_dynamic_data(), &get_rosidl_dynamic_data());
}
}
bool
DynamicMessage::match_serialization_support_(
const DynamicSerializationSupport & serialization_support,
const rosidl_dynamic_typesupport_dynamic_data_t & rosidl_dynamic_type_data)
{
if (serialization_support.get_serialization_library_identifier() != std::string(
rosidl_dynamic_type_data.serialization_support->serialization_library_identifier))
{
RCUTILS_LOG_ERROR("serialization support library identifier does not match dynamic data's");
return false;
}
return true;
}
// GETTERS =======================================================================================
const std::string
DynamicMessage::get_serialization_library_identifier() const
{
return std::string(
get_rosidl_dynamic_data().serialization_support->serialization_library_identifier);
}
const std::string
DynamicMessage::get_name() const
{
size_t buf_length;
const char * buf;
if (
rosidl_dynamic_typesupport_dynamic_data_get_name(
&get_rosidl_dynamic_data(), &buf,
&buf_length) !=
RCUTILS_RET_OK)
{
throw std::runtime_error(
std::string("could not get name for dynamic data") + rcl_get_error_string().str);
}
return std::string(buf, buf_length);
}
rosidl_dynamic_typesupport_dynamic_data_t &
DynamicMessage::get_rosidl_dynamic_data()
{
return rosidl_dynamic_data_;
}
const rosidl_dynamic_typesupport_dynamic_data_t &
DynamicMessage::get_rosidl_dynamic_data() const
{
return rosidl_dynamic_data_;
}
DynamicSerializationSupport::SharedPtr
DynamicMessage::get_shared_dynamic_serialization_support()
{
return serialization_support_;
}
DynamicSerializationSupport::ConstSharedPtr
DynamicMessage::get_shared_dynamic_serialization_support() const
{
return serialization_support_;
}
size_t
DynamicMessage::get_item_count() const
{
size_t item_count;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_get_item_count(
&get_rosidl_dynamic_data(), &item_count);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error("could not get item count of dynamic data");
}
return item_count;
}
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::get_member_id(size_t index) const
{
rosidl_dynamic_typesupport_member_id_t member_id;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_get_member_id_at_index(
&get_rosidl_dynamic_data(), index, &member_id);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error("could not member id of dynamic data element by index");
}
return member_id;
}
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::get_member_id(const std::string & name) const
{
rosidl_dynamic_typesupport_member_id_t member_id;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_get_member_id_by_name(
&get_rosidl_dynamic_data(), name.c_str(), name.size(), &member_id);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error("could not member id of dynamic data element by name");
}
return member_id;
}
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::get_array_index(size_t index) const
{
rosidl_dynamic_typesupport_member_id_t array_index;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_get_array_index(
&get_rosidl_dynamic_data(), index, &array_index);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error("could not array index of dynamic data element by index");
}
return array_index;
}
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::get_array_index(const std::string & name) const
{
return get_array_index(get_member_id(name));
}
// METHODS =======================================================================================
DynamicMessage
DynamicMessage::clone(rcl_allocator_t allocator)
{
rosidl_dynamic_typesupport_dynamic_data_t rosidl_dynamic_data =
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_data();
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_clone(
&get_rosidl_dynamic_data(), &allocator, &rosidl_dynamic_data);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error(
std::string("could not clone dynamic data: ") + rcl_get_error_string().str);
}
return DynamicMessage(get_shared_dynamic_serialization_support(), std::move(rosidl_dynamic_data));
}
DynamicMessage::SharedPtr
DynamicMessage::clone_shared(rcl_allocator_t allocator)
{
rosidl_dynamic_typesupport_dynamic_data_t rosidl_dynamic_data =
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_data();
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_clone(
&get_rosidl_dynamic_data(), &allocator, &rosidl_dynamic_data);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error(
std::string("could not clone dynamic data: ") + rcl_get_error_string().str);
}
return DynamicMessage::make_shared(
get_shared_dynamic_serialization_support(), std::move(rosidl_dynamic_data));
}
DynamicMessage
DynamicMessage::init_from_type(DynamicMessageType & type, rcl_allocator_t allocator) const
{
rosidl_dynamic_typesupport_dynamic_data_t rosidl_dynamic_data =
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_data();
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_init_from_dynamic_type(
&type.get_rosidl_dynamic_type(), &allocator, &rosidl_dynamic_data);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error("could not init new dynamic data object from dynamic type");
}
return DynamicMessage(serialization_support_, std::move(rosidl_dynamic_data));
}
DynamicMessage::SharedPtr
DynamicMessage::init_from_type_shared(DynamicMessageType & type, rcl_allocator_t allocator) const
{
rosidl_dynamic_typesupport_dynamic_data_t rosidl_dynamic_data =
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_data();
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_init_from_dynamic_type(
&type.get_rosidl_dynamic_type(), &allocator, &rosidl_dynamic_data);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error("could not init new dynamic data object from dynamic type");
}
return DynamicMessage::make_shared(serialization_support_, std::move(rosidl_dynamic_data));
}
bool
DynamicMessage::equals(const DynamicMessage & other) const
{
if (get_serialization_library_identifier() != other.get_serialization_library_identifier()) {
throw std::runtime_error("library identifiers don't match");
}
bool equals;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_equals(
&get_rosidl_dynamic_data(), &other.get_rosidl_dynamic_data(), &equals);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error("could not equate dynamic messages");
}
return equals;
}
DynamicMessage::SharedPtr
DynamicMessage::loan_value(
rosidl_dynamic_typesupport_member_id_t id,
rcl_allocator_t allocator)
{
rosidl_dynamic_typesupport_dynamic_data_t rosidl_dynamic_data =
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_data();
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_loan_value(
&get_rosidl_dynamic_data(), id, &allocator, &rosidl_dynamic_data);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error(
std::string("could not loan dynamic data: ") + rcl_get_error_string().str);
}
return DynamicMessage::make_shared(shared_from_this(), std::move(rosidl_dynamic_data));
}
DynamicMessage::SharedPtr
DynamicMessage::loan_value(const std::string & name, rcl_allocator_t allocator)
{
return loan_value(get_member_id(name), allocator);
}
void
DynamicMessage::clear_all_values()
{
rosidl_dynamic_typesupport_dynamic_data_clear_all_values(&get_rosidl_dynamic_data());
}
void
DynamicMessage::clear_nonkey_values()
{
rosidl_dynamic_typesupport_dynamic_data_clear_nonkey_values(&get_rosidl_dynamic_data());
}
void
DynamicMessage::clear_value(rosidl_dynamic_typesupport_member_id_t id)
{
rosidl_dynamic_typesupport_dynamic_data_clear_value(&get_rosidl_dynamic_data(), id);
}
void
DynamicMessage::clear_value(const std::string & name)
{
clear_value(get_member_id(name));
}
void
DynamicMessage::clear_sequence()
{
rosidl_dynamic_typesupport_dynamic_data_clear_sequence_data(&get_rosidl_dynamic_data());
}
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::insert_sequence_data()
{
rosidl_dynamic_typesupport_member_id_t out;
rosidl_dynamic_typesupport_dynamic_data_insert_sequence_data(&get_rosidl_dynamic_data(), &out);
return out;
}
void
DynamicMessage::remove_sequence_data(rosidl_dynamic_typesupport_member_id_t index)
{
rosidl_dynamic_typesupport_dynamic_data_remove_sequence_data(
&get_rosidl_dynamic_data(), index);
}
bool
DynamicMessage::serialize(rcl_serialized_message_t & buffer)
{
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_serialize(
&get_rosidl_dynamic_data(), &buffer);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error(
std::string("could serialize loan dynamic data: ") + rcl_get_error_string().str);
}
return true;
}
bool
DynamicMessage::deserialize(rcl_serialized_message_t & buffer)
{
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_deserialize(
&get_rosidl_dynamic_data(), &buffer);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error(
std::string("could deserialize loan dynamic data: ") + rcl_get_error_string().str);
}
return true;
}
// MEMBER ACCESS ===================================================================================
// Defined in "detail/dynamic_message_impl.hpp"
// FIXED STRING MEMBER ACCESS ======================================================================
const std::string
DynamicMessage::get_fixed_string_value(
rosidl_dynamic_typesupport_member_id_t id, size_t string_length)
{
size_t buf_length;
char * buf = nullptr;
rosidl_dynamic_typesupport_dynamic_data_get_fixed_string_value(
&get_rosidl_dynamic_data(), id, &buf, &buf_length, string_length);
auto out = std::string(buf, buf_length);
delete buf;
return out;
}
const std::string
DynamicMessage::get_fixed_string_value(const std::string & name, size_t string_length)
{
return get_fixed_string_value(get_member_id(name), string_length);
}
const std::u16string
DynamicMessage::get_fixed_wstring_value(
rosidl_dynamic_typesupport_member_id_t id, size_t wstring_length)
{
size_t buf_length;
char16_t * buf = nullptr;
rosidl_dynamic_typesupport_dynamic_data_get_fixed_wstring_value(
&get_rosidl_dynamic_data(), id, &buf, &buf_length, wstring_length);
auto out = std::u16string(buf, buf_length);
delete buf;
return out;
}
const std::u16string
DynamicMessage::get_fixed_wstring_value(const std::string & name, size_t wstring_length)
{
return get_fixed_wstring_value(get_member_id(name), wstring_length);
}
void
DynamicMessage::set_fixed_string_value(
rosidl_dynamic_typesupport_member_id_t id, const std::string value, size_t string_length)
{
rosidl_dynamic_typesupport_dynamic_data_set_fixed_string_value(
&get_rosidl_dynamic_data(), id, value.c_str(), value.size(), string_length);
}
void
DynamicMessage::set_fixed_string_value(
const std::string & name, const std::string value, size_t string_length)
{
set_fixed_string_value(get_member_id(name), value, string_length);
}
void
DynamicMessage::set_fixed_wstring_value(
rosidl_dynamic_typesupport_member_id_t id, const std::u16string value, size_t wstring_length)
{
rosidl_dynamic_typesupport_dynamic_data_set_fixed_wstring_value(
&get_rosidl_dynamic_data(), id, value.c_str(), value.size(), wstring_length);
}
void
DynamicMessage::set_fixed_wstring_value(
const std::string & name, const std::u16string value, size_t wstring_length)
{
set_fixed_wstring_value(get_member_id(name), value, wstring_length);
}
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::insert_fixed_string_value(const std::string value, size_t string_length)
{
rosidl_dynamic_typesupport_member_id_t out;
rosidl_dynamic_typesupport_dynamic_data_insert_fixed_string_value(
&get_rosidl_dynamic_data(), value.c_str(), value.size(), string_length, &out);
return out;
}
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::insert_fixed_wstring_value(const std::u16string value, size_t wstring_length)
{
rosidl_dynamic_typesupport_member_id_t out;
rosidl_dynamic_typesupport_dynamic_data_insert_fixed_wstring_value(
&get_rosidl_dynamic_data(), value.c_str(), value.size(), wstring_length, &out);
return out;
}
// BOUNDED STRING MEMBER ACCESS ====================================================================
const std::string
DynamicMessage::get_bounded_string_value(
rosidl_dynamic_typesupport_member_id_t id, size_t string_bound)
{
size_t buf_length;
char * buf = nullptr;
rosidl_dynamic_typesupport_dynamic_data_get_bounded_string_value(
&get_rosidl_dynamic_data(), id, &buf, &buf_length, string_bound);
auto out = std::string(buf, buf_length);
delete buf;
return out;
}
const std::string
DynamicMessage::get_bounded_string_value(const std::string & name, size_t string_bound)
{
return get_bounded_string_value(get_member_id(name), string_bound);
}
const std::u16string
DynamicMessage::get_bounded_wstring_value(
rosidl_dynamic_typesupport_member_id_t id, size_t wstring_bound)
{
size_t buf_length;
char16_t * buf = nullptr;
rosidl_dynamic_typesupport_dynamic_data_get_bounded_wstring_value(
&get_rosidl_dynamic_data(), id, &buf, &buf_length, wstring_bound);
auto out = std::u16string(buf, buf_length);
delete buf;
return out;
}
const std::u16string
DynamicMessage::get_bounded_wstring_value(const std::string & name, size_t wstring_bound)
{
return get_bounded_wstring_value(get_member_id(name), wstring_bound);
}
void
DynamicMessage::set_bounded_string_value(
rosidl_dynamic_typesupport_member_id_t id, const std::string value, size_t string_bound)
{
rosidl_dynamic_typesupport_dynamic_data_set_bounded_string_value(
&get_rosidl_dynamic_data(), id, value.c_str(), value.size(), string_bound);
}
void
DynamicMessage::set_bounded_string_value(
const std::string & name, const std::string value, size_t string_bound)
{
set_bounded_string_value(get_member_id(name), value, string_bound);
}
void
DynamicMessage::set_bounded_wstring_value(
rosidl_dynamic_typesupport_member_id_t id, const std::u16string value, size_t wstring_bound)
{
rosidl_dynamic_typesupport_dynamic_data_set_bounded_wstring_value(
&get_rosidl_dynamic_data(), id, value.c_str(), value.size(), wstring_bound);
}
void
DynamicMessage::set_bounded_wstring_value(
const std::string & name, const std::u16string value, size_t wstring_bound)
{
set_bounded_wstring_value(get_member_id(name), value, wstring_bound);
}
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::insert_bounded_string_value(const std::string value, size_t string_bound)
{
rosidl_dynamic_typesupport_member_id_t out;
rosidl_dynamic_typesupport_dynamic_data_insert_bounded_string_value(
&get_rosidl_dynamic_data(), value.c_str(), value.size(), string_bound, &out);
return out;
}
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::insert_bounded_wstring_value(const std::u16string value, size_t wstring_bound)
{
rosidl_dynamic_typesupport_member_id_t out;
rosidl_dynamic_typesupport_dynamic_data_insert_bounded_wstring_value(
&get_rosidl_dynamic_data(), value.c_str(), value.size(), wstring_bound, &out);
return out;
}
// NESTED MEMBER ACCESS ============================================================================
DynamicMessage
DynamicMessage::get_nested_data(
rosidl_dynamic_typesupport_member_id_t id, rcl_allocator_t allocator)
{
rosidl_dynamic_typesupport_dynamic_data_t out =
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_data();
rosidl_dynamic_typesupport_dynamic_data_get_nested_data(
&get_rosidl_dynamic_data(), id, &allocator, &out);
return DynamicMessage(get_shared_dynamic_serialization_support(), std::move(out));
}
DynamicMessage
DynamicMessage::get_nested_data(const std::string & name, rcl_allocator_t allocator)
{
return get_nested_data(get_member_id(name), allocator);
}
DynamicMessage::SharedPtr
DynamicMessage::get_nested_data_shared(
rosidl_dynamic_typesupport_member_id_t id, rcl_allocator_t allocator)
{
rosidl_dynamic_typesupport_dynamic_data_t out =
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_data();
rosidl_dynamic_typesupport_dynamic_data_get_nested_data(
&get_rosidl_dynamic_data(), id, &allocator, &out);
return DynamicMessage::make_shared(get_shared_dynamic_serialization_support(), std::move(out));
}
DynamicMessage::SharedPtr
DynamicMessage::get_nested_data_shared(const std::string & name, rcl_allocator_t allocator)
{
return get_nested_data_shared(get_member_id(name), allocator);
}
void
DynamicMessage::set_nested_data(
rosidl_dynamic_typesupport_member_id_t id, DynamicMessage & value)
{
rosidl_dynamic_typesupport_dynamic_data_set_nested_data(
&get_rosidl_dynamic_data(), id, &value.get_rosidl_dynamic_data());
}
void
DynamicMessage::set_nested_data(const std::string & name, DynamicMessage & value)
{
set_nested_data(get_member_id(name), value);
}
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::insert_nested_data_copy(const DynamicMessage & value)
{
rosidl_dynamic_typesupport_member_id_t out;
rosidl_dynamic_typesupport_dynamic_data_insert_nested_data_copy(
&get_rosidl_dynamic_data(), &value.get_rosidl_dynamic_data(), &out);
return out;
}
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::insert_nested_data(DynamicMessage & value)
{
rosidl_dynamic_typesupport_member_id_t out;
rosidl_dynamic_typesupport_dynamic_data_insert_nested_data(
&get_rosidl_dynamic_data(), &value.get_rosidl_dynamic_data(), &out);
return out;
}
{} // STUBBED

View File

@@ -34,248 +34,5 @@ using rclcpp::dynamic_typesupport::DynamicMessageType;
using rclcpp::dynamic_typesupport::DynamicMessageTypeBuilder;
using rclcpp::dynamic_typesupport::DynamicSerializationSupport;
// CONSTRUCTION ====================================================================================
DynamicMessageType::DynamicMessageType(DynamicMessageTypeBuilder::SharedPtr dynamic_type_builder)
: DynamicMessageType::DynamicMessageType(
dynamic_type_builder, dynamic_type_builder->get_rosidl_dynamic_type_builder().allocator) {}
DynamicMessageType::DynamicMessageType(
DynamicMessageTypeBuilder::SharedPtr dynamic_type_builder,
rcl_allocator_t allocator)
: serialization_support_(dynamic_type_builder->get_shared_dynamic_serialization_support()),
rosidl_dynamic_type_(rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type())
{
if (!serialization_support_) {
throw std::runtime_error("dynamic type could not bind serialization support!");
}
rosidl_dynamic_typesupport_dynamic_type_builder_t rosidl_dynamic_type_builder =
dynamic_type_builder->get_rosidl_dynamic_type_builder();
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_init_from_dynamic_type_builder(
&rosidl_dynamic_type_builder, &allocator, &get_rosidl_dynamic_type());
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error("could not init new dynamic type object");
}
}
DynamicMessageType::DynamicMessageType(
DynamicSerializationSupport::SharedPtr serialization_support,
rosidl_dynamic_typesupport_dynamic_type_t && rosidl_dynamic_type)
: serialization_support_(serialization_support),
rosidl_dynamic_type_(std::move(rosidl_dynamic_type))
{
if (serialization_support) {
if (!match_serialization_support_(*serialization_support, rosidl_dynamic_type)) {
throw std::runtime_error(
"serialization support library identifier does not match dynamic type's!");
}
}
}
DynamicMessageType::DynamicMessageType(
DynamicSerializationSupport::SharedPtr serialization_support,
const rosidl_runtime_c__type_description__TypeDescription & description,
rcl_allocator_t allocator)
: serialization_support_(serialization_support),
rosidl_dynamic_type_(rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type())
{
init_from_description(description, allocator, serialization_support);
}
DynamicMessageType::DynamicMessageType(DynamicMessageType && other) noexcept
: serialization_support_(std::exchange(other.serialization_support_, nullptr)),
rosidl_dynamic_type_(std::exchange(
other.rosidl_dynamic_type_, rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type()))
{}
DynamicMessageType &
DynamicMessageType::operator=(DynamicMessageType && other) noexcept
{
std::swap(serialization_support_, other.serialization_support_);
std::swap(rosidl_dynamic_type_, other.rosidl_dynamic_type_);
return *this;
}
DynamicMessageType::~DynamicMessageType()
{
if (rosidl_dynamic_typesupport_dynamic_type_fini(&get_rosidl_dynamic_type()) != RCUTILS_RET_OK) {
RCUTILS_LOG_ERROR("could not fini rosidl dynamic type");
}
}
void
DynamicMessageType::init_from_description(
const rosidl_runtime_c__type_description__TypeDescription & description,
rcl_allocator_t allocator,
DynamicSerializationSupport::SharedPtr serialization_support)
{
if (serialization_support) {
// Swap serialization support if serialization support is given
serialization_support_ = serialization_support;
}
rosidl_dynamic_typesupport_dynamic_type_t rosidl_dynamic_type =
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type();
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_init_from_description(
&serialization_support_->get_rosidl_serialization_support(),
&description,
&allocator,
&rosidl_dynamic_type);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error("could not init new dynamic type object");
}
rosidl_dynamic_type_ = std::move(rosidl_dynamic_type);
}
bool
DynamicMessageType::match_serialization_support_(
const DynamicSerializationSupport & serialization_support,
const rosidl_dynamic_typesupport_dynamic_type_t & rosidl_dynamic_type)
{
if (serialization_support.get_serialization_library_identifier() != std::string(
rosidl_dynamic_type.serialization_support->serialization_library_identifier))
{
RCUTILS_LOG_ERROR(
"serialization support library identifier does not match dynamic type's (%s vs %s)",
serialization_support.get_serialization_library_identifier().c_str(),
rosidl_dynamic_type.serialization_support->serialization_library_identifier);
return false;
}
return true;
}
// GETTERS =========================================================================================
const std::string
DynamicMessageType::get_serialization_library_identifier() const
{
return std::string(
get_rosidl_dynamic_type().serialization_support->serialization_library_identifier);
}
const std::string
DynamicMessageType::get_name() const
{
size_t buf_length;
const char * buf;
rosidl_dynamic_typesupport_dynamic_type_get_name(&get_rosidl_dynamic_type(), &buf, &buf_length);
return std::string(buf, buf_length);
}
size_t
DynamicMessageType::get_member_count() const
{
size_t out;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_get_member_count(
&get_rosidl_dynamic_type(), &out);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error(
std::string("could not get member count: ") + rcl_get_error_string().str);
}
return out;
}
rosidl_dynamic_typesupport_dynamic_type_t &
DynamicMessageType::get_rosidl_dynamic_type()
{
return rosidl_dynamic_type_;
}
const rosidl_dynamic_typesupport_dynamic_type_t &
DynamicMessageType::get_rosidl_dynamic_type() const
{
return rosidl_dynamic_type_;
}
DynamicSerializationSupport::SharedPtr
DynamicMessageType::get_shared_dynamic_serialization_support()
{
return serialization_support_;
}
DynamicSerializationSupport::ConstSharedPtr
DynamicMessageType::get_shared_dynamic_serialization_support() const
{
return serialization_support_;
}
// METHODS =========================================================================================
DynamicMessageType
DynamicMessageType::clone(rcl_allocator_t allocator)
{
rosidl_dynamic_typesupport_dynamic_type_t rosidl_dynamic_type =
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type();
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_clone(
&get_rosidl_dynamic_type(), &allocator, &rosidl_dynamic_type);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error(
std::string("could not clone dynamic type: ") + rcl_get_error_string().str);
}
return DynamicMessageType(
get_shared_dynamic_serialization_support(), std::move(rosidl_dynamic_type));
}
DynamicMessageType::SharedPtr
DynamicMessageType::clone_shared(rcl_allocator_t allocator)
{
rosidl_dynamic_typesupport_dynamic_type_t rosidl_dynamic_type =
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type();
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_clone(
&get_rosidl_dynamic_type(), &allocator, &rosidl_dynamic_type);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error(
std::string("could not clone dynamic type: ") + rcl_get_error_string().str);
}
return DynamicMessageType::make_shared(
get_shared_dynamic_serialization_support(), std::move(rosidl_dynamic_type));
}
bool
DynamicMessageType::equals(const DynamicMessageType & other) const
{
if (get_serialization_library_identifier() != other.get_serialization_library_identifier()) {
throw std::runtime_error("library identifiers don't match");
}
bool out;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_equals(
&get_rosidl_dynamic_type(), &other.get_rosidl_dynamic_type(), &out);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error(
std::string("could not equate dynamic message types: ") + rcl_get_error_string().str);
}
return out;
}
DynamicMessage
DynamicMessageType::build_dynamic_message(rcl_allocator_t allocator)
{
return DynamicMessage(shared_from_this(), allocator);
}
DynamicMessage::SharedPtr
DynamicMessageType::build_dynamic_message_shared(rcl_allocator_t allocator)
{
return DynamicMessage::make_shared(shared_from_this(), allocator);
}
{} // STUBBED

View File

@@ -33,582 +33,5 @@ using rclcpp::dynamic_typesupport::DynamicMessageType;
using rclcpp::dynamic_typesupport::DynamicMessageTypeBuilder;
using rclcpp::dynamic_typesupport::DynamicSerializationSupport;
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_TYPE_BUILDER_IMPL_HPP_
// Template specialization implementations
#include "rclcpp/dynamic_typesupport/detail/dynamic_message_type_builder_impl.hpp"
#endif
// CONSTRUCTION ====================================================================================
DynamicMessageTypeBuilder::DynamicMessageTypeBuilder(
DynamicSerializationSupport::SharedPtr serialization_support, const std::string & name)
: DynamicMessageTypeBuilder::DynamicMessageTypeBuilder(
serialization_support,
name,
serialization_support->get_rosidl_serialization_support().allocator) {}
DynamicMessageTypeBuilder::DynamicMessageTypeBuilder(
DynamicSerializationSupport::SharedPtr serialization_support,
const std::string & name,
rcl_allocator_t allocator)
: serialization_support_(serialization_support),
rosidl_dynamic_type_builder_(
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type_builder())
{
init_from_serialization_support_(serialization_support, name, allocator);
}
DynamicMessageTypeBuilder::DynamicMessageTypeBuilder(
DynamicSerializationSupport::SharedPtr serialization_support,
rosidl_dynamic_typesupport_dynamic_type_builder_t && rosidl_dynamic_type_builder)
: serialization_support_(serialization_support),
rosidl_dynamic_type_builder_(
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type_builder())
{
if (!serialization_support) {
throw std::runtime_error("serialization support cannot be nullptr!");
}
if (!match_serialization_support_(*serialization_support, rosidl_dynamic_type_builder)) {
throw std::runtime_error(
"serialization support library does not match dynamic type builder's!");
}
}
DynamicMessageTypeBuilder::DynamicMessageTypeBuilder(
DynamicSerializationSupport::SharedPtr serialization_support,
const rosidl_runtime_c__type_description__TypeDescription & description,
rcl_allocator_t allocator)
: serialization_support_(serialization_support),
rosidl_dynamic_type_builder_(
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type_builder())
{
if (!serialization_support) {
throw std::runtime_error("serialization support cannot be nullptr!");
}
init_from_description(description, allocator, serialization_support);
}
DynamicMessageTypeBuilder::DynamicMessageTypeBuilder(DynamicMessageTypeBuilder && other) noexcept
: serialization_support_(std::exchange(other.serialization_support_, nullptr)),
rosidl_dynamic_type_builder_(std::exchange(
other.rosidl_dynamic_type_builder_,
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type_builder())) {}
DynamicMessageTypeBuilder &
DynamicMessageTypeBuilder::operator=(DynamicMessageTypeBuilder && other) noexcept
{
std::swap(serialization_support_, other.serialization_support_);
std::swap(rosidl_dynamic_type_builder_, other.rosidl_dynamic_type_builder_);
return *this;
}
DynamicMessageTypeBuilder::~DynamicMessageTypeBuilder()
{
if (rosidl_dynamic_typesupport_dynamic_type_builder_fini(&get_rosidl_dynamic_type_builder()) !=
RCUTILS_RET_OK)
{
RCUTILS_LOG_ERROR("could not fini rosidl dynamic type builder");
}
}
void
DynamicMessageTypeBuilder::init_from_description(
const rosidl_runtime_c__type_description__TypeDescription & description,
rcl_allocator_t allocator,
DynamicSerializationSupport::SharedPtr serialization_support)
{
if (serialization_support) {
// Swap serialization support if serialization support is given
serialization_support_ = serialization_support;
}
rosidl_dynamic_typesupport_dynamic_type_builder_t rosidl_dynamic_type_builder =
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type_builder();
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_builder_init_from_description(
&serialization_support_->get_rosidl_serialization_support(),
&description,
&allocator,
&rosidl_dynamic_type_builder);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error("could not init new dynamic type builder object");
}
rosidl_dynamic_type_builder_ = std::move(rosidl_dynamic_type_builder);
}
void
DynamicMessageTypeBuilder::init_from_serialization_support_(
DynamicSerializationSupport::SharedPtr serialization_support,
const std::string & name,
rcl_allocator_t allocator)
{
if (!serialization_support) {
throw std::runtime_error("serialization support cannot be nullptr!");
}
if (!&serialization_support->get_rosidl_serialization_support()) {
throw std::runtime_error("serialization support raw pointer cannot be nullptr!");
}
rosidl_dynamic_typesupport_dynamic_type_builder_t rosidl_dynamic_type_builder =
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type_builder();
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_builder_init(
&serialization_support->get_rosidl_serialization_support(),
name.c_str(), name.size(),
&allocator,
&rosidl_dynamic_type_builder);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error(
std::string("could not init dynamic type builder: ") + rcl_get_error_string().str);
}
}
bool
DynamicMessageTypeBuilder::match_serialization_support_(
const DynamicSerializationSupport & serialization_support,
const rosidl_dynamic_typesupport_dynamic_type_builder_t & rosidl_dynamic_type_builder)
{
if (serialization_support.get_serialization_library_identifier() != std::string(
rosidl_dynamic_type_builder.serialization_support->serialization_library_identifier))
{
RCUTILS_LOG_ERROR(
"serialization support library identifier does not match dynamic type builder's");
return false;
}
return true;
}
// GETTERS =======================================================================================
const std::string
DynamicMessageTypeBuilder::get_serialization_library_identifier() const
{
return std::string(
get_rosidl_dynamic_type_builder().serialization_support->serialization_library_identifier);
}
const std::string
DynamicMessageTypeBuilder::get_name() const
{
size_t buf_length;
const char * buf;
rosidl_dynamic_typesupport_dynamic_type_builder_get_name(
&get_rosidl_dynamic_type_builder(), &buf, &buf_length);
return std::string(buf, buf_length);
}
rosidl_dynamic_typesupport_dynamic_type_builder_t &
DynamicMessageTypeBuilder::get_rosidl_dynamic_type_builder()
{
return rosidl_dynamic_type_builder_;
}
const rosidl_dynamic_typesupport_dynamic_type_builder_t &
DynamicMessageTypeBuilder::get_rosidl_dynamic_type_builder() const
{
return rosidl_dynamic_type_builder_;
}
DynamicSerializationSupport::SharedPtr
DynamicMessageTypeBuilder::get_shared_dynamic_serialization_support()
{
return serialization_support_;
}
DynamicSerializationSupport::ConstSharedPtr
DynamicMessageTypeBuilder::get_shared_dynamic_serialization_support() const
{
return serialization_support_;
}
// METHODS =======================================================================================
void
DynamicMessageTypeBuilder::set_name(const std::string & name)
{
rosidl_dynamic_typesupport_dynamic_type_builder_set_name(
&get_rosidl_dynamic_type_builder(), name.c_str(), name.size());
}
DynamicMessageTypeBuilder
DynamicMessageTypeBuilder::clone(rcl_allocator_t allocator)
{
rosidl_dynamic_typesupport_dynamic_type_builder_t rosidl_dynamic_type_builder =
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type_builder();
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_builder_clone(
&get_rosidl_dynamic_type_builder(), &allocator, &rosidl_dynamic_type_builder);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error(
std::string("could not clone dynamic type builder: ") + rcl_get_error_string().str);
}
return DynamicMessageTypeBuilder(
get_shared_dynamic_serialization_support(), std::move(rosidl_dynamic_type_builder));
}
DynamicMessageTypeBuilder::SharedPtr
DynamicMessageTypeBuilder::clone_shared(rcl_allocator_t allocator)
{
rosidl_dynamic_typesupport_dynamic_type_builder_t rosidl_dynamic_type_builder =
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type_builder();
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_builder_clone(
&get_rosidl_dynamic_type_builder(), &allocator, &rosidl_dynamic_type_builder);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error(
std::string("could not clone dynamic type builder: ") + rcl_get_error_string().str);
}
return DynamicMessageTypeBuilder::make_shared(
get_shared_dynamic_serialization_support(), std::move(rosidl_dynamic_type_builder));
}
void
DynamicMessageTypeBuilder::clear(rcl_allocator_t allocator)
{
if (!serialization_support_) {
throw std::runtime_error(
"cannot call clear() on a dynamic type builder with uninitialized serialization support"
);
}
const std::string & name = get_name();
init_from_serialization_support_(serialization_support_, name, allocator);
}
DynamicMessage
DynamicMessageTypeBuilder::build_dynamic_message(rcl_allocator_t allocator)
{
return DynamicMessage(shared_from_this(), allocator);
}
DynamicMessage::SharedPtr
DynamicMessageTypeBuilder::build_dynamic_message_shared(rcl_allocator_t allocator)
{
return DynamicMessage::make_shared(shared_from_this(), allocator);
}
DynamicMessageType
DynamicMessageTypeBuilder::build_dynamic_message_type(rcl_allocator_t allocator)
{
return DynamicMessageType(shared_from_this(), allocator);
}
DynamicMessageType::SharedPtr
DynamicMessageTypeBuilder::build_dynamic_message_type_shared(rcl_allocator_t allocator)
{
return DynamicMessageType::make_shared(shared_from_this(), allocator);
}
// ADD MEMBERS =====================================================================================
// Defined in "detail/dynamic_message_type_builder_impl.hpp"
// ADD FIXED STRING MEMBERS ========================================================================
void
DynamicMessageTypeBuilder::add_fixed_string_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_length,
const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_fixed_string_member(
&get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
string_length);
}
void
DynamicMessageTypeBuilder::add_fixed_wstring_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_length,
const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_fixed_wstring_member(
&get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
wstring_length);
}
void
DynamicMessageTypeBuilder::add_fixed_string_array_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t string_length, size_t array_length, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_fixed_string_array_member(
&get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
string_length, array_length);
}
void
DynamicMessageTypeBuilder::add_fixed_wstring_array_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t wstring_length, size_t array_length, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_fixed_wstring_array_member(
&get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
wstring_length, array_length);
}
void
DynamicMessageTypeBuilder::add_fixed_string_unbounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_length,
const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_fixed_string_unbounded_sequence_member(
&get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
string_length);
}
void
DynamicMessageTypeBuilder::add_fixed_wstring_unbounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_length,
const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_fixed_wstring_unbounded_sequence_member(
&get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
wstring_length);
}
void
DynamicMessageTypeBuilder::add_fixed_string_bounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t string_length, size_t sequence_bound, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_fixed_string_bounded_sequence_member(
&get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
string_length, sequence_bound);
}
void
DynamicMessageTypeBuilder::add_fixed_wstring_bounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t wstring_length, size_t sequence_bound, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_fixed_wstring_bounded_sequence_member(
&get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
wstring_length, sequence_bound);
}
// ADD BOUNDED STRING MEMBERS ======================================================================
void
DynamicMessageTypeBuilder::add_bounded_string_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_bound,
const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_bounded_string_member(
&get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
string_bound);
}
void
DynamicMessageTypeBuilder::add_bounded_wstring_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_bound,
const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_bounded_wstring_member(
&get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
wstring_bound);
}
void
DynamicMessageTypeBuilder::add_bounded_string_array_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t string_bound, size_t array_length, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_bounded_string_array_member(
&get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
string_bound, array_length);
}
void
DynamicMessageTypeBuilder::add_bounded_wstring_array_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t wstring_bound, size_t array_length, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_bounded_wstring_array_member(
&get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
wstring_bound, array_length);
}
void
DynamicMessageTypeBuilder::add_bounded_string_unbounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_bound,
const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_bounded_string_unbounded_sequence_member(
&get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
string_bound);
}
void
DynamicMessageTypeBuilder::add_bounded_wstring_unbounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_bound,
const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_bounded_wstring_unbounded_sequence_member(
&get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
wstring_bound);
}
void
DynamicMessageTypeBuilder::add_bounded_string_bounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t string_bound, size_t sequence_bound, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_bounded_string_bounded_sequence_member(
&get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
string_bound, sequence_bound);
}
void
DynamicMessageTypeBuilder::add_bounded_wstring_bounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t wstring_bound, size_t sequence_bound, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_bounded_wstring_bounded_sequence_member(
&get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
wstring_bound, sequence_bound);
}
// ADD NESTED MEMBERS ==============================================================================
void
DynamicMessageTypeBuilder::add_complex_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageType & nested_type, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_complex_member(
&get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
&nested_type.get_rosidl_dynamic_type());
}
void
DynamicMessageTypeBuilder::add_complex_array_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageType & nested_type, size_t array_length, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_complex_array_member(
&get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
&nested_type.get_rosidl_dynamic_type(), array_length);
}
void
DynamicMessageTypeBuilder::add_complex_unbounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageType & nested_type, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_complex_unbounded_sequence_member(
&get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
&nested_type.get_rosidl_dynamic_type());
}
void
DynamicMessageTypeBuilder::add_complex_bounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageType & nested_type, size_t sequence_bound, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_complex_bounded_sequence_member(
&get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
&nested_type.get_rosidl_dynamic_type(), sequence_bound);
}
void
DynamicMessageTypeBuilder::add_complex_member_builder(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageTypeBuilder & nested_type_builder, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_complex_member_builder(
&get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
&nested_type_builder.get_rosidl_dynamic_type_builder());
}
void
DynamicMessageTypeBuilder::add_complex_array_member_builder(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageTypeBuilder & nested_type_builder, size_t array_length,
const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_complex_array_member_builder(
&get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
&nested_type_builder.get_rosidl_dynamic_type_builder(), array_length);
}
void
DynamicMessageTypeBuilder::add_complex_unbounded_sequence_member_builder(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageTypeBuilder & nested_type_builder, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_complex_unbounded_sequence_member_builder(
&get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
&nested_type_builder.get_rosidl_dynamic_type_builder());
}
void
DynamicMessageTypeBuilder::add_complex_bounded_sequence_member_builder(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageTypeBuilder & nested_type_builder, size_t sequence_bound,
const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_complex_bounded_sequence_member_builder(
&get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
&nested_type_builder.get_rosidl_dynamic_type_builder(), sequence_bound);
}
{} // STUBBED

View File

@@ -45,273 +45,5 @@ using rclcpp::dynamic_typesupport::DynamicMessageType;
using rclcpp::dynamic_typesupport::DynamicMessageTypeSupport;
using rclcpp::dynamic_typesupport::DynamicSerializationSupport;
// CONSTRUCTION ====================================================================================
DynamicMessageTypeSupport::DynamicMessageTypeSupport(
const rosidl_runtime_c__type_description__TypeDescription & description,
const std::string & serialization_library_name,
rcl_allocator_t allocator)
: serialization_support_(nullptr),
dynamic_message_type_(nullptr),
dynamic_message_(nullptr),
rosidl_message_type_support_(rosidl_get_zero_initialized_message_type_support_handle())
{
rcl_ret_t ret;
if (serialization_library_name.empty()) {
ret = rcl_dynamic_message_type_support_handle_init(
nullptr, &description, &allocator, &rosidl_message_type_support_);
} else {
ret = rcl_dynamic_message_type_support_handle_init(
serialization_library_name.c_str(), &description, &allocator, &rosidl_message_type_support_);
}
if (ret != RCL_RET_OK) {
std::string error_msg =
std::string("error initializing rosidl message type support: ") + rcl_get_error_string().str;
rcl_reset_error();
throw std::runtime_error(error_msg);
}
if (rosidl_message_type_support_.typesupport_identifier !=
rosidl_get_dynamic_typesupport_identifier())
{
throw std::runtime_error("rosidl message type support is of the wrong type");
}
auto ts_impl = static_cast<rosidl_dynamic_message_type_support_impl_t *>(const_cast<void *>(
rosidl_message_type_support_.data));
serialization_support_ = DynamicSerializationSupport::make_shared(
std::move(ts_impl->serialization_support));
dynamic_message_type_ = DynamicMessageType::make_shared(
get_shared_dynamic_serialization_support(), std::move(*ts_impl->dynamic_message_type));
dynamic_message_ = DynamicMessage::make_shared(
get_shared_dynamic_serialization_support(), std::move(*ts_impl->dynamic_message));
}
DynamicMessageTypeSupport::DynamicMessageTypeSupport(
DynamicSerializationSupport::SharedPtr serialization_support,
const rosidl_runtime_c__type_description__TypeDescription & description,
rcl_allocator_t allocator)
: serialization_support_(serialization_support),
dynamic_message_type_(nullptr),
dynamic_message_(nullptr),
rosidl_message_type_support_(rosidl_get_zero_initialized_message_type_support_handle())
{
// Check null
if (!serialization_support) {
throw std::runtime_error("serialization_support cannot be nullptr.");
}
rosidl_type_hash_t type_hash;
rcutils_ret_t hash_ret = rcl_calculate_type_hash(
// TODO(methylDragon): Swap this out with the conversion function when it is ready
reinterpret_cast<const type_description_interfaces__msg__TypeDescription *>(&description),
&type_hash);
if (hash_ret != RCL_RET_OK) {
throw std::runtime_error("failed to get type hash");
}
rcutils_ret_t ret = rosidl_dynamic_message_type_support_handle_init(
&serialization_support->get_rosidl_serialization_support(),
&type_hash, // type_hash
&description, // type_description
nullptr, // type_description_sources (not implemented for dynamic types)
&allocator,
&rosidl_message_type_support_);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error("could not init rosidl message type support");
}
if (rosidl_message_type_support_.typesupport_identifier !=
rosidl_get_dynamic_typesupport_identifier())
{
throw std::runtime_error("rosidl message type support is of the wrong type");
}
auto ts_impl = static_cast<const rosidl_dynamic_message_type_support_impl_t *>(
rosidl_message_type_support_.data);
dynamic_message_type_ = DynamicMessageType::make_shared(
get_shared_dynamic_serialization_support(), std::move(*ts_impl->dynamic_message_type));
dynamic_message_ = DynamicMessage::make_shared(
get_shared_dynamic_serialization_support(), std::move(*ts_impl->dynamic_message));
}
DynamicMessageTypeSupport::DynamicMessageTypeSupport(
DynamicSerializationSupport::SharedPtr serialization_support,
DynamicMessageType::SharedPtr dynamic_message_type,
DynamicMessage::SharedPtr dynamic_message,
const rosidl_runtime_c__type_description__TypeDescription & description,
rcl_allocator_t allocator)
: serialization_support_(serialization_support),
dynamic_message_type_(dynamic_message_type),
dynamic_message_(dynamic_message),
rosidl_message_type_support_(rosidl_get_zero_initialized_message_type_support_handle())
{
// Check null
if (!serialization_support) {
throw std::runtime_error("serialization_support cannot be nullptr.");
}
if (!dynamic_message_type) {
throw std::runtime_error("dynamic_message_type cannot be nullptr.");
}
if (!dynamic_message) {
throw std::runtime_error("dynamic_message cannot be nullptr.");
}
// Check identifiers
if (serialization_support->get_serialization_library_identifier() !=
dynamic_message_type->get_serialization_library_identifier())
{
throw std::runtime_error(
"serialization support library identifier does not match "
"dynamic message type library identifier.");
}
if (dynamic_message_type->get_serialization_library_identifier() !=
dynamic_message->get_serialization_library_identifier())
{
throw std::runtime_error(
"dynamic message type library identifier does not match "
"dynamic message library identifier.");
}
rosidl_type_hash_t type_hash;
rcutils_ret_t hash_ret = rcl_calculate_type_hash(
// TODO(methylDragon): Swap this out with the conversion function when it is ready
// from https://github.com/ros2/rcl/pull/1052
reinterpret_cast<const type_description_interfaces__msg__TypeDescription *>(&description),
&type_hash);
if (hash_ret != RCL_RET_OK) {
std::string error_msg = std::string("failed to get type hash: ") + rcl_get_error_string().str;
rcl_reset_error();
throw std::runtime_error(error_msg);
}
auto ts_impl = static_cast<rosidl_dynamic_message_type_support_impl_t *>(
allocator.zero_allocate(1, sizeof(rosidl_dynamic_message_type_support_impl_t), allocator.state)
);
if (!ts_impl) {
throw std::runtime_error("could not allocate rosidl_message_type_support_t");
}
ts_impl->allocator = allocator;
ts_impl->type_hash = type_hash;
if (!rosidl_runtime_c__type_description__TypeDescription__copy(
&description, &ts_impl->type_description))
{
throw std::runtime_error("could not copy type description");
}
// ts_impl->type_description_sources = // Not used
ts_impl->serialization_support = serialization_support->get_rosidl_serialization_support();
ts_impl->dynamic_message_type = &dynamic_message_type->get_rosidl_dynamic_type();
ts_impl->dynamic_message = &dynamic_message->get_rosidl_dynamic_data();
rosidl_message_type_support_ = {
rosidl_get_dynamic_typesupport_identifier(), // typesupport_identifier
ts_impl, // data
get_message_typesupport_handle_function, // func
// get_type_hash_func
rosidl_get_dynamic_message_type_support_type_hash_function,
// get_type_description_func
rosidl_get_dynamic_message_type_support_type_description_function,
// get_type_description_sources_func
rosidl_get_dynamic_message_type_support_type_description_sources_function
};
}
DynamicMessageTypeSupport::~DynamicMessageTypeSupport()
{
// These must go first
serialization_support_.reset();
dynamic_message_type_.reset();
dynamic_message_.reset();
// Early return if type support isn't populated to avoid segfaults
if (!rosidl_message_type_support_.data) {
return;
}
// We only partially finalize the rosidl_message_type_support->data since its pointer members are
// managed by their respective SharedPtr wrapper classes.
auto ts_impl = static_cast<rosidl_dynamic_message_type_support_impl_t *>(
const_cast<void *>(rosidl_message_type_support_.data)
);
rcutils_allocator_t allocator = ts_impl->allocator;
rosidl_runtime_c__type_description__TypeDescription__fini(&ts_impl->type_description);
rosidl_runtime_c__type_description__TypeSource__Sequence__fini(
&ts_impl->type_description_sources);
allocator.deallocate(static_cast<void *>(ts_impl), allocator.state); // Always C allocated
}
// GETTERS =========================================================================================
const std::string
DynamicMessageTypeSupport::get_serialization_library_identifier() const
{
return serialization_support_->get_serialization_library_identifier();
}
rosidl_message_type_support_t &
DynamicMessageTypeSupport::get_rosidl_message_type_support()
{
return rosidl_message_type_support_;
}
const rosidl_message_type_support_t &
DynamicMessageTypeSupport::get_const_rosidl_message_type_support()
{
return rosidl_message_type_support_;
}
const rosidl_message_type_support_t &
DynamicMessageTypeSupport::get_const_rosidl_message_type_support() const
{
return rosidl_message_type_support_;
}
const rosidl_runtime_c__type_description__TypeDescription &
DynamicMessageTypeSupport::get_rosidl_runtime_c_type_description() const
{
auto ts_impl = static_cast<const rosidl_dynamic_message_type_support_impl_t *>(
get_const_rosidl_message_type_support().data
);
return ts_impl->type_description;
}
DynamicSerializationSupport::SharedPtr
DynamicMessageTypeSupport::get_shared_dynamic_serialization_support()
{
return serialization_support_;
}
DynamicSerializationSupport::ConstSharedPtr
DynamicMessageTypeSupport::get_shared_dynamic_serialization_support() const
{
return serialization_support_;
}
DynamicMessageType::SharedPtr
DynamicMessageTypeSupport::get_shared_dynamic_message_type()
{
return dynamic_message_type_;
}
DynamicMessageType::ConstSharedPtr
DynamicMessageTypeSupport::get_shared_dynamic_message_type() const
{
return dynamic_message_type_;
}
DynamicMessage::SharedPtr
DynamicMessageTypeSupport::get_shared_dynamic_message()
{
return dynamic_message_;
}
DynamicMessage::ConstSharedPtr
DynamicMessageTypeSupport::get_shared_dynamic_message() const
{
return dynamic_message_;
}
{} // STUBBED

View File

@@ -28,71 +28,19 @@ using rclcpp::dynamic_typesupport::DynamicSerializationSupport;
// CONSTRUCTION ====================================================================================
DynamicSerializationSupport::DynamicSerializationSupport(rcl_allocator_t allocator)
: DynamicSerializationSupport::DynamicSerializationSupport("", allocator) {}
: DynamicSerializationSupport::DynamicSerializationSupport("", allocator)
{
throw std::runtime_error("Unimplemented");
}
DynamicSerializationSupport::DynamicSerializationSupport(
const std::string & serialization_library_name,
rcl_allocator_t allocator)
const std::string & /*serialization_library_name*/,
rcl_allocator_t /*allocator*/)
: rosidl_serialization_support_(
rosidl_dynamic_typesupport_get_zero_initialized_serialization_support())
{
rmw_ret_t ret = RMW_RET_ERROR;
if (serialization_library_name.empty()) {
ret = rmw_serialization_support_init(NULL, &allocator, &rosidl_serialization_support_);
} else {
ret = rmw_serialization_support_init(
serialization_library_name.c_str(), &allocator, &rosidl_serialization_support_);
}
if (ret != RCL_RET_OK) {
std::string error_msg =
std::string("could not initialize new serialization support object: ") +
rcl_get_error_string().str;
rcl_reset_error();
throw std::runtime_error(error_msg);
}
}
DynamicSerializationSupport::DynamicSerializationSupport(
rosidl_dynamic_typesupport_serialization_support_t && rosidl_serialization_support)
: rosidl_serialization_support_(std::move(rosidl_serialization_support)) {}
DynamicSerializationSupport::DynamicSerializationSupport(
DynamicSerializationSupport && other) noexcept
: rosidl_serialization_support_(std::exchange(
other.rosidl_serialization_support_,
rosidl_dynamic_typesupport_get_zero_initialized_serialization_support())) {}
DynamicSerializationSupport &
DynamicSerializationSupport::operator=(DynamicSerializationSupport && other) noexcept
{
std::swap(rosidl_serialization_support_, other.rosidl_serialization_support_);
return *this;
throw std::runtime_error("Unimplemented");
}
DynamicSerializationSupport::~DynamicSerializationSupport()
{
rosidl_dynamic_typesupport_serialization_support_fini(&rosidl_serialization_support_);
}
// GETTERS =========================================================================================
const std::string
DynamicSerializationSupport::get_serialization_library_identifier() const
{
return std::string(
rosidl_dynamic_typesupport_serialization_support_get_library_identifier(
&rosidl_serialization_support_));
}
rosidl_dynamic_typesupport_serialization_support_t &
DynamicSerializationSupport::get_rosidl_serialization_support()
{
return rosidl_serialization_support_;
}
const rosidl_dynamic_typesupport_serialization_support_t &
DynamicSerializationSupport::get_rosidl_serialization_support() const
{
return rosidl_serialization_support_;
}
{} // STUBBED

View File

@@ -84,7 +84,9 @@ Executor::Executor(const rclcpp::ExecutorOptions & options)
notify_waitable_->add_guard_condition(interrupt_guard_condition_);
notify_waitable_->add_guard_condition(shutdown_guard_condition_);
wait_set_.add_waitable(notify_waitable_);
// we need to initially rebuild the collection,
// so that the notify_waitable_ is added
collect_entities();
}
Executor::~Executor()
@@ -129,7 +131,7 @@ Executor::~Executor()
}
void
Executor::handle_updated_entities(bool notify)
Executor::trigger_entity_recollect(bool notify)
{
this->entities_need_rebuild_.store(true);
@@ -174,11 +176,11 @@ Executor::add_callback_group(
this->collector_.add_callback_group(group_ptr);
try {
this->handle_updated_entities(notify);
this->trigger_entity_recollect(notify);
} catch (const rclcpp::exceptions::RCLError & ex) {
throw std::runtime_error(
std::string(
"Failed to handle entities update on callback group add: ") + ex.what());
"Failed to trigger guard condition on callback group add: ") + ex.what());
}
}
@@ -188,11 +190,11 @@ Executor::add_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_pt
this->collector_.add_node(node_ptr);
try {
this->handle_updated_entities(notify);
this->trigger_entity_recollect(notify);
} catch (const rclcpp::exceptions::RCLError & ex) {
throw std::runtime_error(
std::string(
"Failed to handle entities update on node add: ") + ex.what());
"Failed to trigger guard condition on node add: ") + ex.what());
}
}
@@ -204,11 +206,11 @@ Executor::remove_callback_group(
this->collector_.remove_callback_group(group_ptr);
try {
this->handle_updated_entities(notify);
this->trigger_entity_recollect(notify);
} catch (const rclcpp::exceptions::RCLError & ex) {
throw std::runtime_error(
std::string(
"Failed to handle entities update on callback group remove: ") + ex.what());
"Failed to trigger guard condition on callback group remove: ") + ex.what());
}
}
@@ -224,11 +226,11 @@ Executor::remove_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node
this->collector_.remove_node(node_ptr);
try {
this->handle_updated_entities(notify);
this->trigger_entity_recollect(notify);
} catch (const rclcpp::exceptions::RCLError & ex) {
throw std::runtime_error(
std::string(
"Failed to handle entities update on node remove: ") + ex.what());
"Failed to trigger guard condition on node remove: ") + ex.what());
}
}
@@ -371,7 +373,14 @@ Executor::spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive)
// both spin_some and spin_all wait for work at the beginning
wait_result_.reset();
wait_for_work(std::chrono::milliseconds(0));
bool just_waited = true;
bool entity_states_fully_polled = true;
if (entities_need_rebuild_) {
// if the last wait triggered a collection rebuild, we need to call
// wait_for_work once more, in order to do a collection rebuild and collect
// events from the just added entities
entity_states_fully_polled = false;
}
// The logic of this while loop is as follows:
//
@@ -393,12 +402,14 @@ Executor::spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive)
AnyExecutable any_exec;
if (get_next_ready_executable(any_exec)) {
execute_any_executable(any_exec);
just_waited = false;
// during the execution some entity might got ready therefore we need
// to repoll the states of all entities
entity_states_fully_polled = false;
} else {
// if nothing is ready, reset the result to clear it
wait_result_.reset();
if (just_waited) {
if (entity_states_fully_polled) {
// there was no work after just waiting, always exit in this case
// before the exhaustive condition can be checked
break;
@@ -408,7 +419,13 @@ Executor::spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive)
// if exhaustive, wait for work again
// this only happens for spin_all; spin_some only waits at the start
wait_for_work(std::chrono::milliseconds(0));
just_waited = true;
entity_states_fully_polled = true;
if (entities_need_rebuild_) {
// if the last wait triggered a collection rebuild, we need to call
// wait_for_work once more, in order to do a collection rebuild and
// collect events from the just added entities
entity_states_fully_polled = false;
}
} else {
break;
}
@@ -610,25 +627,10 @@ Executor::execute_subscription(rclcpp::SubscriptionBase::SharedPtr subscription)
}
// DYNAMIC SUBSCRIPTION ========================================================================
// If a subscription is dynamic, then it will use its serialization-specific dynamic data.
//
// Two cases:
// - Dynamic type subscription using dynamic type stored in its own internal type support struct
// - Non-dynamic type subscription with no stored dynamic type
// - Subscriptions of this type must be able to lookup the local message description to
// generate a dynamic type at runtime!
// - TODO(methylDragon): I won't be handling this case yet
// Deliver dynamic message
case rclcpp::DeliveredMessageKind::DYNAMIC_MESSAGE:
{
DynamicMessage::SharedPtr dynamic_message = subscription->create_dynamic_message();
take_and_do_error_handling(
"taking a dynamic message from topic",
subscription->get_topic_name(),
// This modifies the stored dynamic data in the DynamicMessage in-place
[&]() {return subscription->take_dynamic_message(*dynamic_message, message_info);},
[&]() {subscription->handle_dynamic_message(dynamic_message, message_info);});
subscription->return_dynamic_message(dynamic_message);
break;
throw std::runtime_error("Unimplemented");
}
default:

View File

@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <iostream>
#include "rclcpp/exceptions.hpp"
#include "rclcpp/executors/executor_notify_waitable.hpp"
@@ -89,9 +91,9 @@ ExecutorNotifyWaitable::is_ready(const rcl_wait_set_t & wait_set)
}
void
ExecutorNotifyWaitable::execute(const std::shared_ptr<void> & /*data*/)
ExecutorNotifyWaitable::execute(const std::shared_ptr<void> & data)
{
std::lock_guard<std::mutex> lock(execute_mutex_);
(void) data;
this->execute_callback_();
}
@@ -147,14 +149,6 @@ ExecutorNotifyWaitable::clear_on_ready_callback()
}
}
RCLCPP_PUBLIC
void
ExecutorNotifyWaitable::set_execute_callback(std::function<void(void)> on_execute_callback)
{
std::lock_guard<std::mutex> lock(execute_mutex_);
execute_callback_ = on_execute_callback;
}
void
ExecutorNotifyWaitable::add_guard_condition(rclcpp::GuardCondition::WeakPtr weak_guard_condition)
{

View File

@@ -52,36 +52,29 @@ EventsExecutor::EventsExecutor(
timers_manager_ =
std::make_shared<rclcpp::experimental::TimersManager>(context_, timer_on_ready_cb);
entities_need_rebuild_ = false;
this->current_entities_collection_ =
std::make_shared<rclcpp::executors::ExecutorEntitiesCollection>();
this->setup_notify_waitable();
// Ensure that the entities collection is empty (the base class may have added elements
// that we are not interested in)
this->current_collection_.clear();
// Make sure that the notify waitable is immediately added to the collection
// to avoid missing events
this->add_notify_waitable_to_collection(current_collection_.waitables);
}
void
EventsExecutor::setup_notify_waitable()
{
// The base class already created this object but the events-executor
// needs different callbacks.
assert(notify_waitable_ && "The notify waitable should have already been constructed");
notify_waitable_->set_execute_callback(
notify_waitable_ = std::make_shared<rclcpp::executors::ExecutorNotifyWaitable>(
[this]() {
// This callback is invoked when:
// - the interrupt or shutdown guard condition is triggered:
// ---> we need to wake up the executor so that it can terminate
// - a node or callback group guard condition is triggered:
// ---> the entities collection is changed, we need to update callbacks
this->handle_updated_entities(false);
this->refresh_current_collection_from_callback_groups();
});
// Make sure that the notify waitable is immediately added to the collection
// to avoid missing events
this->add_notify_waitable_to_collection(current_entities_collection_->waitables);
notify_waitable_->add_guard_condition(interrupt_guard_condition_);
notify_waitable_->add_guard_condition(shutdown_guard_condition_);
notify_waitable_->set_on_ready_callback(
this->create_waitable_callback(notify_waitable_.get()));
auto notify_waitable_entity_id = notify_waitable_.get();
notify_waitable_->set_on_ready_callback(
[this, notify_waitable_entity_id](size_t num_events, int waitable_data) {
@@ -91,7 +84,7 @@ EventsExecutor::setup_notify_waitable()
// For the same reason, if an event of this type has already been pushed but it has not been
// processed yet, we avoid pushing additional events.
(void)num_events;
if (entities_need_rebuild_.exchange(true)) {
if (notify_waitable_event_pushed_.exchange(true)) {
return;
}
@@ -99,6 +92,9 @@ EventsExecutor::setup_notify_waitable()
{notify_waitable_entity_id, nullptr, waitable_data, ExecutorEventType::WAITABLE_EVENT, 1};
this->events_queue_->enqueue(event);
});
this->entities_collector_ =
std::make_shared<rclcpp::executors::ExecutorEntitiesCollector>(notify_waitable_);
}
EventsExecutor::~EventsExecutor()
@@ -172,7 +168,7 @@ EventsExecutor::spin_some_impl(std::chrono::nanoseconds max_duration, bool exhau
// A non-exhaustive spin would not check for work a second time, thus delaying the execution
// of some entities to the next invocation of spin.
if (!exhaustive) {
this->handle_updated_entities(false);
this->refresh_current_collection_from_callback_groups();
}
// Get the number of events and timers ready at start
@@ -240,6 +236,46 @@ EventsExecutor::spin_once_impl(std::chrono::nanoseconds timeout)
}
}
void
EventsExecutor::add_node(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify)
{
// This field is unused because we don't have to wake up the executor when a node is added.
(void) notify;
// Add node to entities collector
this->entities_collector_->add_node(node_ptr);
this->refresh_current_collection_from_callback_groups();
}
void
EventsExecutor::add_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify)
{
this->add_node(node_ptr->get_node_base_interface(), notify);
}
void
EventsExecutor::remove_node(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify)
{
// This field is unused because we don't have to wake up the executor when a node is removed.
(void)notify;
// Remove node from entities collector.
// This will result in un-setting all the event callbacks from its entities.
// After this function returns, this executor will not receive any more events associated
// to these entities.
this->entities_collector_->remove_node(node_ptr);
this->refresh_current_collection_from_callback_groups();
}
void
EventsExecutor::remove_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify)
{
this->remove_node(node_ptr->get_node_base_interface(), notify);
}
void
EventsExecutor::execute_event(const ExecutorEvent & event)
@@ -249,9 +285,10 @@ EventsExecutor::execute_event(const ExecutorEvent & event)
{
rclcpp::ClientBase::SharedPtr client;
{
std::lock_guard<std::recursive_mutex> lock(collection_mutex_);
client = this->retrieve_entity(
static_cast<const rcl_client_t *>(event.entity_key),
current_collection_.clients);
current_entities_collection_->clients);
}
if (client) {
for (size_t i = 0; i < event.num_events; i++) {
@@ -265,9 +302,10 @@ EventsExecutor::execute_event(const ExecutorEvent & event)
{
rclcpp::SubscriptionBase::SharedPtr subscription;
{
std::lock_guard<std::recursive_mutex> lock(collection_mutex_);
subscription = this->retrieve_entity(
static_cast<const rcl_subscription_t *>(event.entity_key),
current_collection_.subscriptions);
current_entities_collection_->subscriptions);
}
if (subscription) {
for (size_t i = 0; i < event.num_events; i++) {
@@ -280,9 +318,10 @@ EventsExecutor::execute_event(const ExecutorEvent & event)
{
rclcpp::ServiceBase::SharedPtr service;
{
std::lock_guard<std::recursive_mutex> lock(collection_mutex_);
service = this->retrieve_entity(
static_cast<const rcl_service_t *>(event.entity_key),
current_collection_.services);
current_entities_collection_->services);
}
if (service) {
for (size_t i = 0; i < event.num_events; i++) {
@@ -302,9 +341,10 @@ EventsExecutor::execute_event(const ExecutorEvent & event)
{
rclcpp::Waitable::SharedPtr waitable;
{
std::lock_guard<std::recursive_mutex> lock(collection_mutex_);
waitable = this->retrieve_entity(
static_cast<const rclcpp::Waitable *>(event.entity_key),
current_collection_.waitables);
current_entities_collection_->waitables);
}
if (waitable) {
for (size_t i = 0; i < event.num_events; i++) {
@@ -318,23 +358,71 @@ EventsExecutor::execute_event(const ExecutorEvent & event)
}
void
EventsExecutor::handle_updated_entities(bool notify)
EventsExecutor::add_callback_group(
rclcpp::CallbackGroup::SharedPtr group_ptr,
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
bool notify)
{
// This field is unused because we don't have to wake up
// the executor when a callback group is added.
(void)notify;
(void)node_ptr;
this->entities_collector_->add_callback_group(group_ptr);
this->refresh_current_collection_from_callback_groups();
}
void
EventsExecutor::remove_callback_group(
rclcpp::CallbackGroup::SharedPtr group_ptr, bool notify)
{
// This field is unused because we don't have to wake up
// the executor when a callback group is removed.
(void)notify;
this->entities_collector_->remove_callback_group(group_ptr);
this->refresh_current_collection_from_callback_groups();
}
std::vector<rclcpp::CallbackGroup::WeakPtr>
EventsExecutor::get_all_callback_groups()
{
this->entities_collector_->update_collections();
return this->entities_collector_->get_all_callback_groups();
}
std::vector<rclcpp::CallbackGroup::WeakPtr>
EventsExecutor::get_manually_added_callback_groups()
{
this->entities_collector_->update_collections();
return this->entities_collector_->get_manually_added_callback_groups();
}
std::vector<rclcpp::CallbackGroup::WeakPtr>
EventsExecutor::get_automatically_added_callback_groups_from_nodes()
{
this->entities_collector_->update_collections();
return this->entities_collector_->get_automatically_added_callback_groups();
}
void
EventsExecutor::refresh_current_collection_from_callback_groups()
{
// Do not rebuild if we don't need to.
// A rebuild event could be generated, but then
// this function could end up being called from somewhere else
// before that event gets processed, for example if
// a node or callback group is manually added to the executor.
const bool notify_waitable_triggered = entities_need_rebuild_.exchange(false);
if (!notify_waitable_triggered && !this->collector_.has_pending()) {
const bool notify_waitable_triggered = notify_waitable_event_pushed_.exchange(false);
if (!notify_waitable_triggered && !this->entities_collector_->has_pending()) {
return;
}
// Build the new collection
this->collector_.update_collections();
auto callback_groups = this->collector_.get_all_callback_groups();
this->entities_collector_->update_collections();
auto callback_groups = this->entities_collector_->get_all_callback_groups();
rclcpp::executors::ExecutorEntitiesCollection new_collection;
rclcpp::executors::build_entities_collection(callback_groups, new_collection);
@@ -344,11 +432,14 @@ EventsExecutor::handle_updated_entities(bool notify)
// We could explicitly check for the notify waitable ID when we receive a waitable event
// but I think that it's better if the waitable was in the collection and it could be
// retrieved in the "standard" way.
// To do it, we need to add the notify waitable as an entry in the new collection
// such that it's neither added or removed (it should have already been added
// to the current collection in the constructor)
// To do it, we need to add the notify waitable as an entry in both the new and
// current collections such that it's neither added or removed.
this->add_notify_waitable_to_collection(new_collection.waitables);
// Acquire lock before modifying the current collection
std::lock_guard<std::recursive_mutex> lock(collection_mutex_);
this->add_notify_waitable_to_collection(current_entities_collection_->waitables);
this->refresh_current_collection(new_collection);
}
@@ -357,19 +448,14 @@ EventsExecutor::refresh_current_collection(
const rclcpp::executors::ExecutorEntitiesCollection & new_collection)
{
// Acquire lock before modifying the current collection
std::lock_guard<std::mutex> guard(mutex_);
std::lock_guard<std::recursive_mutex> lock(collection_mutex_);
// Remove expired entities to ensure re-initialized objects
// are updated. This fixes issues with stale state entities.
// See: https://github.com/ros2/rclcpp/pull/2586
current_collection_.remove_expired_entities();
current_collection_.timers.update(
current_entities_collection_->timers.update(
new_collection.timers,
[this](rclcpp::TimerBase::SharedPtr timer) {timers_manager_->add_timer(timer);},
[this](rclcpp::TimerBase::SharedPtr timer) {timers_manager_->remove_timer(timer);});
current_collection_.subscriptions.update(
current_entities_collection_->subscriptions.update(
new_collection.subscriptions,
[this](auto subscription) {
subscription->set_on_new_message_callback(
@@ -378,7 +464,7 @@ EventsExecutor::refresh_current_collection(
},
[](auto subscription) {subscription->clear_on_new_message_callback();});
current_collection_.clients.update(
current_entities_collection_->clients.update(
new_collection.clients,
[this](auto client) {
client->set_on_new_response_callback(
@@ -387,7 +473,7 @@ EventsExecutor::refresh_current_collection(
},
[](auto client) {client->clear_on_new_response_callback();});
current_collection_.services.update(
current_entities_collection_->services.update(
new_collection.services,
[this](auto service) {
service->set_on_new_request_callback(
@@ -398,12 +484,12 @@ EventsExecutor::refresh_current_collection(
// DO WE NEED THIS? WE ARE NOT DOING ANYTHING WITH GUARD CONDITIONS
/*
current_collection_.guard_conditions.update(new_collection.guard_conditions,
current_entities_collection_->guard_conditions.update(new_collection.guard_conditions,
[](auto guard_condition) {(void)guard_condition;},
[](auto guard_condition) {guard_condition->set_on_trigger_callback(nullptr);});
*/
current_collection_.waitables.update(
current_entities_collection_->waitables.update(
new_collection.waitables,
[this](auto waitable) {
waitable->set_on_ready_callback(

View File

@@ -31,31 +31,22 @@ GenericClient::GenericClient(
rcl_client_options_t & client_options)
: ClientBase(node_base, node_graph)
{
const rosidl_service_type_support_t * service_ts;
try {
ts_lib_ = get_typesupport_library(
service_type, "rosidl_typesupport_cpp");
ts_lib_ = get_typesupport_library(
service_type, "rosidl_typesupport_cpp");
service_ts = get_service_typesupport_handle(
service_type, "rosidl_typesupport_cpp", *ts_lib_);
auto service_ts_ = get_service_typesupport_handle(
service_type, "rosidl_typesupport_cpp", *ts_lib_);
auto response_type_support_intro = get_message_typesupport_handle(
service_ts->response_typesupport,
rosidl_typesupport_introspection_cpp::typesupport_identifier);
response_members_ = static_cast<const rosidl_typesupport_introspection_cpp::MessageMembers *>(
response_type_support_intro->data);
} catch (std::runtime_error & err) {
RCLCPP_ERROR(
rclcpp::get_node_logger(node_handle_.get()).get_child("rclcpp"),
"Invalid service type: %s",
err.what());
throw rclcpp::exceptions::InvalidServiceTypeError(err.what());
}
auto response_type_support_intro = get_message_typesupport_handle(
service_ts_->response_typesupport,
rosidl_typesupport_introspection_cpp::typesupport_identifier);
response_members_ = static_cast<const rosidl_typesupport_introspection_cpp::MessageMembers *>(
response_type_support_intro->data);
rcl_ret_t ret = rcl_client_init(
this->get_client_handle().get(),
this->get_rcl_node_handle(),
service_ts,
service_ts_,
service_name.c_str(),
&client_options);
if (ret != RCL_RET_OK) {
@@ -109,13 +100,6 @@ GenericClient::handle_response(
if (std::holds_alternative<Promise>(value)) {
auto & promise = std::get<Promise>(value);
promise.set_value(std::move(response));
} else if (std::holds_alternative<CallbackTypeValueVariant>(value)) {
auto & inner = std::get<CallbackTypeValueVariant>(value);
const auto & callback = std::get<CallbackType>(inner);
auto & promise = std::get<Promise>(inner);
auto & future = std::get<SharedFuture>(inner);
promise.set_value(std::move(response));
callback(std::move(future));
}
}
@@ -135,18 +119,6 @@ GenericClient::remove_pending_request(int64_t request_id)
return pending_requests_.erase(request_id) != 0u;
}
bool
GenericClient::remove_pending_request(const FutureAndRequestId & future)
{
return this->remove_pending_request(future.request_id);
}
bool
GenericClient::remove_pending_request(const SharedFutureAndRequestId & future)
{
return this->remove_pending_request(future.request_id);
}
std::optional<GenericClient::CallbackInfoVariant>
GenericClient::get_and_erase_pending_request(int64_t request_number)
{

View File

@@ -1,172 +0,0 @@
// Copyright 2024 Sony Group Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "rclcpp/generic_service.hpp"
namespace rclcpp
{
GenericService::GenericService(
std::shared_ptr<rcl_node_t> node_handle,
const std::string & service_name,
const std::string & service_type,
GenericServiceCallback any_callback,
rcl_service_options_t & service_options)
: ServiceBase(node_handle),
any_callback_(any_callback)
{
const rosidl_service_type_support_t * service_ts;
try {
ts_lib_ = get_typesupport_library(
service_type, "rosidl_typesupport_cpp");
service_ts = get_service_typesupport_handle(
service_type, "rosidl_typesupport_cpp", *ts_lib_);
auto request_type_support_intro = get_message_typesupport_handle(
service_ts->request_typesupport,
rosidl_typesupport_introspection_cpp::typesupport_identifier);
request_members_ = static_cast<const rosidl_typesupport_introspection_cpp::MessageMembers *>(
request_type_support_intro->data);
auto response_type_support_intro = get_message_typesupport_handle(
service_ts->response_typesupport,
rosidl_typesupport_introspection_cpp::typesupport_identifier);
response_members_ = static_cast<const rosidl_typesupport_introspection_cpp::MessageMembers *>(
response_type_support_intro->data);
} catch (std::runtime_error & err) {
RCLCPP_ERROR(
rclcpp::get_node_logger(node_handle_.get()).get_child("rclcpp"),
"Invalid service type: %s",
err.what());
throw rclcpp::exceptions::InvalidServiceTypeError(err.what());
}
// rcl does the static memory allocation here
service_handle_ = std::shared_ptr<rcl_service_t>(
new rcl_service_t, [handle = node_handle_, service_name](rcl_service_t * service)
{
if (rcl_service_fini(service, handle.get()) != RCL_RET_OK) {
RCLCPP_ERROR(
rclcpp::get_node_logger(handle.get()).get_child("rclcpp"),
"Error in destruction of rcl service handle: %s",
rcl_get_error_string().str);
rcl_reset_error();
}
delete service;
});
*service_handle_.get() = rcl_get_zero_initialized_service();
rcl_ret_t ret = rcl_service_init(
service_handle_.get(),
node_handle.get(),
service_ts,
service_name.c_str(),
&service_options);
if (ret != RCL_RET_OK) {
if (ret == RCL_RET_SERVICE_NAME_INVALID) {
auto rcl_node_handle = get_rcl_node_handle();
// this will throw on any validation problem
rcl_reset_error();
expand_topic_or_service_name(
service_name,
rcl_node_get_name(rcl_node_handle),
rcl_node_get_namespace(rcl_node_handle),
true);
}
rclcpp::exceptions::throw_from_rcl_error(ret, "could not create service");
}
TRACETOOLS_TRACEPOINT(
rclcpp_service_callback_added,
static_cast<const void *>(get_service_handle().get()),
static_cast<const void *>(&any_callback_));
#ifndef TRACETOOLS_DISABLED
any_callback_.register_callback_for_tracing();
#endif
}
bool
GenericService::take_request(
SharedRequest request_out,
rmw_request_id_t & request_id_out)
{
request_out = create_request();
return this->take_type_erased_request(request_out.get(), request_id_out);
}
std::shared_ptr<void>
GenericService::create_request()
{
Request request = new uint8_t[request_members_->size_of_];
request_members_->init_function(request, rosidl_runtime_cpp::MessageInitialization::ZERO);
return std::shared_ptr<void>(
request,
[this](void * p)
{
request_members_->fini_function(p);
delete[] reinterpret_cast<uint8_t *>(p);
});
}
std::shared_ptr<void>
GenericService::create_response()
{
Response response = new uint8_t[response_members_->size_of_];
response_members_->init_function(response, rosidl_runtime_cpp::MessageInitialization::ZERO);
return std::shared_ptr<void>(
response,
[this](void * p)
{
response_members_->fini_function(p);
delete[] reinterpret_cast<uint8_t *>(p);
});
}
std::shared_ptr<rmw_request_id_t>
GenericService::create_request_header()
{
return std::make_shared<rmw_request_id_t>();
}
void
GenericService::handle_request(
std::shared_ptr<rmw_request_id_t> request_header,
std::shared_ptr<void> request)
{
auto response = any_callback_.dispatch(
this->shared_from_this(), request_header, request, create_response());
if (response) {
send_response(*request_header, response);
}
}
void
GenericService::send_response(rmw_request_id_t & req_id, SharedResponse & response)
{
rcl_ret_t ret = rcl_send_response(get_service_handle().get(), &req_id, response.get());
if (ret == RCL_RET_TIMEOUT) {
RCLCPP_WARN(
node_logger_.get_child("rclcpp"),
"failed to send response to %s (timeout): %s",
this->get_service_name(), rcl_get_error_string().str);
rcl_reset_error();
return;
}
if (ret != RCL_RET_OK) {
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to send response");
}
}
} // namespace rclcpp

View File

@@ -46,7 +46,8 @@ GenericSubscription::handle_message(
"handle_message is not implemented for GenericSubscription");
}
void GenericSubscription::handle_serialized_message(
void
GenericSubscription::handle_serialized_message(
const std::shared_ptr<rclcpp::SerializedMessage> & message,
const rclcpp::MessageInfo & message_info)
{

View File

@@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <filesystem>
#include <memory>
#include <string>
#include <utility>
@@ -55,14 +54,6 @@ get_node_logger(const rcl_node_t * node)
return rclcpp::get_logger(logger_name);
}
// TODO(ahcorde): Remove deprecated class on the next release (in Rolling after Kilted).
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
rcpputils::fs::path
get_logging_directory()
{
@@ -76,26 +67,6 @@ get_logging_directory()
allocator.deallocate(log_dir, allocator.state);
return path;
}
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
std::filesystem::path
get_log_directory()
{
char * log_dir = NULL;
auto allocator = rcutils_get_default_allocator();
rcl_logging_ret_t ret = rcl_logging_get_logging_directory(allocator, &log_dir);
if (RCL_LOGGING_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
std::string path{log_dir};
allocator.deallocate(log_dir, allocator.state);
return path;
}
Logger
Logger::get_child(const std::string & suffix)

View File

@@ -135,28 +135,15 @@ void
PublisherBase::bind_event_callbacks(
const PublisherEventCallbacks & event_callbacks, bool use_default_callbacks)
{
try {
if (event_callbacks.deadline_callback) {
this->add_event_handler(
event_callbacks.deadline_callback,
RCL_PUBLISHER_OFFERED_DEADLINE_MISSED);
}
} catch (const UnsupportedEventTypeException & /*exc*/) {
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"Failed to add event handler for deadline; not supported");
if (event_callbacks.deadline_callback) {
this->add_event_handler(
event_callbacks.deadline_callback,
RCL_PUBLISHER_OFFERED_DEADLINE_MISSED);
}
try {
if (event_callbacks.liveliness_callback) {
this->add_event_handler(
event_callbacks.liveliness_callback,
RCL_PUBLISHER_LIVELINESS_LOST);
}
} catch (const UnsupportedEventTypeException & /*exc*/) {
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"Failed to add event handler for liveliness; not supported");
if (event_callbacks.liveliness_callback) {
this->add_event_handler(
event_callbacks.liveliness_callback,
RCL_PUBLISHER_LIVELINESS_LOST);
}
QOSOfferedIncompatibleQoSCallbackType incompatible_qos_cb;
@@ -173,9 +160,9 @@ PublisherBase::bind_event_callbacks(
this->add_event_handler(incompatible_qos_cb, RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS);
}
} catch (const UnsupportedEventTypeException & /*exc*/) {
RCLCPP_WARN(
RCLCPP_DEBUG(
rclcpp::get_logger("rclcpp"),
"Failed to add event handler for incompatible qos; not supported");
"Failed to add event handler for incompatible qos; wrong callback type");
}
IncompatibleTypeCallbackType incompatible_type_cb;
@@ -192,21 +179,14 @@ PublisherBase::bind_event_callbacks(
this->add_event_handler(incompatible_type_cb, RCL_PUBLISHER_INCOMPATIBLE_TYPE);
}
} catch (UnsupportedEventTypeException & /*exc*/) {
RCLCPP_WARN(
RCLCPP_DEBUG(
rclcpp::get_logger("rclcpp"),
"Failed to add event handler for incompatible type; not supported");
"Failed to add event handler for incompatible type; wrong callback type");
}
try {
if (event_callbacks.matched_callback) {
this->add_event_handler(
event_callbacks.matched_callback,
RCL_PUBLISHER_MATCHED);
}
} catch (const UnsupportedEventTypeException & /*exc*/) {
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"Failed to add event handler for matched; not supported");
if (event_callbacks.matched_callback) {
this->add_event_handler(
event_callbacks.matched_callback,
RCL_PUBLISHER_MATCHED);
}
}

View File

@@ -71,6 +71,12 @@ Rate::sleep()
return true;
}
bool
Rate::is_steady() const
{
return clock_->get_clock_type() == RCL_STEADY_TIME;
}
rcl_clock_type_t
Rate::get_type() const
{

View File

@@ -36,7 +36,6 @@ SerializationBase::SerializationBase(const rosidl_message_type_support_t * type_
void SerializationBase::serialize_message(
const void * ros_message, SerializedMessage * serialized_message) const
{
rcpputils::check_true(nullptr != type_support_, "Typesupport is nullpointer.");
rcpputils::check_true(nullptr != ros_message, "ROS message is nullpointer.");
rcpputils::check_true(nullptr != serialized_message, "Serialized message is nullpointer.");
@@ -52,7 +51,6 @@ void SerializationBase::serialize_message(
void SerializationBase::deserialize_message(
const SerializedMessage * serialized_message, void * ros_message) const
{
rcpputils::check_true(nullptr != type_support_, "Typesupport is nullpointer.");
rcpputils::check_true(nullptr != serialized_message, "Serialized message is nullpointer.");
rcpputils::check_true(
0u != serialized_message->capacity(),

View File

@@ -112,28 +112,16 @@ void
SubscriptionBase::bind_event_callbacks(
const SubscriptionEventCallbacks & event_callbacks, bool use_default_callbacks)
{
try {
if (event_callbacks.deadline_callback) {
this->add_event_handler(
event_callbacks.deadline_callback,
RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED);
}
} catch (const UnsupportedEventTypeException & /*exc*/) {
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"Failed to add event handler for deadline; not supported");
if (event_callbacks.deadline_callback) {
this->add_event_handler(
event_callbacks.deadline_callback,
RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED);
}
try {
if (event_callbacks.liveliness_callback) {
this->add_event_handler(
event_callbacks.liveliness_callback,
RCL_SUBSCRIPTION_LIVELINESS_CHANGED);
}
} catch (const UnsupportedEventTypeException & /*exc*/) {
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"Failed to add event handler for liveliness; not supported");
if (event_callbacks.liveliness_callback) {
this->add_event_handler(
event_callbacks.liveliness_callback,
RCL_SUBSCRIPTION_LIVELINESS_CHANGED);
}
QOSRequestedIncompatibleQoSCallbackType incompatible_qos_cb;
@@ -151,9 +139,7 @@ SubscriptionBase::bind_event_callbacks(
this->add_event_handler(incompatible_qos_cb, RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS);
}
} catch (const UnsupportedEventTypeException & /*exc*/) {
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"Failed to add event handler for incompatible qos; not supported");
// pass
}
IncompatibleTypeCallbackType incompatible_type_cb;
@@ -170,33 +156,18 @@ SubscriptionBase::bind_event_callbacks(
this->add_event_handler(incompatible_type_cb, RCL_SUBSCRIPTION_INCOMPATIBLE_TYPE);
}
} catch (UnsupportedEventTypeException & /*exc*/) {
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"Failed to add event handler for incompatible type; not supported");
// pass
}
try {
if (event_callbacks.message_lost_callback) {
this->add_event_handler(
event_callbacks.message_lost_callback,
RCL_SUBSCRIPTION_MESSAGE_LOST);
}
} catch (const UnsupportedEventTypeException & /*exc*/) {
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"Failed to add event handler for message lost; not supported");
if (event_callbacks.message_lost_callback) {
this->add_event_handler(
event_callbacks.message_lost_callback,
RCL_SUBSCRIPTION_MESSAGE_LOST);
}
try {
if (event_callbacks.matched_callback) {
this->add_event_handler(
event_callbacks.matched_callback,
RCL_SUBSCRIPTION_MATCHED);
}
} catch (const UnsupportedEventTypeException & /*exc*/) {
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"Failed to add event handler for matched; not supported");
if (event_callbacks.matched_callback) {
this->add_event_handler(
event_callbacks.matched_callback,
RCL_SUBSCRIPTION_MATCHED);
}
}
@@ -573,30 +544,9 @@ SubscriptionBase::get_content_filter() const
// DYNAMIC TYPE ==================================================================================
bool
SubscriptionBase::take_dynamic_message(
rclcpp::dynamic_typesupport::DynamicMessage & message_out,
rclcpp::MessageInfo & message_info_out)
rclcpp::dynamic_typesupport::DynamicMessage & /*message_out*/,
rclcpp::MessageInfo & /*message_info_out*/)
{
if (rmw_feature_supported(RMW_MIDDLEWARE_CAN_TAKE_DYNAMIC_MESSAGE)) {
rcl_ret_t ret = rcl_take_dynamic_message(
this->get_subscription_handle().get(),
&message_out.get_rosidl_dynamic_data(),
&message_info_out.get_rmw_message_info(),
nullptr);
if (RCL_RET_SUBSCRIPTION_TAKE_FAILED == ret) {
return false;
} else if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret, "Error when taking dynamic message");
}
} else { // Fall back to serialized conversion if direct dynamic message taking isn't supported
std::shared_ptr<rclcpp::SerializedMessage> serialized_msg = this->create_serialized_message();
if (!this->take_serialized(*serialized_msg.get(), message_info_out)) {
std::runtime_error("Couldn't take serialized message when attempting to take dynamic data!");
}
bool ret = message_out.deserialize(serialized_msg->get_rcl_serialized_message());
if (!ret) {
throw std::runtime_error("Couldn't convert serialized message to dynamic data!");
}
this->return_serialized_message(serialized_msg);
}
return true;
throw std::runtime_error("Unimplemented");
return false;
}

View File

@@ -60,10 +60,6 @@ Time::Time(int32_t seconds, uint32_t nanoseconds, rcl_clock_type_t clock_type)
Time::Time(int64_t nanoseconds, rcl_clock_type_t clock_type)
: rcl_time_(init_time_point(clock_type))
{
if (nanoseconds < 0) {
throw std::runtime_error("cannot store a negative time point in rclcpp::Time");
}
rcl_time_.nanoseconds = nanoseconds;
}
@@ -253,9 +249,6 @@ Time::operator+=(const rclcpp::Duration & rhs)
}
rcl_time_.nanoseconds += rhs.nanoseconds();
if (rcl_time_.nanoseconds < 0) {
throw std::runtime_error("cannot store a negative time point in rclcpp::Time");
}
return *this;
}
@@ -271,9 +264,6 @@ Time::operator-=(const rclcpp::Duration & rhs)
}
rcl_time_.nanoseconds -= rhs.nanoseconds();
if (rcl_time_.nanoseconds < 0) {
throw std::runtime_error("cannot store a negative time point in rclcpp::Time");
}
return *this;
}

View File

@@ -54,8 +54,114 @@ Waitable::get_number_of_ready_guard_conditions()
return 0u;
}
std::shared_ptr<void>
Waitable::take_data_by_entity_id(size_t id)
{
(void)id;
throw std::runtime_error(
"Custom waitables should override take_data_by_entity_id "
"if they want to use it.");
}
bool
Waitable::exchange_in_use_by_wait_set_state(bool in_use_state)
{
return in_use_by_wait_set_.exchange(in_use_state);
}
void
Waitable::set_on_ready_callback(std::function<void(size_t, int)> callback)
{
(void)callback;
throw std::runtime_error(
"Custom waitables should override set_on_ready_callback "
"if they want to use it.");
}
void
Waitable::clear_on_ready_callback()
{
throw std::runtime_error(
"Custom waitables should override clear_on_ready_callback if they "
"want to use it and make sure to call it on the waitable destructor.");
}
void
Waitable::add_to_wait_set(rcl_wait_set_t * wait_set)
{
this->add_to_wait_set(*wait_set);
}
void
Waitable::add_to_wait_set(rcl_wait_set_t & wait_set)
{
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
this->add_to_wait_set(&wait_set);
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
}
bool
Waitable::is_ready(rcl_wait_set_t * wait_set)
{
const rcl_wait_set_t & const_wait_set_ref = *wait_set;
return this->is_ready(const_wait_set_ref);
}
bool
Waitable::is_ready(const rcl_wait_set_t & wait_set)
{
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
// note this const cast is only required to support a deprecated function
return this->is_ready(&const_cast<rcl_wait_set_t &>(wait_set));
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
}
void
Waitable::execute(std::shared_ptr<void> & data)
{
const std::shared_ptr<void> & const_data = data;
this->execute(const_data);
}
void
Waitable::execute(const std::shared_ptr<void> & data)
{
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
// note this const cast is only required to support a deprecated function
this->execute(const_cast<std::shared_ptr<void> &>(data));
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
}

View File

@@ -189,6 +189,71 @@ BENCHMARK_F(PerformanceTestExecutorSimple, multi_thread_executor_remove_node)(be
}
}
BENCHMARK_F(
PerformanceTestExecutorSimple,
static_single_thread_executor_add_node)(benchmark::State & st)
{
rclcpp::executors::StaticSingleThreadedExecutor executor;
for (auto _ : st) {
(void)_;
executor.add_node(node);
st.PauseTiming();
executor.remove_node(node);
st.ResumeTiming();
}
}
BENCHMARK_F(
PerformanceTestExecutorSimple,
static_single_thread_executor_remove_node)(benchmark::State & st)
{
rclcpp::executors::StaticSingleThreadedExecutor executor;
for (auto _ : st) {
(void)_;
st.PauseTiming();
executor.add_node(node);
st.ResumeTiming();
executor.remove_node(node);
}
}
BENCHMARK_F(
PerformanceTestExecutorSimple,
static_single_thread_executor_spin_until_future_complete)(benchmark::State & st)
{
rclcpp::executors::StaticSingleThreadedExecutor executor;
// test success of an immediately finishing future
std::promise<bool> promise;
std::future<bool> future = promise.get_future();
promise.set_value(true);
auto shared_future = future.share();
auto ret = executor.spin_until_future_complete(shared_future, 100ms);
if (ret != rclcpp::FutureReturnCode::SUCCESS) {
st.SkipWithError(rcutils_get_error_string().str);
}
reset_heap_counters();
for (auto _ : st) {
(void)_;
// static_single_thread_executor has a special design. We need to add/remove the node each
// time you call spin
st.PauseTiming();
executor.add_node(node);
st.ResumeTiming();
ret = executor.spin_until_future_complete(shared_future, 100ms);
if (ret != rclcpp::FutureReturnCode::SUCCESS) {
st.SkipWithError(rcutils_get_error_string().str);
break;
}
st.PauseTiming();
executor.remove_node(node);
st.ResumeTiming();
}
}
BENCHMARK_F(
PerformanceTestExecutorSimple,
single_thread_executor_spin_node_until_future_complete)(benchmark::State & st)
@@ -249,6 +314,30 @@ BENCHMARK_F(
}
}
BENCHMARK_F(
PerformanceTestExecutorSimple,
static_single_thread_executor_spin_node_until_future_complete)(benchmark::State & st)
{
rclcpp::executors::StaticSingleThreadedExecutor executor;
// test success of an immediately finishing future
std::promise<bool> promise;
std::future<bool> future = promise.get_future();
promise.set_value(true);
auto shared_future = future.share();
reset_heap_counters();
for (auto _ : st) {
(void)_;
auto ret = rclcpp::executors::spin_node_until_future_complete(
executor, node, shared_future, 1s);
if (ret != rclcpp::FutureReturnCode::SUCCESS) {
st.SkipWithError(rcutils_get_error_string().str);
break;
}
}
}
BENCHMARK_F(PerformanceTestExecutorSimple, spin_until_future_complete)(benchmark::State & st)
{
// test success of an immediately finishing future

View File

@@ -31,7 +31,6 @@ endif()
ament_add_gtest(
test_exceptions
exceptions/test_exceptions.cpp)
ament_add_test_label(test_exceptions mimick)
if(TARGET test_exceptions)
target_link_libraries(test_exceptions ${PROJECT_NAME} mimick)
endif()
@@ -53,15 +52,18 @@ if(TARGET test_any_subscription_callback)
target_link_libraries(test_any_subscription_callback ${PROJECT_NAME} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_client test_client.cpp)
ament_add_test_label(test_client mimick)
if(TARGET test_client)
target_link_libraries(test_client ${PROJECT_NAME} mimick ${rcl_interfaces_TARGETS} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_clock test_clock.cpp)
ament_add_test_label(test_clock mimick)
if(TARGET test_clock)
target_link_libraries(test_clock ${PROJECT_NAME} mimick ${rcl_interfaces_TARGETS} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_clock_conditional test_clock_conditional.cpp)
ament_add_test_label(test_clock_conditional mimick)
if(TARGET test_clock_conditional)
target_link_libraries(test_clock_conditional ${PROJECT_NAME} mimick ${rcl_interfaces_TARGETS} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_copy_all_parameter_values test_copy_all_parameter_values.cpp)
if(TARGET test_copy_all_parameter_values)
target_link_libraries(test_copy_all_parameter_values ${PROJECT_NAME})
@@ -72,7 +74,6 @@ if(TARGET test_create_timer)
target_include_directories(test_create_timer PRIVATE ./)
endif()
ament_add_gtest(test_generic_client test_generic_client.cpp)
ament_add_test_label(test_generic_client mimick)
if(TARGET test_generic_client)
target_link_libraries(test_generic_client ${PROJECT_NAME}
mimick
@@ -83,20 +84,7 @@ if(TARGET test_generic_client)
${test_msgs_TARGETS}
)
endif()
ament_add_gtest(test_generic_service test_generic_service.cpp)
ament_add_test_label(test_generic_service mimick)
if(TARGET test_generic_service)
target_link_libraries(test_generic_service ${PROJECT_NAME}
mimick
${rcl_interfaces_TARGETS}
rmw::rmw
rosidl_runtime_cpp::rosidl_runtime_cpp
rosidl_typesupport_cpp::rosidl_typesupport_cpp
${test_msgs_TARGETS}
)
endif()
ament_add_gtest(test_client_common test_client_common.cpp)
ament_add_test_label(test_client_common mimick)
if(TARGET test_client_common)
target_link_libraries(test_client_common ${PROJECT_NAME}
mimick
@@ -111,8 +99,18 @@ ament_add_gtest(test_create_subscription test_create_subscription.cpp)
if(TARGET test_create_subscription)
target_link_libraries(test_create_subscription ${PROJECT_NAME} ${test_msgs_TARGETS})
endif()
function(test_add_callback_groups_to_executor_for_rmw_implementation)
set(rmw_implementation_env_var RMW_IMPLEMENTATION=${rmw_implementation})
ament_add_gmock(test_add_callback_groups_to_executor${target_suffix} test_add_callback_groups_to_executor.cpp
ENV ${rmw_implementation_env_var}
TIMEOUT 120
)
if(TARGET test_add_callback_groups_to_executor${target_suffix})
target_link_libraries(test_add_callback_groups_to_executor${target_suffix} ${PROJECT_NAME} ${test_msgs_TARGETS})
endif()
endfunction()
call_for_each_rmw_implementation(test_add_callback_groups_to_executor_for_rmw_implementation)
ament_add_gtest(test_expand_topic_or_service_name test_expand_topic_or_service_name.cpp)
ament_add_test_label(test_expand_topic_or_service_name mimick)
if(TARGET test_expand_topic_or_service_name)
target_link_libraries(test_expand_topic_or_service_name ${PROJECT_NAME} mimick rcl::rcl rmw::rmw)
endif()
@@ -144,7 +142,6 @@ if(TARGET test_intra_process_buffer)
endif()
ament_add_gtest(test_loaned_message test_loaned_message.cpp)
ament_add_test_label(test_loaned_message mimick)
target_link_libraries(test_loaned_message ${PROJECT_NAME} mimick ${test_msgs_TARGETS})
ament_add_gtest(test_memory_strategy test_memory_strategy.cpp)
@@ -154,7 +151,6 @@ ament_add_gtest(test_message_memory_strategy test_message_memory_strategy.cpp)
target_link_libraries(test_message_memory_strategy ${PROJECT_NAME} ${test_msgs_TARGETS})
ament_add_gtest(test_node test_node.cpp TIMEOUT 240)
ament_add_test_label(test_node mimick)
if(TARGET test_node)
target_link_libraries(test_node ${PROJECT_NAME} mimick rcpputils::rcpputils rmw::rmw ${test_msgs_TARGETS})
endif()
@@ -166,7 +162,6 @@ if(TARGET test_node_interfaces__get_node_interfaces)
endif()
ament_add_gtest(test_node_interfaces__node_base
node_interfaces/test_node_base.cpp)
ament_add_test_label(test_node_interfaces__node_base mimick)
if(TARGET test_node_interfaces__node_base)
target_link_libraries(test_node_interfaces__node_base ${PROJECT_NAME} mimick rcl::rcl rmw::rmw)
endif()
@@ -178,7 +173,6 @@ endif()
ament_add_gtest(test_node_interfaces__node_graph
node_interfaces/test_node_graph.cpp
TIMEOUT 120)
ament_add_test_label(test_node_interfaces__node_graph mimick)
if(TARGET test_node_interfaces__node_graph)
target_link_libraries(test_node_interfaces__node_graph ${PROJECT_NAME} mimick rcl::rcl ${test_msgs_TARGETS})
endif()
@@ -189,25 +183,21 @@ if(TARGET test_node_interfaces__node_interfaces)
endif()
ament_add_gtest(test_node_interfaces__node_parameters
node_interfaces/test_node_parameters.cpp)
ament_add_test_label(test_node_interfaces__node_parameters mimick)
if(TARGET test_node_interfaces__node_parameters)
target_link_libraries(test_node_interfaces__node_parameters ${PROJECT_NAME} mimick rcpputils::rcpputils)
endif()
ament_add_gtest(test_node_interfaces__node_services
node_interfaces/test_node_services.cpp)
ament_add_test_label(test_node_interfaces__node_services mimick)
if(TARGET test_node_interfaces__node_services)
target_link_libraries(test_node_interfaces__node_services ${PROJECT_NAME} mimick rcl::rcl)
endif()
ament_add_gtest(test_node_interfaces__node_timers
node_interfaces/test_node_timers.cpp)
ament_add_test_label(test_node_interfaces__node_timers mimick)
if(TARGET test_node_interfaces__node_timers)
target_link_libraries(test_node_interfaces__node_timers ${PROJECT_NAME} mimick rcl::rcl)
endif()
ament_add_gtest(test_node_interfaces__node_topics
node_interfaces/test_node_topics.cpp)
ament_add_test_label(test_node_interfaces__node_topics mimick)
if(TARGET test_node_interfaces__node_topics)
target_link_libraries(test_node_interfaces__node_topics ${PROJECT_NAME} mimick rcl::rcl ${test_msgs_TARGETS})
endif()
@@ -218,7 +208,6 @@ if(TARGET test_node_interfaces__node_type_descriptions)
endif()
ament_add_gtest(test_node_interfaces__node_waitables
node_interfaces/test_node_waitables.cpp)
ament_add_test_label(test_node_interfaces__node_waitables mimick)
if(TARGET test_node_interfaces__node_waitables)
target_link_libraries(test_node_interfaces__node_waitables ${PROJECT_NAME} mimick rcl::rcl)
endif()
@@ -254,12 +243,10 @@ if(TARGET test_node_global_args)
target_link_libraries(test_node_global_args ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_options test_node_options.cpp)
ament_add_test_label(test_node_options mimick)
if(TARGET test_node_options)
target_link_libraries(test_node_options ${PROJECT_NAME} mimick rcl::rcl)
endif()
ament_add_gtest(test_init_options test_init_options.cpp)
ament_add_test_label(test_init_options mimick)
if(TARGET test_init_options)
target_link_libraries(test_init_options ${PROJECT_NAME} mimick rcl::rcl)
endif()
@@ -288,7 +275,6 @@ if(TARGET test_parameter_map)
target_link_libraries(test_parameter_map ${PROJECT_NAME} rcl::rcl rcl_yaml_param_parser::rcl_yaml_param_parser rcutils::rcutils)
endif()
ament_add_gtest(test_publisher test_publisher.cpp TIMEOUT 120)
ament_add_test_label(test_publisher mimick)
if(TARGET test_publisher)
target_link_libraries(test_publisher ${PROJECT_NAME} mimick rcl::rcl rcutils::rcutils ${test_msgs_TARGETS})
endif()
@@ -338,6 +324,27 @@ if(TARGET test_qos)
rmw::rmw
)
endif()
function(test_generic_pubsub_for_rmw_implementation)
set(rmw_implementation_env_var RMW_IMPLEMENTATION=${rmw_implementation})
ament_add_gmock(test_generic_pubsub${target_suffix} test_generic_pubsub.cpp
ENV ${rmw_implementation_env_var}
)
if(TARGET test_generic_pubsub${target_suffix})
target_link_libraries(test_generic_pubsub${target_suffix} ${PROJECT_NAME} rcl::rcl ${test_msgs_TARGETS})
endif()
endfunction()
call_for_each_rmw_implementation(test_generic_pubsub_for_rmw_implementation)
function(test_qos_event_for_rmw_implementation)
set(rmw_implementation_env_var RMW_IMPLEMENTATION=${rmw_implementation})
ament_add_gmock(test_qos_event${target_suffix} test_qos_event.cpp
ENV ${rmw_implementation_env_var}
)
if(TARGET test_qos_event${target_suffix})
target_link_libraries(test_qos_event${target_suffix} ${PROJECT_NAME} mimick rcutils::rcutils rmw::rmw ${test_msgs_TARGETS})
endif()
endfunction()
call_for_each_rmw_implementation(test_qos_event_for_rmw_implementation)
ament_add_gmock(test_qos_overriding_options test_qos_overriding_options.cpp)
if(TARGET test_qos_overriding_options)
@@ -360,18 +367,15 @@ if(TARGET test_serialized_message)
target_link_libraries(test_serialized_message ${PROJECT_NAME} rcpputils::rcpputils ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_service test_service.cpp)
ament_add_test_label(test_service mimick)
if(TARGET test_service)
target_link_libraries(test_service ${PROJECT_NAME} mimick ${rcl_interfaces_TARGES} ${test_msgs_TARGETS})
endif()
ament_add_gmock(test_service_introspection test_service_introspection.cpp)
ament_add_test_label(test_service_introspection mimick)
if(TARGET test_service_introspection)
target_link_libraries(test_service_introspection ${PROJECT_NAME} mimick ${service_msgs_TARGETS} ${test_msgs_TARGETS})
endif()
# Creating and destroying nodes is slow with Connext, so this needs larger timeout.
ament_add_gtest(test_subscription test_subscription.cpp TIMEOUT 120)
ament_add_test_label(test_subscription mimick)
if(TARGET test_subscription)
target_link_libraries(test_subscription ${PROJECT_NAME} mimick ${test_msgs_TARGETS})
endif()
@@ -422,7 +426,6 @@ endif()
ament_add_gtest(test_timer test_timer.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
ament_add_test_label(test_timer mimick)
if(TARGET test_timer)
target_link_libraries(test_timer ${PROJECT_NAME} mimick rcl::rcl)
endif()
@@ -441,7 +444,6 @@ endif()
ament_add_gtest(test_utilities test_utilities.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
ament_add_test_label(test_utilities mimick)
if(TARGET test_utilities)
target_link_libraries(test_utilities ${PROJECT_NAME} mimick rcl::rcl)
endif()
@@ -462,13 +464,6 @@ if(TARGET test_interface_traits)
target_link_libraries(test_interface_traits ${PROJECT_NAME})
endif()
ament_add_gtest(test_reinitialized_timers
executors/test_reinitialized_timers.cpp
TIMEOUT 30)
if(TARGET test_reinitialized_timers)
target_link_libraries(test_reinitialized_timers ${PROJECT_NAME})
endif()
ament_add_gtest(
test_executors
executors/test_executors.cpp
@@ -487,7 +482,7 @@ ament_add_gtest(
executors/test_executors_timer_cancel_behavior.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}"
TIMEOUT 180)
if(TARGET test_executors_timer_cancel_behavior)
if(TARGET test_executors)
target_link_libraries(test_executors_timer_cancel_behavior ${PROJECT_NAME} ${rosgraph_msgs_TARGETS})
endif()
@@ -496,7 +491,7 @@ ament_add_gtest(
executors/test_executors_callback_group_behavior.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}"
TIMEOUT 180)
if(TARGET test_executors_callback_group_behavior)
if(TARGET test_executors)
target_link_libraries(test_executors_callback_group_behavior ${PROJECT_NAME})
endif()
@@ -505,7 +500,7 @@ ament_add_gtest(
executors/test_executors_intraprocess.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}"
TIMEOUT 180)
if(TARGET test_executors_intraprocess)
if(TARGET test_executors)
target_link_libraries(test_executors_intraprocess ${PROJECT_NAME} ${test_msgs_TARGETS})
endif()
@@ -531,7 +526,6 @@ endif()
ament_add_gtest(test_static_single_threaded_executor executors/test_static_single_threaded_executor.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
ament_add_test_label(test_static_single_threaded_executor mimick)
if(TARGET test_static_single_threaded_executor)
target_link_libraries(test_static_single_threaded_executor ${PROJECT_NAME} mimick ${test_msgs_TARGETS})
endif()
@@ -550,12 +544,11 @@ endif()
ament_add_gtest(test_executor_notify_waitable executors/test_executor_notify_waitable.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}" TIMEOUT 120)
ament_add_test_label(test_executor_notify_waitable mimick)
if(TARGET test_executor_notify_waitable)
target_link_libraries(test_executor_notify_waitable ${PROJECT_NAME} mimick rcpputils::rcpputils)
endif()
ament_add_gtest(test_events_executor executors/test_events_executor.cpp TIMEOUT 60)
ament_add_gtest(test_events_executor executors/test_events_executor.cpp TIMEOUT 5)
if(TARGET test_events_executor)
target_link_libraries(test_events_executor ${PROJECT_NAME} ${test_msgs_TARGETS})
endif()
@@ -568,7 +561,6 @@ endif()
ament_add_gtest(test_guard_condition test_guard_condition.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
ament_add_test_label(test_guard_condition mimick)
if(TARGET test_guard_condition)
target_link_libraries(test_guard_condition ${PROJECT_NAME} mimick)
endif()
@@ -602,7 +594,6 @@ if(TARGET test_dynamic_storage)
endif()
ament_add_gtest(test_storage_policy_common wait_set_policies/test_storage_policy_common.cpp)
ament_add_test_label(test_storage_policy_common mimick)
if(TARGET test_storage_policy_common)
target_link_libraries(test_storage_policy_common ${PROJECT_NAME} mimick ${test_msgs_TARGETS})
endif()
@@ -635,62 +626,24 @@ endif()
ament_add_gtest(test_executor test_executor.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}"
TIMEOUT 120)
ament_add_test_label(test_executor mimick)
if(TARGET test_executor)
target_link_libraries(test_executor ${PROJECT_NAME} mimick ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_graph_listener test_graph_listener.cpp)
ament_add_test_label(test_graph_listener mimick)
if(TARGET test_graph_listener)
target_link_libraries(test_graph_listener ${PROJECT_NAME} mimick)
endif()
ament_add_gmock_executable(test_qos_event test_qos_event.cpp)
if(TARGET test_qos_event)
target_link_libraries(test_qos_event ${PROJECT_NAME} mimick rcutils::rcutils rmw::rmw ${test_msgs_TARGETS})
endif()
ament_add_gmock_executable(test_generic_pubsub test_generic_pubsub.cpp)
if(TARGET test_generic_pubsub)
target_link_libraries(test_generic_pubsub ${PROJECT_NAME} rcl::rcl ${test_msgs_TARGETS})
endif()
ament_add_gmock_executable(test_add_callback_groups_to_executor test_add_callback_groups_to_executor.cpp)
if(TARGET test_add_callback_groups_to_executor)
target_link_libraries(test_add_callback_groups_to_executor ${PROJECT_NAME} ${test_msgs_TARGETS})
endif()
ament_add_gmock_executable(test_subscription_content_filter test_subscription_content_filter.cpp)
if(TARGET test_subscription_content_filter)
target_link_libraries(test_subscription_content_filter ${PROJECT_NAME} mimick ${test_msgs_TARGETS})
endif()
function(test_on_all_rmws)
function(test_subscription_content_filter_for_rmw_implementation)
set(rmw_implementation_env_var RMW_IMPLEMENTATION=${rmw_implementation})
ament_add_gmock_test(test_qos_event
TEST_NAME test_qos_event${target_suffix}
ENV ${rmw_implementation_env_var}
)
ament_add_test_label(test_qos_event${target_suffix} mimick)
ament_add_gmock_test(test_generic_pubsub
TEST_NAME test_generic_pubsub${target_suffix}
ENV ${rmw_implementation_env_var}
)
ament_add_gmock_test(test_add_callback_groups_to_executor
TEST_NAME test_add_callback_groups_to_executor${target_suffix}
ament_add_gmock(test_subscription_content_filter${target_suffix}
test_subscription_content_filter.cpp
ENV ${rmw_implementation_env_var}
TIMEOUT 120
)
ament_add_gmock_test(test_subscription_content_filter
TEST_NAME test_subscription_content_filter${target_suffix}
ENV ${rmw_implementation_env_var}
TIMEOUT 120
)
ament_add_test_label(test_subscription_content_filter${target_suffix} mimick)
if(TARGET test_subscription_content_filter${target_suffix})
target_link_libraries(test_subscription_content_filter${target_suffix} ${PROJECT_NAME} mimick ${test_msgs_TARGETS})
endif()
endfunction()
call_for_each_rmw_implementation(test_on_all_rmws)
call_for_each_rmw_implementation(test_subscription_content_filter_for_rmw_implementation)

View File

@@ -25,37 +25,12 @@
#include "rclcpp/executors/static_single_threaded_executor.hpp"
#include "rclcpp/executors/multi_threaded_executor.hpp"
// suppress deprecated StaticSingleThreadedExecutor warning
// we define an alias that explicitly indicates that this class is deprecated, while avoiding
// polluting a lot of files the gcc pragmas
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
using DeprecatedStaticSingleThreadedExecutor = rclcpp::executors::StaticSingleThreadedExecutor;
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
using ExecutorTypes =
::testing::Types<
rclcpp::executors::SingleThreadedExecutor,
rclcpp::executors::MultiThreadedExecutor,
DeprecatedStaticSingleThreadedExecutor,
rclcpp::executors::StaticSingleThreadedExecutor,
rclcpp::experimental::executors::EventsExecutor>;
#ifdef __clang__
# pragma clang diagnostic pop
#endif
class ExecutorTypeNames
{
@@ -71,16 +46,10 @@ public:
if (std::is_same<T, rclcpp::executors::MultiThreadedExecutor>()) {
return "MultiThreadedExecutor";
}
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
if (std::is_same<T, DeprecatedStaticSingleThreadedExecutor>()) {
if (std::is_same<T, rclcpp::executors::StaticSingleThreadedExecutor>()) {
return "StaticSingleThreadedExecutor";
}
#ifdef __clang__
# pragma clang diagnostic pop
#endif
if (std::is_same<T, rclcpp::experimental::executors::EventsExecutor>()) {
return "EventsExecutor";

View File

@@ -479,21 +479,14 @@ TEST_F(TestEventsExecutor, test_default_incompatible_qos_callbacks)
const auto timeout = std::chrono::seconds(10);
ex.spin_until_future_complete(log_msgs_future, timeout);
rclcpp::QoSCheckCompatibleResult qos_compatible = rclcpp::qos_check_compatible(
publisher->get_actual_qos(), subscription->get_actual_qos());
if (qos_compatible.compatibility == rclcpp::QoSCompatibility::Error) {
EXPECT_EQ(
"New subscription discovered on topic '/test_topic', requesting incompatible QoS. "
"No messages will be sent to it. Last incompatible policy: DURABILITY_QOS_POLICY",
pub_log_msg);
EXPECT_EQ(
"New publisher discovered on topic '/test_topic', offering incompatible QoS. "
"No messages will be sent to it. Last incompatible policy: DURABILITY_QOS_POLICY",
sub_log_msg);
} else {
EXPECT_EQ("", pub_log_msg);
EXPECT_EQ("", sub_log_msg);
}
EXPECT_EQ(
"New subscription discovered on topic '/test_topic', requesting incompatible QoS. "
"No messages will be sent to it. Last incompatible policy: DURABILITY_QOS_POLICY",
pub_log_msg);
EXPECT_EQ(
"New publisher discovered on topic '/test_topic', offering incompatible QoS. "
"No messages will be sent to it. Last incompatible policy: DURABILITY_QOS_POLICY",
sub_log_msg);
rcutils_logging_set_output_handler(original_output_handler);
}

View File

@@ -76,8 +76,7 @@ TEST_F(TestExecutorNotifyWaitable, wait) {
std::make_shared<rclcpp::executors::ExecutorNotifyWaitable>(on_execute_callback);
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
auto notify_guard_condition =
node->get_node_base_interface()->get_shared_notify_guard_condition();
auto notify_guard_condition = std::make_shared<rclcpp::GuardCondition>();
EXPECT_NO_THROW(waitable->add_guard_condition(notify_guard_condition));
auto default_cbg = node->get_node_base_interface()->get_default_callback_group();
@@ -86,12 +85,15 @@ TEST_F(TestExecutorNotifyWaitable, wait) {
auto waitables = node->get_node_waitables_interface();
waitables->add_waitable(std::static_pointer_cast<rclcpp::Waitable>(waitable), default_cbg);
// notify the guard condition, this should trigger the on_execute_callback
notify_guard_condition->trigger();
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node);
executor.spin_all(std::chrono::seconds(1));
EXPECT_EQ(1u, on_execute_calls);
// on_execute_callback doesn't change if the topology doesn't change
// no further trigger, therefore no further callback
executor.spin_all(std::chrono::seconds(1));
EXPECT_EQ(1u, on_execute_calls);
}

View File

@@ -480,14 +480,20 @@ TYPED_TEST(TestExecutors, spinSome)
// The purpose of this test is to check that the ExecutorT.spin_some() method:
// - does not continue executing after max_duration has elapsed
// TODO(wjwwood): The `StaticSingleThreadedExecutor`
// do not properly implement max_duration (it seems), so disable this test
// for them in the meantime.
// see: https://github.com/ros2/rclcpp/issues/2462
TYPED_TEST(TestExecutorsStable, spinSomeMaxDuration)
TYPED_TEST(TestExecutors, spinSomeMaxDuration)
{
using ExecutorType = TypeParam;
// TODO(wjwwood): The `StaticSingleThreadedExecutor`
// do not properly implement max_duration (it seems), so disable this test
// for them in the meantime.
// see: https://github.com/ros2/rclcpp/issues/2462
if (
std::is_same<ExecutorType, rclcpp::executors::StaticSingleThreadedExecutor>())
{
GTEST_SKIP();
}
// Use an isolated callback group to avoid interference from any housekeeping
// items that may be in the default callback group of the node.
constexpr bool automatically_add_to_executor_with_node = false;
@@ -632,7 +638,7 @@ TYPED_TEST(TestExecutors, testSpinUntilFutureCompleteInterrupted)
// and b) refreshing the executor collections.
// The inconsistent state would happen if the event was processed before the collections were
// finished to be refreshed: the executor would pick up the event but be unable to process it.
// This would leave the `entities_need_rebuild_` flag to true, preventing additional
// This would leave the `notify_waitable_event_pushed_` flag to true, preventing additional
// notify waitable events to be pushed.
// The behavior is observable only under heavy load, so this test spawns several worker
// threads. Due to the nature of the bug, this test may still succeed even if the
@@ -661,20 +667,20 @@ TYPED_TEST(TestExecutors, testRaceConditionAddNode)
}
// Create an executor
ExecutorType executor;
auto executor = std::make_shared<ExecutorType>();
// Start spinning
auto executor_thread = std::thread(
[&executor]() {
executor.spin();
[executor]() {
executor->spin();
});
// Add a node to the executor
executor.add_node(this->node);
executor->add_node(this->node);
// Cancel the executor (make sure that it's already spinning first)
while (!executor.is_spinning() && rclcpp::ok()) {
while (!executor->is_spinning() && rclcpp::ok()) {
continue;
}
executor.cancel();
executor->cancel();
// Try to join the thread after cancelling the executor
// This is the "test". We want to make sure that we can still cancel the executor
@@ -688,81 +694,6 @@ TYPED_TEST(TestExecutors, testRaceConditionAddNode)
}
}
// Check that executors are correctly notified while they are spinning
// we notify twice to ensure that the notify waitable is still working
// after the first notification
TYPED_TEST(TestExecutors, notifyTwiceWhileSpinning)
{
using ExecutorType = TypeParam;
// Create executor, add the node and start spinning
ExecutorType executor;
executor.add_node(this->node);
std::thread spinner([&]() {executor.spin();});
// Wait for executor to be spinning
while (!executor.is_spinning()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
// Create the first subscription while the executor is already spinning
std::atomic<size_t> sub1_msg_count {0};
auto sub1 = this->node->template create_subscription<test_msgs::msg::Empty>(
this->publisher->get_topic_name(),
rclcpp::QoS(10),
[&sub1_msg_count](test_msgs::msg::Empty::ConstSharedPtr) {
sub1_msg_count++;
});
// Wait for the subscription to be matched
size_t tries = 10000;
while (this->publisher->get_subscription_count() < 2 && tries-- > 0) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
ASSERT_EQ(this->publisher->get_subscription_count(), 2);
// Publish a message and verify it's received
this->publisher->publish(test_msgs::msg::Empty());
auto start = std::chrono::steady_clock::now();
while (sub1_msg_count == 0 && (std::chrono::steady_clock::now() - start) < 10s) {
std::this_thread::sleep_for(1ms);
}
EXPECT_EQ(sub1_msg_count, 1u);
// Create a second subscription while the executor is already spinning
std::atomic<size_t> sub2_msg_count {0};
auto sub2 = this->node->template create_subscription<test_msgs::msg::Empty>(
this->publisher->get_topic_name(),
rclcpp::QoS(10),
[&sub2_msg_count](test_msgs::msg::Empty::ConstSharedPtr) {
sub2_msg_count++;
});
// Wait for the subscription to be matched
tries = 10000;
while (this->publisher->get_subscription_count() < 3 && tries-- > 0) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
ASSERT_EQ(this->publisher->get_subscription_count(), 3);
// Publish a message and verify it's received by both subscriptions
this->publisher->publish(test_msgs::msg::Empty());
start = std::chrono::steady_clock::now();
while (
sub1_msg_count == 1 &&
sub2_msg_count == 0 &&
(std::chrono::steady_clock::now() - start) < 10s)
{
std::this_thread::sleep_for(1ms);
}
EXPECT_EQ(sub1_msg_count, 2u);
EXPECT_EQ(sub2_msg_count, 1u);
// Cancel needs to be called before join, so that executor.spin() returns.
executor.cancel();
spinner.join();
}
// Check spin_until_future_complete with node base pointer (instantiates its own executor)
TEST(TestExecutors, testSpinUntilFutureCompleteNodeBasePtr)
{
@@ -890,3 +821,276 @@ TYPED_TEST(TestExecutors, testRaceDropCallbackGroupFromSecondThread)
executor.cancel();
executor_thread.join();
}
TYPED_TEST(TestExecutors, dropSomeTimer)
{
using ExecutorType = TypeParam;
ExecutorType executor;
auto node = std::make_shared<rclcpp::Node>("test_node");
bool timer1_works = false;
bool timer2_works = false;
auto timer1 = node->create_timer(std::chrono::milliseconds(10), [&timer1_works]() {
timer1_works = true;
});
auto timer2 = node->create_timer(std::chrono::milliseconds(10), [&timer2_works]() {
timer2_works = true;
});
executor.add_node(node);
// first let's make sure that both timers work
auto max_end_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
while(!timer1_works || !timer2_works) {
// let the executor pick up the node and the timers
executor.spin_all(std::chrono::milliseconds(10));
const auto cur_time = std::chrono::steady_clock::now();
ASSERT_LT(cur_time, max_end_time);
}
// delete timer 2. Note, the executor uses an unordered map internally, to order
// the entities added to the rcl waitset therefore the order is kind of undefined,
// and this test may be flaky. In case it triggers, something is most likely
// really broken.
timer2.reset();
timer1_works = false;
timer2_works = false;
max_end_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
while(!timer1_works && !timer2_works) {
// let the executor pick up the node and the timers
executor.spin_all(std::chrono::milliseconds(10));
const auto cur_time = std::chrono::steady_clock::now();
ASSERT_LT(cur_time, max_end_time);
}
ASSERT_TRUE(timer1_works || timer2_works);
}
TYPED_TEST(TestExecutors, dropSomeNodeWithTimer)
{
using ExecutorType = TypeParam;
ExecutorType executor;
auto node1 = std::make_shared<rclcpp::Node>("test_node_1");
auto node2 = std::make_shared<rclcpp::Node>("test_node_2");
bool timer1_works = false;
bool timer2_works = false;
auto timer1 = node1->create_timer(std::chrono::milliseconds(10), [&timer1_works]() {
timer1_works = true;
});
auto timer2 = node2->create_timer(std::chrono::milliseconds(10), [&timer2_works]() {
timer2_works = true;
});
executor.add_node(node1);
executor.add_node(node2);
// first let's make sure that both timers work
auto max_end_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
while(!timer1_works || !timer2_works) {
// let the executor pick up the node and the timers
executor.spin_all(std::chrono::milliseconds(10));
const auto cur_time = std::chrono::steady_clock::now();
ASSERT_LT(cur_time, max_end_time);
}
// delete node 1.
node1 = nullptr;
timer2_works = false;
max_end_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
while(!timer2_works) {
// let the executor pick up the node and the timer
executor.spin_all(std::chrono::milliseconds(10));
const auto cur_time = std::chrono::steady_clock::now();
ASSERT_LT(cur_time, max_end_time);
}
ASSERT_TRUE(timer2_works);
}
TYPED_TEST(TestExecutors, dropSomeSubscription)
{
using ExecutorType = TypeParam;
ExecutorType executor;
auto node = std::make_shared<rclcpp::Node>("test_node");
bool sub1_works = false;
bool sub2_works = false;
auto sub1 = node->create_subscription<test_msgs::msg::Empty>("/test_drop", 10,
[&sub1_works](const test_msgs::msg::Empty &) {
sub1_works = true;
});
auto sub2 = node->create_subscription<test_msgs::msg::Empty>("/test_drop", 10,
[&sub2_works](const test_msgs::msg::Empty &) {
sub2_works = true;
});
auto pub = node->create_publisher<test_msgs::msg::Empty>("/test_drop", 10);
executor.add_node(node);
// first let's make sure that both timers work
auto max_end_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
while(!sub1_works || !sub2_works) {
pub->publish(test_msgs::msg::Empty());
// let the executor pick up the node and the timers
executor.spin_all(std::chrono::milliseconds(10));
const auto cur_time = std::chrono::steady_clock::now();
ASSERT_LT(cur_time, max_end_time);
}
// delete subscription 2. Note, the executor uses an unordered map internally, to order
// the entities added to the rcl waitset therefore the order is kind of undefined,
// and this test may be flaky. In case it triggers, something is most likely
// really broken.
sub2.reset();
sub1_works = false;
sub2_works = false;
max_end_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
while(!sub1_works && !sub2_works) {
pub->publish(test_msgs::msg::Empty());
// let the executor pick up the node and the timers
executor.spin_all(std::chrono::milliseconds(10));
const auto cur_time = std::chrono::steady_clock::now();
ASSERT_LT(cur_time, max_end_time);
}
ASSERT_TRUE(sub1_works || sub2_works);
}
TYPED_TEST(TestExecutors, dropSomeNodesWithSubscription)
{
using ExecutorType = TypeParam;
ExecutorType executor;
auto node = std::make_shared<rclcpp::Node>("test_node");
auto node1 = std::make_shared<rclcpp::Node>("test_node_1");
auto node2 = std::make_shared<rclcpp::Node>("test_node_2");
bool sub1_works = false;
bool sub2_works = false;
auto sub1 = node1->create_subscription<test_msgs::msg::Empty>("/test_drop", 10,
[&sub1_works](const test_msgs::msg::Empty &) {
sub1_works = true;
});
auto sub2 = node2->create_subscription<test_msgs::msg::Empty>("/test_drop", 10,
[&sub2_works](const test_msgs::msg::Empty &) {
sub2_works = true;
});
auto pub = node->create_publisher<test_msgs::msg::Empty>("/test_drop", 10);
executor.add_node(node);
executor.add_node(node1);
executor.add_node(node2);
// first let's make sure that both subscribers work
auto max_end_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
while(!sub1_works || !sub2_works) {
pub->publish(test_msgs::msg::Empty());
// let the executor pick up the node and the timers
executor.spin_all(std::chrono::milliseconds(10));
const auto cur_time = std::chrono::steady_clock::now();
ASSERT_LT(cur_time, max_end_time);
}
// delete node 2.
node2 = nullptr;
sub1_works = false;
max_end_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
while(!sub1_works) {
pub->publish(test_msgs::msg::Empty());
// let the executor pick up the node and the timers
executor.spin_all(std::chrono::milliseconds(10));
const auto cur_time = std::chrono::steady_clock::now();
ASSERT_LT(cur_time, max_end_time);
}
ASSERT_TRUE(sub1_works);
}
TYPED_TEST(TestExecutors, dropSubscriptionDuringCallback)
{
using ExecutorType = TypeParam;
ExecutorType executor;
auto node = std::make_shared<rclcpp::Node>("test_node");
bool sub1_works = false;
bool sub2_works = false;
auto cbg = node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive, true);
rclcpp::SubscriptionOptions sub_ops;
sub_ops.callback_group = cbg;
rclcpp::SubscriptionBase::SharedPtr sub1;
rclcpp::SubscriptionBase::SharedPtr sub2;
// Note, the executor uses an unordered map internally, to order
// the entities added to the rcl waitset therefore the order of the subscriptions
// is kind of undefined. Therefore each sub deletes the other one.
sub1 = node->create_subscription<test_msgs::msg::Empty>("/test_drop", 10,
[&sub1_works, &sub2](const test_msgs::msg::Empty &) {
sub1_works = true;
// delete the other subscriber
sub2.reset();
}, sub_ops);
sub2 = node->create_subscription<test_msgs::msg::Empty>("/test_drop", 10,
[&sub2_works, &sub1](const test_msgs::msg::Empty &) {
sub2_works = true;
// delete the other subscriber
sub1.reset();
}, sub_ops);
auto pub = node->create_publisher<test_msgs::msg::Empty>("/test_drop", 10);
// wait for both subs to be connected
auto max_end_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(1500);
while ((sub1->get_publisher_count() == 0) || (sub2->get_publisher_count() == 0)) {
const auto cur_time = std::chrono::steady_clock::now();
ASSERT_LT(cur_time, max_end_time);
}
executor.add_node(node);
// publish some messages, until one subscriber fired. As both subscribers are
// connected to the same topic, they should fire in the same wait.
max_end_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
while (!sub1_works && !sub2_works) {
pub->publish(test_msgs::msg::Empty());
// let the executor pick up the node and the timers
executor.spin_all(std::chrono::milliseconds(10));
const auto cur_time = std::chrono::steady_clock::now();
ASSERT_LT(cur_time, max_end_time);
}
// only one subscriber must have worked, as the other
// one was deleted during the callback
ASSERT_TRUE(!sub1_works || !sub2_works);
}

View File

@@ -47,6 +47,9 @@ public:
auto waitable_interfaces = node->get_node_waitables_interface();
waitable = std::make_shared<TestWaitable>();
waitable_interfaces->add_waitable(waitable, callback_group);
executor = std::make_shared<T>();
executor->add_callback_group(callback_group, node->get_node_base_interface());
}
void TearDown() override
@@ -105,6 +108,7 @@ public:
rclcpp::CallbackGroup::SharedPtr callback_group;
std::shared_ptr<TestWaitable> waitable;
std::chrono::steady_clock::time_point start_time;
std::shared_ptr<T> executor;
bool has_executed;
};
@@ -112,16 +116,10 @@ TYPED_TEST_SUITE(TestBusyWaiting, ExecutorTypes, ExecutorTypeNames);
TYPED_TEST(TestBusyWaiting, test_spin_all)
{
using ExecutorType = TypeParam;
ExecutorType executor;
executor.add_callback_group(
this->callback_group,
this->node->get_node_base_interface());
this->set_up_and_trigger_waitable();
auto start_time = std::chrono::steady_clock::now();
executor.spin_all(this->max_duration);
this->executor->spin_all(this->max_duration);
this->check_for_busy_waits(start_time);
// this should get the initial trigger, and the follow up from in the callback
ASSERT_EQ(this->waitable->get_count(), 2u);
@@ -129,16 +127,10 @@ TYPED_TEST(TestBusyWaiting, test_spin_all)
TYPED_TEST(TestBusyWaiting, test_spin_some)
{
using ExecutorType = TypeParam;
ExecutorType executor;
executor.add_callback_group(
this->callback_group,
this->node->get_node_base_interface());
this->set_up_and_trigger_waitable();
auto start_time = std::chrono::steady_clock::now();
executor.spin_some(this->max_duration);
this->executor->spin_some(this->max_duration);
this->check_for_busy_waits(start_time);
// this should get the inital trigger, but not the follow up in the callback
ASSERT_EQ(this->waitable->get_count(), 1u);
@@ -146,12 +138,6 @@ TYPED_TEST(TestBusyWaiting, test_spin_some)
TYPED_TEST(TestBusyWaiting, test_spin)
{
using ExecutorType = TypeParam;
ExecutorType executor;
executor.add_callback_group(
this->callback_group,
this->node->get_node_base_interface());
std::condition_variable cv;
std::mutex cv_m;
bool first_check_passed = false;
@@ -165,8 +151,8 @@ TYPED_TEST(TestBusyWaiting, test_spin)
});
auto start_time = std::chrono::steady_clock::now();
std::thread t([&executor]() {
executor.spin();
std::thread t([this]() {
this->executor->spin();
});
// wait until thread has started (first execute of waitable)
@@ -186,7 +172,7 @@ TYPED_TEST(TestBusyWaiting, test_spin)
}
EXPECT_EQ(this->waitable->get_count(), 2u);
executor.cancel();
this->executor->cancel();
t.join();
this->check_for_busy_waits(start_time);

View File

@@ -267,12 +267,15 @@ public:
void TearDown()
{
node.reset();
executor.cancel();
// Clean up thread object
if (standalone_thread.joinable()) {
standalone_thread.join();
}
node.reset();
sim_clock_node.reset();
}
std::shared_ptr<TimerNode> node;
@@ -282,20 +285,12 @@ public:
T executor;
};
#if !defined(_WIN32)
# ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
# endif
#endif
using MainExecutorTypes =
::testing::Types<
rclcpp::executors::SingleThreadedExecutor,
rclcpp::executors::MultiThreadedExecutor,
DeprecatedStaticSingleThreadedExecutor>;
#ifdef __clang__
# pragma clang diagnostic pop
#endif
rclcpp::executors::StaticSingleThreadedExecutor>;
// TODO(@fujitatomoya): this test excludes EventExecutor because it does not
// support simulation time used for this test to relax the racy condition.
// See more details for https://github.com/ros2/rclcpp/issues/2457.
@@ -310,7 +305,6 @@ TYPED_TEST(TestTimerCancelBehavior, testTimer1CancelledWithExecutorSpin) {
this->sim_clock_node->sleep_for(50ms);
this->node->CancelTimer1();
this->sim_clock_node->sleep_for(150ms);
this->executor.cancel();
int t1_runs = this->node->GetTimer1Cnt();
int t2_runs = this->node->GetTimer2Cnt();
@@ -328,7 +322,6 @@ TYPED_TEST(TestTimerCancelBehavior, testTimer2CancelledWithExecutorSpin) {
this->sim_clock_node->sleep_for(50ms);
this->node->CancelTimer2();
this->sim_clock_node->sleep_for(150ms);
this->executor.cancel();
int t1_runs = this->node->GetTimer1Cnt();
int t2_runs = this->node->GetTimer2Cnt();
@@ -355,8 +348,6 @@ TYPED_TEST(TestTimerCancelBehavior, testHeadTimerCancelThenResetBehavior) {
int t1_runs_final = this->node->GetTimer1Cnt();
int t2_runs_final = this->node->GetTimer2Cnt();
this->executor.cancel();
// T1 should have been restarted, and execute about 15 additional times.
// Check 10 greater than initial, to account for some timing jitter.
EXPECT_LT(t1_runs_initial + 50, t1_runs_final);
@@ -384,8 +375,6 @@ TYPED_TEST(TestTimerCancelBehavior, testBackTimerCancelThenResetBehavior) {
int t1_runs_final = this->node->GetTimer1Cnt();
int t2_runs_final = this->node->GetTimer2Cnt();
this->executor.cancel();
// T2 should have been restarted, and execute about 15 additional times.
// Check 10 greater than initial, to account for some timing jitter.
EXPECT_LT(t2_runs_initial + 50, t2_runs_final);
@@ -419,8 +408,6 @@ TYPED_TEST(TestTimerCancelBehavior, testBothTimerCancelThenResetT1Behavior) {
int t1_runs_final = this->node->GetTimer1Cnt();
int t2_runs_final = this->node->GetTimer2Cnt();
this->executor.cancel();
// T1 and T2 should have the same initial count.
EXPECT_LE(std::abs(t1_runs_initial - t2_runs_initial), 1);
@@ -458,8 +445,6 @@ TYPED_TEST(TestTimerCancelBehavior, testBothTimerCancelThenResetT2Behavior) {
int t1_runs_final = this->node->GetTimer1Cnt();
int t2_runs_final = this->node->GetTimer2Cnt();
this->executor.cancel();
// T1 and T2 should have the same initial count.
EXPECT_LE(std::abs(t1_runs_initial - t2_runs_initial), 1);

View File

@@ -99,14 +99,6 @@ TYPED_TEST(TestExecutorsWarmup, spin_all_doesnt_require_warmup_with_cbgroup)
{
using ExecutorType = TypeParam;
// TODO(alsora): Enable when https://github.com/ros2/rclcpp/pull/2595 gets merged
if (
std::is_same<ExecutorType, rclcpp::executors::SingleThreadedExecutor>() ||
std::is_same<ExecutorType, rclcpp::executors::MultiThreadedExecutor>())
{
GTEST_SKIP();
}
ExecutorType executor;
// Enable intra-process to guarantee deterministic and synchronous delivery of the message / event

View File

@@ -32,11 +32,6 @@ protected:
{
rclcpp::init(0, nullptr);
}
static void TearDownTestCase()
{
rclcpp::shutdown();
}
};
constexpr std::chrono::milliseconds PERIOD_MS = 1000ms;

View File

@@ -1,88 +0,0 @@
// Copyright 2024 iRobot Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include <chrono>
#include <cstddef>
#include <memory>
#include <thread>
#include "rclcpp/rclcpp.hpp"
#include "./executor_types.hpp"
template<typename ExecutorType>
class TestTimersLifecycle : public testing::Test
{
public:
void SetUp() override {rclcpp::init(0, nullptr);}
void TearDown() override {rclcpp::shutdown();}
};
TYPED_TEST_SUITE(TestTimersLifecycle, ExecutorTypes, ExecutorTypeNames);
TYPED_TEST(TestTimersLifecycle, timers_lifecycle_reinitialized_object)
{
using ExecutorType = TypeParam;
ExecutorType executor;
auto timers_period = std::chrono::milliseconds(50);
auto node = std::make_shared<rclcpp::Node>("test_node");
executor.add_node(node);
size_t count_1 = 0;
auto timer_1 = rclcpp::create_timer(
node, node->get_clock(), rclcpp::Duration(timers_period), [&count_1]() {count_1++;});
size_t count_2 = 0;
auto timer_2 = rclcpp::create_timer(
node, node->get_clock(), rclcpp::Duration(timers_period), [&count_2]() {count_2++;});
{
std::thread executor_thread([&executor]() {executor.spin();});
while (count_2 < 10u) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
executor.cancel();
executor_thread.join();
EXPECT_GE(count_2, 10u);
EXPECT_LE(count_2 - count_1, 1u);
}
count_1 = 0;
timer_1 = rclcpp::create_timer(
node, node->get_clock(), rclcpp::Duration(timers_period), [&count_1]() {count_1++;});
count_2 = 0;
timer_2 = rclcpp::create_timer(
node, node->get_clock(), rclcpp::Duration(timers_period), [&count_2]() {count_2++;});
{
std::thread executor_thread([&executor]() {executor.spin();});
while (count_2 < 10u) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
executor.cancel();
executor_thread.join();
EXPECT_GE(count_2, 10u);
EXPECT_LE(count_2 - count_1, 1u);
}
}

View File

@@ -20,13 +20,12 @@
#include <stdexcept>
#include "rclcpp/exceptions.hpp"
#include "rclcpp/executors.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp/executors.hpp"
#include "test_msgs/srv/empty.hpp"
#include "./executor_types.hpp"
#include "../../mocking_utils/patch.hpp"
#include "../../utils/rclcpp_gtest_macros.hpp"
@@ -47,15 +46,7 @@ public:
};
TEST_F(TestStaticSingleThreadedExecutor, add_callback_group_trigger_guard_failed) {
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
DeprecatedStaticSingleThreadedExecutor executor;
#ifdef __clang__
# pragma clang diagnostic pop
#endif
rclcpp::executors::StaticSingleThreadedExecutor executor;
auto node = std::make_shared<rclcpp::Node>("node", "ns");
rclcpp::CallbackGroup::SharedPtr cb_group = node->create_callback_group(
rclcpp::CallbackGroupType::MutuallyExclusive);
@@ -65,20 +56,12 @@ TEST_F(TestStaticSingleThreadedExecutor, add_callback_group_trigger_guard_failed
"lib:rclcpp", rcl_trigger_guard_condition, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
executor.add_callback_group(cb_group, node->get_node_base_interface(), true),
std::runtime_error("Failed to handle entities update on callback group add: error not set"));
std::runtime_error("Failed to trigger guard condition on callback group add: error not set"));
}
}
TEST_F(TestStaticSingleThreadedExecutor, add_node_trigger_guard_failed) {
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
DeprecatedStaticSingleThreadedExecutor executor;
#ifdef __clang__
# pragma clang diagnostic pop
#endif
rclcpp::executors::StaticSingleThreadedExecutor executor;
auto node = std::make_shared<rclcpp::Node>("node", "ns");
{
@@ -86,20 +69,12 @@ TEST_F(TestStaticSingleThreadedExecutor, add_node_trigger_guard_failed) {
"lib:rclcpp", rcl_trigger_guard_condition, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
executor.add_node(node),
std::runtime_error("Failed to handle entities update on node add: error not set"));
std::runtime_error("Failed to trigger guard condition on node add: error not set"));
}
}
TEST_F(TestStaticSingleThreadedExecutor, remove_callback_group_trigger_guard_failed) {
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
DeprecatedStaticSingleThreadedExecutor executor;
#ifdef __clang__
# pragma clang diagnostic pop
#endif
rclcpp::executors::StaticSingleThreadedExecutor executor;
auto node = std::make_shared<rclcpp::Node>("node", "ns");
rclcpp::CallbackGroup::SharedPtr cb_group = node->create_callback_group(
rclcpp::CallbackGroupType::MutuallyExclusive);
@@ -112,20 +87,12 @@ TEST_F(TestStaticSingleThreadedExecutor, remove_callback_group_trigger_guard_fai
RCLCPP_EXPECT_THROW_EQ(
executor.remove_callback_group(cb_group, true),
std::runtime_error(
"Failed to handle entities update on callback group remove: error not set"));
"Failed to trigger guard condition on callback group remove: error not set"));
}
}
TEST_F(TestStaticSingleThreadedExecutor, remove_node_failed) {
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
DeprecatedStaticSingleThreadedExecutor executor;
#ifdef __clang__
# pragma clang diagnostic pop
#endif
rclcpp::executors::StaticSingleThreadedExecutor executor;
auto node = std::make_shared<rclcpp::Node>("node", "ns");
{
@@ -138,15 +105,7 @@ TEST_F(TestStaticSingleThreadedExecutor, remove_node_failed) {
}
TEST_F(TestStaticSingleThreadedExecutor, remove_node_trigger_guard_failed) {
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
DeprecatedStaticSingleThreadedExecutor executor;
#ifdef __clang__
# pragma clang diagnostic pop
#endif
rclcpp::executors::StaticSingleThreadedExecutor executor;
auto node = std::make_shared<rclcpp::Node>("node", "ns");
executor.add_node(node);
@@ -156,20 +115,12 @@ TEST_F(TestStaticSingleThreadedExecutor, remove_node_trigger_guard_failed) {
"lib:rclcpp", rcl_trigger_guard_condition, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
executor.remove_node(node, true),
std::runtime_error("Failed to handle entities update on node remove: error not set"));
std::runtime_error("Failed to trigger guard condition on node remove: error not set"));
}
}
TEST_F(TestStaticSingleThreadedExecutor, execute_service) {
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
DeprecatedStaticSingleThreadedExecutor executor;
#ifdef __clang__
# pragma clang diagnostic pop
#endif
rclcpp::executors::StaticSingleThreadedExecutor executor;
auto node = std::make_shared<rclcpp::Node>("node", "ns");
executor.add_node(node);

View File

@@ -38,7 +38,6 @@ protected:
{
node.reset();
wrapped_node.reset();
rclcpp::shutdown();
}
static rclcpp::Node::SharedPtr node;

View File

@@ -47,13 +47,9 @@ constexpr char absolute_namespace[] = "/ns";
class TestNodeGraph : public ::testing::Test
{
public:
static void SetUpTestCase()
{
rclcpp::init(0, nullptr);
}
void SetUp()
{
rclcpp::init(0, nullptr);
node_ = std::make_shared<rclcpp::Node>(node_name, node_namespace);
// This dynamic cast is not necessary for the unittests, but instead is used to ensure
@@ -63,7 +59,7 @@ public:
ASSERT_NE(nullptr, node_graph_);
}
static void TearDownTestCase()
void TearDown()
{
rclcpp::shutdown();
}

View File

@@ -21,7 +21,6 @@
#include <gtest/gtest.h>
#include <algorithm>
#include <filesystem>
#include <memory>
#include <string>
#include <vector>
@@ -62,7 +61,7 @@ protected:
std::shared_ptr<rclcpp::Node> node;
rclcpp::node_interfaces::NodeParameters * node_parameters;
std::filesystem::path test_resources_path{TEST_RESOURCES_DIRECTORY};
rcpputils::fs::path test_resources_path{TEST_RESOURCES_DIRECTORY};
};
TEST_F(TestNodeParameters, construct_destruct_rcl_errors) {

View File

@@ -31,13 +31,13 @@ public:
void add_to_wait_set(rcl_wait_set_t &) override {}
bool is_ready(const rcl_wait_set_t &) override {return false;}
std::shared_ptr<void> take_data() override {return nullptr;}
std::shared_ptr<void>
take_data() override
{
return nullptr;
}
void execute(const std::shared_ptr<void> &) override {}
void set_on_ready_callback(std::function<void(size_t, int)>) override {}
void clear_on_ready_callback() override {}
std::shared_ptr<void> take_data_by_entity_id(size_t) override {return nullptr;}
};
class TestNodeWaitables : public ::testing::Test

View File

@@ -51,13 +51,13 @@ public:
return test_waitable_result;
}
std::shared_ptr<void> take_data() override {return nullptr;}
std::shared_ptr<void>
take_data() override
{
return nullptr;
}
void execute(const std::shared_ptr<void> &) override {}
void set_on_ready_callback(std::function<void(size_t, int)>) override {}
void clear_on_ready_callback() override {}
std::shared_ptr<void> take_data_by_entity_id(size_t) override {return nullptr;}
};
struct RclWaitSetSizes

View File

@@ -23,14 +23,13 @@
#include "rclcpp/node.hpp"
#include "test_msgs/msg/empty.hpp"
#include "test_msgs/msg/empty.h"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/executors.hpp"
#include "rclcpp/executor.hpp"
#include "rclcpp/rclcpp.hpp"
#include "./executors/executor_types.hpp"
using namespace std::chrono_literals;
template<typename T>
@@ -50,8 +49,48 @@ public:
template<typename T>
class TestAddCallbackGroupsToExecutorStable : public TestAddCallbackGroupsToExecutor<T> {};
using ExecutorTypes =
::testing::Types<
rclcpp::executors::SingleThreadedExecutor,
rclcpp::executors::MultiThreadedExecutor,
rclcpp::executors::StaticSingleThreadedExecutor,
rclcpp::experimental::executors::EventsExecutor>;
class ExecutorTypeNames
{
public:
template<typename T>
static std::string GetName(int idx)
{
(void)idx;
if (std::is_same<T, rclcpp::executors::SingleThreadedExecutor>()) {
return "SingleThreadedExecutor";
}
if (std::is_same<T, rclcpp::executors::MultiThreadedExecutor>()) {
return "MultiThreadedExecutor";
}
if (std::is_same<T, rclcpp::executors::StaticSingleThreadedExecutor>()) {
return "StaticSingleThreadedExecutor";
}
if (std::is_same<T, rclcpp::experimental::executors::EventsExecutor>()) {
return "EventsExecutor";
}
return "";
}
};
TYPED_TEST_SUITE(TestAddCallbackGroupsToExecutor, ExecutorTypes, ExecutorTypeNames);
// StaticSingleThreadedExecutor is not included in these tests for now
using StandardExecutors =
::testing::Types<
rclcpp::executors::SingleThreadedExecutor,
rclcpp::executors::MultiThreadedExecutor,
rclcpp::experimental::executors::EventsExecutor>;
TYPED_TEST_SUITE(TestAddCallbackGroupsToExecutorStable, StandardExecutors, ExecutorTypeNames);
/*
@@ -177,6 +216,7 @@ TYPED_TEST(TestAddCallbackGroupsToExecutor, add_callback_groups_after_add_node_t
std::atomic_size_t timer_count {0};
auto timer_callback = [&executor, &timer_count]() {
auto cur_timer_count = timer_count++;
printf("in timer_callback(%zu)\n", cur_timer_count);
if (cur_timer_count > 0) {
executor.cancel();
}
@@ -305,30 +345,32 @@ TYPED_TEST(TestAddCallbackGroupsToExecutorStable, subscriber_triggered_to_receiv
received_message_promise.set_value(true);
};
rclcpp::Subscription<test_msgs::msg::Empty>::SharedPtr subscription;
rclcpp::Publisher<test_msgs::msg::Empty>::SharedPtr publisher;
// to create a timer with a callback run on another executor
rclcpp::TimerBase::SharedPtr timer = nullptr;
std::promise<void> timer_promise;
// create a subscription using the 'cb_grp' callback group
rclcpp::QoS qos = rclcpp::QoS(1).reliable();
auto options = rclcpp::SubscriptionOptions();
options.callback_group = cb_grp;
rclcpp::Subscription<test_msgs::msg::Empty>::SharedPtr subscription =
node->create_subscription<test_msgs::msg::Empty>("topic_name", qos, sub_callback, options);
// create a publisher to send data
rclcpp::Publisher<test_msgs::msg::Empty>::SharedPtr publisher =
node->create_publisher<test_msgs::msg::Empty>("topic_name", qos);
auto timer_callback =
[&publisher, &timer_promise]() {
if (publisher->get_subscription_count() == 0) {
// If discovery hasn't happened yet, get out.
return;
[&subscription, &publisher, &timer, &cb_grp, &node, &sub_callback, &timer_promise]() {
if (timer) {
timer.reset();
}
// create a subscription using the `cb_grp` callback group
rclcpp::QoS qos = rclcpp::QoS(1).reliable();
auto options = rclcpp::SubscriptionOptions();
options.callback_group = cb_grp;
subscription =
node->create_subscription<test_msgs::msg::Empty>("topic_name", qos, sub_callback, options);
// create a publisher to send data
publisher =
node->create_publisher<test_msgs::msg::Empty>("topic_name", qos);
publisher->publish(test_msgs::msg::Empty());
timer_promise.set_value();
};
// Another executor to run the timer with a callback
ExecutorType timer_executor;
rclcpp::TimerBase::SharedPtr timer = node->create_wall_timer(100ms, timer_callback);
timer = node->create_wall_timer(100ms, timer_callback);
timer_executor.add_node(node);
auto future = timer_promise.get_future();
timer_executor.spin_until_future_complete(future);

View File

@@ -24,6 +24,7 @@
#include "rclcpp/any_service_callback.hpp"
#include "rclcpp/service.hpp"
#include "test_msgs/srv/empty.hpp"
#include "test_msgs/srv/empty.h"
class TestAnyServiceCallback : public ::testing::Test
{

View File

@@ -21,6 +21,7 @@
#include "rclcpp/any_subscription_callback.hpp"
#include "test_msgs/msg/empty.hpp"
#include "test_msgs/msg/empty.h"
// Type adapter to be used in tests.
struct MyEmpty {};

View File

@@ -89,10 +89,31 @@ TEST_F(TestClient, construction_and_destruction) {
{
auto client = node->create_client<ListParameters>("service");
}
{
// suppress deprecated function warning
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
auto client = node->create_client<ListParameters>(
"service", rmw_qos_profile_services_default);
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
}
{
auto client = node->create_client<ListParameters>(
"service", rclcpp::ServicesQoS());
}
{
ASSERT_THROW(
{
@@ -102,6 +123,27 @@ TEST_F(TestClient, construction_and_destruction) {
}
TEST_F(TestClient, construction_with_free_function) {
{
auto client = rclcpp::create_client<rcl_interfaces::srv::ListParameters>(
node->get_node_base_interface(),
node->get_node_graph_interface(),
node->get_node_services_interface(),
"service",
rmw_qos_profile_services_default,
nullptr);
}
{
ASSERT_THROW(
{
auto client = rclcpp::create_client<rcl_interfaces::srv::ListParameters>(
node->get_node_base_interface(),
node->get_node_graph_interface(),
node->get_node_services_interface(),
"invalid_?service",
rmw_qos_profile_services_default,
nullptr);
}, rclcpp::exceptions::InvalidServiceNameError);
}
{
auto client = rclcpp::create_client<rcl_interfaces::srv::ListParameters>(
node->get_node_base_interface(),

View File

@@ -0,0 +1,246 @@
// Copyright 2025 Cellumation GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include <chrono>
#include "rcl/error_handling.h"
#include "rcl/time.h"
#include "rclcpp/clock.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp/time_source.hpp"
#include "../utils/rclcpp_gtest_macros.hpp"
using namespace std::chrono_literals;
class TestClockWakeup : public ::testing::TestWithParam<rcl_clock_type_e>
{
public:
void test_wakeup_before_sleep(const rclcpp::Clock::SharedPtr & clock)
{
std::atomic_bool thread_finished = false;
rclcpp::ClockConditionalVariable cond(clock);
bool stopSleeping = false;
std::thread wait_thread = std::thread(
[&cond, &clock, &stopSleeping, &thread_finished]()
{
// make sure the thread starts sleeping late
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::unique_lock lk(cond.mutex());
cond.wait_until(lk, clock->now() + std::chrono::seconds(3),
[&stopSleeping] () {return stopSleeping;});
thread_finished = true;
});
{
std::lock_guard lk(cond.mutex());
// stop sleeping after next notification
stopSleeping = true;
}
// notify the conditional, to recheck it pred
cond.notify_one();
auto start_time = std::chrono::steady_clock::now();
auto cur_time = start_time;
while (!thread_finished && start_time + std::chrono::seconds(1) > cur_time) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
cur_time = std::chrono::steady_clock::now();
}
wait_thread.join();
EXPECT_TRUE(thread_finished);
EXPECT_LT(cur_time, start_time + std::chrono::seconds(1));
}
void test_wakeup_after_sleep(const rclcpp::Clock::SharedPtr & clock)
{
std::atomic_bool thread_finished = false;
rclcpp::ClockConditionalVariable cond(clock);
bool stopSleeping = false;
std::thread wait_thread = std::thread(
[&cond, &clock, &stopSleeping, &thread_finished]()
{
std::unique_lock lk(cond.mutex());
cond.wait_until(lk, clock->now() + std::chrono::seconds(3),
[&stopSleeping] () {return stopSleeping;});
thread_finished = true;
});
// make sure the thread is already sleeping before we send the cancel
std::this_thread::sleep_for(std::chrono::milliseconds(100));
{
std::lock_guard lk(cond.mutex());
// stop sleeping after next notification
stopSleeping = true;
}
// notify the conditional, to recheck it pred
cond.notify_one();
auto start_time = std::chrono::steady_clock::now();
auto cur_time = start_time;
while (!thread_finished && start_time + std::chrono::seconds(1) > cur_time) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
cur_time = std::chrono::steady_clock::now();
}
wait_thread.join();
EXPECT_TRUE(thread_finished);
EXPECT_LT(cur_time, start_time + std::chrono::seconds(1));
}
protected:
static void SetUpTestCase()
{
rclcpp::init(0, nullptr);
}
static void TearDownTestCase()
{
rclcpp::shutdown();
}
void SetUp()
{
node = std::make_shared<rclcpp::Node>("my_node");
}
void TearDown()
{
node.reset();
}
rclcpp::Node::SharedPtr node;
};
INSTANTIATE_TEST_SUITE_P(
ClockConditionalVariable,
TestClockWakeup,
::testing::Values(
RCL_SYSTEM_TIME, RCL_ROS_TIME, RCL_STEADY_TIME
));
TEST_P(TestClockWakeup, wakeup_sleep) {
auto clock = std::make_shared<rclcpp::Clock>(GetParam());
test_wakeup_after_sleep(clock);
test_wakeup_before_sleep(clock);
}
TEST_F(TestClockWakeup, wakeup_sleep_ros_time_active) {
node->set_parameter({"use_sim_time", true});
auto clock = std::make_shared<rclcpp::Clock>(RCL_ROS_TIME);
rclcpp::TimeSource time_source(node);
time_source.attachClock(clock);
EXPECT_TRUE(clock->ros_time_is_active());
test_wakeup_after_sleep(clock);
test_wakeup_before_sleep(clock);
}
TEST_F(TestClockWakeup, no_wakeup_on_sim_time) {
node->set_parameter({"use_sim_time", true});
auto clock = std::make_shared<rclcpp::Clock>(RCL_ROS_TIME);
EXPECT_FALSE(clock->ros_time_is_active());
rclcpp::TimeSource time_source(node);
time_source.attachClock(clock);
EXPECT_TRUE(clock->ros_time_is_active());
std::atomic_bool thread_finished = false;
rclcpp::ClockConditionalVariable cond(clock);
bool stopSleeping = false;
std::thread wait_thread = std::thread(
[&cond, &clock, &stopSleeping, &thread_finished]()
{
std::unique_lock lk(cond.mutex());
// only sleep for an short period
cond.wait_until(lk, clock->now() + std::chrono::milliseconds(10),
[&stopSleeping] () {return stopSleeping;});
thread_finished = true;
});
// make sure, that the sim time clock does not wakeup, as no clock is provided
std::this_thread::sleep_for(std::chrono::milliseconds(500));
EXPECT_FALSE(thread_finished);
{
std::lock_guard lk(cond.mutex());
// stop sleeping after next notification
stopSleeping = true;
}
// notify the conditional, to recheck it pred
cond.notify_one();
auto start_time = std::chrono::steady_clock::now();
auto cur_time = start_time;
while (!thread_finished && start_time + std::chrono::seconds(1) > cur_time) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
cur_time = std::chrono::steady_clock::now();
}
wait_thread.join();
EXPECT_TRUE(thread_finished);
EXPECT_LT(cur_time, start_time + std::chrono::seconds(1));
}
TEST_F(TestClockWakeup, wakeup_on_ros_shutdown) {
auto clock = std::make_shared<rclcpp::Clock>(RCL_ROS_TIME);
std::atomic_bool thread_finished = false;
rclcpp::ClockConditionalVariable cond(clock);
bool stopSleeping = false;
std::thread wait_thread = std::thread(
[&cond, &clock, &stopSleeping, &thread_finished]()
{
std::unique_lock lk(cond.mutex());
// only sleep for an short period
cond.wait_until(lk, clock->now() + std::chrono::seconds(10),
[&stopSleeping] () {return stopSleeping;});
thread_finished = true;
});
// wait a bit to be sure the thread is sleeping
std::this_thread::sleep_for(std::chrono::milliseconds(500));
EXPECT_FALSE(thread_finished);
rclcpp::shutdown();
auto start_time = std::chrono::steady_clock::now();
auto cur_time = start_time;
while (!thread_finished && start_time + std::chrono::seconds(1) > cur_time) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
cur_time = std::chrono::steady_clock::now();
}
EXPECT_TRUE(thread_finished);
wait_thread.join();
EXPECT_LT(cur_time, start_time + std::chrono::seconds(1));
}

View File

@@ -20,6 +20,7 @@
#include "rclcpp/create_subscription.hpp"
#include "rclcpp/node.hpp"
#include "test_msgs/msg/empty.hpp"
#include "test_msgs/msg/empty.h"
using namespace std::chrono_literals;

View File

@@ -138,7 +138,7 @@ TEST_F(TestExecutor, add_callback_group_failed_trigger_guard_condition) {
"lib:rclcpp", rcl_trigger_guard_condition, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
dummy.add_callback_group(cb_group, node->get_node_base_interface(), true),
std::runtime_error("Failed to handle entities update on callback group add: error not set"));
std::runtime_error("Failed to trigger guard condition on callback group add: error not set"));
}
TEST_F(TestExecutor, remove_callback_group_null_node) {
@@ -175,7 +175,7 @@ TEST_F(TestExecutor, remove_callback_group_failed_trigger_guard_condition) {
RCLCPP_EXPECT_THROW_EQ(
dummy.remove_callback_group(cb_group, true),
std::runtime_error(
"Failed to handle entities update on callback group remove: error not set"));
"Failed to trigger guard condition on callback group remove: error not set"));
}
TEST_F(TestExecutor, remove_node_not_associated) {

View File

@@ -34,11 +34,6 @@ protected:
{
rclcpp::init(0, nullptr);
}
static void TearDownTestCase()
{
rclcpp::shutdown();
}
};
void

View File

@@ -27,11 +27,6 @@ protected:
{
rclcpp::init(0, nullptr);
}
static void TearDownTestCase()
{
rclcpp::shutdown();
}
};
TEST_F(TestFindWeakNodes, allocator_strategy_with_weak_nodes) {

View File

@@ -14,8 +14,6 @@
#include <gtest/gtest.h>
#include <chrono>
#include <cstdint>
#include <string>
#include <memory>
#include <utility>
@@ -30,7 +28,6 @@
#include "../mocking_utils/patch.hpp"
#include "test_msgs/srv/empty.hpp"
#include "test_msgs/srv/basic_types.hpp"
using namespace std::chrono_literals;
@@ -108,7 +105,7 @@ TEST_F(TestGenericClient, construction_and_destruction) {
ASSERT_THROW(
{
auto client = node->create_generic_client("test_service", "test_msgs/srv/InvalidType");
}, rclcpp::exceptions::InvalidServiceTypeError);
}, std::runtime_error);
}
}
@@ -231,69 +228,3 @@ TEST_F(TestGenericClientSub, construction_and_destruction) {
}, rclcpp::exceptions::InvalidServiceNameError);
}
}
TEST_F(TestGenericClientSub, async_send_request_with_request) {
const std::string service_name = "test_service";
int64_t expected_change = 1111;
auto client = node->create_generic_client(service_name, "test_msgs/srv/BasicTypes");
auto callback = [&expected_change](
const test_msgs::srv::BasicTypes::Request::SharedPtr request,
test_msgs::srv::BasicTypes::Response::SharedPtr response) {
response->int64_value = request->int64_value + expected_change;
};
auto service =
node->create_service<test_msgs::srv::BasicTypes>(service_name, std::move(callback));
ASSERT_TRUE(client->wait_for_service(std::chrono::seconds(5)));
ASSERT_TRUE(client->service_is_ready());
test_msgs::srv::BasicTypes::Request request;
request.int64_value = 12345678;
auto future = client->async_send_request(static_cast<void *>(&request));
rclcpp::spin_until_future_complete(
node->get_node_base_interface(), future, std::chrono::seconds(5));
ASSERT_TRUE(future.valid());
auto get_untyped_response = future.get();
auto typed_response =
static_cast<test_msgs::srv::BasicTypes::Response *>(get_untyped_response.get());
EXPECT_EQ(typed_response->int64_value, (request.int64_value + expected_change));
}
TEST_F(TestGenericClientSub, async_send_request_with_request_and_callback) {
const std::string service_name = "test_service";
int64_t expected_change = 2222;
auto client = node->create_generic_client(service_name, "test_msgs/srv/BasicTypes");
auto server_callback = [&expected_change](
const test_msgs::srv::BasicTypes::Request::SharedPtr request,
test_msgs::srv::BasicTypes::Response::SharedPtr response) {
response->int64_value = request->int64_value + expected_change;
};
auto service =
node->create_service<test_msgs::srv::BasicTypes>(service_name, std::move(server_callback));
ASSERT_TRUE(client->wait_for_service(std::chrono::seconds(5)));
ASSERT_TRUE(client->service_is_ready());
test_msgs::srv::BasicTypes::Request request;
request.int64_value = 12345678;
auto client_callback = [&request, &expected_change](
rclcpp::GenericClient::SharedFuture future) {
auto untyped_response = future.get();
auto typed_response =
static_cast<test_msgs::srv::BasicTypes::Response *>(untyped_response.get());
EXPECT_EQ(typed_response->int64_value, (request.int64_value + expected_change));
};
auto future =
client->async_send_request(static_cast<void *>(&request), client_callback);
rclcpp::spin_until_future_complete(
node->get_node_base_interface(), future, std::chrono::seconds(5));
}

View File

@@ -89,9 +89,9 @@ public:
T2 message;
write_message(data, message);
rclcpp::Serialization<T2> serialization_support;
rclcpp::Serialization<T2> ser;
SerializedMessage result;
serialization_support.serialize_message(&message, &result);
ser.serialize_message(&message, &result);
return result;
}

View File

@@ -1,422 +0,0 @@
// Copyright 2024 Sony Group Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include <chrono>
#include <cstddef>
#include <functional>
#include <memory>
#include <stdexcept>
#include <string>
#include <utility>
#include "rclcpp/exceptions.hpp"
#include "rclcpp/rclcpp.hpp"
#include "../mocking_utils/patch.hpp"
#include "../utils/rclcpp_gtest_macros.hpp"
#include "rcl_interfaces/srv/list_parameters.hpp"
#include "test_msgs/srv/empty.hpp"
#include "test_msgs/srv/basic_types.hpp"
using namespace std::chrono_literals;
class TestGenericService : public ::testing::Test
{
protected:
static void SetUpTestCase()
{
rclcpp::init(0, nullptr);
}
static void TearDownTestCase()
{
rclcpp::shutdown();
}
void SetUp()
{
node = std::make_shared<rclcpp::Node>("test_node", "/ns");
}
void TearDown()
{
node.reset();
}
rclcpp::Node::SharedPtr node;
};
class TestGenericServiceSub : public ::testing::Test
{
protected:
static void SetUpTestCase()
{
rclcpp::init(0, nullptr);
}
static void TearDownTestCase()
{
rclcpp::shutdown();
}
void SetUp()
{
node = std::make_shared<rclcpp::Node>("test_node", "/ns");
subnode = node->create_sub_node("sub_ns");
}
void TearDown()
{
node.reset();
}
rclcpp::Node::SharedPtr node;
rclcpp::Node::SharedPtr subnode;
};
/*
Testing service construction and destruction.
*/
TEST_F(TestGenericService, construction_and_destruction) {
auto callback = [](
rclcpp::GenericService::SharedRequest,
rclcpp::GenericService::SharedResponse) {};
{
auto generic_service = node->create_generic_service(
"test_generic_service", "rcl_interfaces/srv/ListParameters", callback);
EXPECT_NE(nullptr, generic_service->get_service_handle());
const rclcpp::ServiceBase * const_service_base = generic_service.get();
EXPECT_NE(nullptr, const_service_base->get_service_handle());
}
{
ASSERT_THROW(
{
auto generic_service = node->create_generic_service(
"invalid_service?", "test_msgs/srv/Empty", callback);
}, rclcpp::exceptions::InvalidServiceNameError);
}
{
ASSERT_THROW(
{
auto generic_service = node->create_generic_service(
"test_generic_service", "test_msgs/srv/NotExist", callback);
}, rclcpp::exceptions::InvalidServiceTypeError);
}
}
/*
Testing service construction and destruction for subnodes.
*/
TEST_F(TestGenericServiceSub, construction_and_destruction) {
auto callback = [](
rclcpp::GenericService::SharedRequest,
rclcpp::GenericService::SharedResponse) {};
{
auto generic_service = subnode->create_generic_service(
"test_generic_service", "rcl_interfaces/srv/ListParameters", callback);
EXPECT_STREQ(generic_service->get_service_name(), "/ns/sub_ns/test_generic_service");
}
{
ASSERT_THROW(
{
auto generic_service = subnode->create_generic_service(
"invalid_service?", "test_msgs/srv/Empty", callback);
}, rclcpp::exceptions::InvalidServiceNameError);
}
{
ASSERT_THROW(
{
auto generic_service = subnode->create_generic_service(
"test_generic_service", "test_msgs/srv/NotExist", callback);
}, rclcpp::exceptions::InvalidServiceTypeError);
}
}
TEST_F(TestGenericService, construction_and_destruction_rcl_errors) {
auto callback = [](
rclcpp::GenericService::SharedRequest, rclcpp::GenericService::SharedResponse) {};
{
auto mock = mocking_utils::patch_and_return("lib:rclcpp", rcl_service_init, RCL_RET_ERROR);
// reset() isn't necessary for this exception, it just avoids unused return value warning
EXPECT_THROW(
node->create_generic_service("service", "test_msgs/srv/Empty", callback).reset(),
rclcpp::exceptions::RCLError);
}
{
// reset() is required for this one
auto mock = mocking_utils::patch_and_return("lib:rclcpp", rcl_service_fini, RCL_RET_ERROR);
EXPECT_NO_THROW(
node->create_generic_service("service", "test_msgs/srv/Empty", callback).reset());
}
}
TEST_F(TestGenericService, generic_service_take_request) {
auto callback = [](
rclcpp::GenericService::SharedRequest, rclcpp::GenericService::SharedResponse) {};
auto generic_service =
node->create_generic_service("test_service", "test_msgs/srv/Empty", callback);
{
auto request_id = generic_service->create_request_header();
auto request = generic_service->create_request();
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_take_request, RCL_RET_OK);
EXPECT_TRUE(generic_service->take_request(request, *request_id.get()));
}
{
auto request_id = generic_service->create_request_header();
auto request = generic_service->create_request();
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_take_request, RCL_RET_SERVICE_TAKE_FAILED);
EXPECT_FALSE(generic_service->take_request(request, *request_id.get()));
}
{
auto request_id = generic_service->create_request_header();
auto request = generic_service->create_request();
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_take_request, RCL_RET_ERROR);
EXPECT_THROW(
generic_service->take_request(request, *request_id.get()), rclcpp::exceptions::RCLError);
}
}
TEST_F(TestGenericService, generic_service_send_response) {
auto callback = [](
const rclcpp::GenericService::SharedRequest, rclcpp::GenericService::SharedResponse) {};
auto generic_service =
node->create_generic_service("test_service", "test_msgs/srv/Empty", callback);
{
auto request_id = generic_service->create_request_header();
auto response = generic_service->create_response();
auto mock = mocking_utils::patch_and_return("lib:rclcpp", rcl_send_response, RCL_RET_OK);
EXPECT_NO_THROW(generic_service->send_response(*request_id.get(), response));
}
{
auto request_id = generic_service->create_request_header();
auto response = generic_service->create_response();
auto mock = mocking_utils::patch_and_return("lib:rclcpp", rcl_send_response, RCL_RET_ERROR);
EXPECT_THROW(
generic_service->send_response(*request_id.get(), response),
rclcpp::exceptions::RCLError);
}
}
/*
Testing on_new_request callbacks.
*/
TEST_F(TestGenericService, generic_service_on_new_request_callback) {
auto server_callback = [](
const rclcpp::GenericService::SharedRequest, rclcpp::GenericService::SharedResponse) {FAIL();};
rclcpp::ServicesQoS service_qos;
service_qos.keep_last(3);
auto generic_service = node->create_generic_service(
"~/test_service", "test_msgs/srv/Empty", server_callback, service_qos);
std::atomic<size_t> c1 {0};
auto increase_c1_cb = [&c1](size_t count_msgs) {c1 += count_msgs;};
generic_service->set_on_new_request_callback(increase_c1_cb);
auto client = node->create_client<test_msgs::srv::Empty>(
"~/test_service", service_qos);
{
auto request = std::make_shared<test_msgs::srv::Empty::Request>();
client->async_send_request(request);
}
auto start = std::chrono::steady_clock::now();
do {
std::this_thread::sleep_for(100ms);
} while (c1 == 0 && std::chrono::steady_clock::now() - start < 10s);
EXPECT_EQ(c1.load(), 1u);
std::atomic<size_t> c2 {0};
auto increase_c2_cb = [&c2](size_t count_msgs) {c2 += count_msgs;};
generic_service->set_on_new_request_callback(increase_c2_cb);
{
auto request = std::make_shared<test_msgs::srv::Empty::Request>();
client->async_send_request(request);
}
start = std::chrono::steady_clock::now();
do {
std::this_thread::sleep_for(100ms);
} while (c2 == 0 && std::chrono::steady_clock::now() - start < 10s);
EXPECT_EQ(c1.load(), 1u);
EXPECT_EQ(c2.load(), 1u);
generic_service->clear_on_new_request_callback();
{
auto request = std::make_shared<test_msgs::srv::Empty::Request>();
client->async_send_request(request);
client->async_send_request(request);
client->async_send_request(request);
}
std::atomic<size_t> c3 {0};
auto increase_c3_cb = [&c3](size_t count_msgs) {c3 += count_msgs;};
generic_service->set_on_new_request_callback(increase_c3_cb);
start = std::chrono::steady_clock::now();
do {
std::this_thread::sleep_for(100ms);
} while (c3 < 3 && std::chrono::steady_clock::now() - start < 10s);
EXPECT_EQ(c1.load(), 1u);
EXPECT_EQ(c2.load(), 1u);
EXPECT_EQ(c3.load(), 3u);
std::function<void(size_t)> invalid_cb = nullptr;
EXPECT_THROW(generic_service->set_on_new_request_callback(invalid_cb), std::invalid_argument);
}
TEST_F(TestGenericService, rcl_service_response_publisher_get_actual_qos_error) {
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_service_response_publisher_get_actual_qos, nullptr);
auto callback = [](
const rclcpp::GenericService::SharedRequest, rclcpp::GenericService::SharedResponse) {};
auto generic_service =
node->create_generic_service("test_service", "test_msgs/srv/Empty", callback);
RCLCPP_EXPECT_THROW_EQ(
generic_service->get_response_publisher_actual_qos(),
std::runtime_error("failed to get service's response publisher qos settings: error not set"));
}
TEST_F(TestGenericService, rcl_service_request_subscription_get_actual_qos_error) {
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_service_request_subscription_get_actual_qos, nullptr);
auto callback = [](
const rclcpp::GenericService::SharedRequest, rclcpp::GenericService::SharedResponse) {};
auto generic_service =
node->create_generic_service("test_service", "test_msgs/srv/Empty", callback);
RCLCPP_EXPECT_THROW_EQ(
generic_service->get_request_subscription_actual_qos(),
std::runtime_error("failed to get service's request subscription qos settings: error not set"));
}
TEST_F(TestGenericService, generic_service_qos) {
rclcpp::ServicesQoS qos_profile;
qos_profile.liveliness(rclcpp::LivelinessPolicy::Automatic);
rclcpp::Duration duration(std::chrono::milliseconds(1));
qos_profile.deadline(duration);
qos_profile.lifespan(duration);
qos_profile.liveliness_lease_duration(duration);
auto callback = [](
const rclcpp::GenericService::SharedRequest, rclcpp::GenericService::SharedResponse) {};
auto generic_service =
node->create_generic_service("test_service", "test_msgs/srv/Empty", callback, qos_profile);
auto rs_qos = generic_service->get_request_subscription_actual_qos();
auto rp_qos = generic_service->get_response_publisher_actual_qos();
EXPECT_EQ(qos_profile, rp_qos);
// Lifespan has no meaning for subscription/readers
rs_qos.lifespan(qos_profile.lifespan());
EXPECT_EQ(qos_profile, rs_qos);
}
TEST_F(TestGenericService, generic_service_qos_depth) {
uint64_t server_cb_count_ = 0;
auto server_callback = [&](
const rclcpp::GenericService::SharedRequest,
rclcpp::GenericService::SharedResponse) {server_cb_count_++;};
auto server_node = std::make_shared<rclcpp::Node>("server_node", "/ns");
rclcpp::QoS server_qos_profile(2);
auto generic_service = server_node->create_generic_service(
"test_qos_depth", "test_msgs/srv/Empty", std::move(server_callback), server_qos_profile);
rclcpp::QoS client_qos_profile(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_default));
auto client = node->create_client<test_msgs::srv::Empty>("test_qos_depth", client_qos_profile);
::testing::AssertionResult request_result = ::testing::AssertionSuccess();
auto request = std::make_shared<test_msgs::srv::Empty::Request>();
auto client_callback = [&request_result](
rclcpp::Client<test_msgs::srv::Empty>::SharedFuture future_response) {
if (nullptr == future_response.get()) {
request_result = ::testing::AssertionFailure() << "Future response was null";
}
};
uint64_t client_requests = 5;
for (uint64_t i = 0; i < client_requests; i++) {
client->async_send_request(request, client_callback);
std::this_thread::sleep_for(10ms);
}
auto start = std::chrono::steady_clock::now();
while ((server_cb_count_ < server_qos_profile.depth()) &&
(std::chrono::steady_clock::now() - start) < 1s)
{
rclcpp::spin_some(server_node);
std::this_thread::sleep_for(1ms);
}
// Spin an extra time to check if server QoS depth has been ignored,
// so more server responses might be processed than expected.
rclcpp::spin_some(server_node);
EXPECT_EQ(server_cb_count_, server_qos_profile.depth());
}
TEST_F(TestGenericService, generic_service_and_client) {
const std::string service_name = "test_service";
const std::string service_type = "test_msgs/srv/BasicTypes";
int64_t expected_change = 87654321;
auto callback = [&expected_change](
const rclcpp::GenericService::SharedRequest request,
rclcpp::GenericService::SharedResponse response) {
auto typed_request = static_cast<test_msgs::srv::BasicTypes_Request *>(request.get());
auto typed_response = static_cast<test_msgs::srv::BasicTypes_Response *>(response.get());
typed_response->int64_value = typed_request->int64_value + expected_change;
};
auto generic_service = node->create_generic_service(service_name, service_type, callback);
auto client = node->create_client<test_msgs::srv::BasicTypes>(service_name);
ASSERT_TRUE(client->wait_for_service(std::chrono::seconds(5)));
ASSERT_TRUE(client->service_is_ready());
auto request = std::make_shared<test_msgs::srv::BasicTypes::Request>();
request->int64_value = 12345678;
auto generic_client_callback = [&request, &expected_change](
std::shared_future<test_msgs::srv::BasicTypes_Response::SharedPtr> future) {
auto response = future.get();
EXPECT_EQ(response->int64_value, (request->int64_value + expected_change));
};
auto future =
client->async_send_request(request, generic_client_callback);
rclcpp::spin_until_future_complete(
node->get_node_base_interface(), future, std::chrono::seconds(5));
}

View File

@@ -27,11 +27,6 @@ protected:
{
rclcpp::init(0, nullptr);
}
static void TearDownTestCase()
{
rclcpp::shutdown();
}
};
/*

Some files were not shown because too many files have changed in this diff Show More