rclnodejs 1.8.1 → 1.8.3
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/index.js +33 -23
- package/lib/action/client.js +6 -0
- package/lib/action/server.js +1 -3
- package/lib/distro.js +2 -1
- package/lib/lifecycle.js +2 -1
- package/lib/lifecycle_publisher.js +2 -2
- package/lib/node.js +37 -11
- package/lib/parameter.js +6 -10
- package/lib/service.js +8 -4
- package/lib/time_source.js +3 -20
- package/package.json +4 -4
- package/prebuilds/linux-arm64/humble-jammy-arm64-rclnodejs.node +0 -0
- package/prebuilds/linux-arm64/jazzy-noble-arm64-rclnodejs.node +0 -0
- package/prebuilds/linux-arm64/kilted-noble-arm64-rclnodejs.node +0 -0
- package/prebuilds/linux-x64/humble-jammy-x64-rclnodejs.node +0 -0
- package/prebuilds/linux-x64/jazzy-noble-x64-rclnodejs.node +0 -0
- package/prebuilds/linux-x64/kilted-noble-x64-rclnodejs.node +0 -0
- package/rosidl_gen/generate_worker.js +3 -13
- package/rosidl_gen/idl_generator.js +210 -0
- package/rosidl_gen/index.js +3 -12
- package/rosidl_gen/packages.js +7 -4
- package/rosidl_gen/primitive_types.js +2 -2
- package/rosidl_parser/idl_parser.py +437 -0
- package/rosidl_parser/parser.py +2 -4
- package/rosidl_parser/rosidl_parser.js +27 -0
- package/src/executor.cpp +1 -0
- package/src/macros.h +2 -2
- package/src/rcl_action_client_bindings.cpp +18 -11
- package/src/rcl_action_server_bindings.cpp +24 -13
- package/src/rcl_bindings.cpp +1 -1
- package/src/rcl_client_bindings.cpp +13 -5
- package/src/rcl_context_bindings.cpp +7 -8
- package/src/rcl_guard_condition_bindings.cpp +12 -3
- package/src/rcl_lifecycle_bindings.cpp +53 -11
- package/src/rcl_node_bindings.cpp +11 -4
- package/src/rcl_publisher_bindings.cpp +12 -3
- package/src/rcl_service_bindings.cpp +12 -3
- package/src/rcl_subscription_bindings.cpp +24 -21
- package/src/rcl_timer_bindings.cpp +24 -9
- package/src/rcl_type_description_service_bindings.cpp +9 -1
- package/test_data_integrity.js +108 -0
- package/test_repro_exact.js +57 -0
- package/test_repro_hz.js +86 -0
- package/test_repro_pub.js +36 -0
- package/test_repro_stress.js +83 -0
- package/test_repro_sub.js +64 -0
- package/test_xproc_data.js +64 -0
- package/rosidl_convertor/README.md +0 -298
- package/rosidl_convertor/idl_convertor.js +0 -50
- package/rosidl_convertor/idl_convertor.py +0 -1250
|
@@ -76,10 +76,18 @@ Napi::Value ActionCreateServer(const Napi::CallbackInfo& info) {
|
|
|
76
76
|
malloc(sizeof(rcl_action_server_t)));
|
|
77
77
|
*action_server = rcl_action_get_zero_initialized_server();
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
79
|
+
{
|
|
80
|
+
rcl_ret_t ret =
|
|
81
|
+
rcl_action_server_init(action_server, node, clock, ts,
|
|
82
|
+
action_name.c_str(), &action_server_ops);
|
|
83
|
+
if (RCL_RET_OK != ret) {
|
|
84
|
+
std::string error_msg = rcl_get_error_string().str;
|
|
85
|
+
rcl_reset_error();
|
|
86
|
+
free(action_server);
|
|
87
|
+
Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
|
|
88
|
+
return env.Undefined();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
83
91
|
auto js_obj = RclHandle::NewInstance(
|
|
84
92
|
env, action_server, node_handle, [node, env](void* ptr) {
|
|
85
93
|
rcl_action_server_t* action_server =
|
|
@@ -118,6 +126,7 @@ Napi::Value ActionTakeResultRequest(const Napi::CallbackInfo& info) {
|
|
|
118
126
|
return js_obj;
|
|
119
127
|
}
|
|
120
128
|
|
|
129
|
+
free(header);
|
|
121
130
|
return env.Undefined();
|
|
122
131
|
}
|
|
123
132
|
|
|
@@ -140,6 +149,7 @@ Napi::Value ActionTakeGoalRequest(const Napi::CallbackInfo& info) {
|
|
|
140
149
|
return js_obj;
|
|
141
150
|
}
|
|
142
151
|
|
|
152
|
+
free(header);
|
|
143
153
|
return env.Undefined();
|
|
144
154
|
}
|
|
145
155
|
|
|
@@ -213,14 +223,14 @@ Napi::Value ActionTakeGoalResponse(const Napi::CallbackInfo& info) {
|
|
|
213
223
|
free(header);
|
|
214
224
|
|
|
215
225
|
if (ret != RCL_RET_OK && ret != RCL_RET_ACTION_CLIENT_TAKE_FAILED) {
|
|
226
|
+
std::string error_msg = rcl_get_error_string().str;
|
|
216
227
|
rcl_reset_error();
|
|
217
|
-
Napi::Error::New(env,
|
|
218
|
-
.ThrowAsJavaScriptException();
|
|
228
|
+
Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
|
|
219
229
|
return env.Undefined();
|
|
220
230
|
}
|
|
221
231
|
|
|
222
232
|
if (ret != RCL_RET_ACTION_CLIENT_TAKE_FAILED) {
|
|
223
|
-
return Napi::Number::New(env, static_cast<
|
|
233
|
+
return Napi::Number::New(env, static_cast<double>(sequence_number));
|
|
224
234
|
}
|
|
225
235
|
return env.Undefined();
|
|
226
236
|
}
|
|
@@ -242,14 +252,14 @@ Napi::Value ActionTakeCancelResponse(const Napi::CallbackInfo& info) {
|
|
|
242
252
|
free(header);
|
|
243
253
|
|
|
244
254
|
if (ret != RCL_RET_OK && ret != RCL_RET_ACTION_CLIENT_TAKE_FAILED) {
|
|
255
|
+
std::string error_msg = rcl_get_error_string().str;
|
|
245
256
|
rcl_reset_error();
|
|
246
|
-
Napi::Error::New(env,
|
|
247
|
-
.ThrowAsJavaScriptException();
|
|
257
|
+
Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
|
|
248
258
|
return env.Undefined();
|
|
249
259
|
}
|
|
250
260
|
|
|
251
261
|
if (ret != RCL_RET_ACTION_CLIENT_TAKE_FAILED) {
|
|
252
|
-
return Napi::Number::New(env, static_cast<
|
|
262
|
+
return Napi::Number::New(env, static_cast<double>(sequence_number));
|
|
253
263
|
}
|
|
254
264
|
return env.Undefined();
|
|
255
265
|
}
|
|
@@ -271,14 +281,14 @@ Napi::Value ActionTakeResultResponse(const Napi::CallbackInfo& info) {
|
|
|
271
281
|
free(header);
|
|
272
282
|
|
|
273
283
|
if (ret != RCL_RET_OK && ret != RCL_RET_ACTION_CLIENT_TAKE_FAILED) {
|
|
284
|
+
std::string error_msg = rcl_get_error_string().str;
|
|
274
285
|
rcl_reset_error();
|
|
275
|
-
Napi::Error::New(env,
|
|
276
|
-
.ThrowAsJavaScriptException();
|
|
286
|
+
Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
|
|
277
287
|
return env.Undefined();
|
|
278
288
|
}
|
|
279
289
|
|
|
280
290
|
if (ret != RCL_RET_ACTION_CLIENT_TAKE_FAILED) {
|
|
281
|
-
return Napi::Number::New(env, static_cast<
|
|
291
|
+
return Napi::Number::New(env, static_cast<double>(sequence_number));
|
|
282
292
|
}
|
|
283
293
|
return env.Undefined();
|
|
284
294
|
}
|
|
@@ -455,6 +465,7 @@ Napi::Value ActionTakeCancelRequest(const Napi::CallbackInfo& info) {
|
|
|
455
465
|
return js_obj;
|
|
456
466
|
}
|
|
457
467
|
|
|
468
|
+
free(header);
|
|
458
469
|
return env.Undefined();
|
|
459
470
|
}
|
|
460
471
|
|
package/src/rcl_bindings.cpp
CHANGED
|
@@ -49,9 +49,17 @@ Napi::Value CreateClient(const Napi::CallbackInfo& info) {
|
|
|
49
49
|
client_ops.qos = *qos_profile;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
{
|
|
53
|
+
rcl_ret_t ret =
|
|
54
|
+
rcl_client_init(client, node, ts, service_name.c_str(), &client_ops);
|
|
55
|
+
if (RCL_RET_OK != ret) {
|
|
56
|
+
std::string error_msg = rcl_get_error_string().str;
|
|
57
|
+
rcl_reset_error();
|
|
58
|
+
free(client);
|
|
59
|
+
Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
|
|
60
|
+
return env.Undefined();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
55
63
|
|
|
56
64
|
auto js_obj = RclHandle::NewInstance(
|
|
57
65
|
env, client, node_handle, [node, env](void* ptr) {
|
|
@@ -80,7 +88,7 @@ Napi::Value SendRequest(const Napi::CallbackInfo& info) {
|
|
|
80
88
|
THROW_ERROR_IF_NOT_EQUAL(rcl_send_request(client, buffer, &sequence_number),
|
|
81
89
|
RCL_RET_OK, rcl_get_error_string().str);
|
|
82
90
|
|
|
83
|
-
return Napi::Number::New(env, static_cast<
|
|
91
|
+
return Napi::Number::New(env, static_cast<double>(sequence_number));
|
|
84
92
|
}
|
|
85
93
|
|
|
86
94
|
Napi::Value RclTakeResponse(const Napi::CallbackInfo& info) {
|
|
@@ -96,7 +104,7 @@ Napi::Value RclTakeResponse(const Napi::CallbackInfo& info) {
|
|
|
96
104
|
int64_t sequence_number = header.request_id.sequence_number;
|
|
97
105
|
|
|
98
106
|
if (ret == RCL_RET_OK) {
|
|
99
|
-
return Napi::Number::New(env, static_cast<
|
|
107
|
+
return Napi::Number::New(env, static_cast<double>(sequence_number));
|
|
100
108
|
}
|
|
101
109
|
|
|
102
110
|
rcl_reset_error();
|
|
@@ -120,14 +120,13 @@ Napi::Value CreateContext(const Napi::CallbackInfo& info) {
|
|
|
120
120
|
rcl_context_t* context =
|
|
121
121
|
reinterpret_cast<rcl_context_t*>(malloc(sizeof(rcl_context_t)));
|
|
122
122
|
*context = rcl_get_zero_initialized_context();
|
|
123
|
-
auto js_obj =
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
});
|
|
123
|
+
auto js_obj = RclHandle::NewInstance(env, context, nullptr, [env](void* ptr) {
|
|
124
|
+
rcl_context_t* context = reinterpret_cast<rcl_context_t*>(ptr);
|
|
125
|
+
rcl_ret_t ret = DestroyContext(env, context);
|
|
126
|
+
free(ptr);
|
|
127
|
+
THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
|
|
128
|
+
rcl_get_error_string().str);
|
|
129
|
+
});
|
|
131
130
|
|
|
132
131
|
return js_obj;
|
|
133
132
|
}
|
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
#include <rcl/error_handling.h>
|
|
18
18
|
#include <rcl/rcl.h>
|
|
19
19
|
|
|
20
|
+
#include <string>
|
|
21
|
+
|
|
20
22
|
#include "macros.h"
|
|
21
23
|
#include "rcl_handle.h"
|
|
22
24
|
#include "rcl_utilities.h"
|
|
@@ -37,9 +39,16 @@ Napi::Value CreateGuardCondition(const Napi::CallbackInfo& info) {
|
|
|
37
39
|
rcl_guard_condition_options_t gc_options =
|
|
38
40
|
rcl_guard_condition_get_default_options();
|
|
39
41
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
{
|
|
43
|
+
rcl_ret_t ret = rcl_guard_condition_init(gc, context, gc_options);
|
|
44
|
+
if (RCL_RET_OK != ret) {
|
|
45
|
+
std::string error_msg = rcl_get_error_string().str;
|
|
46
|
+
rcl_reset_error();
|
|
47
|
+
free(gc);
|
|
48
|
+
Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
|
|
49
|
+
return env.Undefined();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
43
52
|
|
|
44
53
|
auto handle = RclHandle::NewInstance(env, gc, nullptr, [env](void* ptr) {
|
|
45
54
|
rcl_guard_condition_t* gc = reinterpret_cast<rcl_guard_condition_t*>(ptr);
|
|
@@ -71,16 +71,51 @@ Napi::Value CreateLifecycleStateMachine(const Napi::CallbackInfo& info) {
|
|
|
71
71
|
const rosidl_service_type_support_t* gs =
|
|
72
72
|
GetServiceTypeSupport("lifecycle_msgs", "GetState");
|
|
73
73
|
|
|
74
|
-
#if ROS_VERSION >=
|
|
74
|
+
#if ROS_VERSION >= 5000 // ROS2 Rolling
|
|
75
75
|
rcl_lifecycle_state_machine_options_t options =
|
|
76
76
|
rcl_lifecycle_get_default_state_machine_options();
|
|
77
77
|
options.enable_com_interface = info[1].As<Napi::Boolean>().Value();
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
RclHandle* clock_handle = RclHandle::Unwrap(info[2].As<Napi::Object>());
|
|
80
|
+
rcl_clock_t* clock = reinterpret_cast<rcl_clock_t*>(clock_handle->ptr());
|
|
81
|
+
|
|
82
|
+
{
|
|
83
|
+
rcl_ret_t ret = rcl_lifecycle_state_machine_init(
|
|
84
|
+
state_machine, node, clock, pn, cs, gs, gas, gat, gtg, &options);
|
|
85
|
+
if (RCL_RET_OK != ret) {
|
|
86
|
+
std::string error_msg = rcl_get_error_string().str;
|
|
87
|
+
rcl_reset_error();
|
|
88
|
+
free(state_machine);
|
|
89
|
+
Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
|
|
90
|
+
return env.Undefined();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
auto js_obj = RclHandle::NewInstance(
|
|
95
|
+
env, state_machine, node_handle, [node, env](void* ptr) {
|
|
96
|
+
rcl_lifecycle_state_machine_t* state_machine =
|
|
97
|
+
reinterpret_cast<rcl_lifecycle_state_machine_t*>(ptr);
|
|
98
|
+
rcl_ret_t ret = rcl_lifecycle_state_machine_fini(state_machine, node);
|
|
99
|
+
free(ptr);
|
|
100
|
+
THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
|
|
101
|
+
rcl_get_error_string().str);
|
|
102
|
+
});
|
|
103
|
+
#elif ROS_VERSION >= 2105
|
|
104
|
+
rcl_lifecycle_state_machine_options_t options =
|
|
105
|
+
rcl_lifecycle_get_default_state_machine_options();
|
|
106
|
+
options.enable_com_interface = info[1].As<Napi::Boolean>().Value();
|
|
107
|
+
|
|
108
|
+
{
|
|
109
|
+
rcl_ret_t ret = rcl_lifecycle_state_machine_init(
|
|
110
|
+
state_machine, node, pn, cs, gs, gas, gat, gtg, &options);
|
|
111
|
+
if (RCL_RET_OK != ret) {
|
|
112
|
+
std::string error_msg = rcl_get_error_string().str;
|
|
113
|
+
rcl_reset_error();
|
|
114
|
+
free(state_machine);
|
|
115
|
+
Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
|
|
116
|
+
return env.Undefined();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
84
119
|
|
|
85
120
|
auto js_obj = RclHandle::NewInstance(
|
|
86
121
|
env, state_machine, node_handle, [node, env](void* ptr) {
|
|
@@ -95,11 +130,18 @@ Napi::Value CreateLifecycleStateMachine(const Napi::CallbackInfo& info) {
|
|
|
95
130
|
const rcl_node_options_t* node_options =
|
|
96
131
|
reinterpret_cast<const rcl_node_options_t*>(rcl_node_get_options(node));
|
|
97
132
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
133
|
+
{
|
|
134
|
+
rcl_ret_t ret = rcl_lifecycle_state_machine_init(
|
|
135
|
+
state_machine, node, pn, cs, gs, gas, gat, gtg, true,
|
|
136
|
+
&node_options->allocator);
|
|
137
|
+
if (RCL_RET_OK != ret) {
|
|
138
|
+
std::string error_msg = rcl_get_error_string().str;
|
|
139
|
+
rcl_reset_error();
|
|
140
|
+
free(state_machine);
|
|
141
|
+
Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
|
|
142
|
+
return env.Undefined();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
103
145
|
|
|
104
146
|
auto js_obj = RclHandle::NewInstance(
|
|
105
147
|
env, state_machine, node_handle, [node, node_options, env](void* ptr) {
|
|
@@ -224,10 +224,17 @@ Napi::Value CreateNode(const Napi::CallbackInfo& info) {
|
|
|
224
224
|
options.rosout_qos = *qos_profile;
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
227
|
+
{
|
|
228
|
+
rcl_ret_t ret = rcl_node_init(node, node_name.c_str(), name_space.c_str(),
|
|
229
|
+
context, &options);
|
|
230
|
+
if (RCL_RET_OK != ret) {
|
|
231
|
+
std::string error_msg = rcl_get_error_string().str;
|
|
232
|
+
rcl_reset_error();
|
|
233
|
+
free(node);
|
|
234
|
+
Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
|
|
235
|
+
return env.Undefined();
|
|
236
|
+
}
|
|
237
|
+
}
|
|
231
238
|
|
|
232
239
|
auto handle = RclHandle::NewInstance(env, node, nullptr, [env](void* ptr) {
|
|
233
240
|
rcl_node_t* node = reinterpret_cast<rcl_node_t*>(ptr);
|
|
@@ -51,9 +51,17 @@ Napi::Value CreatePublisher(const Napi::CallbackInfo& info) {
|
|
|
51
51
|
publisher_ops.qos = *qos_profile;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
{
|
|
55
|
+
rcl_ret_t ret = rcl_publisher_init(publisher, node, ts, topic.c_str(),
|
|
56
|
+
&publisher_ops);
|
|
57
|
+
if (RCL_RET_OK != ret) {
|
|
58
|
+
std::string error_msg = rcl_get_error_string().str;
|
|
59
|
+
rcl_reset_error();
|
|
60
|
+
free(publisher);
|
|
61
|
+
Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
|
|
62
|
+
return env.Undefined();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
57
65
|
|
|
58
66
|
auto js_obj = RclHandle::NewInstance(
|
|
59
67
|
env, publisher, node_handle, [node, env](void* ptr) {
|
|
@@ -66,6 +74,7 @@ Napi::Value CreatePublisher(const Napi::CallbackInfo& info) {
|
|
|
66
74
|
|
|
67
75
|
return js_obj;
|
|
68
76
|
} else {
|
|
77
|
+
free(publisher);
|
|
69
78
|
Napi::Error::New(env, GetErrorMessageAndClear())
|
|
70
79
|
.ThrowAsJavaScriptException();
|
|
71
80
|
return env.Undefined();
|
|
@@ -52,9 +52,17 @@ Napi::Value CreateService(const Napi::CallbackInfo& info) {
|
|
|
52
52
|
service_ops.qos = *qos_profile;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
{
|
|
56
|
+
rcl_ret_t ret = rcl_service_init(service, node, ts, service_name.c_str(),
|
|
57
|
+
&service_ops);
|
|
58
|
+
if (RCL_RET_OK != ret) {
|
|
59
|
+
std::string error_msg = rcl_get_error_string().str;
|
|
60
|
+
rcl_reset_error();
|
|
61
|
+
free(service);
|
|
62
|
+
Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
|
|
63
|
+
return env.Undefined();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
58
66
|
auto js_obj = RclHandle::NewInstance(
|
|
59
67
|
env, service, node_handle, [node, env](void* ptr) {
|
|
60
68
|
rcl_service_t* service = reinterpret_cast<rcl_service_t*>(ptr);
|
|
@@ -88,6 +96,7 @@ Napi::Value RclTakeRequest(const Napi::CallbackInfo& info) {
|
|
|
88
96
|
return js_obj;
|
|
89
97
|
}
|
|
90
98
|
|
|
99
|
+
free(header);
|
|
91
100
|
return env.Undefined();
|
|
92
101
|
}
|
|
93
102
|
|
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
|
|
20
20
|
#include <cstdio>
|
|
21
21
|
#include <memory>
|
|
22
|
+
#include <rcpputils/scope_exit.hpp>
|
|
23
|
+
// NOLINTNEXTLINE
|
|
22
24
|
#include <string>
|
|
23
25
|
|
|
24
26
|
#include "macros.h"
|
|
@@ -108,12 +110,6 @@ Napi::Value CreateSubscription(const Napi::CallbackInfo& info) {
|
|
|
108
110
|
rcl_ret_t ret = rcl_subscription_options_set_content_filter_options(
|
|
109
111
|
expression.c_str(), argc, (const char**)argv, &subscription_ops);
|
|
110
112
|
|
|
111
|
-
if (ret != RCL_RET_OK) {
|
|
112
|
-
std::string error_string = rcl_get_error_string().str;
|
|
113
|
-
rcl_reset_error();
|
|
114
|
-
Napi::Error::New(env, error_string).ThrowAsJavaScriptException();
|
|
115
|
-
}
|
|
116
|
-
|
|
117
113
|
if (argc) {
|
|
118
114
|
for (int i = 0; i < argc; i++) {
|
|
119
115
|
free(argv[i]);
|
|
@@ -122,7 +118,10 @@ Napi::Value CreateSubscription(const Napi::CallbackInfo& info) {
|
|
|
122
118
|
}
|
|
123
119
|
|
|
124
120
|
if (ret != RCL_RET_OK) {
|
|
121
|
+
std::string error_string = rcl_get_error_string().str;
|
|
122
|
+
rcl_reset_error();
|
|
125
123
|
free(subscription);
|
|
124
|
+
Napi::Error::New(env, error_string).ThrowAsJavaScriptException();
|
|
126
125
|
return env.Undefined();
|
|
127
126
|
}
|
|
128
127
|
}
|
|
@@ -137,8 +136,8 @@ Napi::Value CreateSubscription(const Napi::CallbackInfo& info) {
|
|
|
137
136
|
if (ret != RCL_RET_OK) {
|
|
138
137
|
std::string error_msg = rcl_get_error_string().str;
|
|
139
138
|
rcl_reset_error();
|
|
140
|
-
Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
|
|
141
139
|
free(subscription);
|
|
140
|
+
Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
|
|
142
141
|
return env.Undefined();
|
|
143
142
|
}
|
|
144
143
|
|
|
@@ -157,9 +156,9 @@ Napi::Value CreateSubscription(const Napi::CallbackInfo& info) {
|
|
|
157
156
|
|
|
158
157
|
return js_obj;
|
|
159
158
|
} else {
|
|
160
|
-
|
|
161
|
-
.ThrowAsJavaScriptException();
|
|
159
|
+
std::string error_msg = GetErrorMessageAndClear();
|
|
162
160
|
free(subscription);
|
|
161
|
+
Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
|
|
163
162
|
return env.Undefined();
|
|
164
163
|
}
|
|
165
164
|
}
|
|
@@ -194,10 +193,16 @@ Napi::Value RclTakeRaw(const Napi::CallbackInfo& info) {
|
|
|
194
193
|
return env.Undefined();
|
|
195
194
|
}
|
|
196
195
|
|
|
196
|
+
RCPPUTILS_SCOPE_EXIT({
|
|
197
|
+
rcl_ret_t fini_ret = rmw_serialized_message_fini(&msg);
|
|
198
|
+
if (fini_ret != RCL_RET_OK) {
|
|
199
|
+
rcl_reset_error();
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
|
|
197
203
|
Napi::Buffer<char> buffer = Napi::Buffer<char>::Copy(
|
|
198
204
|
env, reinterpret_cast<char*>(msg.buffer), msg.buffer_length);
|
|
199
|
-
|
|
200
|
-
"Failed to deallocate message buffer");
|
|
205
|
+
|
|
201
206
|
return buffer;
|
|
202
207
|
}
|
|
203
208
|
|
|
@@ -369,6 +374,14 @@ Napi::Value GetContentFilter(const Napi::CallbackInfo& info) {
|
|
|
369
374
|
return env.Undefined();
|
|
370
375
|
}
|
|
371
376
|
|
|
377
|
+
RCPPUTILS_SCOPE_EXIT({
|
|
378
|
+
rcl_ret_t fini_ret =
|
|
379
|
+
rcl_subscription_content_filter_options_fini(subscription, &options);
|
|
380
|
+
if (fini_ret != RCL_RET_OK) {
|
|
381
|
+
rcl_reset_error();
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
|
|
372
385
|
// Create result object
|
|
373
386
|
Napi::Object result = Napi::Object::New(env);
|
|
374
387
|
result.Set(
|
|
@@ -387,16 +400,6 @@ Napi::Value GetContentFilter(const Napi::CallbackInfo& info) {
|
|
|
387
400
|
}
|
|
388
401
|
result.Set("parameters", parameters);
|
|
389
402
|
|
|
390
|
-
// Cleanup
|
|
391
|
-
rcl_ret_t fini_ret =
|
|
392
|
-
rcl_subscription_content_filter_options_fini(subscription, &options);
|
|
393
|
-
if (fini_ret != RCL_RET_OK) {
|
|
394
|
-
std::string error_msg = rcl_get_error_string().str;
|
|
395
|
-
rcl_reset_error();
|
|
396
|
-
Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
|
|
397
|
-
return env.Undefined();
|
|
398
|
-
}
|
|
399
|
-
|
|
400
403
|
return result;
|
|
401
404
|
}
|
|
402
405
|
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
#include <memory>
|
|
21
21
|
#include <mutex>
|
|
22
|
+
#include <string>
|
|
22
23
|
#include <unordered_map>
|
|
23
24
|
|
|
24
25
|
#include "macros.h"
|
|
@@ -82,16 +83,30 @@ Napi::Value CreateTimer(const Napi::CallbackInfo& info) {
|
|
|
82
83
|
*timer = rcl_get_zero_initialized_timer();
|
|
83
84
|
|
|
84
85
|
#if ROS_VERSION > 2305 // After Iron.
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
{
|
|
87
|
+
rcl_ret_t ret = rcl_timer_init2(timer, clock, context, period_nsec, nullptr,
|
|
88
|
+
rcl_get_default_allocator(),
|
|
89
|
+
/*autostart=*/true);
|
|
90
|
+
if (RCL_RET_OK != ret) {
|
|
91
|
+
std::string error_msg = rcl_get_error_string().str;
|
|
92
|
+
rcl_reset_error();
|
|
93
|
+
free(timer);
|
|
94
|
+
Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
|
|
95
|
+
return env.Undefined();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
90
98
|
#else
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
99
|
+
{
|
|
100
|
+
rcl_ret_t ret = rcl_timer_init(timer, clock, context, period_nsec, nullptr,
|
|
101
|
+
rcl_get_default_allocator());
|
|
102
|
+
if (RCL_RET_OK != ret) {
|
|
103
|
+
std::string error_msg = rcl_get_error_string().str;
|
|
104
|
+
rcl_reset_error();
|
|
105
|
+
free(timer);
|
|
106
|
+
Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
|
|
107
|
+
return env.Undefined();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
95
110
|
#endif
|
|
96
111
|
|
|
97
112
|
auto js_obj =
|
|
@@ -15,9 +15,12 @@
|
|
|
15
15
|
#include "rcl_type_description_service_bindings.h"
|
|
16
16
|
|
|
17
17
|
#include <napi.h>
|
|
18
|
+
#include <rcl/error_handling.h>
|
|
18
19
|
#include <rcl/rcl.h>
|
|
19
20
|
#include <rmw/types.h>
|
|
20
21
|
|
|
22
|
+
#include <string>
|
|
23
|
+
|
|
21
24
|
#include "rcl_handle.h"
|
|
22
25
|
|
|
23
26
|
namespace rclnodejs {
|
|
@@ -31,8 +34,13 @@ Napi::Value InitTypeDescriptionService(const Napi::CallbackInfo& info) {
|
|
|
31
34
|
*service = rcl_get_zero_initialized_service();
|
|
32
35
|
rcl_ret_t ret = rcl_node_type_description_service_init(service, node);
|
|
33
36
|
if (RCL_RET_OK != ret) {
|
|
34
|
-
|
|
37
|
+
std::string error_msg = rcl_get_error_string().str;
|
|
38
|
+
rcl_reset_error();
|
|
39
|
+
free(service);
|
|
40
|
+
Napi::Error::New(
|
|
41
|
+
env, "Failed to initialize type description service: " + error_msg)
|
|
35
42
|
.ThrowAsJavaScriptException();
|
|
43
|
+
return env.Undefined();
|
|
36
44
|
}
|
|
37
45
|
|
|
38
46
|
auto service_handle =
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// Data integrity + throughput test for subscription
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const rclnodejs = require('./index.js');
|
|
5
|
+
|
|
6
|
+
const PUBLISH_HZ = 50;
|
|
7
|
+
const TEST_DURATION_SEC = 10;
|
|
8
|
+
|
|
9
|
+
async function main() {
|
|
10
|
+
await rclnodejs.init();
|
|
11
|
+
|
|
12
|
+
const pubNode = new rclnodejs.Node('data_pub_node');
|
|
13
|
+
const subNode = new rclnodejs.Node('data_sub_node');
|
|
14
|
+
|
|
15
|
+
const publisher = pubNode.createPublisher(
|
|
16
|
+
'std_msgs/msg/Float64MultiArray',
|
|
17
|
+
'/data_integrity_topic'
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
let msgCount = 0;
|
|
21
|
+
let errCount = 0;
|
|
22
|
+
let lastTs = null;
|
|
23
|
+
const hzSamples = [];
|
|
24
|
+
const errors = [];
|
|
25
|
+
|
|
26
|
+
subNode.createSubscription(
|
|
27
|
+
'std_msgs/msg/Float64MultiArray',
|
|
28
|
+
'/data_integrity_topic',
|
|
29
|
+
(msg) => {
|
|
30
|
+
const now = Date.now();
|
|
31
|
+
msgCount++;
|
|
32
|
+
|
|
33
|
+
// --- Data validation ---
|
|
34
|
+
// Each published message has data = [seqNo, seqNo*1.5, seqNo*2.5]
|
|
35
|
+
// Verify structure and values
|
|
36
|
+
if (!msg || !msg.data) {
|
|
37
|
+
errCount++;
|
|
38
|
+
errors.push(`msg#${msgCount}: missing data field, got: ${JSON.stringify(msg)}`);
|
|
39
|
+
} else if (!Array.isArray(msg.data) && !(msg.data instanceof Float64Array)) {
|
|
40
|
+
errCount++;
|
|
41
|
+
errors.push(`msg#${msgCount}: data is not array-like, type=${typeof msg.data}`);
|
|
42
|
+
} else if (msg.data.length !== 3) {
|
|
43
|
+
errCount++;
|
|
44
|
+
errors.push(`msg#${msgCount}: expected 3 elements, got ${msg.data.length}`);
|
|
45
|
+
} else {
|
|
46
|
+
const seqNo = msg.data[0];
|
|
47
|
+
const expectedB = seqNo * 1.5;
|
|
48
|
+
const expectedC = seqNo * 2.5;
|
|
49
|
+
|
|
50
|
+
if (Math.abs(msg.data[1] - expectedB) > 1e-9) {
|
|
51
|
+
errCount++;
|
|
52
|
+
errors.push(
|
|
53
|
+
`msg#${msgCount}: data[1] expected ${expectedB}, got ${msg.data[1]}`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
if (Math.abs(msg.data[2] - expectedC) > 1e-9) {
|
|
57
|
+
errCount++;
|
|
58
|
+
errors.push(
|
|
59
|
+
`msg#${msgCount}: data[2] expected ${expectedC}, got ${msg.data[2]}`
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (lastTs) {
|
|
65
|
+
hzSamples.push(1000 / (now - lastTs));
|
|
66
|
+
}
|
|
67
|
+
lastTs = now;
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
pubNode.spin();
|
|
72
|
+
subNode.spin();
|
|
73
|
+
|
|
74
|
+
let pubSeq = 0;
|
|
75
|
+
const pubInterval = setInterval(() => {
|
|
76
|
+
pubSeq++;
|
|
77
|
+
publisher.publish({ data: [pubSeq, pubSeq * 1.5, pubSeq * 2.5] });
|
|
78
|
+
}, 1000 / PUBLISH_HZ);
|
|
79
|
+
|
|
80
|
+
setTimeout(() => {
|
|
81
|
+
clearInterval(pubInterval);
|
|
82
|
+
|
|
83
|
+
console.log(`\n=== Data Integrity Test Results ===`);
|
|
84
|
+
console.log(`Published: ${pubSeq} messages at ${PUBLISH_HZ} Hz`);
|
|
85
|
+
console.log(`Received: ${msgCount} messages`);
|
|
86
|
+
console.log(`Data errors: ${errCount}`);
|
|
87
|
+
|
|
88
|
+
if (errors.length > 0) {
|
|
89
|
+
console.log(`\nFirst 10 errors:`);
|
|
90
|
+
errors.slice(0, 10).forEach((e) => console.log(` ${e}`));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (hzSamples.length > 0) {
|
|
94
|
+
const avgHz = hzSamples.reduce((a, b) => a + b, 0) / hzSamples.length;
|
|
95
|
+
console.log(`\nAvg Hz: ${avgHz.toFixed(2)}`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const pass = errCount === 0 && msgCount > 0;
|
|
99
|
+
console.log(`\nResult: ${pass ? 'PASS - all data correct' : 'FAIL'}`);
|
|
100
|
+
|
|
101
|
+
pubNode.stop();
|
|
102
|
+
subNode.stop();
|
|
103
|
+
rclnodejs.shutdown();
|
|
104
|
+
process.exit(pass ? 0 : 1);
|
|
105
|
+
}, TEST_DURATION_SEC * 1000);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
main().catch(console.error);
|