rclnodejs 1.1.0 → 1.3.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 +5 -0
- package/index.js +26 -3
- package/lib/context.js +4 -2
- package/lib/event_handler.js +474 -0
- package/lib/lifecycle.js +9 -0
- package/lib/lifecycle_publisher.js +2 -2
- package/lib/node.js +163 -28
- package/lib/publisher.js +31 -4
- package/lib/serialization.js +60 -0
- package/lib/subscription.js +48 -4
- package/lib/type_description_service.js +27 -1
- package/package.json +1 -1
- package/rosidl_gen/templates/message.dot +1 -1
- package/scripts/npmjs-readme.md +4 -4
- package/src/addon.cpp +4 -0
- package/src/executor.cpp +3 -4
- package/src/handle_manager.cpp +13 -2
- package/src/handle_manager.h +4 -1
- package/src/macros.h +17 -1
- package/src/rcl_action_client_bindings.cpp +3 -2
- package/src/rcl_action_goal_bindings.cpp +3 -2
- package/src/rcl_action_server_bindings.cpp +7 -5
- package/src/rcl_client_bindings.cpp +4 -3
- package/src/rcl_context_bindings.cpp +29 -19
- package/src/rcl_event_handle_bindings.cpp +294 -0
- package/src/rcl_event_handle_bindings.h +26 -0
- package/src/rcl_guard_condition_bindings.cpp +3 -2
- package/src/rcl_lifecycle_bindings.cpp +18 -4
- package/src/rcl_node_bindings.cpp +111 -3
- package/src/rcl_publisher_bindings.cpp +4 -3
- package/src/rcl_serialization_bindings.cpp +116 -0
- package/src/rcl_serialization_bindings.h +26 -0
- package/src/rcl_service_bindings.cpp +4 -3
- package/src/rcl_subscription_bindings.cpp +3 -2
- package/src/rcl_time_point_bindings.cpp +3 -2
- package/src/rcl_timer_bindings.cpp +8 -6
- package/src/rcl_utilities.cpp +31 -0
- package/src/rcl_utilities.h +7 -0
- package/tsconfig.json +2 -2
- package/types/context.d.ts +3 -2
- package/types/index.d.ts +26 -1
- package/types/lifecycle.d.ts +7 -0
- package/types/node.d.ts +60 -10
|
@@ -83,12 +83,13 @@ Napi::Value CreateLifecycleStateMachine(const Napi::CallbackInfo& info) {
|
|
|
83
83
|
rcl_get_error_string().str);
|
|
84
84
|
|
|
85
85
|
auto js_obj = RclHandle::NewInstance(
|
|
86
|
-
env, state_machine, node_handle, [node](void* ptr) {
|
|
86
|
+
env, state_machine, node_handle, [node, env](void* ptr) {
|
|
87
87
|
rcl_lifecycle_state_machine_t* state_machine =
|
|
88
88
|
reinterpret_cast<rcl_lifecycle_state_machine_t*>(ptr);
|
|
89
89
|
rcl_ret_t ret = rcl_lifecycle_state_machine_fini(state_machine, node);
|
|
90
90
|
free(ptr);
|
|
91
|
-
|
|
91
|
+
THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
|
|
92
|
+
rcl_get_error_string().str);
|
|
92
93
|
});
|
|
93
94
|
#else
|
|
94
95
|
const rcl_node_options_t* node_options =
|
|
@@ -101,13 +102,14 @@ Napi::Value CreateLifecycleStateMachine(const Napi::CallbackInfo& info) {
|
|
|
101
102
|
rcl_get_error_string().str);
|
|
102
103
|
|
|
103
104
|
auto js_obj = RclHandle::NewInstance(
|
|
104
|
-
env, state_machine, node_handle, [node, node_options](void* ptr) {
|
|
105
|
+
env, state_machine, node_handle, [node, node_options, env](void* ptr) {
|
|
105
106
|
rcl_lifecycle_state_machine_t* state_machine =
|
|
106
107
|
reinterpret_cast<rcl_lifecycle_state_machine_t*>(ptr);
|
|
107
108
|
rcl_ret_t ret = rcl_lifecycle_state_machine_fini(
|
|
108
109
|
state_machine, node, &node_options->allocator);
|
|
109
110
|
free(ptr);
|
|
110
|
-
|
|
111
|
+
THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
|
|
112
|
+
rcl_get_error_string().str);
|
|
111
113
|
});
|
|
112
114
|
#endif
|
|
113
115
|
|
|
@@ -372,6 +374,17 @@ Napi::Value IsInitialized(const Napi::CallbackInfo& info) {
|
|
|
372
374
|
return Napi::Boolean::New(env, is_initialized);
|
|
373
375
|
}
|
|
374
376
|
|
|
377
|
+
Napi::Value Print(const Napi::CallbackInfo& info) {
|
|
378
|
+
Napi::Env env = info.Env();
|
|
379
|
+
RclHandle* state_machine_handle =
|
|
380
|
+
RclHandle::Unwrap(info[0].As<Napi::Object>());
|
|
381
|
+
rcl_lifecycle_state_machine_t* state_machine =
|
|
382
|
+
reinterpret_cast<rcl_lifecycle_state_machine_t*>(
|
|
383
|
+
state_machine_handle->ptr());
|
|
384
|
+
rcl_print_state_machine(state_machine);
|
|
385
|
+
return env.Undefined();
|
|
386
|
+
}
|
|
387
|
+
|
|
375
388
|
Napi::Object InitLifecycleBindings(Napi::Env env, Napi::Object exports) {
|
|
376
389
|
exports.Set("createLifecycleStateMachine",
|
|
377
390
|
Napi::Function::New(env, CreateLifecycleStateMachine));
|
|
@@ -396,6 +409,7 @@ Napi::Object InitLifecycleBindings(Napi::Env env, Napi::Object exports) {
|
|
|
396
409
|
exports.Set("getLifecycleShutdownTransitionLabel",
|
|
397
410
|
Napi::Function::New(env, GetLifecycleShutdownTransitionLabel));
|
|
398
411
|
exports.Set("isInitialized", Napi::Function::New(env, IsInitialized));
|
|
412
|
+
exports.Set("print", Napi::Function::New(env, Print));
|
|
399
413
|
return exports;
|
|
400
414
|
}
|
|
401
415
|
|
|
@@ -20,10 +20,13 @@
|
|
|
20
20
|
#include <rcl/arguments.h>
|
|
21
21
|
#include <rcl/error_handling.h>
|
|
22
22
|
#include <rcl/rcl.h>
|
|
23
|
+
#include <rcl/remap.h>
|
|
23
24
|
#include <rcl_action/rcl_action.h>
|
|
24
25
|
#include <rcl_yaml_param_parser/parser.h>
|
|
25
26
|
#include <rcl_yaml_param_parser/types.h>
|
|
26
27
|
|
|
28
|
+
#include <rcpputils/scope_exit.hpp>
|
|
29
|
+
// NOLINTNEXTLINE
|
|
27
30
|
#include <string>
|
|
28
31
|
|
|
29
32
|
#include "macros.h"
|
|
@@ -180,21 +183,46 @@ Napi::Value CreateNode(const Napi::CallbackInfo& info) {
|
|
|
180
183
|
rcl_context_t* context =
|
|
181
184
|
reinterpret_cast<rcl_context_t*>(context_handle->ptr());
|
|
182
185
|
|
|
183
|
-
|
|
186
|
+
Napi::Array jsArgv = info[3].As<Napi::Array>();
|
|
187
|
+
size_t argc = jsArgv.Length();
|
|
188
|
+
char** argv = AbstractArgsFromNapiArray(jsArgv);
|
|
189
|
+
RCPPUTILS_SCOPE_EXIT({ FreeArgs(argv, argc); });
|
|
190
|
+
|
|
191
|
+
rcl_arguments_t arguments = rcl_get_zero_initialized_arguments();
|
|
192
|
+
rcl_ret_t ret =
|
|
193
|
+
rcl_parse_arguments(argc, argv, rcl_get_default_allocator(), &arguments);
|
|
194
|
+
if ((ret != RCL_RET_OK) || HasUnparsedROSArgs(arguments)) {
|
|
195
|
+
Napi::Error::New(env, "failed to parse arguments")
|
|
196
|
+
.ThrowAsJavaScriptException();
|
|
197
|
+
return env.Undefined();
|
|
198
|
+
}
|
|
184
199
|
|
|
200
|
+
RCPPUTILS_SCOPE_EXIT({
|
|
201
|
+
if (RCL_RET_OK != rcl_arguments_fini(&arguments)) {
|
|
202
|
+
Napi::Error::New(env, "failed to fini arguments")
|
|
203
|
+
.ThrowAsJavaScriptException();
|
|
204
|
+
rcl_reset_error();
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
bool use_global_arguments = info[4].As<Napi::Boolean>().Value();
|
|
208
|
+
rcl_node_t* node = reinterpret_cast<rcl_node_t*>(malloc(sizeof(rcl_node_t)));
|
|
185
209
|
*node = rcl_get_zero_initialized_node();
|
|
210
|
+
|
|
186
211
|
rcl_node_options_t options = rcl_node_get_default_options();
|
|
212
|
+
options.use_global_arguments = use_global_arguments;
|
|
213
|
+
options.arguments = arguments;
|
|
187
214
|
|
|
188
215
|
THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK,
|
|
189
216
|
rcl_node_init(node, node_name.c_str(),
|
|
190
217
|
name_space.c_str(), context, &options),
|
|
191
218
|
rcl_get_error_string().str);
|
|
192
219
|
|
|
193
|
-
auto handle = RclHandle::NewInstance(env, node, nullptr, [](void* ptr) {
|
|
220
|
+
auto handle = RclHandle::NewInstance(env, node, nullptr, [env](void* ptr) {
|
|
194
221
|
rcl_node_t* node = reinterpret_cast<rcl_node_t*>(ptr);
|
|
195
222
|
rcl_ret_t ret = rcl_node_fini(node);
|
|
196
223
|
free(ptr);
|
|
197
|
-
|
|
224
|
+
THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
|
|
225
|
+
rcl_get_error_string().str);
|
|
198
226
|
});
|
|
199
227
|
|
|
200
228
|
return handle;
|
|
@@ -446,6 +474,82 @@ Napi::Value GetFullyQualifiedName(const Napi::CallbackInfo& info) {
|
|
|
446
474
|
return Napi::String::New(env, fully_qualified_node_name);
|
|
447
475
|
}
|
|
448
476
|
|
|
477
|
+
Napi::Value GetRMWImplementationIdentifier(const Napi::CallbackInfo& info) {
|
|
478
|
+
return Napi::String::New(info.Env(), rmw_get_implementation_identifier());
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
Napi::Value ResolveName(const Napi::CallbackInfo& info) {
|
|
482
|
+
Napi::Env env = info.Env();
|
|
483
|
+
|
|
484
|
+
RclHandle* node_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
|
|
485
|
+
rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
|
|
486
|
+
const rcl_node_options_t* node_options = rcl_node_get_options(node);
|
|
487
|
+
std::string topic_name = info[1].As<Napi::String>().Utf8Value();
|
|
488
|
+
bool only_expand = info[2].As<Napi::Boolean>().Value();
|
|
489
|
+
bool is_service = info[3].As<Napi::Boolean>().Value();
|
|
490
|
+
|
|
491
|
+
char* output_cstr = nullptr;
|
|
492
|
+
rcl_ret_t ret =
|
|
493
|
+
rcl_node_resolve_name(node, topic_name.c_str(), node_options->allocator,
|
|
494
|
+
is_service, only_expand, &output_cstr);
|
|
495
|
+
|
|
496
|
+
auto name_deleter = [&]() {
|
|
497
|
+
node_options->allocator.deallocate(output_cstr,
|
|
498
|
+
node_options->allocator.state);
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
RCPPUTILS_SCOPE_EXIT({ name_deleter(); });
|
|
502
|
+
|
|
503
|
+
if (RCL_RET_OK != ret) {
|
|
504
|
+
Napi::Error::New(env, ("failed to resolve name"))
|
|
505
|
+
.ThrowAsJavaScriptException();
|
|
506
|
+
return env.Undefined();
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
return Napi::String::New(env, output_cstr);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
Napi::Value RemapTopicName(const Napi::CallbackInfo& info) {
|
|
513
|
+
Napi::Env env = info.Env();
|
|
514
|
+
RclHandle* node_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
|
|
515
|
+
rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
|
|
516
|
+
std::string topic_name = info[1].As<Napi::String>().Utf8Value();
|
|
517
|
+
|
|
518
|
+
const rcl_node_options_t* node_options = rcl_node_get_options(node);
|
|
519
|
+
if (nullptr == node_options) {
|
|
520
|
+
Napi::Error::New(env, "failed to get node options")
|
|
521
|
+
.ThrowAsJavaScriptException();
|
|
522
|
+
return env.Undefined();
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
const rcl_arguments_t* global_args = nullptr;
|
|
526
|
+
if (node_options->use_global_arguments) {
|
|
527
|
+
global_args = &(node->context->global_arguments);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
char* output_cstr = nullptr;
|
|
531
|
+
rcl_ret_t ret = rcl_remap_topic_name(
|
|
532
|
+
&(node_options->arguments), global_args, topic_name.c_str(),
|
|
533
|
+
rcl_node_get_name(node), rcl_node_get_namespace(node),
|
|
534
|
+
node_options->allocator, &output_cstr);
|
|
535
|
+
if (RCL_RET_OK != ret) {
|
|
536
|
+
Napi::Error::New(env, "failed to remap topic name")
|
|
537
|
+
.ThrowAsJavaScriptException();
|
|
538
|
+
return env.Undefined();
|
|
539
|
+
}
|
|
540
|
+
if (nullptr == output_cstr) {
|
|
541
|
+
return Napi::String::New(env, topic_name);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
auto name_deleter = [&]() {
|
|
545
|
+
node_options->allocator.deallocate(output_cstr,
|
|
546
|
+
node_options->allocator.state);
|
|
547
|
+
};
|
|
548
|
+
RCPPUTILS_SCOPE_EXIT({ name_deleter(); });
|
|
549
|
+
|
|
550
|
+
return Napi::String::New(env, output_cstr);
|
|
551
|
+
}
|
|
552
|
+
|
|
449
553
|
Napi::Object InitNodeBindings(Napi::Env env, Napi::Object exports) {
|
|
450
554
|
exports.Set("getParameterOverrides",
|
|
451
555
|
Napi::Function::New(env, GetParameterOverrides));
|
|
@@ -468,6 +572,10 @@ Napi::Object InitNodeBindings(Napi::Env env, Napi::Object exports) {
|
|
|
468
572
|
exports.Set("getNodeNames", Napi::Function::New(env, GetNodeNames));
|
|
469
573
|
exports.Set("getFullyQualifiedName",
|
|
470
574
|
Napi::Function::New(env, GetFullyQualifiedName));
|
|
575
|
+
exports.Set("getRMWImplementationIdentifier",
|
|
576
|
+
Napi::Function::New(env, GetRMWImplementationIdentifier));
|
|
577
|
+
exports.Set("resolveName", Napi::Function::New(env, ResolveName));
|
|
578
|
+
exports.Set("remapTopicName", Napi::Function::New(env, RemapTopicName));
|
|
471
579
|
return exports;
|
|
472
580
|
}
|
|
473
581
|
|
|
@@ -55,12 +55,13 @@ Napi::Value CreatePublisher(const Napi::CallbackInfo& info) {
|
|
|
55
55
|
rcl_publisher_init(publisher, node, ts, topic.c_str(), &publisher_ops),
|
|
56
56
|
RCL_RET_OK, rcl_get_error_string().str);
|
|
57
57
|
|
|
58
|
-
auto js_obj =
|
|
59
|
-
|
|
58
|
+
auto js_obj = RclHandle::NewInstance(
|
|
59
|
+
env, publisher, node_handle, [node, env](void* ptr) {
|
|
60
60
|
rcl_publisher_t* publisher = reinterpret_cast<rcl_publisher_t*>(ptr);
|
|
61
61
|
rcl_ret_t ret = rcl_publisher_fini(publisher, node);
|
|
62
62
|
free(ptr);
|
|
63
|
-
|
|
63
|
+
THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
|
|
64
|
+
rcl_get_error_string().str);
|
|
64
65
|
});
|
|
65
66
|
|
|
66
67
|
return js_obj;
|
|
@@ -0,0 +1,116 @@
|
|
|
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_serialization_bindings.h"
|
|
16
|
+
|
|
17
|
+
#include <rmw/rmw.h>
|
|
18
|
+
#include <rmw/serialized_message.h>
|
|
19
|
+
#include <rosidl_runtime_c/message_type_support_struct.h>
|
|
20
|
+
|
|
21
|
+
#include <string>
|
|
22
|
+
|
|
23
|
+
#include "rcl_utilities.h"
|
|
24
|
+
|
|
25
|
+
namespace {
|
|
26
|
+
|
|
27
|
+
struct SerializedMessage {
|
|
28
|
+
explicit SerializedMessage(Napi::Env env, rcutils_allocator_t allocator)
|
|
29
|
+
: env(env) {
|
|
30
|
+
rcl_msg = rmw_get_zero_initialized_serialized_message();
|
|
31
|
+
rcutils_ret_t rcutils_ret =
|
|
32
|
+
rmw_serialized_message_init(&rcl_msg, 0u, &allocator);
|
|
33
|
+
if (RCUTILS_RET_OK != rcutils_ret) {
|
|
34
|
+
Napi::Error::New(env, "failed to initialize serialized message")
|
|
35
|
+
.ThrowAsJavaScriptException();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
~SerializedMessage() {
|
|
40
|
+
rcutils_ret_t ret = rmw_serialized_message_fini(&rcl_msg);
|
|
41
|
+
if (RCUTILS_RET_OK != ret) {
|
|
42
|
+
Napi::Error::New(env,
|
|
43
|
+
"failed to fini rcl_serialized_msg_t in destructor.")
|
|
44
|
+
.ThrowAsJavaScriptException();
|
|
45
|
+
rcutils_reset_error();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
rcl_serialized_message_t rcl_msg;
|
|
50
|
+
Napi::Env env;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
} // namespace
|
|
54
|
+
|
|
55
|
+
namespace rclnodejs {
|
|
56
|
+
|
|
57
|
+
Napi::Value Serialize(const Napi::CallbackInfo& info) {
|
|
58
|
+
Napi::Env env = info.Env();
|
|
59
|
+
|
|
60
|
+
std::string package_name = info[0].As<Napi::String>().Utf8Value();
|
|
61
|
+
std::string message_sub_folder = info[1].As<Napi::String>().Utf8Value();
|
|
62
|
+
std::string message_name = info[2].As<Napi::String>().Utf8Value();
|
|
63
|
+
void* ros_msg = info[3].As<Napi::Buffer<char>>().Data();
|
|
64
|
+
const rosidl_message_type_support_t* ts =
|
|
65
|
+
GetMessageTypeSupport(package_name, message_sub_folder, message_name);
|
|
66
|
+
|
|
67
|
+
// Create a serialized message object.
|
|
68
|
+
SerializedMessage serialized_msg(env, rcutils_get_default_allocator());
|
|
69
|
+
|
|
70
|
+
rmw_ret_t rmw_ret = rmw_serialize(ros_msg, ts, &serialized_msg.rcl_msg);
|
|
71
|
+
if (RMW_RET_OK != rmw_ret) {
|
|
72
|
+
Napi::Error::New(env, "Failed to serialize ROS message")
|
|
73
|
+
.ThrowAsJavaScriptException();
|
|
74
|
+
return env.Undefined();
|
|
75
|
+
}
|
|
76
|
+
Napi::Buffer<char> buffer = Napi::Buffer<char>::Copy(
|
|
77
|
+
env, reinterpret_cast<const char*>(serialized_msg.rcl_msg.buffer),
|
|
78
|
+
serialized_msg.rcl_msg.buffer_length);
|
|
79
|
+
return buffer;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
Napi::Value Deserialize(const Napi::CallbackInfo& info) {
|
|
83
|
+
Napi::Env env = info.Env();
|
|
84
|
+
|
|
85
|
+
std::string package_name = info[0].As<Napi::String>().Utf8Value();
|
|
86
|
+
std::string message_sub_folder = info[1].As<Napi::String>().Utf8Value();
|
|
87
|
+
std::string message_name = info[2].As<Napi::String>().Utf8Value();
|
|
88
|
+
const rosidl_message_type_support_t* ts =
|
|
89
|
+
GetMessageTypeSupport(package_name, message_sub_folder, message_name);
|
|
90
|
+
Napi::Buffer<char> serialized = info[3].As<Napi::Buffer<char>>();
|
|
91
|
+
void* msg_taken = info[4].As<Napi::Buffer<char>>().Data();
|
|
92
|
+
|
|
93
|
+
// Create a serialized message object.
|
|
94
|
+
rcl_serialized_message_t serialized_msg =
|
|
95
|
+
rmw_get_zero_initialized_serialized_message();
|
|
96
|
+
serialized_msg.buffer_capacity = serialized.Length();
|
|
97
|
+
serialized_msg.buffer_length = serialized.Length();
|
|
98
|
+
serialized_msg.buffer = reinterpret_cast<uint8_t*>(serialized.Data());
|
|
99
|
+
|
|
100
|
+
rmw_ret_t rmw_ret = rmw_deserialize(&serialized_msg, ts, msg_taken);
|
|
101
|
+
|
|
102
|
+
if (RMW_RET_OK != rmw_ret) {
|
|
103
|
+
Napi::Error::New(env, "failed to deserialize ROS message")
|
|
104
|
+
.ThrowAsJavaScriptException();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return env.Undefined();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
Napi::Object InitSerializationBindings(Napi::Env env, Napi::Object exports) {
|
|
111
|
+
exports.Set("serialize", Napi::Function::New(env, Serialize));
|
|
112
|
+
exports.Set("deserialize", Napi::Function::New(env, Deserialize));
|
|
113
|
+
return exports;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
} // 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_SERIALIZATION_BINDINGS_H_
|
|
16
|
+
#define SRC_RCL_SERIALIZATION_BINDINGS_H_
|
|
17
|
+
|
|
18
|
+
#include <napi.h>
|
|
19
|
+
|
|
20
|
+
namespace rclnodejs {
|
|
21
|
+
|
|
22
|
+
Napi::Object InitSerializationBindings(Napi::Env env, Napi::Object exports);
|
|
23
|
+
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
#endif // SRC_RCL_SERIALIZATION_BINDINGS_H_
|
|
@@ -55,12 +55,13 @@ Napi::Value CreateService(const Napi::CallbackInfo& info) {
|
|
|
55
55
|
THROW_ERROR_IF_NOT_EQUAL(
|
|
56
56
|
rcl_service_init(service, node, ts, service_name.c_str(), &service_ops),
|
|
57
57
|
RCL_RET_OK, rcl_get_error_string().str);
|
|
58
|
-
auto js_obj =
|
|
59
|
-
|
|
58
|
+
auto js_obj = RclHandle::NewInstance(
|
|
59
|
+
env, service, node_handle, [node, env](void* ptr) {
|
|
60
60
|
rcl_service_t* service = reinterpret_cast<rcl_service_t*>(ptr);
|
|
61
61
|
rcl_ret_t ret = rcl_service_fini(service, node);
|
|
62
62
|
free(ptr);
|
|
63
|
-
|
|
63
|
+
THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
|
|
64
|
+
rcl_get_error_string().str);
|
|
64
65
|
});
|
|
65
66
|
|
|
66
67
|
return js_obj;
|
|
@@ -136,12 +136,13 @@ Napi::Value CreateSubscription(const Napi::CallbackInfo& info) {
|
|
|
136
136
|
rcl_get_error_string().str);
|
|
137
137
|
|
|
138
138
|
auto js_obj = RclHandle::NewInstance(
|
|
139
|
-
env, subscription, node_handle, [node](void* ptr) {
|
|
139
|
+
env, subscription, node_handle, [node, env](void* ptr) {
|
|
140
140
|
rcl_subscription_t* subscription =
|
|
141
141
|
reinterpret_cast<rcl_subscription_t*>(ptr);
|
|
142
142
|
rcl_ret_t ret = rcl_subscription_fini(subscription, node);
|
|
143
143
|
free(ptr);
|
|
144
|
-
|
|
144
|
+
THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
|
|
145
|
+
rcl_get_error_string().str);
|
|
145
146
|
});
|
|
146
147
|
|
|
147
148
|
return js_obj;
|
|
@@ -151,11 +151,12 @@ Napi::Value CreateClock(const Napi::CallbackInfo& info) {
|
|
|
151
151
|
rcl_clock_init(clock_type, clock, &allocator),
|
|
152
152
|
rcl_get_error_string().str);
|
|
153
153
|
|
|
154
|
-
return RclHandle::NewInstance(env, clock, nullptr, [](void* ptr) {
|
|
154
|
+
return RclHandle::NewInstance(env, clock, nullptr, [env](void* ptr) {
|
|
155
155
|
rcl_clock_t* clock = reinterpret_cast<rcl_clock_t*>(ptr);
|
|
156
156
|
rcl_ret_t ret = rcl_clock_fini(clock);
|
|
157
157
|
free(ptr);
|
|
158
|
-
|
|
158
|
+
THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
|
|
159
|
+
rcl_get_error_string().str);
|
|
159
160
|
});
|
|
160
161
|
}
|
|
161
162
|
|
|
@@ -58,12 +58,14 @@ Napi::Value CreateTimer(const Napi::CallbackInfo& info) {
|
|
|
58
58
|
rcl_get_error_string().str);
|
|
59
59
|
#endif
|
|
60
60
|
|
|
61
|
-
auto js_obj =
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
61
|
+
auto js_obj =
|
|
62
|
+
RclHandle::NewInstance(env, timer, clock_handle, [env](void* ptr) {
|
|
63
|
+
rcl_timer_t* timer = reinterpret_cast<rcl_timer_t*>(ptr);
|
|
64
|
+
rcl_ret_t ret = rcl_timer_fini(timer);
|
|
65
|
+
free(ptr);
|
|
66
|
+
THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
|
|
67
|
+
rcl_get_error_string().str);
|
|
68
|
+
});
|
|
67
69
|
|
|
68
70
|
return js_obj;
|
|
69
71
|
}
|
package/src/rcl_utilities.cpp
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
#include <rmw/topic_endpoint_info.h>
|
|
20
20
|
#include <uv.h>
|
|
21
21
|
|
|
22
|
+
#include <cstdio>
|
|
22
23
|
#include <memory>
|
|
23
24
|
#include <string>
|
|
24
25
|
|
|
@@ -260,4 +261,34 @@ Napi::Array ConvertToJSTopicEndpointInfoList(
|
|
|
260
261
|
return list;
|
|
261
262
|
}
|
|
262
263
|
|
|
264
|
+
char** AbstractArgsFromNapiArray(const Napi::Array& jsArgv) {
|
|
265
|
+
size_t argc = jsArgv.Length();
|
|
266
|
+
char** argv = nullptr;
|
|
267
|
+
|
|
268
|
+
if (argc > 0) {
|
|
269
|
+
argv = reinterpret_cast<char**>(malloc(argc * sizeof(char*)));
|
|
270
|
+
for (size_t i = 0; i < argc; i++) {
|
|
271
|
+
std::string arg = jsArgv.Get(i).As<Napi::String>().Utf8Value();
|
|
272
|
+
int len = arg.length() + 1;
|
|
273
|
+
argv[i] = reinterpret_cast<char*>(malloc(len * sizeof(char)));
|
|
274
|
+
snprintf(argv[i], len, "%s", arg.c_str());
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return argv;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
void FreeArgs(char** argv, size_t argc) {
|
|
281
|
+
if (argv) {
|
|
282
|
+
for (size_t i = 0; i < argc; i++) {
|
|
283
|
+
free(argv[i]);
|
|
284
|
+
}
|
|
285
|
+
free(argv);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
bool HasUnparsedROSArgs(const rcl_arguments_t& rcl_args) {
|
|
290
|
+
int unparsed_ros_args_count = rcl_arguments_get_count_unparsed_ros(&rcl_args);
|
|
291
|
+
return unparsed_ros_args_count != 0;
|
|
292
|
+
}
|
|
293
|
+
|
|
263
294
|
} // namespace rclnodejs
|
package/src/rcl_utilities.h
CHANGED
|
@@ -53,6 +53,13 @@ Napi::Array ConvertToJSTopicEndpointInfoList(
|
|
|
53
53
|
|
|
54
54
|
Napi::Value ConvertToQoS(Napi::Env env, const rmw_qos_profile_t* qos_profile);
|
|
55
55
|
|
|
56
|
+
// `AbstractArgsFromNapiArray` and `FreeArgs` must be called in pairs.
|
|
57
|
+
char** AbstractArgsFromNapiArray(const Napi::Array& jsArgv);
|
|
58
|
+
// `AbstractArgsFromNapiArray` and `FreeArgs` must be called in pairs.
|
|
59
|
+
void FreeArgs(char** argv, size_t argc);
|
|
60
|
+
|
|
61
|
+
bool HasUnparsedROSArgs(const rcl_arguments_t& rcl_args);
|
|
62
|
+
|
|
56
63
|
} // namespace rclnodejs
|
|
57
64
|
|
|
58
65
|
#endif // SRC_RCL_UTILITIES_H_
|
package/tsconfig.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"compilerOptions": {
|
|
3
3
|
"module": "commonjs",
|
|
4
4
|
"moduleResolution": "node",
|
|
5
|
-
"target": "
|
|
5
|
+
"target": "es2020",
|
|
6
6
|
/* Strict Type-Checking Options */
|
|
7
7
|
"strict": true,
|
|
8
8
|
/* Additional Checks */
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"noUnusedParameters": true,
|
|
12
12
|
"noImplicitReturns": true,
|
|
13
13
|
"noFallthroughCasesInSwitch": true,
|
|
14
|
-
"lib": ["
|
|
14
|
+
"lib": ["es2020"]
|
|
15
15
|
},
|
|
16
16
|
"include": [
|
|
17
17
|
"types/**/*"
|
package/types/context.d.ts
CHANGED
|
@@ -38,8 +38,9 @@ declare module 'rclnodejs' {
|
|
|
38
38
|
* Create a new instance in uninitialized state.
|
|
39
39
|
* Call rcl.init(context) to initialize this context state for
|
|
40
40
|
* use in creating nodes, etc.
|
|
41
|
+
* @param {bigint} - Optional, The domain ID of this context.
|
|
41
42
|
*/
|
|
42
|
-
constructor();
|
|
43
|
+
constructor(domainId?: bigint);
|
|
43
44
|
|
|
44
45
|
/**
|
|
45
46
|
* Test if this context has not been initialized by rcl.init(context).
|
|
@@ -92,6 +93,6 @@ declare module 'rclnodejs' {
|
|
|
92
93
|
* Get the domain ID of this context.
|
|
93
94
|
* @returns domain ID of this context
|
|
94
95
|
*/
|
|
95
|
-
domainId():
|
|
96
|
+
domainId(): bigint;
|
|
96
97
|
}
|
|
97
98
|
}
|
package/types/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/// <reference path="./base.d.ts" />
|
|
2
2
|
|
|
3
3
|
declare module 'rclnodejs' {
|
|
4
|
+
type Class = new (...args: any[]) => any;
|
|
5
|
+
|
|
4
6
|
/**
|
|
5
7
|
* Create a node.
|
|
6
8
|
*
|
|
@@ -11,6 +13,9 @@ declare module 'rclnodejs' {
|
|
|
11
13
|
* @param namespace - The namespace used in ROS, default is an empty string.
|
|
12
14
|
* @param context - The context, default is Context.defaultContext().
|
|
13
15
|
* @param options - The node options, default is NodeOptions.defaultOptions.
|
|
16
|
+
* @param args - The arguments to be passed to the node, default is an empty array.
|
|
17
|
+
* @param useGlobalArguments - If true, the node will use global arguments, default is true.
|
|
18
|
+
* If false, the node will not use global arguments.
|
|
14
19
|
* @returns The new Node instance.
|
|
15
20
|
* @deprecated since 0.18.0, Use new Node constructor.
|
|
16
21
|
*/
|
|
@@ -18,7 +23,9 @@ declare module 'rclnodejs' {
|
|
|
18
23
|
nodeName: string,
|
|
19
24
|
namespace?: string,
|
|
20
25
|
context?: Context,
|
|
21
|
-
options?: NodeOptions
|
|
26
|
+
options?: NodeOptions,
|
|
27
|
+
args?: string[],
|
|
28
|
+
useGlobalArguments?: boolean
|
|
22
29
|
): Node;
|
|
23
30
|
|
|
24
31
|
/**
|
|
@@ -182,4 +189,22 @@ declare module 'rclnodejs' {
|
|
|
182
189
|
* @returns An array of the names and types.
|
|
183
190
|
*/
|
|
184
191
|
function getActionNamesAndTypes(node: Node): NamesAndTypesQueryResult;
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Serialize a message to a Buffer.
|
|
195
|
+
*
|
|
196
|
+
* @param message - The message to be serialized.
|
|
197
|
+
* @param typeClass - The type class of the message.
|
|
198
|
+
* @returns A Buffer containing the serialized message.
|
|
199
|
+
*/
|
|
200
|
+
function serializeMessage(message: object, typeClass: Class): Buffer;
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Deserialize a message from a Buffer.
|
|
204
|
+
*
|
|
205
|
+
* @param buffer - The Buffer containing the serialized message.
|
|
206
|
+
* @param typeClass - The type class of the message.
|
|
207
|
+
* @returns An Object representing the deserialized message.
|
|
208
|
+
*/
|
|
209
|
+
function deserializeMessage(buffer: Buffer, typeClass: Class): object;
|
|
185
210
|
}
|
package/types/lifecycle.d.ts
CHANGED
|
@@ -333,6 +333,13 @@ declare module 'rclnodejs' {
|
|
|
333
333
|
* @returns {boolean} true if the state machine is initialized; otherwise false.
|
|
334
334
|
*/
|
|
335
335
|
get isInitialized(): boolean;
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Log the state machine data.
|
|
339
|
+
*
|
|
340
|
+
* @returns {undefined} void.
|
|
341
|
+
*/
|
|
342
|
+
print(): void;
|
|
336
343
|
}
|
|
337
344
|
} // lifecycle namespace
|
|
338
345
|
} // rclnodejs namespace
|