rclnodejs 1.1.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/README.md +4 -4
- package/binding.gyp +4 -0
- package/lib/event_handler.js +474 -0
- package/lib/lifecycle_publisher.js +2 -2
- package/lib/node.js +57 -10
- package/lib/publisher.js +31 -4
- package/lib/subscription.js +48 -4
- package/package.json +1 -1
- package/scripts/npmjs-readme.md +4 -4
- package/src/addon.cpp +2 -0
- package/src/executor.cpp +3 -4
- package/src/handle_manager.cpp +13 -2
- package/src/handle_manager.h +4 -1
- package/src/rcl_event_handle_bindings.cpp +294 -0
- package/src/rcl_event_handle_bindings.h +26 -0
- package/src/rcl_node_bindings.cpp +6 -0
- package/types/node.d.ts +12 -2
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(
|
|
67
|
+
static createPublisher(node, typeClass, topic, options, eventCallbacks) {
|
|
64
68
|
let type = typeClass.type();
|
|
65
69
|
let handle = rclnodejs.createPublisher(
|
|
66
|
-
|
|
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(
|
|
77
|
+
return new Publisher(
|
|
78
|
+
handle,
|
|
79
|
+
typeClass,
|
|
80
|
+
topic,
|
|
81
|
+
options,
|
|
82
|
+
node,
|
|
83
|
+
eventCallbacks
|
|
84
|
+
);
|
|
74
85
|
}
|
|
75
86
|
|
|
76
87
|
/**
|
|
@@ -99,6 +110,22 @@ class Publisher extends Entity {
|
|
|
99
110
|
waitForAllAcked(timeout) {
|
|
100
111
|
return rclnodejs.waitForAllAcked(this._handle, timeout);
|
|
101
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
|
+
}
|
|
102
129
|
}
|
|
103
130
|
|
|
104
131
|
module.exports = Publisher;
|
package/lib/subscription.js
CHANGED
|
@@ -29,11 +29,24 @@ const debug = require('debug')('rclnodejs:subscription');
|
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
31
|
class Subscription extends Entity {
|
|
32
|
-
constructor(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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;
|
package/package.json
CHANGED
package/scripts/npmjs-readme.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# rclnodejs ](https://github.com/RobotWebTools/rclnodejs/actions/workflows/linux-x64-build-and-test.yml?query=branch%3Adevelop)[](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/
|
|
26
|
-
- **DON'T FORGET TO [SOURCE THE ROS 2 STARTUP FILES](https://docs.ros.org/en/
|
|
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
|
|
|
@@ -45,7 +45,7 @@ npm i rclnodejs@x.y.z
|
|
|
45
45
|
|
|
46
46
|
| RCLNODEJS Version | Compatible ROS 2 LTS |
|
|
47
47
|
| :----------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|
|
48
|
-
| latest version (currently [v1.
|
|
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
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
#include "rcl_time_point_bindings.h"
|
|
36
36
|
#include "rcl_timer_bindings.h"
|
|
37
37
|
#if ROS_VERSION > 2205 // ROS2 > Humble
|
|
38
|
+
#include "rcl_event_handle_bindings.h"
|
|
38
39
|
#include "rcl_type_description_service_bindings.h"
|
|
39
40
|
#endif
|
|
40
41
|
#include "rcl_utilities.h"
|
|
@@ -84,6 +85,7 @@ Napi::Object InitModule(Napi::Env env, Napi::Object exports) {
|
|
|
84
85
|
rclnodejs::InitTimerBindings(env, exports);
|
|
85
86
|
#if ROS_VERSION > 2205 // ROS2 > Humble
|
|
86
87
|
rclnodejs::InitTypeDescriptionServiceBindings(env, exports);
|
|
88
|
+
rclnodejs::InitEventHandleBindings(env, exports);
|
|
87
89
|
#endif
|
|
88
90
|
rclnodejs::InitLifecycleBindings(env, exports);
|
|
89
91
|
rclnodejs::ShadowNode::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);
|
package/src/handle_manager.cpp
CHANGED
|
@@ -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
|
}
|
package/src/handle_manager.h
CHANGED
|
@@ -68,13 +68,15 @@ class HandleManager {
|
|
|
68
68
|
rcl_ret_t CollectReadyHandles(rcl_wait_set_t* wait_set);
|
|
69
69
|
rcl_ret_t GetEntityCounts(size_t* subscriptions_size,
|
|
70
70
|
size_t* guard_conditions_size, size_t* timers_size,
|
|
71
|
-
size_t* clients_size, size_t* services_size
|
|
71
|
+
size_t* clients_size, size_t* services_size,
|
|
72
|
+
size_t* events_size);
|
|
72
73
|
|
|
73
74
|
uint32_t subscription_count() const { return subscriptions_.size(); }
|
|
74
75
|
uint32_t service_count() const { return services_.size(); }
|
|
75
76
|
uint32_t client_count() const { return clients_.size(); }
|
|
76
77
|
uint32_t timer_count() const { return timers_.size(); }
|
|
77
78
|
uint32_t guard_condition_count() const { return guard_conditions_.size(); }
|
|
79
|
+
uint32_t event_count() const { return events_.size(); }
|
|
78
80
|
uv_rwlock_t* handle_rwlock() { return &sync_handles_rwlock_; }
|
|
79
81
|
|
|
80
82
|
uint32_t ready_handles_count();
|
|
@@ -110,6 +112,7 @@ class HandleManager {
|
|
|
110
112
|
std::vector<rclnodejs::RclHandle*> action_servers_;
|
|
111
113
|
std::vector<rclnodejs::RclHandle*> action_clients_;
|
|
112
114
|
std::vector<rclnodejs::RclHandle*> ready_handles_;
|
|
115
|
+
std::vector<rclnodejs::RclHandle*> events_;
|
|
113
116
|
|
|
114
117
|
// Protects the handles.
|
|
115
118
|
uv_rwlock_t sync_handles_rwlock_;
|
|
@@ -0,0 +1,294 @@
|
|
|
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_event_handle_bindings.h"
|
|
16
|
+
|
|
17
|
+
#include <rcl/error_handling.h>
|
|
18
|
+
#include <rcl/rcl.h>
|
|
19
|
+
|
|
20
|
+
#include "rcl_handle.h"
|
|
21
|
+
|
|
22
|
+
namespace {
|
|
23
|
+
|
|
24
|
+
typedef union event_callback_data {
|
|
25
|
+
// Subscription events
|
|
26
|
+
rmw_requested_deadline_missed_status_t requested_deadline_missed;
|
|
27
|
+
rmw_liveliness_changed_status_t liveliness_changed;
|
|
28
|
+
rmw_message_lost_status_t message_lost;
|
|
29
|
+
rmw_requested_qos_incompatible_event_status_t requested_incompatible_qos;
|
|
30
|
+
rmw_matched_status_t subscription_matched;
|
|
31
|
+
// Publisher events
|
|
32
|
+
rmw_offered_deadline_missed_status_t offered_deadline_missed;
|
|
33
|
+
rmw_liveliness_lost_status_t liveliness_lost;
|
|
34
|
+
rmw_offered_qos_incompatible_event_status_t offered_incompatible_qos;
|
|
35
|
+
rmw_matched_status_t publisher_matched;
|
|
36
|
+
|
|
37
|
+
rmw_incompatible_type_status_t incompatible_type;
|
|
38
|
+
} event_callback_data_t;
|
|
39
|
+
|
|
40
|
+
rcl_event_t* CreateEventHandle() {
|
|
41
|
+
rcl_event_t* event =
|
|
42
|
+
reinterpret_cast<rcl_event_t*>(malloc(sizeof(rcl_event_t)));
|
|
43
|
+
*event = rcl_get_zero_initialized_event();
|
|
44
|
+
return event;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
Napi::Value CreateJSObjectForSubscriptionEvent(
|
|
48
|
+
Napi::Env env, rcl_subscription_event_type_t subscription_event_type,
|
|
49
|
+
const event_callback_data_t& data) {
|
|
50
|
+
Napi::Object obj = Napi::Object::New(env);
|
|
51
|
+
switch (subscription_event_type) {
|
|
52
|
+
case RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED: {
|
|
53
|
+
obj.Set(
|
|
54
|
+
"total_count",
|
|
55
|
+
Napi::Number::New(env, data.requested_deadline_missed.total_count));
|
|
56
|
+
obj.Set("total_count_change",
|
|
57
|
+
Napi::Number::New(
|
|
58
|
+
env, data.requested_deadline_missed.total_count_change));
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
case RCL_SUBSCRIPTION_LIVELINESS_CHANGED: {
|
|
62
|
+
obj.Set("alive_count",
|
|
63
|
+
Napi::Number::New(env, data.liveliness_changed.alive_count));
|
|
64
|
+
obj.Set("not_alive_count",
|
|
65
|
+
Napi::Number::New(env, data.liveliness_changed.not_alive_count));
|
|
66
|
+
obj.Set(
|
|
67
|
+
"alive_count_change",
|
|
68
|
+
Napi::Number::New(env, data.liveliness_changed.alive_count_change));
|
|
69
|
+
obj.Set("not_alive_count_change",
|
|
70
|
+
Napi::Number::New(
|
|
71
|
+
env, data.liveliness_changed.not_alive_count_change));
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
case RCL_SUBSCRIPTION_MESSAGE_LOST: {
|
|
75
|
+
obj.Set("total_count",
|
|
76
|
+
Napi::Number::New(env, data.message_lost.total_count));
|
|
77
|
+
obj.Set("total_count_change",
|
|
78
|
+
Napi::Number::New(env, data.message_lost.total_count_change));
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
case RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS: {
|
|
82
|
+
obj.Set(
|
|
83
|
+
"total_count",
|
|
84
|
+
Napi::Number::New(env, data.requested_incompatible_qos.total_count));
|
|
85
|
+
obj.Set("total_count_change",
|
|
86
|
+
Napi::Number::New(
|
|
87
|
+
env, data.requested_incompatible_qos.total_count_change));
|
|
88
|
+
obj.Set("last_policy_kind",
|
|
89
|
+
Napi::Number::New(
|
|
90
|
+
env, data.requested_incompatible_qos.last_policy_kind));
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
case RCL_SUBSCRIPTION_INCOMPATIBLE_TYPE: {
|
|
94
|
+
obj.Set("total_count",
|
|
95
|
+
Napi::Number::New(env, data.incompatible_type.total_count));
|
|
96
|
+
obj.Set(
|
|
97
|
+
"total_count_change",
|
|
98
|
+
Napi::Number::New(env, data.incompatible_type.total_count_change));
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
case RCL_SUBSCRIPTION_MATCHED: {
|
|
102
|
+
obj.Set("total_count",
|
|
103
|
+
Napi::Number::New(env, data.subscription_matched.total_count));
|
|
104
|
+
obj.Set(
|
|
105
|
+
"total_count_change",
|
|
106
|
+
Napi::Number::New(env, data.subscription_matched.total_count_change));
|
|
107
|
+
obj.Set("current_count",
|
|
108
|
+
Napi::Number::New(env, data.subscription_matched.current_count));
|
|
109
|
+
obj.Set("current_count_change",
|
|
110
|
+
Napi::Number::New(
|
|
111
|
+
env, data.subscription_matched.current_count_change));
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
default:
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
return obj;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
Napi::Value CreateJSObjectForPublisherEvent(
|
|
121
|
+
Napi::Env env, rcl_publisher_event_type_t publisher_event_type,
|
|
122
|
+
const event_callback_data_t& data) {
|
|
123
|
+
Napi::Object obj = Napi::Object::New(env);
|
|
124
|
+
switch (publisher_event_type) {
|
|
125
|
+
case RCL_PUBLISHER_OFFERED_DEADLINE_MISSED: {
|
|
126
|
+
obj.Set("total_count",
|
|
127
|
+
Napi::Number::New(env, data.offered_deadline_missed.total_count));
|
|
128
|
+
obj.Set("total_count_change",
|
|
129
|
+
Napi::Number::New(
|
|
130
|
+
env, data.offered_deadline_missed.total_count_change));
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
case RCL_PUBLISHER_LIVELINESS_LOST: {
|
|
134
|
+
obj.Set("total_count",
|
|
135
|
+
Napi::Number::New(env, data.liveliness_lost.total_count));
|
|
136
|
+
obj.Set("total_count_change",
|
|
137
|
+
Napi::Number::New(env, data.liveliness_lost.total_count_change));
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
case RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS: {
|
|
141
|
+
obj.Set(
|
|
142
|
+
"total_count",
|
|
143
|
+
Napi::Number::New(env, data.offered_incompatible_qos.total_count));
|
|
144
|
+
obj.Set("total_count_change",
|
|
145
|
+
Napi::Number::New(
|
|
146
|
+
env, data.offered_incompatible_qos.total_count_change));
|
|
147
|
+
obj.Set("last_policy_kind",
|
|
148
|
+
Napi::Number::New(
|
|
149
|
+
env, data.offered_incompatible_qos.last_policy_kind));
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
case RCL_PUBLISHER_INCOMPATIBLE_TYPE: {
|
|
153
|
+
obj.Set("total_count",
|
|
154
|
+
Napi::Number::New(env, data.incompatible_type.total_count));
|
|
155
|
+
obj.Set(
|
|
156
|
+
"total_count_change",
|
|
157
|
+
Napi::Number::New(env, data.incompatible_type.total_count_change));
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
case RCL_PUBLISHER_MATCHED: {
|
|
161
|
+
obj.Set("total_count",
|
|
162
|
+
Napi::Number::New(env, data.publisher_matched.total_count));
|
|
163
|
+
obj.Set(
|
|
164
|
+
"total_count_change",
|
|
165
|
+
Napi::Number::New(env, data.publisher_matched.total_count_change));
|
|
166
|
+
obj.Set("current_count",
|
|
167
|
+
Napi::Number::New(env, data.publisher_matched.current_count));
|
|
168
|
+
obj.Set(
|
|
169
|
+
"current_count_change",
|
|
170
|
+
Napi::Number::New(env, data.publisher_matched.current_count_change));
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
default:
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
return obj;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
} // namespace
|
|
180
|
+
|
|
181
|
+
namespace rclnodejs {
|
|
182
|
+
|
|
183
|
+
Napi::Value CreateSubscriptionEventHandle(const Napi::CallbackInfo& info) {
|
|
184
|
+
Napi::Env env = info.Env();
|
|
185
|
+
RclHandle* subscription_handle =
|
|
186
|
+
RclHandle::Unwrap(info[0].As<Napi::Object>());
|
|
187
|
+
rcl_subscription_t* subscription =
|
|
188
|
+
reinterpret_cast<rcl_subscription_t*>(subscription_handle->ptr());
|
|
189
|
+
rcl_subscription_event_type_t event_type =
|
|
190
|
+
static_cast<rcl_subscription_event_type_t>(
|
|
191
|
+
info[1].As<Napi::Number>().Int32Value());
|
|
192
|
+
|
|
193
|
+
rcl_event_t* event = CreateEventHandle();
|
|
194
|
+
rcl_ret_t ret = rcl_subscription_event_init(event, subscription, event_type);
|
|
195
|
+
|
|
196
|
+
if (ret != RCL_RET_OK) {
|
|
197
|
+
Napi::Error::New(env, "failed to create subscription event")
|
|
198
|
+
.ThrowAsJavaScriptException();
|
|
199
|
+
rcl_reset_error();
|
|
200
|
+
free(event);
|
|
201
|
+
return env.Undefined();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
auto js_obj = RclHandle::NewInstance(env, event, nullptr, [env](void* ptr) {
|
|
205
|
+
rcl_event_t* event = reinterpret_cast<rcl_event_t*>(ptr);
|
|
206
|
+
rcl_ret_t ret = rcl_event_fini(event);
|
|
207
|
+
if (ret != RCL_RET_OK) {
|
|
208
|
+
Napi::Error::New(env, rcl_get_error_string().str)
|
|
209
|
+
.ThrowAsJavaScriptException();
|
|
210
|
+
rcl_reset_error();
|
|
211
|
+
}
|
|
212
|
+
free(ptr);
|
|
213
|
+
});
|
|
214
|
+
return js_obj;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
Napi::Value CreatePublisherEventHandle(const Napi::CallbackInfo& info) {
|
|
218
|
+
Napi::Env env = info.Env();
|
|
219
|
+
RclHandle* publisher_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
|
|
220
|
+
rcl_publisher_t* publisher =
|
|
221
|
+
reinterpret_cast<rcl_publisher_t*>(publisher_handle->ptr());
|
|
222
|
+
rcl_publisher_event_type_t event_type =
|
|
223
|
+
static_cast<rcl_publisher_event_type_t>(
|
|
224
|
+
info[1].As<Napi::Number>().Int32Value());
|
|
225
|
+
|
|
226
|
+
rcl_event_t* event = CreateEventHandle();
|
|
227
|
+
rcl_ret_t ret = rcl_publisher_event_init(event, publisher, event_type);
|
|
228
|
+
|
|
229
|
+
if (ret != RCL_RET_OK) {
|
|
230
|
+
Napi::Error::New(env, "failed to create publisher event")
|
|
231
|
+
.ThrowAsJavaScriptException();
|
|
232
|
+
rcl_reset_error();
|
|
233
|
+
free(event);
|
|
234
|
+
return env.Undefined();
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
auto js_obj = RclHandle::NewInstance(env, event, nullptr, [env](void* ptr) {
|
|
238
|
+
rcl_event_t* event = reinterpret_cast<rcl_event_t*>(ptr);
|
|
239
|
+
rcl_ret_t ret = rcl_event_fini(event);
|
|
240
|
+
if (ret != RCL_RET_OK) {
|
|
241
|
+
Napi::Error::New(env, rcl_get_error_string().str)
|
|
242
|
+
.ThrowAsJavaScriptException();
|
|
243
|
+
rcl_reset_error();
|
|
244
|
+
}
|
|
245
|
+
free(ptr);
|
|
246
|
+
});
|
|
247
|
+
return js_obj;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
Napi::Value TakeEvent(const Napi::CallbackInfo& info) {
|
|
251
|
+
Napi::Env env = info.Env();
|
|
252
|
+
RclHandle* event_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
|
|
253
|
+
rcl_event_t* event = reinterpret_cast<rcl_event_t*>(event_handle->ptr());
|
|
254
|
+
auto event_type = info[1].As<Napi::Object>();
|
|
255
|
+
|
|
256
|
+
event_callback_data_t data;
|
|
257
|
+
rcl_ret_t ret;
|
|
258
|
+
if (event_type.Has("subscription_event_type")) {
|
|
259
|
+
rcl_subscription_event_type_t subscription_event_type =
|
|
260
|
+
static_cast<rcl_subscription_event_type_t>(
|
|
261
|
+
event_type.Get("subscription_event_type")
|
|
262
|
+
.As<Napi::Number>()
|
|
263
|
+
.Int32Value());
|
|
264
|
+
ret = rcl_take_event(event, &data);
|
|
265
|
+
if (RCL_RET_OK == ret) {
|
|
266
|
+
return CreateJSObjectForSubscriptionEvent(env, subscription_event_type,
|
|
267
|
+
data);
|
|
268
|
+
}
|
|
269
|
+
} else if (event_type.Has("publisher_event_type")) {
|
|
270
|
+
rcl_publisher_event_type_t publisher_event_type =
|
|
271
|
+
static_cast<rcl_publisher_event_type_t>(
|
|
272
|
+
event_type.Get("publisher_event_type")
|
|
273
|
+
.As<Napi::Number>()
|
|
274
|
+
.Int32Value());
|
|
275
|
+
ret = rcl_take_event(event, &data);
|
|
276
|
+
if (RCL_RET_OK == ret) {
|
|
277
|
+
return CreateJSObjectForPublisherEvent(env, publisher_event_type, data);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
Napi::Error::New(env, "failed to take event").ThrowAsJavaScriptException();
|
|
282
|
+
return env.Undefined();
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
Napi::Object InitEventHandleBindings(Napi::Env env, Napi::Object exports) {
|
|
286
|
+
exports.Set("createSubscriptionEventHandle",
|
|
287
|
+
Napi::Function::New(env, CreateSubscriptionEventHandle));
|
|
288
|
+
exports.Set("createPublisherEventHandle",
|
|
289
|
+
Napi::Function::New(env, CreatePublisherEventHandle));
|
|
290
|
+
exports.Set("takeEvent", Napi::Function::New(env, TakeEvent));
|
|
291
|
+
return exports;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
} // namespace rclnodejs
|
|
@@ -0,0 +1,26 @@
|
|
|
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_EVENT_HANDLE_BINDINGS_H_
|
|
16
|
+
#define SRC_RCL_EVENT_HANDLE_BINDINGS_H_
|
|
17
|
+
|
|
18
|
+
#include <napi.h>
|
|
19
|
+
|
|
20
|
+
namespace rclnodejs {
|
|
21
|
+
|
|
22
|
+
Napi::Object InitEventHandleBindings(Napi::Env env, Napi::Object exports);
|
|
23
|
+
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
#endif // SRC_RCL_EVENT_HANDLE_BINDINGS_H_
|
|
@@ -446,6 +446,10 @@ Napi::Value GetFullyQualifiedName(const Napi::CallbackInfo& info) {
|
|
|
446
446
|
return Napi::String::New(env, fully_qualified_node_name);
|
|
447
447
|
}
|
|
448
448
|
|
|
449
|
+
Napi::Value GetRMWImplementationIdentifier(const Napi::CallbackInfo& info) {
|
|
450
|
+
return Napi::String::New(info.Env(), rmw_get_implementation_identifier());
|
|
451
|
+
}
|
|
452
|
+
|
|
449
453
|
Napi::Object InitNodeBindings(Napi::Env env, Napi::Object exports) {
|
|
450
454
|
exports.Set("getParameterOverrides",
|
|
451
455
|
Napi::Function::New(env, GetParameterOverrides));
|
|
@@ -468,6 +472,8 @@ Napi::Object InitNodeBindings(Napi::Env env, Napi::Object exports) {
|
|
|
468
472
|
exports.Set("getNodeNames", Napi::Function::New(env, GetNodeNames));
|
|
469
473
|
exports.Set("getFullyQualifiedName",
|
|
470
474
|
Napi::Function::New(env, GetFullyQualifiedName));
|
|
475
|
+
exports.Set("getRMWImplementationIdentifier",
|
|
476
|
+
Napi::Function::New(env, GetRMWImplementationIdentifier));
|
|
471
477
|
return exports;
|
|
472
478
|
}
|
|
473
479
|
|