ads-client 2.0.0-beta.2 → 2.0.0-beta.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/CHANGELOG.md +10 -0
- package/README.md +257 -253
- package/dist/ads-client.d.ts +354 -61
- package/dist/ads-client.js +422 -103
- package/dist/ads-client.js.map +1 -1
- package/dist/types/ads-client-types.d.ts +200 -17
- package/dist/types/ads-client-types.js.map +1 -1
- package/dist/types/ads-protocol-types.d.ts +75 -1
- package/dist/types/ads-protocol-types.js.map +1 -1
- package/package.json +1 -1
package/dist/ads-client.js
CHANGED
|
@@ -51,29 +51,39 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
51
51
|
};
|
|
52
52
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
53
53
|
exports.Client = exports.ADS = void 0;
|
|
54
|
-
const events_1 = __importDefault(require("events"));
|
|
55
54
|
const net_1 = require("net");
|
|
55
|
+
const events_1 = __importDefault(require("events"));
|
|
56
56
|
const debug_1 = __importDefault(require("debug"));
|
|
57
57
|
const long_1 = __importDefault(require("long"));
|
|
58
58
|
const ADS = __importStar(require("./ads-commons"));
|
|
59
59
|
const client_error_1 = __importDefault(require("./client-error"));
|
|
60
|
+
/**
|
|
61
|
+
* Common ADS constants and helper functions
|
|
62
|
+
*
|
|
63
|
+
* @category Client
|
|
64
|
+
*/
|
|
60
65
|
exports.ADS = __importStar(require("./ads-commons"));
|
|
61
66
|
/**
|
|
62
67
|
* A class for handling TwinCAT ADS protocol communication.
|
|
63
68
|
*
|
|
64
69
|
* Settings are provided in constructor - see {@link Client.constructor} and {@link AdsClientSettings}.
|
|
65
70
|
*
|
|
66
|
-
* A client instance should be created for each target
|
|
67
|
-
* can also be used to communicate with
|
|
71
|
+
* A client instance should be created for each target.
|
|
72
|
+
* However, a single client instance can also be used to communicate with
|
|
73
|
+
* multiple endpoints using the `targetOpts` parameter available in all methods.
|
|
68
74
|
*
|
|
69
|
-
*
|
|
75
|
+
* Client also emits different events, such as `client.on('connect', ...)`.
|
|
76
|
+
* See {@link AdsClientEvents} for all available events.
|
|
70
77
|
*
|
|
78
|
+
* @example
|
|
71
79
|
* ```js
|
|
72
80
|
* const client = new Client({
|
|
73
81
|
* targetAmsNetId: "192.168.4.1.1.1",
|
|
74
82
|
* targetAdsPort: 851
|
|
75
83
|
* });
|
|
76
84
|
* ```
|
|
85
|
+
*
|
|
86
|
+
* @category Client
|
|
77
87
|
*/
|
|
78
88
|
class Client extends events_1.default {
|
|
79
89
|
/**
|
|
@@ -222,7 +232,8 @@ class Client extends events_1.default {
|
|
|
222
232
|
connectionDownDelay: 5000,
|
|
223
233
|
allowHalfOpen: false,
|
|
224
234
|
rawClient: false,
|
|
225
|
-
disableCaching: false
|
|
235
|
+
disableCaching: false,
|
|
236
|
+
deleteUnknownSubscriptions: true
|
|
226
237
|
};
|
|
227
238
|
/**
|
|
228
239
|
* Active connection information.
|
|
@@ -247,6 +258,17 @@ class Client extends events_1.default {
|
|
|
247
258
|
};
|
|
248
259
|
}
|
|
249
260
|
;
|
|
261
|
+
/**
|
|
262
|
+
* Emits a warning, which results in a `warning` event, and a console message if `hideConsoleWarnings` is not set.
|
|
263
|
+
*
|
|
264
|
+
* @param message Warning message
|
|
265
|
+
*/
|
|
266
|
+
warn(message) {
|
|
267
|
+
if (!this.settings.hideConsoleWarnings) {
|
|
268
|
+
console.log(`WARNING: ${message}`);
|
|
269
|
+
}
|
|
270
|
+
this.emit('warning', message);
|
|
271
|
+
}
|
|
250
272
|
/**
|
|
251
273
|
* Clears given timer if it's available and increases the ID.
|
|
252
274
|
*
|
|
@@ -409,13 +431,13 @@ class Client extends events_1.default {
|
|
|
409
431
|
}
|
|
410
432
|
//allowHalfOpen allows this, but show some warnings..
|
|
411
433
|
if (!this.metaData.tcSystemState) {
|
|
412
|
-
|
|
434
|
+
this.warn(`"allowHalfOpen" setting is active. Target is connected but no connection to TwinCAT system. If target is not PLC runtime, use setting "rawClient" instead of "allowHalfOpen".`);
|
|
413
435
|
}
|
|
414
436
|
else if (this.metaData.tcSystemState.adsState !== ADS.ADS_STATE.Run) {
|
|
415
|
-
|
|
437
|
+
this.warn(`"allowHalfOpen" setting is active. Target is connected but TwinCAT system is in ${this.metaData.tcSystemState.adsStateStr} instead of run mode. No connection to PLC runtime.`);
|
|
416
438
|
}
|
|
417
439
|
else {
|
|
418
|
-
|
|
440
|
+
this.warn(`"allowHalfOpen" setting is active. No connection to PLC runtime. Check "targetAdsPort" setting and PLC status`);
|
|
419
441
|
}
|
|
420
442
|
}
|
|
421
443
|
}
|
|
@@ -488,6 +510,7 @@ class Client extends events_1.default {
|
|
|
488
510
|
connected: false
|
|
489
511
|
};
|
|
490
512
|
this.metaData = { ...this.defaultMetaData };
|
|
513
|
+
this.activeSubscriptions = {};
|
|
491
514
|
this.socket?.removeAllListeners();
|
|
492
515
|
this.socket?.destroy();
|
|
493
516
|
this.socket = undefined;
|
|
@@ -508,6 +531,7 @@ class Client extends events_1.default {
|
|
|
508
531
|
connected: false
|
|
509
532
|
};
|
|
510
533
|
this.metaData = { ...this.defaultMetaData };
|
|
534
|
+
this.activeSubscriptions = {};
|
|
511
535
|
this.socket?.removeAllListeners();
|
|
512
536
|
this.socket?.destroy();
|
|
513
537
|
this.socket = undefined;
|
|
@@ -525,6 +549,7 @@ class Client extends events_1.default {
|
|
|
525
549
|
connected: false
|
|
526
550
|
};
|
|
527
551
|
this.metaData = { ...this.defaultMetaData };
|
|
552
|
+
this.activeSubscriptions = {};
|
|
528
553
|
this.debug(`disconnectFromTarget(): Connection closing failed, connection was forced to close`);
|
|
529
554
|
this.emit("disconnect", isReconnecting);
|
|
530
555
|
return reject(new client_error_1.default(`disconnect(): Disconnected with errors: ${disconnectError.message}`, err));
|
|
@@ -555,11 +580,11 @@ class Client extends events_1.default {
|
|
|
555
580
|
//Trying to subscribe to previous subscriptions again
|
|
556
581
|
const failures = await this.restoreSubscriptions();
|
|
557
582
|
if (!failures.length) {
|
|
558
|
-
isReconnecting &&
|
|
583
|
+
isReconnecting && this.warn(`Reconnected and all subscriptions were restored!`);
|
|
559
584
|
this.debug(`reconnectToTarget(): Reconnected and all subscriptions were restored!`);
|
|
560
585
|
}
|
|
561
586
|
else {
|
|
562
|
-
|
|
587
|
+
this.warn(`Reconnected but failed to restore following subscriptions:\n - ${failures.join('\n - ')}`);
|
|
563
588
|
this.debug(`reconnectToTarget(): Reconnected but failed to restore following subscriptions: ${failures.join(', ')}`);
|
|
564
589
|
}
|
|
565
590
|
this.emit('reconnect', !failures.length, failures);
|
|
@@ -906,7 +931,7 @@ class Client extends events_1.default {
|
|
|
906
931
|
await this.restoreSubscriptions();
|
|
907
932
|
}
|
|
908
933
|
catch (err) {
|
|
909
|
-
|
|
934
|
+
this.warn(`Target PLC symbol version changed and all subscriptions were not restored (data might be lost from now on). Error info: ${JSON.stringify(err)}`);
|
|
910
935
|
this.debug(`onPlcSymbolVersionChanged(): Failed to restore all subscriptions. Error: %o`, err);
|
|
911
936
|
}
|
|
912
937
|
}
|
|
@@ -920,7 +945,7 @@ class Client extends events_1.default {
|
|
|
920
945
|
* See also {@link Client.socketErrorHandler} which is `onSocketError.bind(this)`
|
|
921
946
|
*/
|
|
922
947
|
onSocketError(err) {
|
|
923
|
-
|
|
948
|
+
this.warn(`Socket connection to target closed to an an error, disconnecting: ${JSON.stringify(err)}`);
|
|
924
949
|
this.onConnectionLost(true);
|
|
925
950
|
}
|
|
926
951
|
/**
|
|
@@ -936,12 +961,12 @@ class Client extends events_1.default {
|
|
|
936
961
|
this.connection.connected = false;
|
|
937
962
|
this.emit('connectionLost', socketFailure);
|
|
938
963
|
if (this.settings.autoReconnect !== true) {
|
|
939
|
-
|
|
964
|
+
this.warn("Connection to target was lost and setting autoReconnect was false -> disconnecting");
|
|
940
965
|
await this.disconnectFromTarget(true).catch();
|
|
941
966
|
return;
|
|
942
967
|
}
|
|
943
968
|
this.socketConnectionLostHandler && this.socket?.off('close', this.socketConnectionLostHandler);
|
|
944
|
-
|
|
969
|
+
this.warn("Connection to target was lost. Trying to reconnect automatically...");
|
|
945
970
|
const tryToReconnect = async (firstRetryAttempt, timerId) => {
|
|
946
971
|
//If the timer has changed, quit here (to prevent multiple timers)
|
|
947
972
|
if (this.reconnectionTimer.id !== timerId) {
|
|
@@ -958,7 +983,7 @@ class Client extends events_1.default {
|
|
|
958
983
|
//Reconnecting failed
|
|
959
984
|
if (firstRetryAttempt) {
|
|
960
985
|
this.debug(`onConnectionLost()/tryToReconnect(): Reconnecting failed, keeping trying in the background (${err.message}`);
|
|
961
|
-
|
|
986
|
+
this.warn(`Reconnecting failed. Keeping trying in the background every ${this.settings.reconnectInterval} ms...`);
|
|
962
987
|
}
|
|
963
988
|
//If this is still a valid timer, start over again
|
|
964
989
|
if (this.reconnectionTimer.id === timerId) {
|
|
@@ -1434,12 +1459,24 @@ class Client extends events_1.default {
|
|
|
1434
1459
|
})
|
|
1435
1460
|
.catch(err => {
|
|
1436
1461
|
this.debug(`onAdsCommandReceived(): Notification received but parsing Javascript object failed: %o`, err);
|
|
1437
|
-
this.emit('client-error', new client_error_1.default(`
|
|
1462
|
+
this.emit('client-error', new client_error_1.default(`An ADS notification received but parsing data to a Javascript object failed. Subscription: ${JSON.stringify(subscription)}`, err));
|
|
1463
|
+
});
|
|
1464
|
+
}
|
|
1465
|
+
else if (this.settings.deleteUnknownSubscriptions) {
|
|
1466
|
+
this.debug(`onAdsCommandReceived(): An ADS notification with an unknown handle ${sample.notificationHandle} was received from ${key}. Trying to delete it to save resources (deleteUnknownSubscriptions is set).`);
|
|
1467
|
+
this.deleteNotificationHandle(sample.notificationHandle, packet.ams.sourceAmsAddress)
|
|
1468
|
+
.then(() => {
|
|
1469
|
+
this.debug(`onAdsCommandReceived(): An ADS notification with an unknown handle ${sample.notificationHandle} was received from ${key} and automatically deleted`);
|
|
1470
|
+
this.warn(`An ADS notification with an unknown handle ${sample.notificationHandle} was received from ${key} and automatically deleted`);
|
|
1471
|
+
})
|
|
1472
|
+
.catch(err => {
|
|
1473
|
+
this.debug(`onAdsCommandReceived(): Failed to delete an unknown ADS notification handle ${sample.notificationHandle} (from ${key}): %o`, err);
|
|
1474
|
+
this.emit('client-error', new client_error_1.default(`Failed to delete an unknown ADS notification handle ${sample.notificationHandle} (from ${key})`, err));
|
|
1438
1475
|
});
|
|
1439
1476
|
}
|
|
1440
1477
|
else {
|
|
1441
|
-
this.
|
|
1442
|
-
this.
|
|
1478
|
+
this.debug(`onAdsCommandReceived(): Notification received with unknown handle ${sample.notificationHandle} (${key})`);
|
|
1479
|
+
this.warn(`An ADS notification with an unknown handle ${sample.notificationHandle} was received from ${key}. Use unsubscribe() or deleteUnknownSubscriptions setting to save resources.`);
|
|
1443
1480
|
}
|
|
1444
1481
|
}
|
|
1445
1482
|
}
|
|
@@ -1454,7 +1491,7 @@ class Client extends events_1.default {
|
|
|
1454
1491
|
}
|
|
1455
1492
|
else {
|
|
1456
1493
|
this.debugD(`onAdsCommandReceived(): Ads command received with unknown invokeId "${packet.ams.invokeId}"`);
|
|
1457
|
-
this.emit('client-error', new client_error_1.default(`
|
|
1494
|
+
this.emit('client-error', new client_error_1.default(`Ads command received with unknown invokeId "${packet.ams.invokeId}"`));
|
|
1458
1495
|
}
|
|
1459
1496
|
break;
|
|
1460
1497
|
}
|
|
@@ -1486,7 +1523,7 @@ class Client extends events_1.default {
|
|
|
1486
1523
|
this.clearTimer(this.tcSystemStatePollerTimer);
|
|
1487
1524
|
this.debug("onRouterStateChanged(): Local loopback connection active, monitoring router state. Reconnecting when router is back running.");
|
|
1488
1525
|
if (this.metaData.routerState.state === ADS.AMS_ROUTER_STATE.START) {
|
|
1489
|
-
|
|
1526
|
+
this.warn(`Local AMS router state has changed to ${this.metaData.routerState.stateStr}. Reconnecting...`);
|
|
1490
1527
|
this.onConnectionLost();
|
|
1491
1528
|
}
|
|
1492
1529
|
else {
|
|
@@ -1859,7 +1896,7 @@ class Client extends events_1.default {
|
|
|
1859
1896
|
}
|
|
1860
1897
|
//If extended flag RefactorInfo is set
|
|
1861
1898
|
if ((symbol.extendedFlags & ADS.ADS_SYMBOL_FLAGS_2.RefactorInfo) === ADS.ADS_SYMBOL_FLAGS_2.RefactorInfo) {
|
|
1862
|
-
|
|
1899
|
+
this.warn(`Symbol ${symbol.name} (${symbol.type}) has extended flag "RefactorInfo" which is not supported. Things might not work now. Please open an issue at Github`);
|
|
1863
1900
|
}
|
|
1864
1901
|
//Reserved, if any
|
|
1865
1902
|
symbol.reserved = data.subarray(pos);
|
|
@@ -2164,7 +2201,7 @@ class Client extends events_1.default {
|
|
|
2164
2201
|
if ((dataType.flags & ADS.ADS_DATA_TYPE_FLAGS.RefactorInfo) === ADS.ADS_DATA_TYPE_FLAGS.RefactorInfo) {
|
|
2165
2202
|
//TODO: this is not working now
|
|
2166
2203
|
//Things probably break now
|
|
2167
|
-
|
|
2204
|
+
this.warn(`Data type ${dataType.name} (${dataType.type}) has flag "RefactorInfo" which is not supported. Things might not work now. Please open an issue at Github`);
|
|
2168
2205
|
}
|
|
2169
2206
|
//If flag ExtendedFlags set
|
|
2170
2207
|
if ((dataType.flags & ADS.ADS_DATA_TYPE_FLAGS.ExtendedFlags) === ADS.ADS_DATA_TYPE_FLAGS.ExtendedFlags) {
|
|
@@ -2181,13 +2218,13 @@ class Client extends events_1.default {
|
|
|
2181
2218
|
if ((dataType.flags & ADS.ADS_DATA_TYPE_FLAGS.ExtendedEnumInfos) === ADS.ADS_DATA_TYPE_FLAGS.ExtendedEnumInfos) {
|
|
2182
2219
|
//TODO: this is not working now
|
|
2183
2220
|
//Things probably break now
|
|
2184
|
-
|
|
2221
|
+
this.warn(`Data type ${dataType.name} (${dataType.type}) has flag "ExtendedEnumInfos" which is not supported. Things might not work now. Please open an issue at Github`);
|
|
2185
2222
|
}
|
|
2186
2223
|
//If flag SoftwareProtectionLevels set
|
|
2187
2224
|
if ((dataType.flags & ADS.ADS_DATA_TYPE_FLAGS.SoftwareProtectionLevels) === ADS.ADS_DATA_TYPE_FLAGS.SoftwareProtectionLevels) {
|
|
2188
2225
|
//TODO: this is not working now
|
|
2189
2226
|
//Things probably break now
|
|
2190
|
-
|
|
2227
|
+
this.warn(`Data type ${dataType.name} (${dataType.type}) has flag "SoftwareProtectionLevels" which is not supported. Things might not work now. Please open an issue at Github`);
|
|
2191
2228
|
}
|
|
2192
2229
|
//Reserved, if any
|
|
2193
2230
|
dataType.reserved = data.subarray(pos);
|
|
@@ -2901,14 +2938,44 @@ class Client extends events_1.default {
|
|
|
2901
2938
|
* - {@link Client.unsubscribe}() - `DeleteNotification` command
|
|
2902
2939
|
* - {@link Client.readWriteRaw}() - `ReadWrite` command
|
|
2903
2940
|
*
|
|
2904
|
-
* @template T ADS response type. If omitted, generic {@link AdsResponse} type is used
|
|
2905
|
-
*
|
|
2906
|
-
* @throws Throws an error if sending the command fails or if target responds with an error
|
|
2907
|
-
*
|
|
2908
2941
|
* @example
|
|
2909
2942
|
* ```js
|
|
2910
|
-
*
|
|
2943
|
+
* try {
|
|
2944
|
+
* //Creating readRaw(16448, 414816, 2) command manually and sending it using sendAdsCommand()
|
|
2945
|
+
*
|
|
2946
|
+
* const data = Buffer.alloc(12);
|
|
2947
|
+
* let pos = 0;
|
|
2948
|
+
*
|
|
2949
|
+
* //0..3 IndexGroup
|
|
2950
|
+
* data.writeUInt32LE(16448, pos);
|
|
2951
|
+
* pos += 4;
|
|
2952
|
+
*
|
|
2953
|
+
* //4..7 IndexOffset
|
|
2954
|
+
* data.writeUInt32LE(414816, pos);
|
|
2955
|
+
* pos += 4;
|
|
2956
|
+
*
|
|
2957
|
+
* //8..11 Read data length
|
|
2958
|
+
* data.writeUInt32LE(2, pos);
|
|
2959
|
+
* pos += 4;
|
|
2960
|
+
*
|
|
2961
|
+
* const res = await this.sendAdsCommand<AdsReadResponse>({
|
|
2962
|
+
* adsCommand: ADS.ADS_COMMAND.Read,
|
|
2963
|
+
* targetAmsNetId: targetOpts.amsNetId,
|
|
2964
|
+
* targetAdsPort: targetOpts.adsPort,
|
|
2965
|
+
* payload: data
|
|
2966
|
+
* });
|
|
2967
|
+
*
|
|
2968
|
+
* console.log(res.ads.payload); //<Buffer ff 7f>
|
|
2969
|
+
*
|
|
2970
|
+
* } catch (err) {
|
|
2971
|
+
* console.log("Error:", err);
|
|
2972
|
+
* }
|
|
2911
2973
|
* ```
|
|
2974
|
+
*
|
|
2975
|
+
* @template T In Typescript, the type of the ADS response. If omitted, generic {@link AdsResponse} type is used.
|
|
2976
|
+
*
|
|
2977
|
+
* @throws Throws an error if sending the command fails or if target responds with an error
|
|
2978
|
+
*
|
|
2912
2979
|
*/
|
|
2913
2980
|
async sendAdsCommand(command) {
|
|
2914
2981
|
return new Promise(async (resolve, reject) => {
|
|
@@ -3221,7 +3288,7 @@ class Client extends events_1.default {
|
|
|
3221
3288
|
this.debug(`setTcSystemToRun(): TwinCAT system at ${this.targetToString(targetOpts)} set to run mode`);
|
|
3222
3289
|
if (reconnect) {
|
|
3223
3290
|
this.debug(`setTcSystemToRun(): Reconnecting after TwinCAT system restart`);
|
|
3224
|
-
|
|
3291
|
+
this.warn("Reconnecting after TwinCAT system restart");
|
|
3225
3292
|
this.onConnectionLost();
|
|
3226
3293
|
}
|
|
3227
3294
|
}
|
|
@@ -3300,7 +3367,7 @@ class Client extends events_1.default {
|
|
|
3300
3367
|
this.debug(`restartTcSystem(): TwinCAT system was restarted`);
|
|
3301
3368
|
}
|
|
3302
3369
|
/**
|
|
3303
|
-
* Returns symbol for given variable path, such as `GVL_Test.ExampleStruct`.
|
|
3370
|
+
* Returns a symbol object for given variable path, such as `GVL_Test.ExampleStruct`.
|
|
3304
3371
|
*
|
|
3305
3372
|
* Returns previously cached value if available, otherwise reads it from the target
|
|
3306
3373
|
* and caches it.
|
|
@@ -3671,7 +3738,7 @@ class Client extends events_1.default {
|
|
|
3671
3738
|
}
|
|
3672
3739
|
}
|
|
3673
3740
|
/**
|
|
3674
|
-
* Subscribes to raw value change notifications (ADS notifications) by raw ADS address (index group, index offset and data length).
|
|
3741
|
+
* Subscribes to raw value change notifications (ADS notifications) by a raw ADS address (index group, index offset and data length).
|
|
3675
3742
|
*
|
|
3676
3743
|
* Provided callback is called with the latest value when the value changes or when
|
|
3677
3744
|
* enough time has passed (depending on settings).
|
|
@@ -3830,19 +3897,8 @@ class Client extends events_1.default {
|
|
|
3830
3897
|
throw new client_error_1.default(`unsubscribe(): Client is not connected. Use connect() to connect to the target first.`);
|
|
3831
3898
|
}
|
|
3832
3899
|
this.debug(`unsubscribe(): Unsubscribing %o`, subscription);
|
|
3833
|
-
//Allocating bytes for request
|
|
3834
|
-
const data = Buffer.alloc(4);
|
|
3835
|
-
let pos = 0;
|
|
3836
|
-
//0..3 Notification handle
|
|
3837
|
-
data.writeUInt32LE(subscription.notificationHandle, pos);
|
|
3838
|
-
pos += 4;
|
|
3839
3900
|
try {
|
|
3840
|
-
|
|
3841
|
-
adsCommand: ADS.ADS_COMMAND.DeleteNotification,
|
|
3842
|
-
targetAmsNetId: subscription.remoteAddress.amsNetId,
|
|
3843
|
-
targetAdsPort: subscription.remoteAddress.adsPort,
|
|
3844
|
-
payload: data
|
|
3845
|
-
});
|
|
3901
|
+
await this.deleteNotificationHandle(subscription.notificationHandle, subscription.remoteAddress);
|
|
3846
3902
|
const address = ADS.amsAddressToString(subscription.remoteAddress);
|
|
3847
3903
|
if (this.activeSubscriptions[address]) {
|
|
3848
3904
|
delete this.activeSubscriptions[address][subscription.notificationHandle];
|
|
@@ -3854,6 +3910,33 @@ class Client extends events_1.default {
|
|
|
3854
3910
|
throw new client_error_1.default(`unsubscribe(): Unsubscribing failed`, err);
|
|
3855
3911
|
}
|
|
3856
3912
|
}
|
|
3913
|
+
/**
|
|
3914
|
+
* Sends a delete ADS notification command to the target system.
|
|
3915
|
+
*
|
|
3916
|
+
* Doesn't delete subscriptions, just sends the ADS command.
|
|
3917
|
+
*
|
|
3918
|
+
* @param notificationHandle Notification handle to delete (number)
|
|
3919
|
+
* @param targetAmsAddress Target system address
|
|
3920
|
+
*
|
|
3921
|
+
* @throws NOTE: Throws error if failed
|
|
3922
|
+
*/
|
|
3923
|
+
async deleteNotificationHandle(notificationHandle, targetAmsAddress) {
|
|
3924
|
+
this.debug(`deleteNotificationHandle(): Sending DeleteNotification command for handle ${notificationHandle} to ${ADS.amsAddressToString(targetAmsAddress)}`);
|
|
3925
|
+
//Allocating bytes for request
|
|
3926
|
+
const data = Buffer.alloc(4);
|
|
3927
|
+
let pos = 0;
|
|
3928
|
+
//0..3 Notification handle
|
|
3929
|
+
data.writeUInt32LE(notificationHandle, pos);
|
|
3930
|
+
pos += 4;
|
|
3931
|
+
const res = await this.sendAdsCommand({
|
|
3932
|
+
adsCommand: ADS.ADS_COMMAND.DeleteNotification,
|
|
3933
|
+
targetAmsNetId: targetAmsAddress.amsNetId,
|
|
3934
|
+
targetAdsPort: targetAmsAddress.adsPort,
|
|
3935
|
+
payload: data
|
|
3936
|
+
});
|
|
3937
|
+
this.debug(`deleteNotificationHandle(): Notification for handle ${notificationHandle} (${ADS.amsAddressToString(targetAmsAddress)}) deleted!`);
|
|
3938
|
+
return res.ads;
|
|
3939
|
+
}
|
|
3857
3940
|
/**
|
|
3858
3941
|
* Unsubscribes all active subscription (deletes all ADS notifications).
|
|
3859
3942
|
*
|
|
@@ -4268,16 +4351,30 @@ class Client extends events_1.default {
|
|
|
4268
4351
|
}
|
|
4269
4352
|
}
|
|
4270
4353
|
/**
|
|
4271
|
-
*
|
|
4354
|
+
* Reads raw data from the target system by a raw ADS address (index group, index offset and data length).
|
|
4272
4355
|
*
|
|
4273
|
-
*
|
|
4356
|
+
* This is the ADS protocol `Read` command.
|
|
4274
4357
|
*
|
|
4275
|
-
*
|
|
4358
|
+
* @example
|
|
4359
|
+
* ```js
|
|
4360
|
+
* try {
|
|
4361
|
+
* const data = await client.readRaw(16448, 414816, 2);
|
|
4362
|
+
* console.log(data); //<Buffer ff 7f>
|
|
4363
|
+
*
|
|
4364
|
+
* const converted = await client.convertFromRaw(data, 'INT');
|
|
4365
|
+
* console.log(converted); //32767
|
|
4366
|
+
*
|
|
4367
|
+
* } catch (err) {
|
|
4368
|
+
* console.log("Error:", err);
|
|
4369
|
+
* }
|
|
4370
|
+
* ```
|
|
4276
4371
|
*
|
|
4277
4372
|
* @param indexGroup Index group (address) of the data to read
|
|
4278
4373
|
* @param indexOffset Index offset (address) of the data to read
|
|
4279
4374
|
* @param size Data length to read (bytes)
|
|
4280
4375
|
* @param targetOpts Optional target settings that override values in `settings`
|
|
4376
|
+
*
|
|
4377
|
+
* @throws Throws an error if sending the command fails or if the target responds with an error.
|
|
4281
4378
|
*/
|
|
4282
4379
|
async readRaw(indexGroup, indexOffset, size, targetOpts = {}) {
|
|
4283
4380
|
if (!this.connection.connected) {
|
|
@@ -4312,16 +4409,28 @@ class Client extends events_1.default {
|
|
|
4312
4409
|
}
|
|
4313
4410
|
}
|
|
4314
4411
|
/**
|
|
4315
|
-
*
|
|
4412
|
+
* Writes raw data to the target system by a raw ADS address (index group, index offset and data length).
|
|
4316
4413
|
*
|
|
4317
|
-
*
|
|
4414
|
+
* This is the ADS protocol `Write` command.
|
|
4318
4415
|
*
|
|
4319
|
-
*
|
|
4416
|
+
* @example
|
|
4417
|
+
* ```js
|
|
4418
|
+
* try {
|
|
4419
|
+
* const data = await client.convertToRaw(32767, 'INT');
|
|
4420
|
+
* console.log(data); //<Buffer ff 7f>
|
|
4421
|
+
*
|
|
4422
|
+
* await client.writeRaw(16448, 414816, data);
|
|
4423
|
+
* } catch (err) {
|
|
4424
|
+
* console.log("Error:", err);
|
|
4425
|
+
* }
|
|
4426
|
+
* ```
|
|
4320
4427
|
*
|
|
4321
4428
|
* @param indexGroup Index group (address) of the data to write to
|
|
4322
4429
|
* @param indexOffset Index offset (address) of the data to write to
|
|
4323
4430
|
* @param value Data to write
|
|
4324
4431
|
* @param targetOpts Optional target settings that override values in `settings`
|
|
4432
|
+
*
|
|
4433
|
+
* @throws Throws an error if sending the command fails or if the target responds with an error.
|
|
4325
4434
|
*/
|
|
4326
4435
|
async writeRaw(indexGroup, indexOffset, value, targetOpts = {}) {
|
|
4327
4436
|
if (!this.connection.connected) {
|
|
@@ -4357,16 +4466,45 @@ class Client extends events_1.default {
|
|
|
4357
4466
|
}
|
|
4358
4467
|
}
|
|
4359
4468
|
/**
|
|
4360
|
-
*
|
|
4469
|
+
* Sends multiple `readRaw()` commands in one ADS packet.
|
|
4361
4470
|
*
|
|
4362
|
-
*
|
|
4471
|
+
* Reads raw data from the target system by a raw ADS addresses (index group, index offset and data length).
|
|
4472
|
+
* Results are returned for each command separately - see {@link ReadRawMultiResult} for details.
|
|
4363
4473
|
*
|
|
4364
|
-
*
|
|
4474
|
+
* Uses ADS sum command under the hood (better and faster performance).
|
|
4475
|
+
* See [Beckhoff Information System](https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_adsdll2/9007199379576075.html&id=9180083787138954512) for more info.
|
|
4365
4476
|
*
|
|
4366
|
-
*
|
|
4477
|
+
* @example
|
|
4478
|
+
* ```js
|
|
4479
|
+
* try {
|
|
4480
|
+
* const results = await client.readRawMulti([
|
|
4481
|
+
* {
|
|
4482
|
+
* indexGroup: 16448,
|
|
4483
|
+
* indexOffset: 414816,
|
|
4484
|
+
* size: 2
|
|
4485
|
+
* },
|
|
4486
|
+
* {
|
|
4487
|
+
* indexGroup: 16448,
|
|
4488
|
+
* indexOffset: 414900,
|
|
4489
|
+
* size: 128
|
|
4490
|
+
* }
|
|
4491
|
+
* ]);
|
|
4492
|
+
*
|
|
4493
|
+
* if(results[0].success) {
|
|
4494
|
+
* console.log(`First result: ${results[0].value}`); //First result: <Buffer ff 7f>
|
|
4495
|
+
* } else {
|
|
4496
|
+
* console.log(`First read command failed: ${results[0].errorStr}`);
|
|
4497
|
+
* }
|
|
4498
|
+
*
|
|
4499
|
+
* } catch (err) {
|
|
4500
|
+
* console.log("Error:", err);
|
|
4501
|
+
* }
|
|
4502
|
+
* ```
|
|
4367
4503
|
*
|
|
4368
4504
|
* @param commands Array of read commands
|
|
4369
4505
|
* @param targetOpts Optional target settings that override values in `settings`
|
|
4506
|
+
*
|
|
4507
|
+
* @throws Throws an error if sending the command fails or if the target responds with an error.
|
|
4370
4508
|
*/
|
|
4371
4509
|
async readRawMulti(commands, targetOpts = {}) {
|
|
4372
4510
|
if (!this.connection.connected) {
|
|
@@ -4442,16 +4580,50 @@ class Client extends events_1.default {
|
|
|
4442
4580
|
}
|
|
4443
4581
|
}
|
|
4444
4582
|
/**
|
|
4445
|
-
*
|
|
4583
|
+
* Sends multiple `writeRaw()` commands in one ADS packet.
|
|
4446
4584
|
*
|
|
4447
|
-
*
|
|
4585
|
+
* Writes raw data to the target system by a raw ADS addresses (index group and index offset).
|
|
4586
|
+
* Results are returned for each command separately - see {@link WriteRawMultiResult} for details.
|
|
4448
4587
|
*
|
|
4449
|
-
*
|
|
4588
|
+
* Uses ADS sum command under the hood (better and faster performance).
|
|
4589
|
+
* See [Beckhoff Information System](https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_adsdll2/9007199379576075.html&id=9180083787138954512) for more info.
|
|
4450
4590
|
*
|
|
4451
|
-
*
|
|
4591
|
+
* @example
|
|
4592
|
+
* ```js
|
|
4593
|
+
* try {
|
|
4594
|
+
* const data1 = await client.convertToRaw(32767, 'INT');
|
|
4595
|
+
* console.log(data1); //<Buffer ff 7f>
|
|
4596
|
+
*
|
|
4597
|
+
* const data2 = Buffer.alloc(128); //example
|
|
4598
|
+
*
|
|
4599
|
+
* const results = await client.writeRawMulti([
|
|
4600
|
+
* {
|
|
4601
|
+
* indexGroup: 16448,
|
|
4602
|
+
* indexOffset: 414816,
|
|
4603
|
+
* value: data1
|
|
4604
|
+
* },
|
|
4605
|
+
* {
|
|
4606
|
+
* indexGroup: 16448,
|
|
4607
|
+
* indexOffset: 414900,
|
|
4608
|
+
* value: data2
|
|
4609
|
+
* }
|
|
4610
|
+
* ]);
|
|
4611
|
+
*
|
|
4612
|
+
* if(results[0].success) {
|
|
4613
|
+
* console.log(`First write command successful`);
|
|
4614
|
+
* } else {
|
|
4615
|
+
* console.log(`First write command failed: ${results[0].errorStr}`);
|
|
4616
|
+
* }
|
|
4617
|
+
*
|
|
4618
|
+
* } catch (err) {
|
|
4619
|
+
* console.log("Error:", err);
|
|
4620
|
+
* }
|
|
4621
|
+
* ```
|
|
4452
4622
|
*
|
|
4453
4623
|
* @param commands Array of write commands
|
|
4454
4624
|
* @param targetOpts Optional target settings that override values in `settings`
|
|
4625
|
+
*
|
|
4626
|
+
* @throws Throws an error if sending the command fails or if the target responds with an error.
|
|
4455
4627
|
*/
|
|
4456
4628
|
async writeRawMulti(commands, targetOpts = {}) {
|
|
4457
4629
|
if (!this.connection.connected) {
|
|
@@ -4523,16 +4695,37 @@ class Client extends events_1.default {
|
|
|
4523
4695
|
}
|
|
4524
4696
|
}
|
|
4525
4697
|
/**
|
|
4526
|
-
*
|
|
4698
|
+
* Reads raw data from the target system by variable path (such as `GVL_Test.ExampleStruct`).
|
|
4699
|
+
*
|
|
4700
|
+
* Supports also reading `POINTER` and `REFERENCE` values (see example).
|
|
4701
|
+
*
|
|
4702
|
+
* This uses the ADS `READ_SYMVAL_BYNAME` under the hood, so only one
|
|
4703
|
+
* round-trip is needed.
|
|
4704
|
+
*
|
|
4705
|
+
* @example
|
|
4706
|
+
* ```js
|
|
4707
|
+
* try {
|
|
4708
|
+
* const data = await client.readRawByPath('GVL_Read.StandardTypes.INT_');
|
|
4709
|
+
* console.log(data); //<Buffer ff 7f>
|
|
4527
4710
|
*
|
|
4528
|
-
*
|
|
4711
|
+
* const converted = await client.convertFromRaw(data, 'INT');
|
|
4712
|
+
* console.log(converted); //32767
|
|
4529
4713
|
*
|
|
4530
|
-
*
|
|
4714
|
+
* //Reading a POINTER value (Note the dereference operator ^)
|
|
4715
|
+
* const ptrValue = await client.readRawByPath('GVL_Read.ComplexTypes.POINTER_^');
|
|
4531
4716
|
*
|
|
4532
|
-
*
|
|
4717
|
+
* //Reading a REFERENCE value
|
|
4718
|
+
* const refValue = await client.readRawByPath('GVL_Read.ComplexTypes.REFERENCE_');
|
|
4719
|
+
*
|
|
4720
|
+
* } catch (err) {
|
|
4721
|
+
* console.log("Error:", err);
|
|
4722
|
+
* }
|
|
4723
|
+
* ```
|
|
4533
4724
|
*
|
|
4534
4725
|
* @param path Variable path in the PLC to read (such as `GVL_Test.ExampleStruct`)
|
|
4535
4726
|
* @param targetOpts Optional target settings that override values in `settings`
|
|
4727
|
+
*
|
|
4728
|
+
* @throws Throws an error if sending the command fails or if the target responds with an error.
|
|
4536
4729
|
*/
|
|
4537
4730
|
async readRawByPath(path, targetOpts = {}) {
|
|
4538
4731
|
if (!this.connection.connected) {
|
|
@@ -4574,17 +4767,39 @@ class Client extends events_1.default {
|
|
|
4574
4767
|
}
|
|
4575
4768
|
}
|
|
4576
4769
|
/**
|
|
4577
|
-
*
|
|
4770
|
+
* Writes raw data to the target system by variable path (such as `GVL_Test.ExampleStruct`).
|
|
4578
4771
|
*
|
|
4579
|
-
*
|
|
4772
|
+
* Supports also writing `POINTER` and `REFERENCE` values (see example).
|
|
4580
4773
|
*
|
|
4581
|
-
*
|
|
4774
|
+
* NOTE: Unlike with {@link readRawByPath}(), this command uses multiple ADS requests for the operation.
|
|
4582
4775
|
*
|
|
4583
|
-
* Unlike `readRawByPath()`, this uses variable handles under the hood, the as there is no direct ADS command available for this.
|
|
4584
4776
|
*
|
|
4585
|
-
* @
|
|
4777
|
+
* @example
|
|
4778
|
+
* ```js
|
|
4779
|
+
* try {
|
|
4780
|
+
* const data = await client.convertToRaw(32767, 'INT');
|
|
4781
|
+
* console.log(data); //<Buffer ff 7f>
|
|
4782
|
+
*
|
|
4783
|
+
* await client.writeRawByPath('GVL_Write.StandardTypes.INT_', data);
|
|
4784
|
+
*
|
|
4785
|
+
* //Writing a POINTER value (Note the dereference operator ^)
|
|
4786
|
+
* const ptrValue = ...
|
|
4787
|
+
* await client.writeRawByPath('GVL_Read.ComplexTypes.POINTER_^', ptrValue);
|
|
4788
|
+
*
|
|
4789
|
+
* //Writing a REFERENCE value
|
|
4790
|
+
* const refValue = ...
|
|
4791
|
+
* await client.readRawByPath('GVL_Read.ComplexTypes.REFERENCE_');
|
|
4792
|
+
*
|
|
4793
|
+
* } catch (err) {
|
|
4794
|
+
* console.log("Error:", err);
|
|
4795
|
+
* }
|
|
4796
|
+
* ```
|
|
4797
|
+
*
|
|
4798
|
+
* @param path Variable path in the PLC to write (such as `GVL_Test.ExampleStruct`)
|
|
4586
4799
|
* @param value Data to write
|
|
4587
4800
|
* @param targetOpts Optional target settings that override values in `settings`
|
|
4801
|
+
*
|
|
4802
|
+
* @throws Throws an error if sending the command fails or if the target responds with an error.
|
|
4588
4803
|
*/
|
|
4589
4804
|
async writeRawByPath(path, value, targetOpts = {}) {
|
|
4590
4805
|
if (!this.connection.connected) {
|
|
@@ -4594,12 +4809,12 @@ class Client extends events_1.default {
|
|
|
4594
4809
|
try {
|
|
4595
4810
|
let handle = null;
|
|
4596
4811
|
try {
|
|
4597
|
-
handle = await this.createVariableHandle(path);
|
|
4598
|
-
await this.writeRawByHandle(handle, value);
|
|
4812
|
+
handle = await this.createVariableHandle(path, targetOpts);
|
|
4813
|
+
await this.writeRawByHandle(handle, value, targetOpts);
|
|
4599
4814
|
}
|
|
4600
4815
|
finally {
|
|
4601
4816
|
if (handle) {
|
|
4602
|
-
await this.deleteVariableHandle(handle);
|
|
4817
|
+
await this.deleteVariableHandle(handle, targetOpts);
|
|
4603
4818
|
}
|
|
4604
4819
|
}
|
|
4605
4820
|
this.debug(`writeRawByPath(): Writing raw data to ${path} done (${value.byteLength} bytes)`);
|
|
@@ -4610,25 +4825,41 @@ class Client extends events_1.default {
|
|
|
4610
4825
|
}
|
|
4611
4826
|
}
|
|
4612
4827
|
/**
|
|
4613
|
-
*
|
|
4828
|
+
* Writes raw data to the target system by a raw ADS address (index group, index offset)
|
|
4829
|
+
* and reads the result as raw data.
|
|
4614
4830
|
*
|
|
4615
|
-
*
|
|
4831
|
+
* This is the ADS protocol `ReadWrite` command.
|
|
4616
4832
|
*
|
|
4617
|
-
*
|
|
4833
|
+
* @example
|
|
4834
|
+
* ```js
|
|
4835
|
+
* const { ADS } = require('../dist/ads-client');
|
|
4836
|
+
*
|
|
4837
|
+
* try {
|
|
4838
|
+
* //Reading raw value by symbol path (= same as readRawByPath())
|
|
4839
|
+
* const path = ADS.encodeStringToPlcStringBuffer('GVL_Read.StandardTypes.INT_');
|
|
4840
|
+
* const data = await client.readWriteRaw(ADS.ADS_RESERVED_INDEX_GROUPS.SymbolValueByName, 0, 0xFFFFFFFF, path);
|
|
4841
|
+
* console.log(data); //<Buffer ff 7f>
|
|
4842
|
+
*
|
|
4843
|
+
* } catch (err) {
|
|
4844
|
+
* console.log("Error:", err);
|
|
4845
|
+
* }
|
|
4846
|
+
* ```
|
|
4618
4847
|
*
|
|
4619
4848
|
* @param indexGroup Address index group
|
|
4620
4849
|
* @param indexOffset Address index offset
|
|
4621
|
-
* @param size
|
|
4622
|
-
* @param
|
|
4850
|
+
* @param size Data length to read (bytes)
|
|
4851
|
+
* @param value Value to write
|
|
4623
4852
|
* @param targetOpts Optional target settings that override values in `settings`
|
|
4853
|
+
*
|
|
4854
|
+
* @throws Throws an error if sending the command fails or if the target responds with an error.
|
|
4624
4855
|
*/
|
|
4625
|
-
async readWriteRaw(indexGroup, indexOffset, size,
|
|
4856
|
+
async readWriteRaw(indexGroup, indexOffset, size, value, targetOpts = {}) {
|
|
4626
4857
|
if (!this.connection.connected) {
|
|
4627
4858
|
throw new client_error_1.default(`readWriteRaw(): Client is not connected. Use connect() to connect to the target first.`);
|
|
4628
4859
|
}
|
|
4629
|
-
this.debug(`readWriteRaw(): Sending ReadWrite command (${JSON.stringify({ indexGroup, indexOffset, size })} with ${
|
|
4860
|
+
this.debug(`readWriteRaw(): Sending ReadWrite command (${JSON.stringify({ indexGroup, indexOffset, size })} with ${value.byteLength} bytes of data`);
|
|
4630
4861
|
//Allocating bytes for request
|
|
4631
|
-
const data = Buffer.alloc(16 +
|
|
4862
|
+
const data = Buffer.alloc(16 + value.byteLength);
|
|
4632
4863
|
let pos = 0;
|
|
4633
4864
|
//0..3 IndexGroup
|
|
4634
4865
|
data.writeUInt32LE(indexGroup, pos);
|
|
@@ -4640,11 +4871,11 @@ class Client extends events_1.default {
|
|
|
4640
4871
|
data.writeUInt32LE(size, pos);
|
|
4641
4872
|
pos += 4;
|
|
4642
4873
|
//12..15 Write data length
|
|
4643
|
-
data.writeUInt32LE(
|
|
4874
|
+
data.writeUInt32LE(value.byteLength, pos);
|
|
4644
4875
|
pos += 4;
|
|
4645
4876
|
//16..n Write data
|
|
4646
|
-
|
|
4647
|
-
pos +=
|
|
4877
|
+
value.copy(data, pos);
|
|
4878
|
+
pos += value.byteLength;
|
|
4648
4879
|
try {
|
|
4649
4880
|
const res = await this.sendAdsCommand({
|
|
4650
4881
|
adsCommand: ADS.ADS_COMMAND.ReadWrite,
|
|
@@ -4661,14 +4892,52 @@ class Client extends events_1.default {
|
|
|
4661
4892
|
}
|
|
4662
4893
|
}
|
|
4663
4894
|
/**
|
|
4664
|
-
*
|
|
4895
|
+
* Sends multiple `readWriteRaw()` commands in one ADS packet.
|
|
4665
4896
|
*
|
|
4666
|
-
*
|
|
4897
|
+
* Writes raw data to the target system by a raw ADS address (index group, index offset)
|
|
4898
|
+
* and reads the result as raw data.
|
|
4667
4899
|
*
|
|
4668
|
-
* Uses ADS sum command under the hood (better performance)
|
|
4900
|
+
* Uses ADS sum command under the hood (better and faster performance).
|
|
4901
|
+
* See [Beckhoff Information System](https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_adsdll2/9007199379576075.html&id=9180083787138954512) for more info.
|
|
4669
4902
|
*
|
|
4670
|
-
* @
|
|
4903
|
+
* @example
|
|
4904
|
+
* ```js
|
|
4905
|
+
* try {
|
|
4906
|
+
* //Reading raw values by symbol paths (= same as readRawByPath())
|
|
4907
|
+
* const path = ADS.encodeStringToPlcStringBuffer('GVL_Read.StandardTypes.INT_');
|
|
4908
|
+
* const path2 = ADS.encodeStringToPlcStringBuffer('GVL_Read.StandardTypes.REAL_');
|
|
4909
|
+
*
|
|
4910
|
+
* const results = await client.readWriteRawMulti([
|
|
4911
|
+
* {
|
|
4912
|
+
* indexGroup: ADS.ADS_RESERVED_INDEX_GROUPS.SymbolValueByName,
|
|
4913
|
+
* indexOffset: 0,
|
|
4914
|
+
* size: 0xFFFF,
|
|
4915
|
+
* value: path
|
|
4916
|
+
* },
|
|
4917
|
+
* {
|
|
4918
|
+
* indexGroup: ADS.ADS_RESERVED_INDEX_GROUPS.SymbolValueByName,
|
|
4919
|
+
* indexOffset: 0,
|
|
4920
|
+
* size: 0xFFFF,
|
|
4921
|
+
* value: path2
|
|
4922
|
+
* }
|
|
4923
|
+
* ]);
|
|
4924
|
+
*
|
|
4925
|
+
* if(results[0].success) {
|
|
4926
|
+
* console.log(`First result: ${results[0].value}`); //First result: <Buffer ff 7f>
|
|
4927
|
+
* } else {
|
|
4928
|
+
* console.log(`First read/write command failed: ${results[0].errorStr}`);
|
|
4929
|
+
* }
|
|
4930
|
+
*
|
|
4931
|
+
* } catch (err) {
|
|
4932
|
+
* console.log("Error:", err);
|
|
4933
|
+
* }
|
|
4934
|
+
*
|
|
4935
|
+
* ```
|
|
4936
|
+
*
|
|
4937
|
+
* @param commands Array of read/write commands
|
|
4671
4938
|
* @param targetOpts Optional target settings that override values in `settings`
|
|
4939
|
+
*
|
|
4940
|
+
* @throws Throws an error if sending the command fails or if the target responds with an error.
|
|
4672
4941
|
*/
|
|
4673
4942
|
async readWriteRawMulti(commands, targetOpts = {}) {
|
|
4674
4943
|
if (!this.connection.connected) {
|
|
@@ -4676,7 +4945,7 @@ class Client extends events_1.default {
|
|
|
4676
4945
|
}
|
|
4677
4946
|
this.debug(`readWriteRawMulti(): Sending ${commands.length} ReadWrite commands`);
|
|
4678
4947
|
const totalSize = commands.reduce((total, command) => total + command.size, 0);
|
|
4679
|
-
const totalWriteSize = commands.reduce((total, command) => total + command.
|
|
4948
|
+
const totalWriteSize = commands.reduce((total, command) => total + command.value.byteLength, 0);
|
|
4680
4949
|
//Allocating bytes for request
|
|
4681
4950
|
const data = Buffer.alloc(16 + commands.length * 16 + totalWriteSize);
|
|
4682
4951
|
let pos = 0;
|
|
@@ -4704,13 +4973,13 @@ class Client extends events_1.default {
|
|
|
4704
4973
|
data.writeUInt32LE(command.size, pos);
|
|
4705
4974
|
pos += 4;
|
|
4706
4975
|
//12..15 Write data length
|
|
4707
|
-
data.writeUInt32LE(command.
|
|
4976
|
+
data.writeUInt32LE(command.value.byteLength, pos);
|
|
4708
4977
|
pos += 4;
|
|
4709
4978
|
});
|
|
4710
4979
|
//data
|
|
4711
4980
|
commands.forEach(command => {
|
|
4712
|
-
command.
|
|
4713
|
-
pos += command.
|
|
4981
|
+
command.value.copy(data, pos);
|
|
4982
|
+
pos += command.value.byteLength;
|
|
4714
4983
|
});
|
|
4715
4984
|
try {
|
|
4716
4985
|
const res = await this.sendAdsCommand({
|
|
@@ -4759,13 +5028,28 @@ class Client extends events_1.default {
|
|
|
4759
5028
|
}
|
|
4760
5029
|
}
|
|
4761
5030
|
/**
|
|
4762
|
-
*
|
|
5031
|
+
* Reads variable's value from the target system by a variable path (such as `GVL_Test.ExampleStruct`)
|
|
5032
|
+
* and returns the value as a Javascript object.
|
|
4763
5033
|
*
|
|
4764
|
-
*
|
|
5034
|
+
* Returns variable's
|
|
5035
|
+
* - converted value
|
|
5036
|
+
* - raw value
|
|
5037
|
+
* - data type
|
|
5038
|
+
* - symbol
|
|
4765
5039
|
*
|
|
4766
|
-
*
|
|
5040
|
+
* **NOTE:** This requires that the target is a PLC runtime or has equivalent ADS protocol support.
|
|
4767
5041
|
*
|
|
4768
|
-
* @
|
|
5042
|
+
* @example
|
|
5043
|
+
* ```js
|
|
5044
|
+
* try {
|
|
5045
|
+
* const res = await client.readValue('GVL_Test.ExampleStruct');
|
|
5046
|
+
* console.log(res.value);
|
|
5047
|
+
* } catch (err) {
|
|
5048
|
+
* console.log("Error:", err);
|
|
5049
|
+
* }
|
|
5050
|
+
* ```
|
|
5051
|
+
*
|
|
5052
|
+
* @param path Variable path in the PLC (such as `GVL_Test.ExampleStruct`)
|
|
4769
5053
|
* @param targetOpts Optional target settings that override values in `settings`
|
|
4770
5054
|
*
|
|
4771
5055
|
* @template T In Typescript, the data type of the value, for example `readValue<number>(...)` or `readValue<ST_TypedStruct>(...)` (default: `any`)
|
|
@@ -4824,13 +5108,30 @@ class Client extends events_1.default {
|
|
|
4824
5108
|
};
|
|
4825
5109
|
}
|
|
4826
5110
|
/**
|
|
4827
|
-
*
|
|
5111
|
+
* Reads variable's value from the target system by a symbol object
|
|
5112
|
+
* and returns the value as a Javascript object.
|
|
4828
5113
|
*
|
|
4829
|
-
*
|
|
5114
|
+
* Returns variable's
|
|
5115
|
+
* - converted value
|
|
5116
|
+
* - raw value
|
|
5117
|
+
* - data type
|
|
5118
|
+
* - symbol
|
|
4830
5119
|
*
|
|
4831
|
-
*
|
|
5120
|
+
* **NOTE:** This requires that the target is a PLC runtime or has equivalent ADS protocol support.
|
|
4832
5121
|
*
|
|
4833
|
-
* @
|
|
5122
|
+
* @example
|
|
5123
|
+
* ```js
|
|
5124
|
+
* try {
|
|
5125
|
+
* const symbol = await client.getSymbol('GVL_Test.ExampleStruct');
|
|
5126
|
+
*
|
|
5127
|
+
* const res = await client.readValueBySymbol(symbol);
|
|
5128
|
+
* console.log(res.value);
|
|
5129
|
+
* } catch (err) {
|
|
5130
|
+
* console.log("Error:", err);
|
|
5131
|
+
* }
|
|
5132
|
+
* ```
|
|
5133
|
+
*
|
|
5134
|
+
* @param symbol Symbol object (acquired using {@link getSymbol}())
|
|
4834
5135
|
* @param targetOpts Optional target settings that override values in `settings`
|
|
4835
5136
|
*
|
|
4836
5137
|
* @template T In Typescript, the data type of the value, for example `readValueBySymbol<number>(...)` or `readValueBySymbol<ST_TypedStruct>(...)` (default: `any`)
|
|
@@ -4842,18 +5143,36 @@ class Client extends events_1.default {
|
|
|
4842
5143
|
return this.readValue(symbol.name, targetOpts);
|
|
4843
5144
|
}
|
|
4844
5145
|
/**
|
|
4845
|
-
*
|
|
5146
|
+
* Writes variable's value to the target system by a variable path (such as `GVL_Test.ExampleStruct`).
|
|
5147
|
+
* Converts the value from a Javascript object to a raw value.
|
|
4846
5148
|
*
|
|
4847
|
-
*
|
|
5149
|
+
* Returns variable's
|
|
5150
|
+
* - converted value
|
|
5151
|
+
* - raw value
|
|
5152
|
+
* - data type
|
|
5153
|
+
* - symbol
|
|
4848
5154
|
*
|
|
4849
|
-
*
|
|
5155
|
+
* **NOTE:** Do not use `autoFill` for `UNION` types, it doesn't work correctly.
|
|
4850
5156
|
*
|
|
4851
|
-
* **NOTE:**
|
|
5157
|
+
* **NOTE:** This requires that the target is a PLC runtime or has equivalent ADS protocol support.
|
|
4852
5158
|
*
|
|
4853
|
-
* @
|
|
5159
|
+
* @example
|
|
5160
|
+
* ```js
|
|
5161
|
+
* try {
|
|
5162
|
+
* const value = {
|
|
5163
|
+
* example: true
|
|
5164
|
+
* };
|
|
5165
|
+
*
|
|
5166
|
+
* const res = await client.writeValue('GVL_Test.ExampleStruct', value);
|
|
5167
|
+
* } catch (err) {
|
|
5168
|
+
* console.log("Error:", err);
|
|
5169
|
+
* }
|
|
5170
|
+
* ```
|
|
5171
|
+
*
|
|
5172
|
+
* @param path Variable path in the PLC (such as `GVL_Test.ExampleStruct`)
|
|
4854
5173
|
* @param value Value to write
|
|
4855
5174
|
* @param targetOpts Optional target settings that override values in `settings`
|
|
4856
|
-
* @param autoFill If
|
|
5175
|
+
* @param autoFill If set and the data type is a container (`STRUCT`, `FUNCTION_BLOCK` etc.), missing properties are automatically set to default values (usually `0` or `''`).
|
|
4857
5176
|
*
|
|
4858
5177
|
* @template T In Typescript, the data type of the value, for example `writeValue<number>(...)` or `writeValue<ST_TypedStruct>(...)`
|
|
4859
5178
|
*/
|