rclnodejs 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/node.js CHANGED
@@ -39,7 +39,10 @@ const Service = require('./service.js');
39
39
  const Subscription = require('./subscription.js');
40
40
  const TimeSource = require('./time_source.js');
41
41
  const Timer = require('./timer.js');
42
+ const TypeDescriptionService = require('./type_description_service.js');
42
43
  const Entity = require('./entity.js');
44
+ const { SubscriptionEventCallbacks } = require('../lib/event_handler.js');
45
+ const { PublisherEventCallbacks } = require('../lib/event_handler.js');
43
46
 
44
47
  // Parameter event publisher constants
45
48
  const PARAMETER_EVENT_MSG_TYPE = 'rcl_interfaces/msg/ParameterEvent';
@@ -95,12 +98,14 @@ class Node extends rclnodejs.ShadowNode {
95
98
  this._services = [];
96
99
  this._timers = [];
97
100
  this._guards = [];
101
+ this._events = [];
98
102
  this._actionClients = [];
99
103
  this._actionServers = [];
100
104
  this._rateTimerServer = null;
101
105
  this._parameterDescriptors = new Map();
102
106
  this._parameters = new Map();
103
107
  this._parameterService = null;
108
+ this._typeDescriptionService = null;
104
109
  this._parameterEventPublisher = null;
105
110
  this._setParametersCallbacks = [];
106
111
  this._logger = new Logging(rclnodejs.getNodeLoggerName(this.handle));
@@ -147,6 +152,14 @@ class Node extends rclnodejs.ShadowNode {
147
152
  this._parameterService = new ParameterService(this);
148
153
  this._parameterService.start();
149
154
  }
155
+
156
+ if (
157
+ DistroUtils.getDistroId() >= DistroUtils.getDistroId('jazzy') &&
158
+ options.startTypeDescriptionService
159
+ ) {
160
+ this._typeDescriptionService = new TypeDescriptionService(this);
161
+ this._typeDescriptionService.start();
162
+ }
150
163
  }
151
164
 
