rclnodejs 1.0.0 → 1.1.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/README.md +3 -3
- package/binding.gyp +8 -0
- package/lib/action/client.js +40 -0
- package/lib/action/server.js +21 -0
- package/lib/client.js +1 -1
- package/lib/distro.js +2 -0
- package/lib/lifecycle.js +9 -0
- package/lib/node.js +28 -1
- package/lib/node_options.js +21 -1
- package/lib/publisher.js +19 -0
- package/lib/service.js +1 -1
- package/lib/type_description_service.js +82 -0
- package/package.json +1 -1
- package/scripts/npmjs-readme.md +3 -3
- package/src/addon.cpp +6 -0
- package/src/rcl_action_client_bindings.cpp +99 -24
- package/src/rcl_action_server_bindings.cpp +69 -19
- package/src/rcl_lifecycle_bindings.cpp +13 -0
- package/src/rcl_node_bindings.cpp +37 -8
- package/src/rcl_publisher_bindings.cpp +19 -0
- package/src/rcl_type_description_service_bindings.cpp +79 -0
- package/src/rcl_type_description_service_bindings.h +27 -0
- package/types/action_client.d.ts +18 -0
- package/types/action_server.d.ts +12 -0
- package/types/lifecycle.d.ts +7 -0
- package/types/node.d.ts +32 -0
- package/types/publisher.d.ts +17 -0
package/README.md
CHANGED
|
@@ -43,9 +43,9 @@ npm i rclnodejs@x.y.z
|
|
|
43
43
|
|
|
44
44
|
#### RCLNODEJS - ROS 2 Version Compatibility
|
|
45
45
|
|
|
46
|
-
| RCLNODEJS Version |
|
|
47
|
-
| :----------------------------------------------------------------------------------------: |
|
|
48
|
-
| latest version (currently [v1.
|
|
46
|
+
| RCLNODEJS Version | Compatible ROS 2 LTS |
|
|
47
|
+
| :----------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|
|
48
|
+
| latest version (currently [v1.1.0](https://github.com/RobotWebTools/rclnodejs/tree/1.1.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/binding.gyp
CHANGED
|
@@ -166,6 +166,14 @@
|
|
|
166
166
|
]
|
|
167
167
|
}
|
|
168
168
|
],
|
|
169
|
+
[
|
|
170
|
+
# After Humble, e.g., Jazzy, Kilted.
|
|
171
|
+
'ros_version > 2205', {
|
|
172
|
+
'sources': [
|
|
173
|
+
'./src/rcl_type_description_service_bindings.cpp',
|
|
174
|
+
]
|
|
175
|
+
}
|
|
176
|
+
],
|
|
169
177
|
[
|
|
170
178
|
'runtime=="electron"', {
|
|
171
179
|
"defines": ["NODE_RUNTIME_ELECTRON=1"]
|
package/lib/action/client.js
CHANGED
|
@@ -19,6 +19,7 @@ const ActionInterfaces = require('./interfaces.js');
|
|
|
19
19
|
const ActionUuid = require('./uuid.js');
|
|
20
20
|
const ClientGoalHandle = require('./client_goal_handle.js');
|
|
21
21
|
const Deferred = require('./deferred.js');
|
|
22
|
+
const DistroUtils = require('../distro.js');
|
|
22
23
|
const Entity = require('../entity.js');
|
|
23
24
|
const loader = require('../interface_loader.js');
|
|
24
25
|
const QoS = require('../qos.js');
|
|
@@ -371,6 +372,45 @@ class ActionClient extends Entity {
|
|
|
371
372
|
|
|
372
373
|
this._node._destroyEntity(this, this._node._actionClients);
|
|
373
374
|
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Get the number of wait set entities that make up an action entity.
|
|
378
|
+
* @return {object} - An object containing the number of various entities.
|
|
379
|
+
* @property {number} subscriptionsNumber - The number of subscriptions.
|
|
380
|
+
* @property {number} guardConditionsNumber - The number of guard conditions.
|
|
381
|
+
* @property {number} timersNumber - The number of timers.
|
|
382
|
+
* @property {number} clientsNumber - The number of clients.
|
|
383
|
+
* @property {number} servicesNumber - The number of services.
|
|
384
|
+
*/
|
|
385
|
+
getNumEntities() {
|
|
386
|
+
return rclnodejs.getNumEntities(this.handle);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Configure introspection.
|
|
391
|
+
* @param {Clock} clock - Clock to use for service event timestamps
|
|
392
|
+
* @param {QoS} qos - QoSProfile for the service event publisher
|
|
393
|
+
* @param {ServiceIntrospectionState} introspectionState - State to set introspection to
|
|
394
|
+
*/
|
|
395
|
+
configureIntrospection(clock, qos, introspectionState) {
|
|
396
|
+
if (DistroUtils.getDistroId() <= DistroUtils.getDistroId('jazzy')) {
|
|
397
|
+
console.warn(
|
|
398
|
+
'Configure action client introspection is not supported by this version of ROS 2'
|
|
399
|
+
);
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
let type = this.typeClass.type();
|
|
404
|
+
rclnodejs.configureActionClientIntrospection(
|
|
405
|
+
this.handle,
|
|
406
|
+
this._node.handle,
|
|
407
|
+
clock.handle,
|
|
408
|
+
type.interfaceName,
|
|
409
|
+
type.pkgName,
|
|
410
|
+
qos,
|
|
411
|
+
introspectionState
|
|
412
|
+
);
|
|
413
|
+
}
|
|
374
414
|
}
|
|
375
415
|
|
|
376
416
|
module.exports = ActionClient;
|
package/lib/action/server.js
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
const rclnodejs = require('bindings')('rclnodejs');
|
|
18
18
|
const ActionInterfaces = require('./interfaces.js');
|
|
19
19
|
const ActionUuid = require('./uuid.js');
|
|
20
|
+
const DistroUtils = require('../distro.js');
|
|
20
21
|
const Entity = require('../entity.js');
|
|
21
22
|
const { CancelResponse, GoalEvent, GoalResponse } = require('./response.js');
|
|
22
23
|
const loader = require('../interface_loader.js');
|
|
@@ -454,6 +455,26 @@ class ActionServer extends Entity {
|
|
|
454
455
|
|
|
455
456
|
this._node._destroyEntity(this, this._node._actionServers);
|
|
456
457
|
}
|
|
458
|
+
|
|
459
|
+
configureIntrospection(clock, qos, introspectionState) {
|
|
460
|
+
if (DistroUtils.getDistroId() <= DistroUtils.getDistroId('jazzy')) {
|
|
461
|
+
console.warn(
|
|
462
|
+
'Configure action server introspection is not supported by this version of ROS 2'
|
|
463
|
+
);
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
let type = this.typeClass.type();
|
|
468
|
+
rclnodejs.configureActionServerIntrospection(
|
|
469
|
+
this.handle,
|
|
470
|
+
this._node.handle,
|
|
471
|
+
clock.handle,
|
|
472
|
+
type.interfaceName,
|
|
473
|
+
type.pkgName,
|
|
474
|
+
qos,
|
|
475
|
+
introspectionState
|
|
476
|
+
);
|
|
477
|
+
}
|
|
457
478
|
}
|
|
458
479
|
|
|
459
480
|
module.exports = ActionServer;
|
package/lib/client.js
CHANGED
|
@@ -141,7 +141,7 @@ class Client extends Entity {
|
|
|
141
141
|
configureIntrospection(clock, qos, introspectionState) {
|
|
142
142
|
if (DistroUtils.getDistroId() <= DistroUtils.getDistroId('humble')) {
|
|
143
143
|
console.warn(
|
|
144
|
-
'Service introspection is not supported by this
|
|
144
|
+
'Service introspection is not supported by this version of ROS 2'
|
|
145
145
|
);
|
|
146
146
|
return;
|
|
147
147
|
}
|
package/lib/distro.js
CHANGED
|
@@ -25,6 +25,7 @@ const DistroId = {
|
|
|
25
25
|
HUMBLE: 2205,
|
|
26
26
|
IRON: 2305,
|
|
27
27
|
JAZZY: 2405,
|
|
28
|
+
KILTED: 2505,
|
|
28
29
|
ROLLING: 5000,
|
|
29
30
|
};
|
|
30
31
|
|
|
@@ -35,6 +36,7 @@ DistroNameIdMap.set('galactic', DistroId.GALACTIC);
|
|
|
35
36
|
DistroNameIdMap.set('humble', DistroId.HUMBLE);
|
|
36
37
|
DistroNameIdMap.set('iron', DistroId.IRON);
|
|
37
38
|
DistroNameIdMap.set('jazzy', DistroId.JAZZY);
|
|
39
|
+
DistroNameIdMap.set('kilted', DistroId.KILTED);
|
|
38
40
|
DistroNameIdMap.set('rolling', DistroId.ROLLING);
|
|
39
41
|
|
|
40
42
|
const DistroUtils = {
|
package/lib/lifecycle.js
CHANGED
|
@@ -591,6 +591,15 @@ class LifecycleNode extends Node {
|
|
|
591
591
|
return this._changeState(SHUTDOWN_TRANSITION_LABEL, callbackReturnValue);
|
|
592
592
|
}
|
|
593
593
|
|
|
594
|
+
/**
|
|
595
|
+
* Check if state machine is initialized.
|
|
596
|
+
*
|
|
597
|
+
* @returns {boolean} true if the state machine is initialized; otherwise false.
|
|
598
|
+
*/
|
|
599
|
+
get isInitialized() {
|
|
600
|
+
return rclnodejs.isInitialized(this._stateMachineHandle);
|
|
601
|
+
}
|
|
602
|
+
|
|
594
603
|
/**
|
|
595
604
|
* The GetState service handler.
|
|
596
605
|
* @param {Object} request - The GetState service request.
|
package/lib/node.js
CHANGED
|
@@ -39,6 +39,7 @@ 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');
|
|
43
44
|
|
|
44
45
|
// Parameter event publisher constants
|
|
@@ -101,6 +102,7 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
101
102
|
this._parameterDescriptors = new Map();
|
|
102
103
|
this._parameters = new Map();
|
|
103
104
|
this._parameterService = null;
|
|
105
|
+
this._typeDescriptionService = null;
|
|
104
106
|
this._parameterEventPublisher = null;
|
|
105
107
|
this._setParametersCallbacks = [];
|
|
106
108
|
this._logger = new Logging(rclnodejs.getNodeLoggerName(this.handle));
|
|
@@ -147,6 +149,14 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
147
149
|
this._parameterService = new ParameterService(this);
|
|
148
150
|
this._parameterService.start();
|
|
149
151
|
}
|
|
152
|
+
|
|
153
|
+
if (
|
|
154
|
+
DistroUtils.getDistroId() >= DistroUtils.getDistroId('jazzy') &&
|
|
155
|
+
options.startTypeDescriptionService
|
|
156
|
+
) {
|
|
157
|
+
this._typeDescriptionService = new TypeDescriptionService(this);
|
|
158
|
+
this._typeDescriptionService.start();
|
|
159
|
+
}
|
|
150
160
|
}
|
|
151
161
|
|
|
152
162
|
execute(handles) {
|
|
@@ -1053,7 +1063,15 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
1053
1063
|
* @return {Array<{name: string, namespace: string}>} An array of the names and namespaces.
|
|
1054
1064
|
*/
|
|
1055
1065
|
getNodeNamesAndNamespaces() {
|
|
1056
|
-
return rclnodejs.getNodeNames(this.handle);
|
|
1066
|
+
return rclnodejs.getNodeNames(this.handle, /*getEnclaves=*/ false);
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
/**
|
|
1070
|
+
* Get the list of nodes and their namespaces with enclaves discovered by the provided node.
|
|
1071
|
+
* @return {Array<{name: string, namespace: string, enclave: string}>} An array of the names, namespaces and enclaves.
|
|
1072
|
+
*/
|
|
1073
|
+
getNodeNamesAndNamespacesWithEnclaves() {
|
|
1074
|
+
return rclnodejs.getNodeNames(this.handle, /*getEnclaves=*/ true);
|
|
1057
1075
|
}
|
|
1058
1076
|
|
|
1059
1077
|
/**
|
|
@@ -1610,6 +1628,15 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
1610
1628
|
}
|
|
1611
1629
|
}
|
|
1612
1630
|
|
|
1631
|
+
/**
|
|
1632
|
+
* Get the fully qualified name of the node.
|
|
1633
|
+
*
|
|
1634
|
+
* @returns {string} - String containing the fully qualified name of the node.
|
|
1635
|
+
*/
|
|
1636
|
+
getFullyQualifiedName() {
|
|
1637
|
+
return rclnodejs.getFullyQualifiedName(this.handle);
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1613
1640
|
// returns on 1st error or result {successful, reason}
|
|
1614
1641
|
_validateParameters(parameters = [], declareParameterMode = false) {
|
|
1615
1642
|
for (const parameter of parameters) {
|
package/lib/node_options.js
CHANGED
|
@@ -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
|
@@ -80,6 +80,25 @@ class Publisher extends Entity {
|
|
|
80
80
|
get subscriptionCount() {
|
|
81
81
|
return rclnodejs.getSubscriptionCount(this._handle);
|
|
82
82
|
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Wait until all published message data is acknowledged or until the specified timeout elapses
|
|
86
|
+
*
|
|
87
|
+
* If the timeout is negative then this function will block indefinitely until all published
|
|
88
|
+
* message data is acknowledged.
|
|
89
|
+
* If the timeout is 0 then it will check if all published message has been acknowledged without
|
|
90
|
+
* waiting.
|
|
91
|
+
* If the timeout is greater than 0 then it will return after that period of time has elapsed or
|
|
92
|
+
* all published message data is acknowledged.
|
|
93
|
+
*
|
|
94
|
+
* Raises an error if failed, such as the middleware not supporting this feature.
|
|
95
|
+
*
|
|
96
|
+
* @param {timeout} timeout - The duration to wait for all published message data to be acknowledged in nanoseconds.
|
|
97
|
+
* @return {boolean} `true` if all published message data is acknowledged before the timeout, otherwise `false`.
|
|
98
|
+
*/
|
|
99
|
+
waitForAllAcked(timeout) {
|
|
100
|
+
return rclnodejs.waitForAllAcked(this._handle, timeout);
|
|
101
|
+
}
|
|
83
102
|
}
|
|
84
103
|
|
|
85
104
|
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
|
|
128
|
+
'Service introspection is not supported by this version of ROS 2'
|
|
129
129
|
);
|
|
130
130
|
return;
|
|
131
131
|
}
|
|
@@ -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
package/scripts/npmjs-readme.md
CHANGED
|
@@ -43,9 +43,9 @@ npm i rclnodejs@x.y.z
|
|
|
43
43
|
|
|
44
44
|
#### RCLNODEJS - ROS 2 Version Compatibility
|
|
45
45
|
|
|
46
|
-
| RCLNODEJS Version |
|
|
47
|
-
| :----------------------------------------------------------------------------------------: |
|
|
48
|
-
| latest version (currently [v1.
|
|
46
|
+
| RCLNODEJS Version | Compatible ROS 2 LTS |
|
|
47
|
+
| :----------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|
|
48
|
+
| latest version (currently [v1.1.0](https://github.com/RobotWebTools/rclnodejs/tree/1.1.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,9 @@
|
|
|
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_type_description_service_bindings.h"
|
|
39
|
+
#endif
|
|
37
40
|
#include "rcl_utilities.h"
|
|
38
41
|
#include "shadow_node.h"
|
|
39
42
|
|
|
@@ -79,6 +82,9 @@ Napi::Object InitModule(Napi::Env env, Napi::Object exports) {
|
|
|
79
82
|
rclnodejs::InitSubscriptionBindings(env, exports);
|
|
80
83
|
rclnodejs::InitTimePointBindings(env, exports);
|
|
81
84
|
rclnodejs::InitTimerBindings(env, exports);
|
|
85
|
+
#if ROS_VERSION > 2205 // ROS2 > Humble
|
|
86
|
+
rclnodejs::InitTypeDescriptionServiceBindings(env, exports);
|
|
87
|
+
#endif
|
|
82
88
|
rclnodejs::InitLifecycleBindings(env, exports);
|
|
83
89
|
rclnodejs::ShadowNode::Init(env, exports);
|
|
84
90
|
rclnodejs::RclHandle::Init(env, exports);
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
#include <rcl/error_handling.h>
|
|
18
18
|
#include <rcl/rcl.h>
|
|
19
|
+
#include <rcl_action/action_client.h>
|
|
19
20
|
#include <rcl_action/rcl_action.h>
|
|
20
21
|
|
|
21
22
|
#include <string>
|
|
@@ -126,28 +127,6 @@ Napi::Value ActionSendGoalRequest(const Napi::CallbackInfo& info) {
|
|
|
126
127
|
return Napi::Number::New(env, static_cast<int32_t>(sequence_number));
|
|
127
128
|
}
|
|
128
129
|
|
|
129
|
-
Napi::Value ActionTakeCancelRequest(const Napi::CallbackInfo& info) {
|
|
130
|
-
Napi::Env env = info.Env();
|
|
131
|
-
|
|
132
|
-
RclHandle* action_server_handle =
|
|
133
|
-
RclHandle::Unwrap(info[0].As<Napi::Object>());
|
|
134
|
-
rcl_action_server_t* action_server =
|
|
135
|
-
reinterpret_cast<rcl_action_server_t*>(action_server_handle->ptr());
|
|
136
|
-
rmw_request_id_t* header =
|
|
137
|
-
reinterpret_cast<rmw_request_id_t*>(malloc(sizeof(rmw_request_id_t)));
|
|
138
|
-
|
|
139
|
-
void* taken_request = info[1].As<Napi::Buffer<char>>().Data();
|
|
140
|
-
rcl_ret_t ret =
|
|
141
|
-
rcl_action_take_cancel_request(action_server, header, taken_request);
|
|
142
|
-
if (ret != RCL_RET_ACTION_SERVER_TAKE_FAILED) {
|
|
143
|
-
auto js_obj = RclHandle::NewInstance(env, header, nullptr,
|
|
144
|
-
[](void* ptr) { free(ptr); });
|
|
145
|
-
return js_obj;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return env.Undefined();
|
|
149
|
-
}
|
|
150
|
-
|
|
151
130
|
Napi::Value ActionSendResultRequest(const Napi::CallbackInfo& info) {
|
|
152
131
|
Napi::Env env = info.Env();
|
|
153
132
|
|
|
@@ -211,6 +190,97 @@ Napi::Value ActionTakeStatus(const Napi::CallbackInfo& info) {
|
|
|
211
190
|
return env.Undefined();
|
|
212
191
|
}
|
|
213
192
|
|
|
193
|
+
Napi::Value GetNumEntities(const Napi::CallbackInfo& info) {
|
|
194
|
+
Napi::Env env = info.Env();
|
|
195
|
+
RclHandle* action_client_handle =
|
|
196
|
+
RclHandle::Unwrap(info[0].As<Napi::Object>());
|
|
197
|
+
rcl_action_client_t* action_client =
|
|
198
|
+
reinterpret_cast<rcl_action_client_t*>(action_client_handle->ptr());
|
|
199
|
+
|
|
200
|
+
size_t num_subscriptions = 0u;
|
|
201
|
+
size_t num_guard_conditions = 0u;
|
|
202
|
+
size_t num_timers = 0u;
|
|
203
|
+
size_t num_clients = 0u;
|
|
204
|
+
size_t num_services = 0u;
|
|
205
|
+
|
|
206
|
+
rcl_ret_t ret;
|
|
207
|
+
ret = rcl_action_client_wait_set_get_num_entities(
|
|
208
|
+
action_client, &num_subscriptions, &num_guard_conditions, &num_timers,
|
|
209
|
+
&num_clients, &num_services);
|
|
210
|
+
if (RCL_RET_OK != ret) {
|
|
211
|
+
rcl_reset_error();
|
|
212
|
+
std::string error_text{
|
|
213
|
+
"Failed to get number of entities for 'rcl_action_client_t'"};
|
|
214
|
+
Napi::Error::New(env, error_text).ThrowAsJavaScriptException();
|
|
215
|
+
return env.Undefined();
|
|
216
|
+
}
|
|
217
|
+
Napi::Object entities = Napi::Object::New(env);
|
|
218
|
+
entities.Set("subscriptionsNumber",
|
|
219
|
+
Napi::Number::New(env, num_subscriptions));
|
|
220
|
+
entities.Set("guardConditionsNumber",
|
|
221
|
+
Napi::Number::New(env, num_guard_conditions));
|
|
222
|
+
entities.Set("timersNumber", Napi::Number::New(env, num_timers));
|
|
223
|
+
entities.Set("clientsNumber", Napi::Number::New(env, num_clients));
|
|
224
|
+
entities.Set("servicesNumber", Napi::Number::New(env, num_services));
|
|
225
|
+
return entities;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
Napi::Value ActionSendCancelRequest(const Napi::CallbackInfo& info) {
|
|
229
|
+
Napi::Env env = info.Env();
|
|
230
|
+
|
|
231
|
+
RclHandle* action_client_handle =
|
|
232
|
+
RclHandle::Unwrap(info[0].As<Napi::Object>());
|
|
233
|
+
rcl_action_client_t* action_client =
|
|
234
|
+
reinterpret_cast<rcl_action_client_t*>(action_client_handle->ptr());
|
|
235
|
+
void* buffer = info[1].As<Napi::Buffer<char>>().Data();
|
|
236
|
+
|
|
237
|
+
int64_t sequence_number;
|
|
238
|
+
THROW_ERROR_IF_NOT_EQUAL(
|
|
239
|
+
rcl_action_send_cancel_request(action_client, buffer, &sequence_number),
|
|
240
|
+
RCL_RET_OK, rcl_get_error_string().str);
|
|
241
|
+
|
|
242
|
+
return Napi::Number::New(env, static_cast<int32_t>(sequence_number));
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
#if ROS_VERSION >= 2505 // ROS2 >= Kilted
|
|
246
|
+
Napi::Value ConfigureActionClientIntrospection(const Napi::CallbackInfo& info) {
|
|
247
|
+
Napi::Env env = info.Env();
|
|
248
|
+
RclHandle* action_client_handle =
|
|
249
|
+
RclHandle::Unwrap(info[0].As<Napi::Object>());
|
|
250
|
+
rcl_action_client_t* action_client =
|
|
251
|
+
reinterpret_cast<rcl_action_client_t*>(action_client_handle->ptr());
|
|
252
|
+
RclHandle* node_handle = RclHandle::Unwrap(info[1].As<Napi::Object>());
|
|
253
|
+
rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
|
|
254
|
+
rcl_clock_t* clock = reinterpret_cast<rcl_clock_t*>(
|
|
255
|
+
RclHandle::Unwrap(info[2].As<Napi::Object>())->ptr());
|
|
256
|
+
|
|
257
|
+
std::string action_name = info[3].As<Napi::String>().Utf8Value();
|
|
258
|
+
std::string package_name = info[4].As<Napi::String>().Utf8Value();
|
|
259
|
+
const rosidl_action_type_support_t* ts =
|
|
260
|
+
GetActionTypeSupport(package_name, action_name);
|
|
261
|
+
rcl_ret_t ret = RCL_RET_ERROR;
|
|
262
|
+
if (ts) {
|
|
263
|
+
rcl_publisher_options_t publisher_ops = rcl_publisher_get_default_options();
|
|
264
|
+
auto qos_profile = GetQoSProfile(info[5]);
|
|
265
|
+
if (qos_profile) {
|
|
266
|
+
publisher_ops.qos = *qos_profile;
|
|
267
|
+
}
|
|
268
|
+
rcl_service_introspection_state_t state =
|
|
269
|
+
static_cast<rcl_service_introspection_state_t>(
|
|
270
|
+
info[6].As<Napi::Number>().Uint32Value());
|
|
271
|
+
ret = rcl_action_client_configure_action_introspection(
|
|
272
|
+
action_client, node, clock, ts, publisher_ops, state);
|
|
273
|
+
if (ret == RCL_RET_OK) {
|
|
274
|
+
return env.Undefined();
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
Napi::Error::New(env, "failed to configure action client introspection")
|
|
279
|
+
.ThrowAsJavaScriptException();
|
|
280
|
+
return env.Undefined();
|
|
281
|
+
}
|
|
282
|
+
#endif // ROS_VERSION >= 2505
|
|
283
|
+
|
|
214
284
|
Napi::Object InitActionClientBindings(Napi::Env env, Napi::Object exports) {
|
|
215
285
|
exports.Set("actionCreateClient",
|
|
216
286
|
Napi::Function::New(env, ActionCreateClient));
|
|
@@ -218,13 +288,18 @@ Napi::Object InitActionClientBindings(Napi::Env env, Napi::Object exports) {
|
|
|
218
288
|
Napi::Function::New(env, ActionServerIsAvailable));
|
|
219
289
|
exports.Set("actionSendGoalRequest",
|
|
220
290
|
Napi::Function::New(env, ActionSendGoalRequest));
|
|
221
|
-
exports.Set("actionTakeCancelRequest",
|
|
222
|
-
Napi::Function::New(env, ActionTakeCancelRequest));
|
|
223
291
|
exports.Set("actionSendResultRequest",
|
|
224
292
|
Napi::Function::New(env, ActionSendResultRequest));
|
|
225
293
|
exports.Set("actionTakeFeedback",
|
|
226
294
|
Napi::Function::New(env, ActionTakeFeedback));
|
|
227
295
|
exports.Set("actionTakeStatus", Napi::Function::New(env, ActionTakeStatus));
|
|
296
|
+
exports.Set("getNumEntities", Napi::Function::New(env, GetNumEntities));
|
|
297
|
+
exports.Set("actionSendCancelRequest",
|
|
298
|
+
Napi::Function::New(env, ActionSendCancelRequest));
|
|
299
|
+
#if ROS_VERSION >= 2505 // ROS2 >= Kilted
|
|
300
|
+
exports.Set("configureActionClientIntrospection",
|
|
301
|
+
Napi::Function::New(env, ConfigureActionClientIntrospection));
|
|
302
|
+
#endif // ROS_VERSION >= 2505
|
|
228
303
|
return exports;
|
|
229
304
|
}
|
|
230
305
|
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
#include <rcl/error_handling.h>
|
|
18
18
|
#include <rcl/rcl.h>
|
|
19
|
+
#include <rcl_action/action_server.h>
|
|
19
20
|
#include <rcl_action/rcl_action.h>
|
|
20
21
|
|
|
21
22
|
#include <string>
|
|
@@ -96,23 +97,6 @@ Napi::Value ActionCreateServer(const Napi::CallbackInfo& info) {
|
|
|
96
97
|
}
|
|
97
98
|
}
|
|
98
99
|
|
|
99
|
-
Napi::Value ActionSendCancelRequest(const Napi::CallbackInfo& info) {
|
|
100
|
-
Napi::Env env = info.Env();
|
|
101
|
-
|
|
102
|
-
RclHandle* action_client_handle =
|
|
103
|
-
RclHandle::Unwrap(info[0].As<Napi::Object>());
|
|
104
|
-
rcl_action_client_t* action_client =
|
|
105
|
-
reinterpret_cast<rcl_action_client_t*>(action_client_handle->ptr());
|
|
106
|
-
void* buffer = info[1].As<Napi::Buffer<char>>().Data();
|
|
107
|
-
|
|
108
|
-
int64_t sequence_number;
|
|
109
|
-
THROW_ERROR_IF_NOT_EQUAL(
|
|
110
|
-
rcl_action_send_cancel_request(action_client, buffer, &sequence_number),
|
|
111
|
-
RCL_RET_OK, rcl_get_error_string().str);
|
|
112
|
-
|
|
113
|
-
return Napi::Number::New(env, static_cast<int32_t>(sequence_number));
|
|
114
|
-
}
|
|
115
|
-
|
|
116
100
|
Napi::Value ActionTakeResultRequest(const Napi::CallbackInfo& info) {
|
|
117
101
|
Napi::Env env = info.Env();
|
|
118
102
|
|
|
@@ -432,11 +416,71 @@ Napi::Value ActionServerGoalExists(const Napi::CallbackInfo& info) {
|
|
|
432
416
|
return Napi::Boolean::New(env, exists);
|
|
433
417
|
}
|
|
434
418
|
|
|
419
|
+
Napi::Value ActionTakeCancelRequest(const Napi::CallbackInfo& info) {
|
|
420
|
+
Napi::Env env = info.Env();
|
|
421
|
+
|
|
422
|
+
RclHandle* action_server_handle =
|
|
423
|
+
RclHandle::Unwrap(info[0].As<Napi::Object>());
|
|
424
|
+
rcl_action_server_t* action_server =
|
|
425
|
+
reinterpret_cast<rcl_action_server_t*>(action_server_handle->ptr());
|
|
426
|
+
rmw_request_id_t* header =
|
|
427
|
+
reinterpret_cast<rmw_request_id_t*>(malloc(sizeof(rmw_request_id_t)));
|
|
428
|
+
|
|
429
|
+
void* taken_request = info[1].As<Napi::Buffer<char>>().Data();
|
|
430
|
+
rcl_ret_t ret =
|
|
431
|
+
rcl_action_take_cancel_request(action_server, header, taken_request);
|
|
432
|
+
if (ret != RCL_RET_ACTION_SERVER_TAKE_FAILED) {
|
|
433
|
+
auto js_obj = RclHandle::NewInstance(env, header, nullptr,
|
|
434
|
+
[](void* ptr) { free(ptr); });
|
|
435
|
+
return js_obj;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
return env.Undefined();
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
#if ROS_VERSION >= 2505 // ROS2 >= Kilted
|
|
442
|
+
Napi::Value ConfigureActionServerIntrospection(const Napi::CallbackInfo& info) {
|
|
443
|
+
Napi::Env env = info.Env();
|
|
444
|
+
RclHandle* action_server_handle =
|
|
445
|
+
RclHandle::Unwrap(info[0].As<Napi::Object>());
|
|
446
|
+
rcl_action_server_t* action_server =
|
|
447
|
+
reinterpret_cast<rcl_action_server_t*>(action_server_handle->ptr());
|
|
448
|
+
RclHandle* node_handle = RclHandle::Unwrap(info[1].As<Napi::Object>());
|
|
449
|
+
rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
|
|
450
|
+
rcl_clock_t* clock = reinterpret_cast<rcl_clock_t*>(
|
|
451
|
+
RclHandle::Unwrap(info[2].As<Napi::Object>())->ptr());
|
|
452
|
+
|
|
453
|
+
std::string action_name = info[3].As<Napi::String>().Utf8Value();
|
|
454
|
+
std::string package_name = info[4].As<Napi::String>().Utf8Value();
|
|
455
|
+
const rosidl_action_type_support_t* ts =
|
|
456
|
+
GetActionTypeSupport(package_name, action_name);
|
|
457
|
+
|
|
458
|
+
rcl_ret_t ret = RCL_RET_ERROR;
|
|
459
|
+
if (ts) {
|
|
460
|
+
rcl_publisher_options_t publisher_ops = rcl_publisher_get_default_options();
|
|
461
|
+
auto qos_profile = GetQoSProfile(info[5]);
|
|
462
|
+
if (qos_profile) {
|
|
463
|
+
publisher_ops.qos = *qos_profile;
|
|
464
|
+
}
|
|
465
|
+
rcl_service_introspection_state_t state =
|
|
466
|
+
static_cast<rcl_service_introspection_state_t>(
|
|
467
|
+
info[6].As<Napi::Number>().Uint32Value());
|
|
468
|
+
ret = rcl_action_server_configure_action_introspection(
|
|
469
|
+
action_server, node, clock, ts, publisher_ops, state);
|
|
470
|
+
if (ret == RCL_RET_OK) {
|
|
471
|
+
return env.Undefined();
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
Napi::Error::New(env, "failed to configure action server introspection")
|
|
476
|
+
.ThrowAsJavaScriptException();
|
|
477
|
+
return env.Undefined();
|
|
478
|
+
}
|
|
479
|
+
#endif // ROS_VERSION >= 2505
|
|
480
|
+
|
|
435
481
|
Napi::Object InitActionServerBindings(Napi::Env env, Napi::Object exports) {
|
|
436
482
|
exports.Set("actionCreateServer",
|
|
437
483
|
Napi::Function::New(env, ActionCreateServer));
|
|
438
|
-
exports.Set("actionSendCancelRequest",
|
|
439
|
-
Napi::Function::New(env, ActionSendCancelRequest));
|
|
440
484
|
exports.Set("actionTakeResultRequest",
|
|
441
485
|
Napi::Function::New(env, ActionTakeResultRequest));
|
|
442
486
|
exports.Set("actionTakeGoalRequest",
|
|
@@ -464,6 +508,12 @@ Napi::Object InitActionServerBindings(Napi::Env env, Napi::Object exports) {
|
|
|
464
508
|
Napi::Function::New(env, ActionProcessCancelRequest));
|
|
465
509
|
exports.Set("actionServerGoalExists",
|
|
466
510
|
Napi::Function::New(env, ActionServerGoalExists));
|
|
511
|
+
exports.Set("actionTakeCancelRequest",
|
|
512
|
+
Napi::Function::New(env, ActionTakeCancelRequest));
|
|
513
|
+
#if ROS_VERSION >= 2505 // ROS2 >= Kilted
|
|
514
|
+
exports.Set("configureActionServerIntrospection",
|
|
515
|
+
Napi::Function::New(env, ConfigureActionServerIntrospection));
|
|
516
|
+
#endif // ROS_VERSION >= 2505
|
|
467
517
|
return exports;
|
|
468
518
|
}
|
|
469
519
|
|
|
@@ -360,6 +360,18 @@ Napi::Value GetLifecycleShutdownTransitionLabel(
|
|
|
360
360
|
return Napi::String::New(env, rcl_lifecycle_shutdown_label);
|
|
361
361
|
}
|
|
362
362
|
|
|
363
|
+
Napi::Value IsInitialized(const Napi::CallbackInfo& info) {
|
|
364
|
+
Napi::Env env = info.Env();
|
|
365
|
+
RclHandle* state_machine_handle =
|
|
366
|
+
RclHandle::Unwrap(info[0].As<Napi::Object>());
|
|
367
|
+
rcl_lifecycle_state_machine_t* state_machine =
|
|
368
|
+
reinterpret_cast<rcl_lifecycle_state_machine_t*>(
|
|
369
|
+
state_machine_handle->ptr());
|
|
370
|
+
const bool is_initialized =
|
|
371
|
+
RCL_RET_OK == rcl_lifecycle_state_machine_is_initialized(state_machine);
|
|
372
|
+
return Napi::Boolean::New(env, is_initialized);
|
|
373
|
+
}
|
|
374
|
+
|
|
363
375
|
Napi::Object InitLifecycleBindings(Napi::Env env, Napi::Object exports) {
|
|
364
376
|
exports.Set("createLifecycleStateMachine",
|
|
365
377
|
Napi::Function::New(env, CreateLifecycleStateMachine));
|
|
@@ -383,6 +395,7 @@ Napi::Object InitLifecycleBindings(Napi::Env env, Napi::Object exports) {
|
|
|
383
395
|
Napi::Function::New(env, GetLifecycleTransitionIdToLabel));
|
|
384
396
|
exports.Set("getLifecycleShutdownTransitionLabel",
|
|
385
397
|
Napi::Function::New(env, GetLifecycleShutdownTransitionLabel));
|
|
398
|
+
exports.Set("isInitialized", Napi::Function::New(env, IsInitialized));
|
|
386
399
|
return exports;
|
|
387
400
|
}
|
|
388
401
|
|
|
@@ -385,40 +385,67 @@ Napi::Value GetNodeNames(const Napi::CallbackInfo& info) {
|
|
|
385
385
|
|
|
386
386
|
RclHandle* node_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
|
|
387
387
|
rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
|
|
388
|
+
bool get_enclaves = info[1].As<Napi::Boolean>().Value();
|
|
388
389
|
rcutils_string_array_t node_names =
|
|
389
390
|
rcutils_get_zero_initialized_string_array();
|
|
390
391
|
rcutils_string_array_t node_namespaces =
|
|
391
392
|
rcutils_get_zero_initialized_string_array();
|
|
393
|
+
rcutils_string_array_t enclaves = rcutils_get_zero_initialized_string_array();
|
|
392
394
|
rcl_allocator_t allocator = rcl_get_default_allocator();
|
|
393
395
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
396
|
+
if (get_enclaves) {
|
|
397
|
+
THROW_ERROR_IF_NOT_EQUAL(
|
|
398
|
+
RCL_RET_OK,
|
|
399
|
+
rcl_get_node_names_with_enclaves(node, allocator, &node_names,
|
|
400
|
+
&node_namespaces, &enclaves),
|
|
401
|
+
"Failed to get_node_names.");
|
|
402
|
+
} else {
|
|
403
|
+
THROW_ERROR_IF_NOT_EQUAL(
|
|
404
|
+
RCL_RET_OK,
|
|
405
|
+
rcl_get_node_names(node, allocator, &node_names, &node_namespaces),
|
|
406
|
+
"Failed to get_node_names.");
|
|
407
|
+
}
|
|
398
408
|
|
|
399
409
|
Napi::Array result_list = Napi::Array::New(env, node_names.size);
|
|
400
410
|
|
|
401
411
|
for (size_t i = 0; i < node_names.size; ++i) {
|
|
402
412
|
Napi::Object item = Napi::Object::New(env);
|
|
403
|
-
|
|
404
413
|
item.Set("name", Napi::String::New(env, node_names.data[i]));
|
|
405
414
|
item.Set("namespace", Napi::String::New(env, node_namespaces.data[i]));
|
|
406
|
-
|
|
415
|
+
if (get_enclaves) {
|
|
416
|
+
item.Set("enclave", Napi::String::New(env, enclaves.data[i]));
|
|
417
|
+
}
|
|
407
418
|
result_list.Set(i, item);
|
|
408
419
|
}
|
|
409
420
|
|
|
410
421
|
rcutils_ret_t fini_names_ret = rcutils_string_array_fini(&node_names);
|
|
411
422
|
rcutils_ret_t fini_namespaces_ret =
|
|
412
423
|
rcutils_string_array_fini(&node_namespaces);
|
|
413
|
-
|
|
424
|
+
rcutils_ret_t fini_enclaves_ret = rcutils_string_array_fini(&enclaves);
|
|
414
425
|
THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK, fini_names_ret,
|
|
415
426
|
"Failed to destroy node_names");
|
|
416
427
|
THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK, fini_namespaces_ret,
|
|
417
428
|
"Failed to destroy node_namespaces");
|
|
418
|
-
|
|
429
|
+
THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK, fini_enclaves_ret,
|
|
430
|
+
"Failed to fini enclaves string array");
|
|
419
431
|
return result_list;
|
|
420
432
|
}
|
|
421
433
|
|
|
434
|
+
Napi::Value GetFullyQualifiedName(const Napi::CallbackInfo& info) {
|
|
435
|
+
Napi::Env env = info.Env();
|
|
436
|
+
|
|
437
|
+
RclHandle* node_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
|
|
438
|
+
rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
|
|
439
|
+
const char* fully_qualified_node_name =
|
|
440
|
+
rcl_node_get_fully_qualified_name(node);
|
|
441
|
+
if (!fully_qualified_node_name) {
|
|
442
|
+
Napi::Error::New(env, "Fully qualified name not set")
|
|
443
|
+
.ThrowAsJavaScriptException();
|
|
444
|
+
return env.Undefined();
|
|
445
|
+
}
|
|
446
|
+
return Napi::String::New(env, fully_qualified_node_name);
|
|
447
|
+
}
|
|
448
|
+
|
|
422
449
|
Napi::Object InitNodeBindings(Napi::Env env, Napi::Object exports) {
|
|
423
450
|
exports.Set("getParameterOverrides",
|
|
424
451
|
Napi::Function::New(env, GetParameterOverrides));
|
|
@@ -439,6 +466,8 @@ Napi::Object InitNodeBindings(Napi::Env env, Napi::Object exports) {
|
|
|
439
466
|
exports.Set("countServices", Napi::Function::New(env, CountServices));
|
|
440
467
|
#endif
|
|
441
468
|
exports.Set("getNodeNames", Napi::Function::New(env, GetNodeNames));
|
|
469
|
+
exports.Set("getFullyQualifiedName",
|
|
470
|
+
Napi::Function::New(env, GetFullyQualifiedName));
|
|
442
471
|
return exports;
|
|
443
472
|
}
|
|
444
473
|
|
|
@@ -128,6 +128,24 @@ Napi::Value GetSubscriptionCount(const Napi::CallbackInfo& info) {
|
|
|
128
128
|
return Napi::Number::New(env, count);
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
Napi::Value WaitForAllAcked(const Napi::CallbackInfo& info) {
|
|
132
|
+
Napi::Env env = info.Env();
|
|
133
|
+
rcl_publisher_t* publisher = reinterpret_cast<rcl_publisher_t*>(
|
|
134
|
+
RclHandle::Unwrap(info[0].As<Napi::Object>())->ptr());
|
|
135
|
+
bool lossless;
|
|
136
|
+
int64_t nanoseconds = info[1].As<Napi::BigInt>().Int64Value(&lossless);
|
|
137
|
+
|
|
138
|
+
rcl_ret_t ret = rcl_publisher_wait_for_all_acked(publisher, nanoseconds);
|
|
139
|
+
if (RCL_RET_OK == ret) {
|
|
140
|
+
return Napi::Boolean::New(env, true);
|
|
141
|
+
} else if (RCL_RET_TIMEOUT == ret) {
|
|
142
|
+
return Napi::Boolean::New(env, false);
|
|
143
|
+
}
|
|
144
|
+
Napi::Error::New(env, "Failed to wait for all acknowledgements")
|
|
145
|
+
.ThrowAsJavaScriptException();
|
|
146
|
+
return env.Undefined();
|
|
147
|
+
}
|
|
148
|
+
|
|
131
149
|
Napi::Object InitPublisherBindings(Napi::Env env, Napi::Object exports) {
|
|
132
150
|
exports.Set("createPublisher", Napi::Function::New(env, CreatePublisher));
|
|
133
151
|
exports.Set("publish", Napi::Function::New(env, Publish));
|
|
@@ -135,6 +153,7 @@ Napi::Object InitPublisherBindings(Napi::Env env, Napi::Object exports) {
|
|
|
135
153
|
exports.Set("publishRawMessage", Napi::Function::New(env, PublishRawMessage));
|
|
136
154
|
exports.Set("getSubscriptionCount",
|
|
137
155
|
Napi::Function::New(env, GetSubscriptionCount));
|
|
156
|
+
exports.Set("waitForAllAcked", Napi::Function::New(env, WaitForAllAcked));
|
|
138
157
|
return exports;
|
|
139
158
|
}
|
|
140
159
|
|
|
@@ -0,0 +1,79 @@
|
|
|
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
|
+
#include "rcl_type_description_service_bindings.h"
|
|
16
|
+
|
|
17
|
+
#include <napi.h>
|
|
18
|
+
#include <rcl/rcl.h>
|
|
19
|
+
#include <rmw/types.h>
|
|
20
|
+
|
|
21
|
+
#include "rcl_handle.h"
|
|
22
|
+
|
|
23
|
+
namespace rclnodejs {
|
|
24
|
+
|
|
25
|
+
Napi::Value InitTypeDescriptionService(const Napi::CallbackInfo& info) {
|
|
26
|
+
Napi::Env env = info.Env();
|
|
27
|
+
RclHandle* node_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
|
|
28
|
+
rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
|
|
29
|
+
rcl_service_t* service =
|
|
30
|
+
reinterpret_cast<rcl_service_t*>(malloc(sizeof(rcl_service_t)));
|
|
31
|
+
*service = rcl_get_zero_initialized_service();
|
|
32
|
+
rcl_ret_t ret = rcl_node_type_description_service_init(service, node);
|
|
33
|
+
if (RCL_RET_OK != ret) {
|
|
34
|
+
Napi::Error::New(env, "Failed to initialize type description service")
|
|
35
|
+
.ThrowAsJavaScriptException();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
auto service_handle =
|
|
39
|
+
RclHandle::NewInstance(env, service, node_handle, [node, env](void* ptr) {
|
|
40
|
+
rcl_service_t* service = reinterpret_cast<rcl_service_t*>(ptr);
|
|
41
|
+
rcl_ret_t ret = rcl_service_fini(service, node);
|
|
42
|
+
if (RCL_RET_OK != ret) {
|
|
43
|
+
Napi::Error::New(env, "Failed to destroy type description service")
|
|
44
|
+
.ThrowAsJavaScriptException();
|
|
45
|
+
}
|
|
46
|
+
free(ptr);
|
|
47
|
+
});
|
|
48
|
+
return service_handle;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
Napi::Value HandleRequest(const Napi::CallbackInfo& info) {
|
|
52
|
+
Napi::Env env = info.Env();
|
|
53
|
+
rcl_node_t* node = reinterpret_cast<rcl_node_t*>(
|
|
54
|
+
RclHandle::Unwrap(info[0].As<Napi::Object>())->ptr());
|
|
55
|
+
void* request = info[1].As<Napi::Buffer<char>>().Data();
|
|
56
|
+
void* taken_response = info[2].As<Napi::Buffer<char>>().Data();
|
|
57
|
+
|
|
58
|
+
rmw_request_id_t header;
|
|
59
|
+
rcl_node_type_description_service_handle_request(
|
|
60
|
+
node, &header,
|
|
61
|
+
static_cast<
|
|
62
|
+
type_description_interfaces__srv__GetTypeDescription_Request*>(
|
|
63
|
+
request),
|
|
64
|
+
static_cast<
|
|
65
|
+
type_description_interfaces__srv__GetTypeDescription_Response*>(
|
|
66
|
+
taken_response));
|
|
67
|
+
return env.Undefined();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
Napi::Object InitTypeDescriptionServiceBindings(Napi::Env env,
|
|
71
|
+
Napi::Object exports) {
|
|
72
|
+
exports.Set("handleRequest", Napi::Function::New(env, HandleRequest));
|
|
73
|
+
exports.Set("initTypeDescriptionService",
|
|
74
|
+
Napi::Function::New(env, InitTypeDescriptionService));
|
|
75
|
+
|
|
76
|
+
return exports;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
} // namespace rclnodejs
|
|
@@ -0,0 +1,27 @@
|
|
|
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
|
+
#ifndef SRC_RCL_TYPE_DESCRIPTION_SERVICE_BINDINGS_H_
|
|
16
|
+
#define SRC_RCL_TYPE_DESCRIPTION_SERVICE_BINDINGS_H_
|
|
17
|
+
|
|
18
|
+
#include <napi.h>
|
|
19
|
+
|
|
20
|
+
namespace rclnodejs {
|
|
21
|
+
|
|
22
|
+
Napi::Object InitTypeDescriptionServiceBindings(Napi::Env env,
|
|
23
|
+
Napi::Object exports);
|
|
24
|
+
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
#endif // SRC_RCL_TYPE_DESCRIPTION_SERVICE_BINDINGS_H_
|
package/types/action_client.d.ts
CHANGED
|
@@ -173,5 +173,23 @@ declare module 'rclnodejs' {
|
|
|
173
173
|
* Destroy the underlying action client handle.
|
|
174
174
|
*/
|
|
175
175
|
destroy(): void;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Get the number of wait set entities that make up an action entity.
|
|
179
|
+
* @return - The number of subscriptions, guard_conditions, timers, and clients and services.
|
|
180
|
+
*/
|
|
181
|
+
getNumEntities(): object;
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Configure introspection.
|
|
185
|
+
* @param clock - Clock to use for service event timestamps
|
|
186
|
+
* @param QoSProfile - QOS profile for the service event publisher
|
|
187
|
+
* @param introspectionState - The state to set introspection to
|
|
188
|
+
*/
|
|
189
|
+
configureIntrospection(
|
|
190
|
+
clock: Clock,
|
|
191
|
+
serviceEventPubQOS: QoS,
|
|
192
|
+
introspectionState: ServiceIntrospectionStates
|
|
193
|
+
): void;
|
|
176
194
|
}
|
|
177
195
|
}
|
package/types/action_server.d.ts
CHANGED
|
@@ -181,5 +181,17 @@ declare module 'rclnodejs' {
|
|
|
181
181
|
* Destroy the action server and all goals.
|
|
182
182
|
*/
|
|
183
183
|
destroy(): void;
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Configure introspection.
|
|
187
|
+
* @param clock - Clock to use for service event timestamps
|
|
188
|
+
* @param QoSProfile - QOS profile for the service event publisher
|
|
189
|
+
* @param introspectionState - The state to set introspection to
|
|
190
|
+
*/
|
|
191
|
+
configureIntrospection(
|
|
192
|
+
clock: Clock,
|
|
193
|
+
serviceEventPubQOS: QoS,
|
|
194
|
+
introspectionState: ServiceIntrospectionStates
|
|
195
|
+
): void;
|
|
184
196
|
}
|
|
185
197
|
}
|
package/types/lifecycle.d.ts
CHANGED
|
@@ -326,6 +326,13 @@ declare module 'rclnodejs' {
|
|
|
326
326
|
topic: string,
|
|
327
327
|
options?: Options
|
|
328
328
|
): LifecyclePublisher<T>;
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Check if state machine is initialized.
|
|
332
|
+
*
|
|
333
|
+
* @returns {boolean} true if the state machine is initialized; otherwise false.
|
|
334
|
+
*/
|
|
335
|
+
get isInitialized(): boolean;
|
|
329
336
|
}
|
|
330
337
|
} // lifecycle namespace
|
|
331
338
|
} // rclnodejs namespace
|
package/types/node.d.ts
CHANGED
|
@@ -142,6 +142,24 @@ declare module 'rclnodejs' {
|
|
|
142
142
|
namespace: string;
|
|
143
143
|
};
|
|
144
144
|
|
|
145
|
+
/**
|
|
146
|
+
* Result of Node.getNodeNames() query
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```
|
|
150
|
+
* [
|
|
151
|
+
* { name: 'gazebo', namespace: '/', enclave: '/'},
|
|
152
|
+
* { name: 'robot_state_publisher', namespace: '/', enclave: '/' },
|
|
153
|
+
* { name: 'cam2image', namespace: '/demo' , enclave: '/'}
|
|
154
|
+
* ]
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
157
|
+
type NodeNamesQueryResultWithEnclaves = {
|
|
158
|
+
name: string;
|
|
159
|
+
namespace: string;
|
|
160
|
+
enclave: string;
|
|
161
|
+
};
|
|
162
|
+
|
|
145
163
|
/**
|
|
146
164
|
* Node is the primary entrypoint in a ROS system for communication.
|
|
147
165
|
* It can be used to create ROS entities such as publishers, subscribers,
|
|
@@ -769,6 +787,13 @@ declare module 'rclnodejs' {
|
|
|
769
787
|
*/
|
|
770
788
|
getNodeNamesAndNamespaces(): Array<NodeNamesQueryResult>;
|
|
771
789
|
|
|
790
|
+
/**
|
|
791
|
+
* Get the list of nodes and their namespaces with enclaves discovered by the provided node.
|
|
792
|
+
*
|
|
793
|
+
* @returns An array of the names, namespaces and enclaves.
|
|
794
|
+
*/
|
|
795
|
+
getNodeNamesAndNamespacesWithEnclaves(): Array<NodeNamesQueryResultWithEnclaves>;
|
|
796
|
+
|
|
772
797
|
/**
|
|
773
798
|
* Return the number of publishers on a given topic.
|
|
774
799
|
* @param topic - The name of the topic.
|
|
@@ -796,5 +821,12 @@ declare module 'rclnodejs' {
|
|
|
796
821
|
* @returns Number of services.
|
|
797
822
|
*/
|
|
798
823
|
countServices(serviceName: string): number;
|
|
824
|
+
|
|
825
|
+
/**
|
|
826
|
+
* Get the fully qualified name of the node.
|
|
827
|
+
*
|
|
828
|
+
* @returns String containing the fully qualified name of the node.
|
|
829
|
+
*/
|
|
830
|
+
getFullyQualifiedName(): string;
|
|
799
831
|
}
|
|
800
832
|
}
|
package/types/publisher.d.ts
CHANGED
|
@@ -20,5 +20,22 @@ declare module 'rclnodejs' {
|
|
|
20
20
|
* @returns The number of subscriptions
|
|
21
21
|
*/
|
|
22
22
|
subscriptionCount(): number;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Wait until all published message data is acknowledged or until the specified timeout elapses
|
|
26
|
+
*
|
|
27
|
+
* If the timeout is negative then this function will block indefinitely until all published
|
|
28
|
+
* message data is acknowledged.
|
|
29
|
+
* If the timeout is 0 then it will check if all published message has been acknowledged without
|
|
30
|
+
* waiting.
|
|
31
|
+
* If the timeout is greater than 0 then it will return after that period of time has elapsed or
|
|
32
|
+
* all published message data is acknowledged.
|
|
33
|
+
*
|
|
34
|
+
* Raises an error if failed, such as the middleware not supporting this feature.
|
|
35
|
+
*
|
|
36
|
+
* @param {timeout} timeout - The duration to wait for all published message data to be acknowledged in nanoseconds.
|
|
37
|
+
* @return {boolean} `true` if all published message data is acknowledged before the timeout, otherwise `false`.
|
|
38
|
+
*/
|
|
39
|
+
waitForAllAcked(timeout: bigint): boolean;
|
|
23
40
|
}
|
|
24
41
|
}
|