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
package/index.js
CHANGED
|
@@ -85,7 +85,7 @@ async function getCurrentGeneratorVersion() {
|
|
|
85
85
|
const jsonFilePath = path.join(generator.generatedRoot, 'generator.json');
|
|
86
86
|
|
|
87
87
|
return new Promise((resolve, reject) => {
|
|
88
|
-
fs.
|
|
88
|
+
fs.readFile(jsonFilePath, 'utf8', (err, data) => {
|
|
89
89
|
if (err) {
|
|
90
90
|
if (err.code === 'ENOENT') {
|
|
91
91
|
resolve(null);
|
|
@@ -93,13 +93,11 @@ async function getCurrentGeneratorVersion() {
|
|
|
93
93
|
reject(err);
|
|
94
94
|
}
|
|
95
95
|
} else {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
});
|
|
96
|
+
try {
|
|
97
|
+
resolve(JSON.parse(data).version);
|
|
98
|
+
} catch (parseErr) {
|
|
99
|
+
reject(parseErr);
|
|
100
|
+
}
|
|
103
101
|
}
|
|
104
102
|
});
|
|
105
103
|
});
|
|
@@ -389,23 +387,35 @@ let rcl = {
|
|
|
389
387
|
|
|
390
388
|
rclnodejs.init(context.handle, argv, context._domainId);
|
|
391
389
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
390
|
+
try {
|
|
391
|
+
if (_rosVersionChecked) {
|
|
392
|
+
// no further processing required
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
396
395
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
396
|
+
const version = await getCurrentGeneratorVersion();
|
|
397
|
+
const forced =
|
|
398
|
+
version === null || compareVersions(version, generator.version(), '<');
|
|
399
|
+
if (forced) {
|
|
400
|
+
debug(
|
|
401
|
+
'The generator will begin to create JavaScript code from ROS IDL files...'
|
|
402
|
+
);
|
|
403
|
+
}
|
|
405
404
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
405
|
+
await generator.generateAll(forced);
|
|
406
|
+
// TODO determine if tsd generateAll() should be here
|
|
407
|
+
_rosVersionChecked = true;
|
|
408
|
+
} catch (error) {
|
|
409
|
+
try {
|
|
410
|
+
context.tryShutdown();
|
|
411
|
+
} catch (shutdownError) {
|
|
412
|
+
const initError =
|
|
413
|
+
error instanceof Error ? error : new Error(String(error));
|
|
414
|
+
initError.message += ` (rollback also failed: ${shutdownError.message})`;
|
|
415
|
+
throw initError;
|
|
416
|
+
}
|
|
417
|
+
throw error;
|
|
418
|
+
}
|
|
409
419
|
},
|
|
410
420
|
|
|
411
421
|
/**
|
package/lib/action/client.js
CHANGED
|
@@ -126,6 +126,12 @@ class ActionClient extends Entity {
|
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
this._goalHandles.set(uuid, goalHandle);
|
|
129
|
+
} else {
|
|
130
|
+
// Clean up feedback callback for rejected goals
|
|
131
|
+
let uuid = ActionUuid.fromMessage(
|
|
132
|
+
this._sequenceNumberGoalIdMap.get(sequence)
|
|
133
|
+
).toString();
|
|
134
|
+
this._feedbackCallbacks.delete(uuid);
|
|
129
135
|
}
|
|
130
136
|
|
|
131
137
|
this._pendingGoalRequests.get(sequence).setResult(goalHandle);
|
package/lib/action/server.js
CHANGED
|
@@ -437,10 +437,8 @@ class ActionServer extends Entity {
|
|
|
437
437
|
|
|
438
438
|
_executeExpiredGoals(result, count) {
|
|
439
439
|
for (let i = 0; i < count; i++) {
|
|
440
|
-
const goal = result.data[i];
|
|
441
|
-
|
|
442
440
|
const goalInfo = new ActionInterfaces.GoalInfo();
|
|
443
|
-
goalInfo.deserialize(
|
|
441
|
+
goalInfo.deserialize(result._refArray[i]);
|
|
444
442
|
|
|
445
443
|
let uuid = ActionUuid.fromBytes(goalInfo.goal_id.uuid).toString();
|
|
446
444
|
this._goalHandles.delete(uuid);
|
package/lib/distro.js
CHANGED
|
@@ -65,7 +65,8 @@ const DistroUtils = {
|
|
|
65
65
|
return process.env.ROS_DISTRO;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
const result = [...DistroNameIdMap].find(([, val]) => val == distroId);
|
|
69
|
+
return result ? result[0] : undefined;
|
|
69
70
|
},
|
|
70
71
|
|
|
71
72
|
getKnownDistroNames: function () {
|
package/lib/lifecycle.js
CHANGED
|
@@ -291,7 +291,8 @@ class LifecycleNode extends Node {
|
|
|
291
291
|
// initialize native handle to rcl_lifecycle_state_machine
|
|
292
292
|
this._stateMachineHandle = rclnodejs.createLifecycleStateMachine(
|
|
293
293
|
this.handle,
|
|
294
|
-
enableCommunicationInterface
|
|
294
|
+
enableCommunicationInterface,
|
|
295
|
+
this._clock.handle
|
|
295
296
|
);
|
|
296
297
|
|
|
297
298
|
// initialize Map<transitionId,TransitionCallback>
|
|
@@ -30,7 +30,7 @@ class LifecyclePublisher extends Publisher {
|
|
|
30
30
|
super(handle, typeClass, /*topic=*/ '', options);
|
|
31
31
|
|
|
32
32
|
this._enabled = false;
|
|
33
|
-
this.
|
|
33
|
+
this._logger = Logging.getLogger('LifecyclePublisher');
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
/**
|
|
@@ -42,7 +42,7 @@ class LifecyclePublisher extends Publisher {
|
|
|
42
42
|
*/
|
|
43
43
|
publish(message) {
|
|
44
44
|
if (!this._enabled) {
|
|
45
|
-
this.
|
|
45
|
+
this._logger.warn(
|
|
46
46
|
`Trying to publish message on the topic ${this.topic}, but the publisher is not activated`
|
|
47
47
|
);
|
|
48
48
|
|
package/lib/node.js
CHANGED
|
@@ -97,7 +97,30 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
97
97
|
);
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
static _normalizeOptions(options) {
|
|
101
|
+
if (options instanceof NodeOptions) {
|
|
102
|
+
return options;
|
|
103
|
+
}
|
|
104
|
+
const defaults = NodeOptions.defaultOptions;
|
|
105
|
+
return {
|
|
106
|
+
startParameterServices:
|
|
107
|
+
options.startParameterServices ?? defaults.startParameterServices,
|
|
108
|
+
parameterOverrides:
|
|
109
|
+
options.parameterOverrides ?? defaults.parameterOverrides,
|
|
110
|
+
automaticallyDeclareParametersFromOverrides:
|
|
111
|
+
options.automaticallyDeclareParametersFromOverrides ??
|
|
112
|
+
defaults.automaticallyDeclareParametersFromOverrides,
|
|
113
|
+
startTypeDescriptionService:
|
|
114
|
+
options.startTypeDescriptionService ??
|
|
115
|
+
defaults.startTypeDescriptionService,
|
|
116
|
+
enableRosout: options.enableRosout ?? defaults.enableRosout,
|
|
117
|
+
rosoutQos: options.rosoutQos ?? defaults.rosoutQos,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
100
121
|
_init(name, namespace, options, context, args, useGlobalArguments) {
|
|
122
|
+
options = Node._normalizeOptions(options);
|
|
123
|
+
|
|
101
124
|
this.handle = rclnodejs.createNode(
|
|
102
125
|
name,
|
|
103
126
|
namespace,
|
|
@@ -151,7 +174,7 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
151
174
|
// override cli parameterOverrides with those specified in options
|
|
152
175
|
if (options.parameterOverrides.length > 0) {
|
|
153
176
|
for (const parameter of options.parameterOverrides) {
|
|
154
|
-
if ((
|
|
177
|
+
if (!(parameter instanceof Parameter)) {
|
|
155
178
|
throw new TypeValidationError(
|
|
156
179
|
'parameterOverride',
|
|
157
180
|
parameter,
|
|
@@ -425,17 +448,20 @@ class Node extends rclnodejs.ShadowNode {
|
|
|
425
448
|
}
|
|
426
449
|
|
|
427
450
|
if (properties.isGoalExpired) {
|
|
428
|
-
let
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
451
|
+
let numGoals = actionServer._goalHandles.size;
|
|
452
|
+
if (numGoals > 0) {
|
|
453
|
+
let GoalInfoArray = ActionInterfaces.GoalInfo.ArrayType;
|
|
454
|
+
let message = new GoalInfoArray(numGoals);
|
|
455
|
+
let count = rclnodejs.actionExpireGoals(
|
|
456
|
+
actionServer.handle,
|
|
457
|
+
numGoals,
|
|
458
|
+
message._refArray.buffer
|
|
459
|
+
);
|
|
460
|
+
if (count > 0) {
|
|
461
|
+
actionServer.processGoalExpired(message, count);
|
|
462
|
+
}
|
|
463
|
+
GoalInfoArray.freeArray(message);
|
|
437
464
|
}
|
|
438
|
-
GoalInfoArray.freeArray(message);
|
|
439
465
|
}
|
|
440
466
|
}
|
|
441
467
|
|
package/lib/parameter.js
CHANGED
|
@@ -864,9 +864,8 @@ function parameterTypeFromValue(value) {
|
|
|
864
864
|
function validType(parameterType) {
|
|
865
865
|
let result =
|
|
866
866
|
typeof parameterType === 'number' &&
|
|
867
|
-
ParameterType.PARAMETER_NOT_SET
|
|
868
|
-
|
|
869
|
-
ParameterType.PARAMETER_STRING_ARRAY;
|
|
867
|
+
parameterType >= ParameterType.PARAMETER_NOT_SET &&
|
|
868
|
+
parameterType <= ParameterType.PARAMETER_STRING_ARRAY;
|
|
870
869
|
|
|
871
870
|
return result;
|
|
872
871
|
}
|
|
@@ -883,7 +882,7 @@ function validValue(value, type) {
|
|
|
883
882
|
return type === ParameterType.PARAMETER_NOT_SET;
|
|
884
883
|
}
|
|
885
884
|
|
|
886
|
-
let result
|
|
885
|
+
let result;
|
|
887
886
|
switch (type) {
|
|
888
887
|
case ParameterType.PARAMETER_NOT_SET:
|
|
889
888
|
result = !value;
|
|
@@ -923,14 +922,11 @@ function _validArray(values, type) {
|
|
|
923
922
|
arrayElementType = ParameterType.PARAMETER_BOOL;
|
|
924
923
|
} else if (type === ParameterType.PARAMETER_BYTE_ARRAY) {
|
|
925
924
|
arrayElementType = PARAMETER_BYTE;
|
|
926
|
-
}
|
|
927
|
-
if (type === ParameterType.PARAMETER_INTEGER_ARRAY) {
|
|
925
|
+
} else if (type === ParameterType.PARAMETER_INTEGER_ARRAY) {
|
|
928
926
|
arrayElementType = ParameterType.PARAMETER_INTEGER;
|
|
929
|
-
}
|
|
930
|
-
if (type === ParameterType.PARAMETER_DOUBLE_ARRAY) {
|
|
927
|
+
} else if (type === ParameterType.PARAMETER_DOUBLE_ARRAY) {
|
|
931
928
|
arrayElementType = ParameterType.PARAMETER_DOUBLE;
|
|
932
|
-
}
|
|
933
|
-
if (type === ParameterType.PARAMETER_STRING_ARRAY) {
|
|
929
|
+
} else if (type === ParameterType.PARAMETER_STRING_ARRAY) {
|
|
934
930
|
arrayElementType = ParameterType.PARAMETER_STRING;
|
|
935
931
|
}
|
|
936
932
|
|
package/lib/service.js
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
const rclnodejs = require('./native_loader.js');
|
|
18
18
|
const DistroUtils = require('./distro.js');
|
|
19
19
|
const Entity = require('./entity.js');
|
|
20
|
+
const Logging = require('./logging.js');
|
|
20
21
|
const debug = require('debug')('rclnodejs:service');
|
|
21
22
|
|
|
22
23
|
/**
|
|
@@ -75,8 +76,8 @@ class Service extends Entity {
|
|
|
75
76
|
|
|
76
77
|
const plainObj = request.toPlainObject(this.typedArrayEnabled);
|
|
77
78
|
const response = new Response(this, headerHandle);
|
|
78
|
-
Promise.resolve(this._callback(plainObj, response))
|
|
79
|
-
(responseToReturn) => {
|
|
79
|
+
Promise.resolve(this._callback(plainObj, response))
|
|
80
|
+
.then((responseToReturn) => {
|
|
80
81
|
if (!response.sent && responseToReturn) {
|
|
81
82
|
responseToReturn = new this._typeClass.Response(responseToReturn);
|
|
82
83
|
const rawResponse = responseToReturn.serialize();
|
|
@@ -86,8 +87,11 @@ class Service extends Entity {
|
|
|
86
87
|
debug(
|
|
87
88
|
`Service has processed the ${this._serviceName} request and sent the response.`
|
|
88
89
|
);
|
|
89
|
-
}
|
|
90
|
-
|
|
90
|
+
})
|
|
91
|
+
.catch((error) => {
|
|
92
|
+
const logger = Logging.getLogger('rclnodejs');
|
|
93
|
+
logger.error(`Error processing ${this._serviceName} request: ${error}`);
|
|
94
|
+
});
|
|
91
95
|
}
|
|
92
96
|
|
|
93
97
|
static createService(nodeHandle, serviceName, typeClass, options, callback) {
|
package/lib/time_source.js
CHANGED
|
@@ -45,26 +45,6 @@ class TimeSource {
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
get isRosTimeActive() {
|
|
49
|
-
return this._isRosTimeActive;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
set isRosTimeActive(enabled) {
|
|
53
|
-
if (this.isRosTimeActive === enabled) return;
|
|
54
|
-
|
|
55
|
-
this._isRosTimeActive = enabled;
|
|
56
|
-
for (const clock in this._associatedClocks) {
|
|
57
|
-
clock.isRosTimeActive = enabled;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (enabled) {
|
|
61
|
-
this._subscribeToClockTopic();
|
|
62
|
-
} else if (this._node && this._clockSubscription) {
|
|
63
|
-
this._node.destroySubscription(this._clockSubscription);
|
|
64
|
-
this._node._clockSubscription = null;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
48
|
/**
|
|
69
49
|
* Return status that whether the ROS time is active.
|
|
70
50
|
* @name TimeSource#get:isRosTimeActive
|
|
@@ -93,6 +73,9 @@ class TimeSource {
|
|
|
93
73
|
});
|
|
94
74
|
if (enabled) {
|
|
95
75
|
this._subscribeToClockTopic();
|
|
76
|
+
} else if (this._node && this._clockSubscription) {
|
|
77
|
+
this._node.destroySubscription(this._clockSubscription);
|
|
78
|
+
this._clockSubscription = undefined;
|
|
96
79
|
}
|
|
97
80
|
}
|
|
98
81
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rclnodejs",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.3",
|
|
4
4
|
"description": "ROS2.0 JavaScript client with Node.js",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "types/index.d.ts",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"url": "git+https://github.com/RobotWebTools/rclnodejs.git"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@eslint/js": "^
|
|
51
|
+
"@eslint/js": "^10.0.1",
|
|
52
52
|
"@types/node": "^25.0.2",
|
|
53
53
|
"@typescript-eslint/eslint-plugin": "^8.18.0",
|
|
54
54
|
"@typescript-eslint/parser": "^8.18.0",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"commander": "^14.0.0",
|
|
57
57
|
"coveralls": "^3.1.1",
|
|
58
58
|
"deep-equal": "^2.2.3",
|
|
59
|
-
"eslint": "^
|
|
59
|
+
"eslint": "^10.0.2",
|
|
60
60
|
"eslint-config-prettier": "^10.0.2",
|
|
61
61
|
"eslint-plugin-prettier": "^5.2.1",
|
|
62
62
|
"globals": "^17.0.0",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"lint-staged": "^16.2.0",
|
|
66
66
|
"mocha": "^11.0.2",
|
|
67
67
|
"node-gyp": "^12.1.0",
|
|
68
|
-
"nyc": "^
|
|
68
|
+
"nyc": "^18.0.0",
|
|
69
69
|
"prebuildify": "^6.0.1",
|
|
70
70
|
"rimraf": "^6.0.1",
|
|
71
71
|
"sinon": "^21.0.0",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -12,14 +12,11 @@
|
|
|
12
12
|
// See the License for the specific language governing permissions and
|
|
13
13
|
// limitations under the License.
|
|
14
14
|
|
|
15
|
-
const fse = require('../lib/utils.js');
|
|
16
15
|
const generateJSStructFromIDL = require('./idl_generator.js');
|
|
17
16
|
const packages = require('./packages.js');
|
|
18
17
|
const path = require('path');
|
|
19
|
-
const idlConvertor = require('../rosidl_convertor/idl_convertor.js');
|
|
20
18
|
|
|
21
19
|
const generatedRoot = path.join(__dirname, '../generated/');
|
|
22
|
-
const idlPath = path.join(generatedRoot, 'share');
|
|
23
20
|
const useIDL = !!process.argv.find((arg) => arg === '--idl');
|
|
24
21
|
|
|
25
22
|
// Get target path from environment variable instead of workerData
|
|
@@ -32,17 +29,10 @@ async function generateInPath(targetPath) {
|
|
|
32
29
|
(await packages.findPackagesInDirectory(targetPath)).values()
|
|
33
30
|
);
|
|
34
31
|
} else {
|
|
32
|
+
// Direct IDL parsing: pass .idl files to the generator which uses
|
|
33
|
+
// rosidl_parser to parse them directly (no .msg/.srv/.action conversion).
|
|
35
34
|
const idlPkgs = await packages.findPackagesInDirectory(targetPath, useIDL);
|
|
36
|
-
|
|
37
|
-
const promises = [];
|
|
38
|
-
idlPkgs.forEach((pkg) => {
|
|
39
|
-
pkg.idls.forEach((idl) => {
|
|
40
|
-
promises.push(idlConvertor(idl.pkgName, idl.filePath, idlPath));
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
await Promise.all(promises);
|
|
44
|
-
const pkgsFromIdl = await packages.findPackagesInDirectory(idlPath, false);
|
|
45
|
-
pkgsInfo = Array.from(pkgsFromIdl.values());
|
|
35
|
+
pkgsInfo = Array.from(idlPkgs.values());
|
|
46
36
|
}
|
|
47
37
|
|
|
48
38
|
await Promise.all(
|
|
@@ -305,7 +305,217 @@ async function generateJSStructFromIDL(pkg, dir) {
|
|
|
305
305
|
pkg.actions.forEach((actionInfo) => {
|
|
306
306
|
results.push(generateActionJSStruct(actionInfo, dir));
|
|
307
307
|
});
|
|
308
|
+
|
|
309
|
+
// Handle .idl files directly (parsed via rosidl_parser, no .msg conversion)
|
|
310
|
+
if (pkg.idls) {
|
|
311
|
+
pkg.idls.forEach((idlInfo) => {
|
|
312
|
+
results.push(generateJSStructFromIdlFile(idlInfo, dir));
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
|
|
308
316
|
await Promise.all(results);
|
|
309
317
|
}
|
|
310
318
|
|
|
319
|
+
/**
|
|
320
|
+
* Parse an .idl file directly and generate the appropriate JS struct.
|
|
321
|
+
* This uses rosidl_parser to parse the IDL and produces the same JSON
|
|
322
|
+
* spec format, so the same templates can be used.
|
|
323
|
+
*/
|
|
324
|
+
async function generateJSStructFromIdlFile(idlInfo, dir) {
|
|
325
|
+
const result = await parser.parseIdlFile(idlInfo.filePath);
|
|
326
|
+
const { type, spec } = result;
|
|
327
|
+
|
|
328
|
+
if (type === 'message') {
|
|
329
|
+
await generateMessageJSStructFromSpec(
|
|
330
|
+
{
|
|
331
|
+
pkgName: idlInfo.pkgName,
|
|
332
|
+
subFolder: idlInfo.subFolder,
|
|
333
|
+
interfaceName: idlInfo.interfaceName,
|
|
334
|
+
},
|
|
335
|
+
dir,
|
|
336
|
+
spec
|
|
337
|
+
);
|
|
338
|
+
} else if (type === 'service') {
|
|
339
|
+
// Generate request and response message JS structs
|
|
340
|
+
const requestMsg = generateMessageJSStructFromSpec(
|
|
341
|
+
{
|
|
342
|
+
pkgName: idlInfo.pkgName,
|
|
343
|
+
subFolder: idlInfo.subFolder,
|
|
344
|
+
interfaceName: `${idlInfo.interfaceName}_Request`,
|
|
345
|
+
},
|
|
346
|
+
dir,
|
|
347
|
+
spec.request
|
|
348
|
+
);
|
|
349
|
+
|
|
350
|
+
const responseMsg = generateMessageJSStructFromSpec(
|
|
351
|
+
{
|
|
352
|
+
pkgName: idlInfo.pkgName,
|
|
353
|
+
subFolder: idlInfo.subFolder,
|
|
354
|
+
interfaceName: `${idlInfo.interfaceName}_Response`,
|
|
355
|
+
},
|
|
356
|
+
dir,
|
|
357
|
+
spec.response
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
// Generate service JS struct
|
|
361
|
+
const serviceInfo = {
|
|
362
|
+
pkgName: idlInfo.pkgName,
|
|
363
|
+
subFolder: idlInfo.subFolder,
|
|
364
|
+
interfaceName: idlInfo.interfaceName,
|
|
365
|
+
};
|
|
366
|
+
const srv = generateServiceJSStruct(
|
|
367
|
+
serviceInfo,
|
|
368
|
+
dir,
|
|
369
|
+
/*isActionService=*/ false
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
await Promise.all([requestMsg, responseMsg, srv]);
|
|
373
|
+
} else if (type === 'action') {
|
|
374
|
+
// Generate goal, result, feedback message JS structs
|
|
375
|
+
const goalMsg = generateMessageJSStructFromSpec(
|
|
376
|
+
{
|
|
377
|
+
pkgName: idlInfo.pkgName,
|
|
378
|
+
subFolder: idlInfo.subFolder,
|
|
379
|
+
interfaceName: `${idlInfo.interfaceName}_Goal`,
|
|
380
|
+
},
|
|
381
|
+
dir,
|
|
382
|
+
spec.goal
|
|
383
|
+
);
|
|
384
|
+
|
|
385
|
+
const resultMsg = generateMessageJSStructFromSpec(
|
|
386
|
+
{
|
|
387
|
+
pkgName: idlInfo.pkgName,
|
|
388
|
+
subFolder: idlInfo.subFolder,
|
|
389
|
+
interfaceName: `${idlInfo.interfaceName}_Result`,
|
|
390
|
+
},
|
|
391
|
+
dir,
|
|
392
|
+
spec.result
|
|
393
|
+
);
|
|
394
|
+
|
|
395
|
+
const feedbackMsg = generateMessageJSStructFromSpec(
|
|
396
|
+
{
|
|
397
|
+
pkgName: idlInfo.pkgName,
|
|
398
|
+
subFolder: idlInfo.subFolder,
|
|
399
|
+
interfaceName: `${idlInfo.interfaceName}_Feedback`,
|
|
400
|
+
},
|
|
401
|
+
dir,
|
|
402
|
+
spec.feedback
|
|
403
|
+
);
|
|
404
|
+
|
|
405
|
+
// Generate derived action messages (SendGoal, GetResult, FeedbackMessage)
|
|
406
|
+
const sendGoalRequestSpec = actionMsgs.createSendGoalRequestSpec(
|
|
407
|
+
idlInfo.pkgName,
|
|
408
|
+
idlInfo.interfaceName
|
|
409
|
+
);
|
|
410
|
+
const sendGoalRequestMsg = generateMessageJSStructFromSpec(
|
|
411
|
+
{
|
|
412
|
+
pkgName: idlInfo.pkgName,
|
|
413
|
+
subFolder: idlInfo.subFolder,
|
|
414
|
+
interfaceName: `${idlInfo.interfaceName}_SendGoal_Request`,
|
|
415
|
+
},
|
|
416
|
+
dir,
|
|
417
|
+
sendGoalRequestSpec
|
|
418
|
+
);
|
|
419
|
+
|
|
420
|
+
const sendGoalResponseSpec = actionMsgs.createSendGoalResponseSpec(
|
|
421
|
+
idlInfo.pkgName,
|
|
422
|
+
idlInfo.interfaceName
|
|
423
|
+
);
|
|
424
|
+
const sendGoalResponseMsg = generateMessageJSStructFromSpec(
|
|
425
|
+
{
|
|
426
|
+
pkgName: idlInfo.pkgName,
|
|
427
|
+
subFolder: idlInfo.subFolder,
|
|
428
|
+
interfaceName: `${idlInfo.interfaceName}_SendGoal_Response`,
|
|
429
|
+
},
|
|
430
|
+
dir,
|
|
431
|
+
sendGoalResponseSpec
|
|
432
|
+
);
|
|
433
|
+
|
|
434
|
+
const sendGoalSrv = generateServiceJSStruct(
|
|
435
|
+
{
|
|
436
|
+
pkgName: idlInfo.pkgName,
|
|
437
|
+
subFolder: idlInfo.subFolder,
|
|
438
|
+
interfaceName: `${idlInfo.interfaceName}_SendGoal`,
|
|
439
|
+
},
|
|
440
|
+
dir
|
|
441
|
+
);
|
|
442
|
+
|
|
443
|
+
const getResultRequestSpec = actionMsgs.createGetResultRequestSpec(
|
|
444
|
+
idlInfo.pkgName,
|
|
445
|
+
idlInfo.interfaceName
|
|
446
|
+
);
|
|
447
|
+
const getResultRequestMsg = generateMessageJSStructFromSpec(
|
|
448
|
+
{
|
|
449
|
+
pkgName: idlInfo.pkgName,
|
|
450
|
+
subFolder: idlInfo.subFolder,
|
|
451
|
+
interfaceName: `${idlInfo.interfaceName}_GetResult_Request`,
|
|
452
|
+
},
|
|
453
|
+
dir,
|
|
454
|
+
getResultRequestSpec
|
|
455
|
+
);
|
|
456
|
+
|
|
457
|
+
const getResultResponseSpec = actionMsgs.createGetResultResponseSpec(
|
|
458
|
+
idlInfo.pkgName,
|
|
459
|
+
idlInfo.interfaceName
|
|
460
|
+
);
|
|
461
|
+
const getResultResponseMsg = generateMessageJSStructFromSpec(
|
|
462
|
+
{
|
|
463
|
+
pkgName: idlInfo.pkgName,
|
|
464
|
+
subFolder: idlInfo.subFolder,
|
|
465
|
+
interfaceName: `${idlInfo.interfaceName}_GetResult_Response`,
|
|
466
|
+
},
|
|
467
|
+
dir,
|
|
468
|
+
getResultResponseSpec
|
|
469
|
+
);
|
|
470
|
+
|
|
471
|
+
const getResultSrv = generateServiceJSStruct(
|
|
472
|
+
{
|
|
473
|
+
pkgName: idlInfo.pkgName,
|
|
474
|
+
subFolder: idlInfo.subFolder,
|
|
475
|
+
interfaceName: `${idlInfo.interfaceName}_GetResult`,
|
|
476
|
+
},
|
|
477
|
+
dir
|
|
478
|
+
);
|
|
479
|
+
|
|
480
|
+
const feedbackMessageSpec = actionMsgs.createFeedbackMessageSpec(
|
|
481
|
+
idlInfo.pkgName,
|
|
482
|
+
idlInfo.interfaceName
|
|
483
|
+
);
|
|
484
|
+
const feedbackMessageMsg = generateMessageJSStructFromSpec(
|
|
485
|
+
{
|
|
486
|
+
pkgName: idlInfo.pkgName,
|
|
487
|
+
subFolder: idlInfo.subFolder,
|
|
488
|
+
interfaceName: `${idlInfo.interfaceName}_FeedbackMessage`,
|
|
489
|
+
},
|
|
490
|
+
dir,
|
|
491
|
+
feedbackMessageSpec
|
|
492
|
+
);
|
|
493
|
+
|
|
494
|
+
const fileName =
|
|
495
|
+
idlInfo.pkgName +
|
|
496
|
+
'__' +
|
|
497
|
+
idlInfo.subFolder +
|
|
498
|
+
'__' +
|
|
499
|
+
idlInfo.interfaceName +
|
|
500
|
+
'.js';
|
|
501
|
+
const generatedCode = generateAction({ actionInfo: idlInfo });
|
|
502
|
+
const actionDir = path.join(dir, idlInfo.pkgName);
|
|
503
|
+
const action = writeGeneratedCode(actionDir, fileName, generatedCode);
|
|
504
|
+
|
|
505
|
+
await Promise.all([
|
|
506
|
+
goalMsg,
|
|
507
|
+
resultMsg,
|
|
508
|
+
feedbackMsg,
|
|
509
|
+
sendGoalRequestMsg,
|
|
510
|
+
sendGoalResponseMsg,
|
|
511
|
+
sendGoalSrv,
|
|
512
|
+
getResultRequestMsg,
|
|
513
|
+
getResultResponseMsg,
|
|
514
|
+
getResultSrv,
|
|
515
|
+
feedbackMessageMsg,
|
|
516
|
+
action,
|
|
517
|
+
]);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
311
521
|
module.exports = generateJSStructFromIDL;
|
package/rosidl_gen/index.js
CHANGED
|
@@ -18,10 +18,8 @@ const fse = require('../lib/utils.js');
|
|
|
18
18
|
const generateJSStructFromIDL = require('./idl_generator.js');
|
|
19
19
|
const packages = require('./packages.js');
|
|
20
20
|
const path = require('path');
|
|
21
|
-
const idlConvertor = require('../rosidl_convertor/idl_convertor.js');
|
|
22
21
|
const generatedRoot = path.join(__dirname, '../generated/');
|
|
23
22
|
const serviceMsgPath = path.join(generatedRoot, 'srv_msg');
|
|
24
|
-
const idlPath = path.join(generatedRoot, 'share');
|
|
25
23
|
const useIDL = !!process.argv.find((arg) => arg === '--idl');
|
|
26
24
|
|
|
27
25
|
function getInstalledPackagePaths() {
|
|
@@ -35,17 +33,10 @@ async function generateInPath(path) {
|
|
|
35
33
|
(await packages.findPackagesInDirectory(path)).values()
|
|
36
34
|
);
|
|
37
35
|
} else {
|
|
36
|
+
// Direct IDL parsing: pass .idl files to the generator which uses
|
|
37
|
+
// rosidl_parser to parse them directly (no .msg/.srv/.action conversion).
|
|
38
38
|
const idlPkgs = await packages.findPackagesInDirectory(path, useIDL);
|
|
39
|
-
|
|
40
|
-
const promises = [];
|
|
41
|
-
idlPkgs.forEach((pkg) => {
|
|
42
|
-
pkg.idls.forEach((idl) => {
|
|
43
|
-
promises.push(idlConvertor(idl.pkgName, idl.filePath, idlPath));
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
await Promise.all(promises);
|
|
47
|
-
const pkgsFromIdl = await packages.findPackagesInDirectory(idlPath, false);
|
|
48
|
-
pkgsInfo = Array.from(pkgsFromIdl.values());
|
|
39
|
+
pkgsInfo = Array.from(idlPkgs.values());
|
|
49
40
|
}
|
|
50
41
|
|
|
51
42
|
await Promise.all(
|