152
165
  execute(handles) {
@@ -171,6 +184,9 @@ class Node extends rclnodejs.ShadowNode {
171
184
  let actionServersReady = this._actionServers.filter((actionServer) =>
172
185
  handles.includes(actionServer.handle)
173
186
  );
187
+ let eventsReady = this._events.filter((event) =>
188
+ handles.includes(event.handle)
189
+ );
174
190
 
175
191
  timersReady.forEach((timer) => {
176
192
  if (timer.isReady()) {
@@ -179,6 +195,10 @@ class Node extends rclnodejs.ShadowNode {
179
195
  }
180
196
  });
181
197
 
198
+ eventsReady.forEach((event) => {
199
+ event.takeData();
200
+ });
201
+
182
202
  for (const subscription of subscriptionsReady) {
183
203
  if (subscription.isDestroyed()) continue;
184
204
  if (subscription.isRaw) {
@@ -578,27 +598,39 @@ class Node extends rclnodejs.ShadowNode {
578
598
  * @param {object} options - The options argument used to parameterize the publisher.
579
599
  * @param {boolean} options.enableTypedArray - The topic will use TypedArray if necessary, default: true.
580
600
  * @param {QoS} options.qos - ROS Middleware "quality of service" settings for the publisher, default: QoS.profileDefault.
601
+ * @param {PublisherEventCallbacks} eventCallbacks - The event callbacks for the publisher.
581
602
  * @return {Publisher} - An instance of Publisher.
582
603
  */
583
- createPublisher(typeClass, topic, options) {
584
- return this._createPublisher(typeClass, topic, options, Publisher);
604
+ createPublisher(typeClass, topic, options, eventCallbacks) {
605
+ return this._createPublisher(
606
+ typeClass,
607
+ topic,
608
+ options,
609
+ Publisher,
610
+ eventCallbacks
611
+ );
585
612
  }
586
613
 
587
- _createPublisher(typeClass, topic, options, publisherClass) {
614
+ _createPublisher(typeClass, topic, options, publisherClass, eventCallbacks) {
588
615
  if (typeof typeClass === 'string' || typeof typeClass === 'object') {
589
616
  typeClass = loader.loadInterface(typeClass);
590
617
  }
591
618
  options = this._validateOptions(options);
592
619
 
593
- if (typeof typeClass !== 'function' || typeof topic !== 'string') {
620
+ if (
621
+ typeof typeClass !== 'function' ||
622
+ typeof topic !== 'string' ||
623
+ (eventCallbacks && !(eventCallbacks instanceof PublisherEventCallbacks))
624
+ ) {
594
625
  throw new TypeError('Invalid argument');
595
626
  }
596
627
 
597
628
  let publisher = publisherClass.createPublisher(
598
- this.handle,
629
+ this,
599
630
  typeClass,
600
631
  topic,
601
- options
632
+ options,
633
+ eventCallbacks
602
634
  );
603
635
  debug('Finish creating publisher, topic = %s.', topic);
604
636
  this._publishers.push(publisher);
@@ -633,12 +665,13 @@ class Node extends rclnodejs.ShadowNode {
633
665
  * the ‘parameters’ (i.e., "%n" tokens) in the filter_expression. The number of supplied parameters must
634
666
  * fit with the requested values in the filter_expression (i.e., the number of %n tokens). default: undefined.
635
667
  * @param {SubscriptionCallback} callback - The callback to be call when receiving the topic subscribed. The topic will be an instance of null-terminated Buffer when options.isRaw is true.
668
+ * @param {SubscriptionEventCallbacks} eventCallbacks - The event callbacks for the subscription.
636
669
  * @return {Subscription} - An instance of Subscription.
637
670
  * @throws {ERROR} - May throw an RMW error if content-filter is malformed.
638
671
  * @see {@link SubscriptionCallback}
639
672
  * @see {@link https://www.omg.org/spec/DDS/1.4/PDF|Content-filter details at DDS 1.4 specification, Annex B}
640
673
  */
641
- createSubscription(typeClass, topic, options, callback) {
674
+ createSubscription(typeClass, topic, options, callback, eventCallbacks) {
642
675
  if (typeof typeClass === 'string' || typeof typeClass === 'object') {
643
676
  typeClass = loader.loadInterface(typeClass);
644
677
  }
@@ -652,17 +685,20 @@ class Node extends rclnodejs.ShadowNode {
652
685
  if (
653
686
  typeof typeClass !== 'function' ||
654
687
  typeof topic !== 'string' ||
655
- typeof callback !== 'function'
688
+ typeof callback !== 'function' ||
689
+ (eventCallbacks &&
690
+ !(eventCallbacks instanceof SubscriptionEventCallbacks))
656
691
  ) {
657
692
  throw new TypeError('Invalid argument');
658
693
  }
659
694
 
660
695
  let subscription = Subscription.createSubscription(
661
- this.handle,
696
+ this,
662
697
  typeClass,
663
698
  topic,
664
699
  options,
665
- callback
700
+ callback,
701
+ eventCallbacks
666
702
  );
667
703
  debug('Finish creating subscription, topic = %s.', topic);
668
704
  this._subscriptions.push(subscription);
@@ -826,6 +862,12 @@ class Node extends rclnodejs.ShadowNode {
826
862
  if (!(publisher instanceof Publisher)) {
827
863
  throw new TypeError('Invalid argument');
828
864
  }
865
+ if (publisher.events) {
866
+ publisher.events.forEach((event) => {
867
+ this._destroyEntity(event, this._events);
868
+ });
869
+ publisher.events = [];
870
+ }
829
871
  this._destroyEntity(publisher, this._publishers, false);
830
872
  }
831
873
 
@@ -838,6 +880,13 @@ class Node extends rclnodejs.ShadowNode {
838
880
  if (!(subscription instanceof Subscription)) {
839
881
  throw new TypeError('Invalid argument');
840
882
  }
883
+ if (subscription.events) {
884
+ subscription.events.forEach((event) => {
885
+ this._destroyEntity(event, this._events);
886
+ });
887
+ subscription.events = [];
888
+ }
889
+
841
890
  this._destroyEntity(subscription, this._subscriptions);
842
891
  }
843
892
 
@@ -1053,7 +1102,15 @@ class Node extends rclnodejs.ShadowNode {
1053
1102
  * @return {Array<{name: string, namespace: string}>} An array of the names and namespaces.
1054
1103
  */
1055
1104
  getNodeNamesAndNamespaces() {
1056
- return rclnodejs.getNodeNames(this.handle);
1105
+ return rclnodejs.getNodeNames(this.handle, /*getEnclaves=*/ false);
1106
+ }
1107
+
1108
+ /**
1109
+ * Get the list of nodes and their namespaces with enclaves discovered by the provided node.
1110
+ * @return {Array<{name: string, namespace: string, enclave: string}>} An array of the names, namespaces and enclaves.
1111
+ */
1112
+ getNodeNamesAndNamespacesWithEnclaves() {
1113
+ return rclnodejs.getNodeNames(this.handle, /*getEnclaves=*/ true);
1057
1114
  }
1058
1115
 
1059
1116
  /**
@@ -1610,6 +1667,23 @@ class Node extends rclnodejs.ShadowNode {
1610
1667
  }
1611
1668
  }
1612
1669
 
1670
+ /**
1671
+ * Get the fully qualified name of the node.
1672
+ *
1673
+ * @returns {string} - String containing the fully qualified name of the node.
1674
+ */
1675
+ getFullyQualifiedName() {
1676
+ return rclnodejs.getFullyQualifiedName(this.handle);
1677
+ }
1678
+
1679
+ /**
1680
+ * Get the RMW implementation identifier
1681
+ * @returns {string} - The RMW implementation identifier.
1682
+ */
1683
+ getRMWImplementationIdentifier() {
1684
+ return rclnodejs.getRMWImplementationIdentifier();
1685
+ }
1686
+
1613
1687
  // returns on 1st error or result {successful, reason}
1614
1688
  _validateParameters(parameters = [], declareParameterMode = false) {
1615
1689
  for (const parameter of parameters) {
@@ -26,16 +26,19 @@ class NodeOptions {
26
26
  * @param {boolean} [startParameterServices=true]
27
27
  * @param {array} [parameterOverrides=[]]
28
28
  * @param {boolean} [automaticallyDeclareParametersFromOverrides=false]
29
+ * @param {boolean} [startTypeDescriptionService=true]
29
30
  */
30
31
  constructor(
31
32
  startParameterServices = true,
32
33
  parameterOverrides = [],
33
- automaticallyDeclareParametersFromOverrides = false
34
+ automaticallyDeclareParametersFromOverrides = false,
35
+ startTypeDescriptionService = true
34
36
  ) {
35
37
  this._startParameterServices = startParameterServices;
36
38
  this._parameterOverrides = parameterOverrides;
37
39
  this._automaticallyDeclareParametersFromOverrides =
38
40
  automaticallyDeclareParametersFromOverrides;
41
+ this._startTypeDescriptionService = startTypeDescriptionService;
39
42
  }
40
43
 
41
44
  /**
@@ -105,6 +108,23 @@ class NodeOptions {
105
108
  this._automaticallyDeclareParametersFromOverrides = declareParamsFlag;
106
109
  }
107
110
 
111
+ /**
112
+ * Get the startTypeDescriptionService option, only available for ROS2 > Humble.
113
+ * Default value = true;
114
+ * @returns {boolean} - true if the type description service is enabled.
115
+ */
116
+ get startTypeDescriptionService() {
117
+ return this._startTypeDescriptionService;
118
+ }
119
+
120
+ /**
121
+ * Set startTypeDescriptionService, only available for ROS2 > Humble
122
+ * @param {boolean} willStartTypeDescriptionService
123
+ */
124
+ set startTypeDescriptionService(willStartTypeDescriptionService) {
125
+ this._startTypeDescriptionService = willStartTypeDescriptionService;
126
+ }
127
+
108
128
  /**
109
129
  * Return an instance configured with default options.
110
130
  * @returns {NodeOptions} - An instance with default values.
package/lib/publisher.js CHANGED
@@ -24,8 +24,12 @@ const Entity = require('./entity.js');
24
24
  */
25
25
 
26
26
  class Publisher extends Entity {
27
- constructor(handle, typeClass, topic, options) {
27
+ constructor(handle, typeClass, topic, options, node, eventCallbacks) {
28
28
  super(handle, typeClass, options);
29
+ if (node && eventCallbacks) {
30
+ this._events = eventCallbacks.createEventHandlers(this.handle);
31
+ node._events.push(...this._events);
32
+ }
29
33
  }
30
34
 
31
35
  /**
@@ -60,17 +64,24 @@ class Publisher extends Entity {
60
64
  debug(`Message of topic ${this.topic} has been published.`);
61
65
  }
62
66
 
63
- static createPublisher(nodeHandle, typeClass, topic, options) {
67
+ static createPublisher(node, typeClass, topic, options, eventCallbacks) {
64
68
  let type = typeClass.type();
65
69
  let handle = rclnodejs.createPublisher(
66
- nodeHandle,
70
+ node.handle,
67
71
  type.pkgName,
68
72
  type.subFolder,
69
73
  type.interfaceName,
70
74
  topic,
71
75
  options.qos
72
76
  );
73
- return new Publisher(handle, typeClass, topic, options);
77
+ return new Publisher(
78
+ handle,
79
+ typeClass,
80
+ topic,
81
+ options,
82
+ node,
83
+ eventCallbacks
84
+ );
74
85
  }
75
86
 
76
87
  /**
@@ -80,6 +91,41 @@ class Publisher extends Entity {
80
91
  get subscriptionCount() {
81
92
  return rclnodejs.getSubscriptionCount(this._handle);
82
93
  }
94
+
95
+ /**
96
+ * Wait until all published message data is acknowledged or until the specified timeout elapses
97
+ *
98
+ * If the timeout is negative then this function will block indefinitely until all published
99
+ * message data is acknowledged.
100
+ * If the timeout is 0 then it will check if all published message has been acknowledged without
101
+ * waiting.
102
+ * If the timeout is greater than 0 then it will return after that period of time has elapsed or
103
+ * all published message data is acknowledged.
104
+ *
105
+ * Raises an error if failed, such as the middleware not supporting this feature.
106
+ *
107
+ * @param {timeout} timeout - The duration to wait for all published message data to be acknowledged in nanoseconds.
108
+ * @return {boolean} `true` if all published message data is acknowledged before the timeout, otherwise `false`.
109
+ */
110
+ waitForAllAcked(timeout) {
111
+ return rclnodejs.waitForAllAcked(this._handle, timeout);
112
+ }
113
+
114
+ /**
115
+ * Get the event handlers for this publisher.
116
+ * @returns {Array} The array of event handlers for this publisher.
117
+ */
118
+ get events() {
119
+ return this._events;
120
+ }
121
+
122
+ /**
123
+ * Set the event handlers for this publisher.
124
+ * @param {Array} events - The array of event handlers to be set for this publisher.
125
+ */
126
+ set events(events) {
127
+ this._events = events;
128
+ }
83
129
  }
84
130
 
85
131
  module.exports = Publisher;
package/lib/service.js CHANGED
@@ -125,7 +125,7 @@ class Service extends Entity {
125
125
  configureIntrospection(clock, qos, introspectionState) {
126
126
  if (DistroUtils.getDistroId() <= DistroUtils.getDistroId('humble')) {
127
127
  console.warn(
128
- 'Service introspection is not supported by this versionof ROS 2'
128
+ 'Service introspection is not supported by this version of ROS 2'
129
129
  );
130
130
  return;
131
131
  }
@@ -29,11 +29,24 @@ const debug = require('debug')('rclnodejs:subscription');
29
29
  */
30
30
 
31
31
  class Subscription extends Entity {
32
- constructor(handle, typeClass, topic, options, callback) {
32
+ constructor(
33
+ handle,
34
+ typeClass,
35
+ topic,
36
+ options,
37
+ callback,
38
+ node,
39
+ eventCallbacks
40
+ ) {
33
41
  super(handle, typeClass, options);
34
42
  this._topic = topic;
35
43
  this._callback = callback;
36
44
  this._isRaw = options.isRaw || false;
45
+
46
+ if (node && eventCallbacks) {
47
+ this._events = eventCallbacks.createEventHandlers(this.handle);
48
+ node._events.push(...this._events);
49
+ }
37
50
  }
38
51
 
39
52
  processResponse(msg) {
@@ -45,7 +58,14 @@ class Subscription extends Entity {
45
58
  }
46
59
  }
47
60
 
48
- static createSubscription(nodeHandle, typeClass, topic, options, callback) {
61
+ static createSubscription(
62
+ node,
63
+ typeClass,
64
+ topic,
65
+ options,
66
+ callback,
67
+ eventCallbacks
68
+ ) {
49
69
  let type = typeClass.type();
50
70
 
51
71
  // convert contentFilter.parameters to a string[]
@@ -56,14 +76,22 @@ class Subscription extends Entity {
56
76
  }
57
77
 
58
78
  let handle = rclnodejs.createSubscription(
59
- nodeHandle,
79
+ node.handle,
60
80
  type.pkgName,
61
81
  type.subFolder,
62
82
  type.interfaceName,
63
83
  topic,
64
84
  options
65
85
  );
66
- return new Subscription(handle, typeClass, topic, options, callback);
86
+ return new Subscription(
87
+ handle,
88
+ typeClass,
89
+ topic,
90
+ options,
91
+ callback,
92
+ node,
93
+ eventCallbacks
94
+ );
67
95
  }
68
96
 
69
97
  /**
@@ -124,6 +152,22 @@ class Subscription extends Entity {
124
152
  get publisherCount() {
125
153
  return rclnodejs.getPublisherCount(this._handle);
126
154
  }
155
+
156
+ /**
157
+ * Get the event handlers for this subscription.
158
+ * @returns {Array} The array of event handlers for this subscription.
159
+ */
160
+ get events() {
161
+ return this._events;
162
+ }
163
+
164
+ /**
165
+ * Set the event handlers for this subscription.
166
+ * @param {Array} events - The array of event handlers for this subscription.
167
+ */
168
+ set events(events) {
169
+ this._events = events;
170
+ }
127
171
  }
128
172
 
129
173
  module.exports = Subscription;
@@ -0,0 +1,82 @@
1
+ // Copyright (c) 2025, The Robot Web Tools Contributors
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ 'use strict';
16
+
17
+ const loader = require('./interface_loader.js');
18
+ const rclnodejs = require('bindings')('rclnodejs');
19
+ const Service = require('./service.js');
20
+
21
+ // This class is used to create a TypeDescriptionService which can be used to
22
+ // retrieve information about types used by the node’s publishers, subscribers,
23
+ // services or actions.
24
+ class TypeDescriptionService {
25
+ constructor(node) {
26
+ this._node = node;
27
+ this._serviceName = this._node.name() + '/get_type_description';
28
+ this._typeDescriptionServiceHandle = rclnodejs.initTypeDescriptionService(
29
+ this._node.handle
30
+ );
31
+ this._typeClass = loader.loadInterface(
32
+ 'type_description_interfaces/srv/GetTypeDescription'
33
+ );
34
+ this._typeDescriptionService = null;
35
+ }
36
+
37
+ start() {
38
+ if (this._typeDescriptionService) {
39
+ return;
40
+ }
41
+
42
+ this._typeDescriptionService = new Service(
43
+ this._node.handle,
44
+ this._typeDescriptionServiceHandle,
45
+ this._serviceName,
46
+ this._typeClass,
47
+ this._node._validateOptions(undefined),
48
+ (request, response) => {
49
+ const responseToBeSent = new this._typeClass.Response();
50
+ const requestReceived = new this._typeClass.Request(request);
51
+ rclnodejs.handleRequest(
52
+ this._node.handle,
53
+ requestReceived.serialize(),
54
+ responseToBeSent.serialize()
55
+ );
56
+ responseToBeSent.deserialize(responseToBeSent.refObject);
57
+ rclnodejs.sendResponse(
58
+ this._typeDescriptionServiceHandle,
59
+ responseToBeSent.serialize(),
60
+ response._header
61
+ );
62
+ return null;
63
+ }
64
+ );
65
+ this._node._services.push(this._typeDescriptionService);
66
+ this._node.syncHandles();
67
+ }
68
+
69
+ /**
70
+ * Get the node this
71
+ * @return {Node} - The supported node.
72
+ */
73
+ get node() {
74
+ return this._node;
75
+ }
76
+
77
+ static toTypeHash(topicTypeHash) {
78
+ return `RIHS0${topicTypeHash.version}_${topicTypeHash.value.toString('hex')}`;
79
+ }
80
+ }
81
+
82
+ module.exports = TypeDescriptionService;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rclnodejs",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "ROS2.0 JavaScript client with Node.js",
5
5
  "main": "index.js",
6
6
  "types": "types/index.d.ts",
@@ -1,4 +1,4 @@
1
- # rclnodejs ![GitHub Workflow Status](https://github.com/RobotWebTools/rclnodejs/actions/workflows/linux-build-and-test.yml/badge.svg?branch=jazzy)
1
+ # rclnodejs [![Linux](https://github.com/RobotWebTools/rclnodejs/actions/workflows/linux-x64-build-and-test.yml/badge.svg?branch=develop)](https://github.com/RobotWebTools/rclnodejs/actions/workflows/linux-x64-build-and-test.yml?query=branch%3Adevelop)[![Linux](https://github.com/RobotWebTools/rclnodejs/actions/workflows/linux-arm64-build-and-test.yml/badge.svg?branch=develop)](https://github.com/RobotWebTools/rclnodejs/actions/workflows/linux-arm64-build-and-test.yml?query=branch%3Adevelop)
2
2
 
3
3
  `rclnodejs` is a Node.js client for the Robot Operating System (ROS 2). It provides a simple and easy JavaScript API for ROS 2 programming. TypeScript declarations are included to support use of rclnodejs in TypeScript projects.
4
4
 
@@ -22,8 +22,8 @@ rclnodejs.init().then(() => {
22
22
 
23
23
  **ROS 2 SDK**
24
24
 
25
- - See the ROS 2 SDK [Installation Guide](https://docs.ros.org/en/jazzy/Installation.html) for details.
26
- - **DON'T FORGET TO [SOURCE THE ROS 2 STARTUP FILES](https://docs.ros.org/en/jazzy/Tutorials/Beginner-CLI-Tools/Configuring-ROS2-Environment.html#source-the-setup-files)**
25
+ - See the ROS 2 SDK [Installation Guide](https://docs.ros.org/en/kilted/Installation.html) for details.
26
+ - **DON'T FORGET TO [SOURCE THE ROS 2 STARTUP FILES](https://docs.ros.org/en/kilted/Tutorials/Beginner-CLI-Tools/Configuring-ROS2-Environment.htmls)**
27
27
 
28
28
  ## Install rclnodejs
29
29
 
@@ -43,9 +43,9 @@ npm i rclnodejs@x.y.z
43
43
 
44
44
  #### RCLNODEJS - ROS 2 Version Compatibility
45
45
 
46
- | RCLNODEJS Version | Compatible ROS 2 LTS |
47
- | :----------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------: |
48
- | latest version (currently [v1.0.0](https://github.com/RobotWebTools/rclnodejs/tree/1.0.0)) | [Humble](https://github.com/RobotWebTools/rclnodejs/tree/humble-hawksbill)<br>[Jazzy](https://github.com/RobotWebTools/rclnodejs/tree/jazzy) |
46
+ | RCLNODEJS Version | Compatible ROS 2 LTS |
47
+ | :----------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
48
+ | latest version (currently [v1.2.0](https://github.com/RobotWebTools/rclnodejs/tree/1.2.0)) | [Kilted](https://github.com/RobotWebTools/rclnodejs/tree/kilted)<br>[Jazzy](https://github.com/RobotWebTools/rclnodejs/tree/jazzy)<br>[Humble](https://github.com/RobotWebTools/rclnodejs/tree/humble-hawksbill) |
49
49
 
50
50
  ## Documentation
51
51
 
package/src/addon.cpp CHANGED
@@ -34,6 +34,10 @@
34
34
  #include "rcl_subscription_bindings.h"
35
35
  #include "rcl_time_point_bindings.h"
36
36
  #include "rcl_timer_bindings.h"
37
+ #if ROS_VERSION > 2205 // ROS2 > Humble
38
+ #include "rcl_event_handle_bindings.h"
39
+ #include "rcl_type_description_service_bindings.h"
40
+ #endif
37
41
  #include "rcl_utilities.h"
38
42
  #include "shadow_node.h"
39
43
 
@@ -79,6 +83,10 @@ Napi::Object InitModule(Napi::Env env, Napi::Object exports) {
79
83
  rclnodejs::InitSubscriptionBindings(env, exports);
80
84
  rclnodejs::InitTimePointBindings(env, exports);
81
85
  rclnodejs::InitTimerBindings(env, exports);
86
+ #if ROS_VERSION > 2205 // ROS2 > Humble
87
+ rclnodejs::InitTypeDescriptionServiceBindings(env, exports);
88
+ rclnodejs::InitEventHandleBindings(env, exports);
89
+ #endif
82
90
  rclnodejs::InitLifecycleBindings(env, exports);
83
91
  rclnodejs::ShadowNode::Init(env, exports);
84
92
  rclnodejs::RclHandle::Init(env, exports);
package/src/executor.cpp CHANGED
@@ -190,10 +190,11 @@ RclResult Executor::WaitForReadyCallbacks(rcl_wait_set_t* wait_set,
190
190
  size_t num_timers = 0u;
191
191
  size_t num_clients = 0u;
192
192
  size_t num_services = 0u;
193
+ size_t num_events = 0u;
193
194
 
194
195
  rcl_ret_t get_entity_ret = handle_manager_->GetEntityCounts(
195
196
  &num_subscriptions, &num_guard_conditions, &num_timers, &num_clients,
196
- &num_services);
197
+ &num_services, &num_events);
197
198
  if (get_entity_ret != RCL_RET_OK) {
198
199
  std::string error_message = std::string("Failed to get entity counts: ") +
199
200
  std::string(rcl_get_error_string().str);
@@ -202,9 +203,7 @@ RclResult Executor::WaitForReadyCallbacks(rcl_wait_set_t* wait_set,
202
203
 
203
204
  rcl_ret_t resize_ret =
204
205
  rcl_wait_set_resize(wait_set, num_subscriptions, num_guard_conditions,
205
- num_timers, num_clients, num_services,
206
- // TODO(minggang): support events.
207
- 0u);
206
+ num_timers, num_clients, num_services, num_events);
208
207
  if (resize_ret != RCL_RET_OK) {
209
208
  std::string error_message = std::string("Failed to resize: ") +
210
209
  std::string(rcl_get_error_string().str);
@@ -40,7 +40,6 @@ HandleManager::~HandleManager() {
40
40
 
41
41
  void HandleManager::SynchronizeHandles(const Napi::Object& node) {
42
42
  Napi::HandleScope scope(node.Env());
43
-
44
43
  Napi::Value timers = node.Get("_timers");
45
44
  Napi::Value subscriptions = node.Get("_subscriptions");
46
45
  Napi::Value clients = node.Get("_clients");
@@ -48,6 +47,7 @@ void HandleManager::SynchronizeHandles(const Napi::Object& node) {
48
47
  Napi::Value guard_conditions = node.Get("_guards");
49
48
  Napi::Value action_clients = node.Get("_actionClients");
50
49
  Napi::Value action_servers = node.Get("_actionServers");
50
+ Napi::Value events = node.Get("_events");
51
51
 
52
52
  uint32_t sum = 0;
53
53
  is_synchronizing_.store(true);
@@ -66,6 +66,7 @@ void HandleManager::SynchronizeHandles(const Napi::Object& node) {
66
66
  &action_clients_);
67
67
  sum += SynchronizeHandlesByType(action_servers.As<Napi::Object>(),
68
68
  &action_servers_);
69
+ sum += SynchronizeHandlesByType(events.As<Napi::Object>(), &events_);
69
70
  }
70
71
  is_synchronizing_.store(false);
71
72
 
@@ -98,6 +99,7 @@ void HandleManager::ClearHandles() {
98
99
  guard_conditions_.clear();
99
100
  action_clients_.clear();
100
101
  action_servers_.clear();
102
+ events_.clear();
101
103
  }
102
104
 
103
105
  rcl_ret_t HandleManager::AddHandlesToWaitSet(rcl_wait_set_t* wait_set) {
@@ -152,6 +154,11 @@ rcl_ret_t HandleManager::AddHandlesToWaitSet(rcl_wait_set_t* wait_set) {
152
154
  if (ret != RCL_RET_OK) return ret;
153
155
  }
154
156
 
157
+ for (auto& event : events_) {
158
+ rcl_event_t* rcl_event = reinterpret_cast<rcl_event_t*>(event->ptr());
159
+ rcl_ret_t ret = rcl_wait_set_add_event(wait_set, rcl_event, nullptr);
160
+ if (ret != RCL_RET_OK) return ret;
161
+ }
155
162
  return RCL_RET_OK;
156
163
  }
157
164
 
@@ -169,6 +176,8 @@ rcl_ret_t HandleManager::CollectReadyHandles(rcl_wait_set_t* wait_set) {
169
176
  CollectReadyHandlesByType(wait_set->guard_conditions,
170
177
  wait_set->size_of_guard_conditions,
171
178
  guard_conditions_, &ready_handles);
179
+ CollectReadyHandlesByType(wait_set->events, wait_set->size_of_events, events_,
180
+ &ready_handles);
172
181
 
173
182
  rcl_ret_t ret = CollectReadyActionHandles(wait_set, &ready_handles);
174
183
  if (!ready_handles.empty()) {
@@ -184,7 +193,8 @@ rcl_ret_t HandleManager::GetEntityCounts(size_t* subscriptions_size,
184
193
  size_t* guard_conditions_size,
185
194
  size_t* timers_size,
186
195
  size_t* clients_size,
187
- size_t* services_size) {
196
+ size_t* services_size,
197
+ size_t* events_size) {
188
198
  size_t num_subscriptions = 0u;
189
199
  size_t num_guard_conditions = 0u;
190
200
  size_t num_timers = 0u;
@@ -230,6 +240,7 @@ rcl_ret_t HandleManager::GetEntityCounts(size_t* subscriptions_size,
230
240
  *timers_size += timer_count();
231
241
  *clients_size += client_count();
232
242
  *services_size += service_count();
243
+ *events_size += event_count();
233
244
 
234
245
  return RCL_RET_OK;
235
246
  }