ads-client 2.0.0-beta.2 → 2.0.0-beta.4

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.
@@ -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, however, a single client
67
- * can also be used to communicate with multiple endpoints.
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
- * @example
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
- !this.settings.hideConsoleWarnings && console.log(`WARNING: "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".`);
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
- !this.settings.hideConsoleWarnings && console.log(`WARNING: "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.`);
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
- !this.settings.hideConsoleWarnings && console.log(`WARNING: "allowHalfOpen" setting is active. No connection to PLC runtime. Check "targetAdsPort" setting and PLC status`);
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 && !this.settings.hideConsoleWarnings && console.log(`Reconnected and all subscriptions were restored!`);
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
- !this.settings.hideConsoleWarnings && console.log(`WARNING: Reconnected but failed to restore following subscriptions:\n - ${failures.join('\n - ')}`);
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);
@@ -634,7 +659,7 @@ class Client extends events_1.default {
634
659
  };
635
660
  this.socket?.once('error', errorHandler);
636
661
  try {
637
- await this.socketWrite(packet);
662
+ this.socketWrite(packet);
638
663
  }
639
664
  catch (err) {
640
665
  this.socket?.off('error', errorHandler);
@@ -690,15 +715,45 @@ class Client extends events_1.default {
690
715
  //Sometimes close event is not received, so resolve already here
691
716
  this.socket.once('end', () => {
692
717
  this.debugD(`unregisterAdsPort(): Socket connection ended, connection closed.`);
718
+ clearTimeout(this.portRegisterTimeoutTimer);
719
+ this.amsTcpCallback = undefined;
693
720
  this.socket?.destroy();
694
721
  resolve();
695
722
  });
723
+ this.amsTcpCallback = (res) => {
724
+ this.amsTcpCallback = undefined;
725
+ clearTimeout(this.portRegisterTimeoutTimer);
726
+ if (res.amsTcp.command === ADS.AMS_HEADER_FLAG.AMS_TCP_PORT_CLOSE) {
727
+ this.debug(`unregisterAdsPort(): ADS port unregistered`);
728
+ this.socket?.destroy();
729
+ resolve();
730
+ }
731
+ };
732
+ //Timeout (if no answer from router)
733
+ this.portRegisterTimeoutTimer = setTimeout(() => {
734
+ //Callback is no longer needed, delete it
735
+ this.amsTcpCallback = undefined;
736
+ //Create a custom "ads error" so that the info is passed onwards
737
+ const adsError = {
738
+ ads: {
739
+ error: true,
740
+ errorCode: -1,
741
+ errorStr: `Timeout - no response in ${this.settings.timeoutDelay} ms`
742
+ }
743
+ };
744
+ this.debug(`unregisterAdsPort(): Failed to unregister ADS port: Timeout - no response in ${this.settings.timeoutDelay} ms`);
745
+ return reject(new client_error_1.default(`unregisterAdsPort(): Timeout - no response in ${this.settings.timeoutDelay} ms`, adsError));
746
+ }, this.settings.timeoutDelay);
696
747
  try {
697
- await this.socketWrite(buffer);
748
+ this.socketWrite(buffer);
698
749
  }
699
750
  catch (err) {
700
751
  reject(err);
701
752
  }
753
+ finally {
754
+ this.amsTcpCallback = undefined;
755
+ clearTimeout(this.portRegisterTimeoutTimer);
756
+ }
702
757
  });
703
758
  }
704
759
  /**
@@ -906,7 +961,7 @@ class Client extends events_1.default {
906
961
  await this.restoreSubscriptions();
907
962
  }
908
963
  catch (err) {
909
- !this.settings.hideConsoleWarnings && console.log(`WARNING: Target PLC symbol version changed and all subscriptions were not restored (data might be lost from now on). Error info: ${JSON.stringify(err)}`);
964
+ 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
965
  this.debug(`onPlcSymbolVersionChanged(): Failed to restore all subscriptions. Error: %o`, err);
911
966
  }
912
967
  }
@@ -920,7 +975,7 @@ class Client extends events_1.default {
920
975
  * See also {@link Client.socketErrorHandler} which is `onSocketError.bind(this)`
921
976
  */
922
977
  onSocketError(err) {
923
- !this.settings.hideConsoleWarnings && console.log(`WARNING: Socket connection to target closed to an an error, disconnecting: ${JSON.stringify(err)}`);
978
+ this.warn(`Socket connection to target closed to an an error, disconnecting: ${JSON.stringify(err)}`);
924
979
  this.onConnectionLost(true);
925
980
  }
926
981
  /**
@@ -936,12 +991,12 @@ class Client extends events_1.default {
936
991
  this.connection.connected = false;
937
992
  this.emit('connectionLost', socketFailure);
938
993
  if (this.settings.autoReconnect !== true) {
939
- !this.settings.hideConsoleWarnings && console.log("WARNING: Connection to target was lost and setting autoReconnect was false -> disconnecting");
994
+ this.warn("Connection to target was lost and setting autoReconnect was false -> disconnecting");
940
995
  await this.disconnectFromTarget(true).catch();
941
996
  return;
942
997
  }
943
998
  this.socketConnectionLostHandler && this.socket?.off('close', this.socketConnectionLostHandler);
944
- !this.settings.hideConsoleWarnings && console.log("WARNING: Connection to target was lost. Trying to reconnect automatically...");
999
+ this.warn("Connection to target was lost. Trying to reconnect automatically...");
945
1000
  const tryToReconnect = async (firstRetryAttempt, timerId) => {
946
1001
  //If the timer has changed, quit here (to prevent multiple timers)
947
1002
  if (this.reconnectionTimer.id !== timerId) {
@@ -958,7 +1013,7 @@ class Client extends events_1.default {
958
1013
  //Reconnecting failed
959
1014
  if (firstRetryAttempt) {
960
1015
  this.debug(`onConnectionLost()/tryToReconnect(): Reconnecting failed, keeping trying in the background (${err.message}`);
961
- !this.settings.hideConsoleWarnings && console.log(`WARNING: Reconnecting failed. Keeping trying in the background every ${this.settings.reconnectInterval} ms...`);
1016
+ this.warn(`Reconnecting failed. Keeping trying in the background every ${this.settings.reconnectInterval} ms...`);
962
1017
  }
963
1018
  //If this is still a valid timer, start over again
964
1019
  if (this.reconnectionTimer.id === timerId) {
@@ -1354,7 +1409,12 @@ class Client extends events_1.default {
1354
1409
  //AMS port unregister
1355
1410
  case ADS.AMS_HEADER_FLAG.AMS_TCP_PORT_CLOSE:
1356
1411
  packet.amsTcp.commandStr = 'Port unregister';
1357
- //No action at the moment
1412
+ if (this.amsTcpCallback) {
1413
+ this.amsTcpCallback(packet);
1414
+ }
1415
+ else {
1416
+ this.debug(`onAmsTcpPacketReceived(): Port unregister response received but no callback was assigned (${packet.amsTcp.commandStr})`);
1417
+ }
1358
1418
  break;
1359
1419
  //AMS port register
1360
1420
  case ADS.AMS_HEADER_FLAG.AMS_TCP_PORT_CONNECT:
@@ -1434,12 +1494,24 @@ class Client extends events_1.default {
1434
1494
  })
1435
1495
  .catch(err => {
1436
1496
  this.debug(`onAdsCommandReceived(): Notification received but parsing Javascript object failed: %o`, err);
1437
- this.emit('client-error', new client_error_1.default(`onAdsCommandReceived(): Ntification received but parsing data to Javascript object failed. Subscription: ${JSON.stringify(subscription)}`, err));
1497
+ 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));
1498
+ });
1499
+ }
1500
+ else if (this.settings.deleteUnknownSubscriptions) {
1501
+ 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).`);
1502
+ this.deleteNotificationHandle(sample.notificationHandle, packet.ams.sourceAmsAddress)
1503
+ .then(() => {
1504
+ this.debug(`onAdsCommandReceived(): An ADS notification with an unknown handle ${sample.notificationHandle} was received from ${key} and automatically deleted`);
1505
+ this.warn(`An ADS notification with an unknown handle ${sample.notificationHandle} was received from ${key} and automatically deleted`);
1506
+ })
1507
+ .catch(err => {
1508
+ this.debug(`onAdsCommandReceived(): Failed to delete an unknown ADS notification handle ${sample.notificationHandle} (from ${key}): %o`, err);
1509
+ this.emit('client-error', new client_error_1.default(`Failed to delete an unknown ADS notification handle ${sample.notificationHandle} (from ${key})`, err));
1438
1510
  });
1439
1511
  }
1440
1512
  else {
1441
- this.debugD(`onAdsCommandReceived(): Notification received with unknown handle ${sample.notificationHandle} (${key}). Use unsubscribe() to save resources`);
1442
- this.emit('client-error', new client_error_1.default(`onAdsCommandReceived(): Notification received with unknown handle ${sample.notificationHandle} (${key}). Use unsubscribe() to save resources.`));
1513
+ this.debug(`onAdsCommandReceived(): Notification received with unknown handle ${sample.notificationHandle} (${key})`);
1514
+ this.warn(`An ADS notification with an unknown handle ${sample.notificationHandle} was received from ${key}. Use unsubscribe() or deleteUnknownSubscriptions setting to save resources.`);
1443
1515
  }
1444
1516
  }
1445
1517
  }
@@ -1454,7 +1526,7 @@ class Client extends events_1.default {
1454
1526
  }
1455
1527
  else {
1456
1528
  this.debugD(`onAdsCommandReceived(): Ads command received with unknown invokeId "${packet.ams.invokeId}"`);
1457
- this.emit('client-error', new client_error_1.default(`onAdsCommandReceived(): Ads command received with unknown invokeId "${packet.ams.invokeId}"`));
1529
+ this.emit('client-error', new client_error_1.default(`Ads command received with unknown invokeId "${packet.ams.invokeId}"`));
1458
1530
  }
1459
1531
  break;
1460
1532
  }
@@ -1486,7 +1558,7 @@ class Client extends events_1.default {
1486
1558
  this.clearTimer(this.tcSystemStatePollerTimer);
1487
1559
  this.debug("onRouterStateChanged(): Local loopback connection active, monitoring router state. Reconnecting when router is back running.");
1488
1560
  if (this.metaData.routerState.state === ADS.AMS_ROUTER_STATE.START) {
1489
- !this.settings.hideConsoleWarnings && console.log(`WARNING: Local AMS router state has changed to ${this.metaData.routerState.stateStr}. Reconnecting...`);
1561
+ this.warn(`Local AMS router state has changed to ${this.metaData.routerState.stateStr}. Reconnecting...`);
1490
1562
  this.onConnectionLost();
1491
1563
  }
1492
1564
  else {
@@ -1859,7 +1931,7 @@ class Client extends events_1.default {
1859
1931
  }
1860
1932
  //If extended flag RefactorInfo is set
1861
1933
  if ((symbol.extendedFlags & ADS.ADS_SYMBOL_FLAGS_2.RefactorInfo) === ADS.ADS_SYMBOL_FLAGS_2.RefactorInfo) {
1862
- !this.settings.hideConsoleWarnings && console.log(`WARNING: Symbol ${symbol.name} (${symbol.type}) has extended flag "RefactorInfo" which is not supported. Things might not work now. Please open an issue at Github`);
1934
+ 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
1935
  }
1864
1936
  //Reserved, if any
1865
1937
  symbol.reserved = data.subarray(pos);
@@ -2164,7 +2236,7 @@ class Client extends events_1.default {
2164
2236
  if ((dataType.flags & ADS.ADS_DATA_TYPE_FLAGS.RefactorInfo) === ADS.ADS_DATA_TYPE_FLAGS.RefactorInfo) {
2165
2237
  //TODO: this is not working now
2166
2238
  //Things probably break now
2167
- !this.settings.hideConsoleWarnings && console.log(`WARNING: Data type ${dataType.name} (${dataType.type}) has flag "RefactorInfo" which is not supported. Things might not work now. Please open an issue at Github`);
2239
+ 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
2240
  }
2169
2241
  //If flag ExtendedFlags set
2170
2242
  if ((dataType.flags & ADS.ADS_DATA_TYPE_FLAGS.ExtendedFlags) === ADS.ADS_DATA_TYPE_FLAGS.ExtendedFlags) {
@@ -2181,13 +2253,13 @@ class Client extends events_1.default {
2181
2253
  if ((dataType.flags & ADS.ADS_DATA_TYPE_FLAGS.ExtendedEnumInfos) === ADS.ADS_DATA_TYPE_FLAGS.ExtendedEnumInfos) {
2182
2254
  //TODO: this is not working now
2183
2255
  //Things probably break now
2184
- !this.settings.hideConsoleWarnings && console.log(`WARNING: Data type ${dataType.name} (${dataType.type}) has flag "ExtendedEnumInfos" which is not supported. Things might not work now. Please open an issue at Github`);
2256
+ 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
2257
  }
2186
2258
  //If flag SoftwareProtectionLevels set
2187
2259
  if ((dataType.flags & ADS.ADS_DATA_TYPE_FLAGS.SoftwareProtectionLevels) === ADS.ADS_DATA_TYPE_FLAGS.SoftwareProtectionLevels) {
2188
2260
  //TODO: this is not working now
2189
2261
  //Things probably break now
2190
- !this.settings.hideConsoleWarnings && console.log(`WARNING: Data type ${dataType.name} (${dataType.type}) has flag "SoftwareProtectionLevels" which is not supported. Things might not work now. Please open an issue at Github`);
2262
+ 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
2263
  }
2192
2264
  //Reserved, if any
2193
2265
  dataType.reserved = data.subarray(pos);
@@ -2288,6 +2360,7 @@ class Client extends events_1.default {
2288
2360
  if (err.adsError && err.adsError?.errorCode === 1808) {
2289
2361
  //Type wasn't found.
2290
2362
  //Might be TwinCAT 2 system that doesn't provide pseudo or base data types by ADS --> check if we know the type ourselves
2363
+ const originalName = name;
2291
2364
  if (ADS.BASE_DATA_TYPES.isPseudoType(name)) {
2292
2365
  //This converts e.g. PVOID to a primitive type
2293
2366
  if (knownSize === undefined) {
@@ -2321,6 +2394,11 @@ class Client extends events_1.default {
2321
2394
  extendedFlags: 0,
2322
2395
  reserved: Buffer.alloc(0)
2323
2396
  };
2397
+ //Adding to cache, even though it's not read from the target
2398
+ //With TwinCAT 2, this prevents trying to read base types again and again from the target (as there aren't any)
2399
+ if (!this.settings.disableCaching && !targetOpts.adsPort && !targetOpts.amsNetId) {
2400
+ this.metaData.plcDataTypes[originalName.toLowerCase()] = dataType;
2401
+ }
2324
2402
  }
2325
2403
  else {
2326
2404
  //Type is unknown - we can't do anything
@@ -2364,7 +2442,7 @@ class Client extends events_1.default {
2364
2442
  }
2365
2443
  }
2366
2444
  else if ((((dataType.type === '' && !ADS.BASE_DATA_TYPES.isPseudoType(dataType.name)) || ADS.BASE_DATA_TYPES.isKnownType(dataType.name))
2367
- && dataType.flagsStr.includes('DataType')
2445
+ && (dataType.flagsStr.includes('DataType') || ADS.BASE_DATA_TYPES.isKnownType(dataType.name)) //isKnownType() call is for TwinCAT 2 support, as base types (like INT16) do not have DataType flag (but it's the final base type)
2368
2446
  && !dataType.flagsStr.includes('EnumInfos')
2369
2447
  && dataType.arrayDimension === 0)) {
2370
2448
  //This is final form (no need to go deeper)
@@ -2372,8 +2450,10 @@ class Client extends events_1.default {
2372
2450
  }
2373
2451
  else if (dataType.arrayDimension > 0) {
2374
2452
  //Data type is an array - get array subtype
2453
+ //TwinCAT 2 support - calculate size if it's array of pointer etc.
2454
+ const size = dataType.size / dataType.arrayInfos.reduce((total, dimension) => total * dimension.length, 1);
2375
2455
  builtType = {
2376
- ...(await this.buildDataType(dataType.type, targetOpts, false))
2456
+ ...(await this.buildDataType(dataType.type, targetOpts, false, size))
2377
2457
  };
2378
2458
  builtType.arrayInfos = [...dataType.arrayInfos, ...builtType.arrayInfos];
2379
2459
  }
@@ -2901,14 +2981,44 @@ class Client extends events_1.default {
2901
2981
  * - {@link Client.unsubscribe}() - `DeleteNotification` command
2902
2982
  * - {@link Client.readWriteRaw}() - `ReadWrite` command
2903
2983
  *
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
2984
  * @example
2909
2985
  * ```js
2910
- * TODO - DOCUMENTATION ONGOING
2986
+ * try {
2987
+ * //Creating readRaw(16448, 414816, 2) command manually and sending it using sendAdsCommand()
2988
+ *
2989
+ * const data = Buffer.alloc(12);
2990
+ * let pos = 0;
2991
+ *
2992
+ * //0..3 IndexGroup
2993
+ * data.writeUInt32LE(16448, pos);
2994
+ * pos += 4;
2995
+ *
2996
+ * //4..7 IndexOffset
2997
+ * data.writeUInt32LE(414816, pos);
2998
+ * pos += 4;
2999
+ *
3000
+ * //8..11 Read data length
3001
+ * data.writeUInt32LE(2, pos);
3002
+ * pos += 4;
3003
+ *
3004
+ * const res = await this.sendAdsCommand<AdsReadResponse>({
3005
+ * adsCommand: ADS.ADS_COMMAND.Read,
3006
+ * targetAmsNetId: targetOpts.amsNetId,
3007
+ * targetAdsPort: targetOpts.adsPort,
3008
+ * payload: data
3009
+ * });
3010
+ *
3011
+ * console.log(res.ads.payload); //<Buffer ff 7f>
3012
+ *
3013
+ * } catch (err) {
3014
+ * console.log("Error:", err);
3015
+ * }
2911
3016
  * ```
3017
+ *
3018
+ * @template T In Typescript, the type of the ADS response. If omitted, generic {@link AdsResponse} type is used.
3019
+ *
3020
+ * @throws Throws an error if sending the command fails or if target responds with an error
3021
+ *
2912
3022
  */
2913
3023
  async sendAdsCommand(command) {
2914
3024
  return new Promise(async (resolve, reject) => {
@@ -3221,7 +3331,7 @@ class Client extends events_1.default {
3221
3331
  this.debug(`setTcSystemToRun(): TwinCAT system at ${this.targetToString(targetOpts)} set to run mode`);
3222
3332
  if (reconnect) {
3223
3333
  this.debug(`setTcSystemToRun(): Reconnecting after TwinCAT system restart`);
3224
- !this.settings.hideConsoleWarnings && console.log("WARNING: Reconnecting after TwinCAT system restart");
3334
+ this.warn("Reconnecting after TwinCAT system restart");
3225
3335
  this.onConnectionLost();
3226
3336
  }
3227
3337
  }
@@ -3300,7 +3410,7 @@ class Client extends events_1.default {
3300
3410
  this.debug(`restartTcSystem(): TwinCAT system was restarted`);
3301
3411
  }
3302
3412
  /**
3303
- * Returns symbol for given variable path, such as `GVL_Test.ExampleStruct`.
3413
+ * Returns a symbol object for given variable path, such as `GVL_Test.ExampleStruct`.
3304
3414
  *
3305
3415
  * Returns previously cached value if available, otherwise reads it from the target
3306
3416
  * and caches it.
@@ -3314,7 +3424,7 @@ class Client extends events_1.default {
3314
3424
  * @example
3315
3425
  * ```js
3316
3426
  * try {
3317
- * const symbol = await client.getSymbol('GVL_Test.ExampleStruct');
3427
+ * const symbol = await client.getSymbol('GVL_Read.StandardTypes.INT_');
3318
3428
  * } catch (err) {
3319
3429
  * console.log("Error:", err);
3320
3430
  * }
@@ -3610,7 +3720,7 @@ class Client extends events_1.default {
3610
3720
  * //Checks if value has changed every 100ms
3611
3721
  * //Callback is called only when the value has changed
3612
3722
  * await client.subscribeValue(
3613
- * 'GVL_Test.ExampleStruct.',
3723
+ * 'GVL_Subscription.NumericValue_10ms',
3614
3724
  * (data, subscription) => {
3615
3725
  * console.log(`Value of ${subscription.symbol.name} has changed: ${data.value}`);
3616
3726
  * },
@@ -3671,7 +3781,7 @@ class Client extends events_1.default {
3671
3781
  }
3672
3782
  }
3673
3783
  /**
3674
- * Subscribes to raw value change notifications (ADS notifications) by raw ADS address (index group, index offset and data length).
3784
+ * Subscribes to raw value change notifications (ADS notifications) by a raw ADS address (index group, index offset and data length).
3675
3785
  *
3676
3786
  * Provided callback is called with the latest value when the value changes or when
3677
3787
  * enough time has passed (depending on settings).
@@ -3758,7 +3868,7 @@ class Client extends events_1.default {
3758
3868
  * //Checks if value has changed every 100ms
3759
3869
  * //Callback is called only when the value has changed
3760
3870
  * await client.subscribe({
3761
- * target: 'GVL_Test.ExampleStruct',
3871
+ * target: 'GVL_Subscription.NumericValue_10ms',
3762
3872
  * callback: (data, subscription) => {
3763
3873
  * console.log(`Value of ${subscription.symbol.name} has changed: ${data.value}`);
3764
3874
  * },
@@ -3830,19 +3940,8 @@ class Client extends events_1.default {
3830
3940
  throw new client_error_1.default(`unsubscribe(): Client is not connected. Use connect() to connect to the target first.`);
3831
3941
  }
3832
3942
  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
3943
  try {
3840
- const res = await this.sendAdsCommand({
3841
- adsCommand: ADS.ADS_COMMAND.DeleteNotification,
3842
- targetAmsNetId: subscription.remoteAddress.amsNetId,
3843
- targetAdsPort: subscription.remoteAddress.adsPort,
3844
- payload: data
3845
- });
3944
+ await this.deleteNotificationHandle(subscription.notificationHandle, subscription.remoteAddress);
3846
3945
  const address = ADS.amsAddressToString(subscription.remoteAddress);
3847
3946
  if (this.activeSubscriptions[address]) {
3848
3947
  delete this.activeSubscriptions[address][subscription.notificationHandle];
@@ -3854,6 +3953,33 @@ class Client extends events_1.default {
3854
3953
  throw new client_error_1.default(`unsubscribe(): Unsubscribing failed`, err);
3855
3954
  }
3856
3955
  }
3956
+ /**
3957
+ * Sends a delete ADS notification command to the target system.
3958
+ *
3959
+ * Doesn't delete subscriptions, just sends the ADS command.
3960
+ *
3961
+ * @param notificationHandle Notification handle to delete (number)
3962
+ * @param targetAmsAddress Target system address
3963
+ *
3964
+ * @throws NOTE: Throws error if failed
3965
+ */
3966
+ async deleteNotificationHandle(notificationHandle, targetAmsAddress) {
3967
+ this.debug(`deleteNotificationHandle(): Sending DeleteNotification command for handle ${notificationHandle} to ${ADS.amsAddressToString(targetAmsAddress)}`);
3968
+ //Allocating bytes for request
3969
+ const data = Buffer.alloc(4);
3970
+ let pos = 0;
3971
+ //0..3 Notification handle
3972
+ data.writeUInt32LE(notificationHandle, pos);
3973
+ pos += 4;
3974
+ const res = await this.sendAdsCommand({
3975
+ adsCommand: ADS.ADS_COMMAND.DeleteNotification,
3976
+ targetAmsNetId: targetAmsAddress.amsNetId,
3977
+ targetAdsPort: targetAmsAddress.adsPort,
3978
+ payload: data
3979
+ });
3980
+ this.debug(`deleteNotificationHandle(): Notification for handle ${notificationHandle} (${ADS.amsAddressToString(targetAmsAddress)}) deleted!`);
3981
+ return res.ads;
3982
+ }
3857
3983
  /**
3858
3984
  * Unsubscribes all active subscription (deletes all ADS notifications).
3859
3985
  *
@@ -4268,16 +4394,30 @@ class Client extends events_1.default {
4268
4394
  }
4269
4395
  }
4270
4396
  /**
4271
- * **TODO - DOCUMENTATION ONGOING**
4397
+ * Reads raw data from the target system by a raw ADS address (index group, index offset and data length).
4398
+ *
4399
+ * This is the ADS protocol `Read` command.
4272
4400
  *
4273
- * Reads raw byte data from the target system by provided index group, index offset and data length (bytes)
4401
+ * @example
4402
+ * ```js
4403
+ * try {
4404
+ * const data = await client.readRaw(16448, 414816, 2);
4405
+ * console.log(data); //<Buffer ff 7f>
4274
4406
  *
4275
- * This is the `ADS read` command in ADS protocol.
4407
+ * const converted = await client.convertFromRaw(data, 'INT');
4408
+ * console.log(converted); //32767
4409
+ *
4410
+ * } catch (err) {
4411
+ * console.log("Error:", err);
4412
+ * }
4413
+ * ```
4276
4414
  *
4277
4415
  * @param indexGroup Index group (address) of the data to read
4278
4416
  * @param indexOffset Index offset (address) of the data to read
4279
4417
  * @param size Data length to read (bytes)
4280
4418
  * @param targetOpts Optional target settings that override values in `settings`
4419
+ *
4420
+ * @throws Throws an error if sending the command fails or if the target responds with an error.
4281
4421
  */
4282
4422
  async readRaw(indexGroup, indexOffset, size, targetOpts = {}) {
4283
4423
  if (!this.connection.connected) {
@@ -4312,16 +4452,28 @@ class Client extends events_1.default {
4312
4452
  }
4313
4453
  }
4314
4454
  /**
4315
- * **TODO - DOCUMENTATION ONGOING**
4455
+ * Writes raw data to the target system by a raw ADS address (index group, index offset and data length).
4456
+ *
4457
+ * This is the ADS protocol `Write` command.
4316
4458
  *
4317
- * Writes raw byte data to the target system by provided index group and index offset.
4459
+ * @example
4460
+ * ```js
4461
+ * try {
4462
+ * const data = await client.convertToRaw(32767, 'INT');
4463
+ * console.log(data); //<Buffer ff 7f>
4318
4464
  *
4319
- * This is the `ADS write` command in ADS protocol.
4465
+ * await client.writeRaw(16448, 414816, data);
4466
+ * } catch (err) {
4467
+ * console.log("Error:", err);
4468
+ * }
4469
+ * ```
4320
4470
  *
4321
4471
  * @param indexGroup Index group (address) of the data to write to
4322
4472
  * @param indexOffset Index offset (address) of the data to write to
4323
4473
  * @param value Data to write
4324
4474
  * @param targetOpts Optional target settings that override values in `settings`
4475
+ *
4476
+ * @throws Throws an error if sending the command fails or if the target responds with an error.
4325
4477
  */
4326
4478
  async writeRaw(indexGroup, indexOffset, value, targetOpts = {}) {
4327
4479
  if (!this.connection.connected) {
@@ -4357,16 +4509,45 @@ class Client extends events_1.default {
4357
4509
  }
4358
4510
  }
4359
4511
  /**
4360
- * **TODO - DOCUMENTATION ONGOING**
4512
+ * Sends multiple `readRaw()` commands in one ADS packet.
4361
4513
  *
4362
- * Sends multiple readRaw() commands in one ADS packet
4514
+ * Reads raw data from the target system by a raw ADS addresses (index group, index offset and data length).
4515
+ * Results are returned for each command separately - see {@link ReadRawMultiResult} for details.
4363
4516
  *
4364
- * Reads raw byte data from the target system by provided index group, index offset and data length (bytes)
4517
+ * Uses ADS sum command under the hood (better and faster performance).
4518
+ * See [Beckhoff Information System](https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_adsdll2/9007199379576075.html&id=9180083787138954512) for more info.
4365
4519
  *
4366
- * Uses ADS sum command under the hood (better performance)
4520
+ * @example
4521
+ * ```js
4522
+ * try {
4523
+ * const results = await client.readRawMulti([
4524
+ * {
4525
+ * indexGroup: 16448,
4526
+ * indexOffset: 414816,
4527
+ * size: 2
4528
+ * },
4529
+ * {
4530
+ * indexGroup: 16448,
4531
+ * indexOffset: 414900,
4532
+ * size: 128
4533
+ * }
4534
+ * ]);
4535
+ *
4536
+ * if(results[0].success) {
4537
+ * console.log(`First result: ${results[0].value}`); //First result: <Buffer ff 7f>
4538
+ * } else {
4539
+ * console.log(`First read command failed: ${results[0].errorStr}`);
4540
+ * }
4541
+ *
4542
+ * } catch (err) {
4543
+ * console.log("Error:", err);
4544
+ * }
4545
+ * ```
4367
4546
  *
4368
4547
  * @param commands Array of read commands
4369
4548
  * @param targetOpts Optional target settings that override values in `settings`
4549
+ *
4550
+ * @throws Throws an error if sending the command fails or if the target responds with an error.
4370
4551
  */
4371
4552
  async readRawMulti(commands, targetOpts = {}) {
4372
4553
  if (!this.connection.connected) {
@@ -4442,16 +4623,50 @@ class Client extends events_1.default {
4442
4623
  }
4443
4624
  }
4444
4625
  /**
4445
- * **TODO - DOCUMENTATION ONGOING**
4626
+ * Sends multiple `writeRaw()` commands in one ADS packet.
4627
+ *
4628
+ * Writes raw data to the target system by a raw ADS addresses (index group and index offset).
4629
+ * Results are returned for each command separately - see {@link WriteRawMultiResult} for details.
4446
4630
  *
4447
- * Sends multiple writeRaw() commands in one ADS packet
4631
+ * Uses ADS sum command under the hood (better and faster performance).
4632
+ * See [Beckhoff Information System](https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_adsdll2/9007199379576075.html&id=9180083787138954512) for more info.
4448
4633
  *
4449
- * Writes raw byte data to the target system by provided index group and index offset.
4634
+ * @example
4635
+ * ```js
4636
+ * try {
4637
+ * const data1 = await client.convertToRaw(32767, 'INT');
4638
+ * console.log(data1); //<Buffer ff 7f>
4639
+ *
4640
+ * const data2 = Buffer.alloc(128); //example
4641
+ *
4642
+ * const results = await client.writeRawMulti([
4643
+ * {
4644
+ * indexGroup: 16448,
4645
+ * indexOffset: 414816,
4646
+ * value: data1
4647
+ * },
4648
+ * {
4649
+ * indexGroup: 16448,
4650
+ * indexOffset: 414900,
4651
+ * value: data2
4652
+ * }
4653
+ * ]);
4654
+ *
4655
+ * if(results[0].success) {
4656
+ * console.log(`First write command successful`);
4657
+ * } else {
4658
+ * console.log(`First write command failed: ${results[0].errorStr}`);
4659
+ * }
4450
4660
  *
4451
- * Uses ADS sum command under the hood (better performance)
4661
+ * } catch (err) {
4662
+ * console.log("Error:", err);
4663
+ * }
4664
+ * ```
4452
4665
  *
4453
4666
  * @param commands Array of write commands
4454
4667
  * @param targetOpts Optional target settings that override values in `settings`
4668
+ *
4669
+ * @throws Throws an error if sending the command fails or if the target responds with an error.
4455
4670
  */
4456
4671
  async writeRawMulti(commands, targetOpts = {}) {
4457
4672
  if (!this.connection.connected) {
@@ -4523,16 +4738,37 @@ class Client extends events_1.default {
4523
4738
  }
4524
4739
  }
4525
4740
  /**
4526
- * **TODO - DOCUMENTATION ONGOING**
4741
+ * Reads raw data from the target system by variable path (such as `GVL_Test.ExampleStruct`).
4527
4742
  *
4528
- * Reads raw byte data from the target system by symbol path.
4743
+ * Supports also reading `POINTER` and `REFERENCE` values (see example).
4529
4744
  *
4530
- * Supports also reading POINTER and REFERENCE values by using deference operator in path (`^`)
4745
+ * This uses the ADS `READ_SYMVAL_BYNAME` under the hood, so only one
4746
+ * round-trip is needed.
4531
4747
  *
4532
- * This uses the ADS command `READ_SYMVAL_BYNAME` under the hood
4748
+ * @example
4749
+ * ```js
4750
+ * try {
4751
+ * const data = await client.readRawByPath('GVL_Read.StandardTypes.INT_');
4752
+ * console.log(data); //<Buffer ff 7f>
4753
+ *
4754
+ * const converted = await client.convertFromRaw(data, 'INT');
4755
+ * console.log(converted); //32767
4756
+ *
4757
+ * //Reading a POINTER value (Note the dereference operator ^)
4758
+ * const ptrValue = await client.readRawByPath('GVL_Read.ComplexTypes.POINTER_^');
4759
+ *
4760
+ * //Reading a REFERENCE value
4761
+ * const refValue = await client.readRawByPath('GVL_Read.ComplexTypes.REFERENCE_');
4762
+ *
4763
+ * } catch (err) {
4764
+ * console.log("Error:", err);
4765
+ * }
4766
+ * ```
4533
4767
  *
4534
4768
  * @param path Variable path in the PLC to read (such as `GVL_Test.ExampleStruct`)
4535
4769
  * @param targetOpts Optional target settings that override values in `settings`
4770
+ *
4771
+ * @throws Throws an error if sending the command fails or if the target responds with an error.
4536
4772
  */
4537
4773
  async readRawByPath(path, targetOpts = {}) {
4538
4774
  if (!this.connection.connected) {
@@ -4574,17 +4810,38 @@ class Client extends events_1.default {
4574
4810
  }
4575
4811
  }
4576
4812
  /**
4577
- * **TODO - DOCUMENTATION ONGOING**
4813
+ * Writes raw data to the target system by variable path (such as `GVL_Test.ExampleStruct`).
4578
4814
  *
4579
- * Writes raw byte data to the target system by symbol path.
4815
+ * Supports also writing `POINTER` and `REFERENCE` values (see example).
4580
4816
  *
4581
- * Supports also reading POINTER and REFERENCE values by using deference operator in path (`^`)
4817
+ * NOTE: Unlike with {@link readRawByPath}(), this command uses multiple ADS requests for the operation.
4582
4818
  *
4583
- * Unlike `readRawByPath()`, this uses variable handles under the hood, the as there is no direct ADS command available for this.
4819
+ * @example
4820
+ * ```js
4821
+ * try {
4822
+ * const data = await client.convertToRaw(32767, 'INT');
4823
+ * console.log(data); //<Buffer ff 7f>
4584
4824
  *
4585
- * @param path Variable path in the PLC to read (such as `GVL_Test.ExampleStruct`)
4825
+ * await client.writeRawByPath('GVL_Write.StandardTypes.INT_', data);
4826
+ *
4827
+ * //Writing a POINTER value (Note the dereference operator ^)
4828
+ * const ptrValue = ...
4829
+ * await client.writeRawByPath('GVL_Read.ComplexTypes.POINTER_^', ptrValue);
4830
+ *
4831
+ * //Writing a REFERENCE value
4832
+ * const refValue = ...
4833
+ * await client.readRawByPath('GVL_Read.ComplexTypes.REFERENCE_');
4834
+ *
4835
+ * } catch (err) {
4836
+ * console.log("Error:", err);
4837
+ * }
4838
+ * ```
4839
+ *
4840
+ * @param path Variable path in the PLC to write (such as `GVL_Test.ExampleStruct`)
4586
4841
  * @param value Data to write
4587
4842
  * @param targetOpts Optional target settings that override values in `settings`
4843
+ *
4844
+ * @throws Throws an error if sending the command fails or if the target responds with an error.
4588
4845
  */
4589
4846
  async writeRawByPath(path, value, targetOpts = {}) {
4590
4847
  if (!this.connection.connected) {
@@ -4594,12 +4851,12 @@ class Client extends events_1.default {
4594
4851
  try {
4595
4852
  let handle = null;
4596
4853
  try {
4597
- handle = await this.createVariableHandle(path);
4598
- await this.writeRawByHandle(handle, value);
4854
+ handle = await this.createVariableHandle(path, targetOpts);
4855
+ await this.writeRawByHandle(handle, value, targetOpts);
4599
4856
  }
4600
4857
  finally {
4601
4858
  if (handle) {
4602
- await this.deleteVariableHandle(handle);
4859
+ await this.deleteVariableHandle(handle, targetOpts);
4603
4860
  }
4604
4861
  }
4605
4862
  this.debug(`writeRawByPath(): Writing raw data to ${path} done (${value.byteLength} bytes)`);
@@ -4610,25 +4867,41 @@ class Client extends events_1.default {
4610
4867
  }
4611
4868
  }
4612
4869
  /**
4613
- * **TODO - DOCUMENTATION ONGOING**
4870
+ * Writes raw data to the target system by a raw ADS address (index group, index offset)
4871
+ * and reads the result as raw data.
4872
+ *
4873
+ * This is the ADS protocol `ReadWrite` command.
4614
4874
  *
4615
- * Writes raw data to the target and reads the result as raw data
4875
+ * @example
4876
+ * ```js
4877
+ * const { ADS } = require('../dist/ads-client');
4616
4878
  *
4617
- * Uses `ADS ReadWrite` command
4879
+ * try {
4880
+ * //Reading raw value by symbol path (= same as readRawByPath())
4881
+ * const path = ADS.encodeStringToPlcStringBuffer('GVL_Read.StandardTypes.INT_');
4882
+ * const data = await client.readWriteRaw(ADS.ADS_RESERVED_INDEX_GROUPS.SymbolValueByName, 0, 0xFFFFFFFF, path);
4883
+ * console.log(data); //<Buffer ff 7f>
4884
+ *
4885
+ * } catch (err) {
4886
+ * console.log("Error:", err);
4887
+ * }
4888
+ * ```
4618
4889
  *
4619
4890
  * @param indexGroup Address index group
4620
4891
  * @param indexOffset Address index offset
4621
- * @param size How many bytes to read
4622
- * @param writeData Data to write
4892
+ * @param size Data length to read (bytes)
4893
+ * @param value Value to write
4623
4894
  * @param targetOpts Optional target settings that override values in `settings`
4895
+ *
4896
+ * @throws Throws an error if sending the command fails or if the target responds with an error.
4624
4897
  */
4625
- async readWriteRaw(indexGroup, indexOffset, size, writeData, targetOpts = {}) {
4898
+ async readWriteRaw(indexGroup, indexOffset, size, value, targetOpts = {}) {
4626
4899
  if (!this.connection.connected) {
4627
4900
  throw new client_error_1.default(`readWriteRaw(): Client is not connected. Use connect() to connect to the target first.`);
4628
4901
  }
4629
- this.debug(`readWriteRaw(): Sending ReadWrite command (${JSON.stringify({ indexGroup, indexOffset, size })} with ${writeData.byteLength} bytes of data`);
4902
+ this.debug(`readWriteRaw(): Sending ReadWrite command (${JSON.stringify({ indexGroup, indexOffset, size })} with ${value.byteLength} bytes of data`);
4630
4903
  //Allocating bytes for request
4631
- const data = Buffer.alloc(16 + writeData.byteLength);
4904
+ const data = Buffer.alloc(16 + value.byteLength);
4632
4905
  let pos = 0;
4633
4906
  //0..3 IndexGroup
4634
4907
  data.writeUInt32LE(indexGroup, pos);
@@ -4640,11 +4913,11 @@ class Client extends events_1.default {
4640
4913
  data.writeUInt32LE(size, pos);
4641
4914
  pos += 4;
4642
4915
  //12..15 Write data length
4643
- data.writeUInt32LE(writeData.byteLength, pos);
4916
+ data.writeUInt32LE(value.byteLength, pos);
4644
4917
  pos += 4;
4645
4918
  //16..n Write data
4646
- writeData.copy(data, pos);
4647
- pos += writeData.byteLength;
4919
+ value.copy(data, pos);
4920
+ pos += value.byteLength;
4648
4921
  try {
4649
4922
  const res = await this.sendAdsCommand({
4650
4923
  adsCommand: ADS.ADS_COMMAND.ReadWrite,
@@ -4661,14 +4934,52 @@ class Client extends events_1.default {
4661
4934
  }
4662
4935
  }
4663
4936
  /**
4664
- * **TODO - DOCUMENTATION ONGOING**
4937
+ * Sends multiple `readWriteRaw()` commands in one ADS packet.
4938
+ *
4939
+ * Writes raw data to the target system by a raw ADS address (index group, index offset)
4940
+ * and reads the result as raw data.
4941
+ *
4942
+ * Uses ADS sum command under the hood (better and faster performance).
4943
+ * See [Beckhoff Information System](https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_adsdll2/9007199379576075.html&id=9180083787138954512) for more info.
4944
+ *
4945
+ * @example
4946
+ * ```js
4947
+ * try {
4948
+ * //Reading raw values by symbol paths (= same as readRawByPath())
4949
+ * const path = ADS.encodeStringToPlcStringBuffer('GVL_Read.StandardTypes.INT_');
4950
+ * const path2 = ADS.encodeStringToPlcStringBuffer('GVL_Read.StandardTypes.REAL_');
4951
+ *
4952
+ * const results = await client.readWriteRawMulti([
4953
+ * {
4954
+ * indexGroup: ADS.ADS_RESERVED_INDEX_GROUPS.SymbolValueByName,
4955
+ * indexOffset: 0,
4956
+ * size: 0xFFFF,
4957
+ * value: path
4958
+ * },
4959
+ * {
4960
+ * indexGroup: ADS.ADS_RESERVED_INDEX_GROUPS.SymbolValueByName,
4961
+ * indexOffset: 0,
4962
+ * size: 0xFFFF,
4963
+ * value: path2
4964
+ * }
4965
+ * ]);
4966
+ *
4967
+ * if(results[0].success) {
4968
+ * console.log(`First result: ${results[0].value}`); //First result: <Buffer ff 7f>
4969
+ * } else {
4970
+ * console.log(`First read/write command failed: ${results[0].errorStr}`);
4971
+ * }
4665
4972
  *
4666
- * Sends multiple readWriteRaw() commands in one ADS packet
4973
+ * } catch (err) {
4974
+ * console.log("Error:", err);
4975
+ * }
4667
4976
  *
4668
- * Uses ADS sum command under the hood (better performance)
4977
+ * ```
4669
4978
  *
4670
- * @param commands Array of read write commands
4979
+ * @param commands Array of read/write commands
4671
4980
  * @param targetOpts Optional target settings that override values in `settings`
4981
+ *
4982
+ * @throws Throws an error if sending the command fails or if the target responds with an error.
4672
4983
  */
4673
4984
  async readWriteRawMulti(commands, targetOpts = {}) {
4674
4985
  if (!this.connection.connected) {
@@ -4676,7 +4987,7 @@ class Client extends events_1.default {
4676
4987
  }
4677
4988
  this.debug(`readWriteRawMulti(): Sending ${commands.length} ReadWrite commands`);
4678
4989
  const totalSize = commands.reduce((total, command) => total + command.size, 0);
4679
- const totalWriteSize = commands.reduce((total, command) => total + command.writeData.byteLength, 0);
4990
+ const totalWriteSize = commands.reduce((total, command) => total + command.value.byteLength, 0);
4680
4991
  //Allocating bytes for request
4681
4992
  const data = Buffer.alloc(16 + commands.length * 16 + totalWriteSize);
4682
4993
  let pos = 0;
@@ -4704,13 +5015,13 @@ class Client extends events_1.default {
4704
5015
  data.writeUInt32LE(command.size, pos);
4705
5016
  pos += 4;
4706
5017
  //12..15 Write data length
4707
- data.writeUInt32LE(command.writeData.byteLength, pos);
5018
+ data.writeUInt32LE(command.value.byteLength, pos);
4708
5019
  pos += 4;
4709
5020
  });
4710
5021
  //data
4711
5022
  commands.forEach(command => {
4712
- command.writeData.copy(data, pos);
4713
- pos += command.writeData.byteLength;
5023
+ command.value.copy(data, pos);
5024
+ pos += command.value.byteLength;
4714
5025
  });
4715
5026
  try {
4716
5027
  const res = await this.sendAdsCommand({
@@ -4759,16 +5070,32 @@ class Client extends events_1.default {
4759
5070
  }
4760
5071
  }
4761
5072
  /**
4762
- * **TODO - DOCUMENTATION ONGOING**
5073
+ * Reads variable's value from the target system by a variable path (such as `GVL_Test.ExampleStruct`)
5074
+ * and returns the value as a Javascript object.
4763
5075
  *
4764
- * Reads a value by a variable path (such as `GVL_Test.ExampleStruct`) and converts the value to a Javascript object.
5076
+ * Returns variable's
5077
+ * - converted value
5078
+ * - raw value
5079
+ * - data type
5080
+ * - symbol
4765
5081
  *
4766
- * Returns the converted value, the raw value, the data type and the symbol.
5082
+ * **NOTE:** This requires that the target is a PLC runtime or has equivalent ADS protocol support.
4767
5083
  *
4768
- * @param path Variable path in the PLC to read (such as `GVL_Test.ExampleStruct`)
5084
+ * @example
5085
+ * ```js
5086
+ * try {
5087
+ * const res = await client.readValue('GVL_Read.StandardTypes.INT_');
5088
+ * console.log(res.value);
5089
+ * } catch (err) {
5090
+ * console.log("Error:", err);
5091
+ * }
5092
+ * ```
5093
+ *
5094
+ * @param path Variable path in the PLC (such as `GVL_Test.ExampleStruct`)
4769
5095
  * @param targetOpts Optional target settings that override values in `settings`
4770
5096
  *
4771
5097
  * @template T In Typescript, the data type of the value, for example `readValue<number>(...)` or `readValue<ST_TypedStruct>(...)` (default: `any`)
5098
+ * @throws Throws an error if sending the command fails or if the target responds with an error.
4772
5099
  */
4773
5100
  async readValue(path, targetOpts = {}) {
4774
5101
  if (!this.connection.connected) {
@@ -4789,7 +5116,8 @@ class Client extends events_1.default {
4789
5116
  let dataType;
4790
5117
  try {
4791
5118
  this.debugD(`readValue(): Getting data type for ${path}`);
4792
- dataType = await this.buildDataType(symbol.type, targetOpts);
5119
+ //Also passing size for TC2 pointer/pseudo type support
5120
+ dataType = await this.buildDataType(symbol.type, targetOpts, true, symbol.size);
4793
5121
  }
4794
5122
  catch (err) {
4795
5123
  this.debug(`readValue(): Getting data type for ${path} failed: %o`, err);
@@ -4824,16 +5152,34 @@ class Client extends events_1.default {
4824
5152
  };
4825
5153
  }
4826
5154
  /**
4827
- * **TODO - DOCUMENTATION ONGOING**
5155
+ * Reads variable's value from the target system by a symbol object (acquired using `getSymbol()`)
5156
+ * and returns the value as a Javascript object.
4828
5157
  *
4829
- * Reads a value by a symbol and converts the value to a Javascript object.
5158
+ * Returns variable's
5159
+ * - converted value
5160
+ * - raw value
5161
+ * - data type
5162
+ * - symbol
4830
5163
  *
4831
- * Returns the converted value, the raw value, the data type and the symbol.
5164
+ * **NOTE:** This requires that the target is a PLC runtime or has equivalent ADS protocol support.
5165
+ *
5166
+ * @example
5167
+ * ```js
5168
+ * try {
5169
+ * const symbol = await client.getSymbol('GVL_Read.StandardTypes.INT_');
4832
5170
  *
4833
- * @param symbol Symbol (acquired using `getSymbol()`)
5171
+ * const res = await client.readValueBySymbol(symbol);
5172
+ * console.log(res.value);
5173
+ * } catch (err) {
5174
+ * console.log("Error:", err);
5175
+ * }
5176
+ * ```
5177
+ *
5178
+ * @param symbol Symbol object
4834
5179
  * @param targetOpts Optional target settings that override values in `settings`
4835
5180
  *
4836
5181
  * @template T In Typescript, the data type of the value, for example `readValueBySymbol<number>(...)` or `readValueBySymbol<ST_TypedStruct>(...)` (default: `any`)
5182
+ * @throws Throws an error if sending the command fails or if the target responds with an error.
4837
5183
  */
4838
5184
  async readValueBySymbol(symbol, targetOpts = {}) {
4839
5185
  if (!this.connection.connected) {
@@ -4842,20 +5188,39 @@ class Client extends events_1.default {
4842
5188
  return this.readValue(symbol.name, targetOpts);
4843
5189
  }
4844
5190
  /**
4845
- * **TODO - DOCUMENTATION ONGOING**
5191
+ * Writes variable's value to the target system by a variable path (such as `GVL_Test.ExampleStruct`).
5192
+ * Converts the value from a Javascript object to a raw value.
4846
5193
  *
4847
- * Writes a value by a variable path (such as `GVL_Test.ExampleStruct`). Converts the value from a Javascript object to a raw value.
5194
+ * Returns variable's
5195
+ * - converted value
5196
+ * - raw value
5197
+ * - data type
5198
+ * - symbol
4848
5199
  *
4849
- * Returns the converted value, the raw value, the data type and the symbol.
5200
+ * **NOTE:** Do not use `autoFill` for `UNION` types, it doesn't work correctly.
4850
5201
  *
4851
- * **NOTE:** Do not use `autoFill` for `UNION` types, it works without errors but the result isn't probably the desired one
5202
+ * **NOTE:** This requires that the target is a PLC runtime or has equivalent ADS protocol support.
4852
5203
  *
4853
- * @param path Variable path in the PLC to read (such as `GVL_Test.ExampleStruct`)
5204
+ * @example
5205
+ * ```js
5206
+ * try {
5207
+ * const value = {
5208
+ * example: true
5209
+ * };
5210
+ *
5211
+ * const res = await client.writeValue('GVL_Read.StandardTypes.INT_', value);
5212
+ * } catch (err) {
5213
+ * console.log("Error:", err);
5214
+ * }
5215
+ * ```
5216
+ *
5217
+ * @param path Variable path in the PLC (such as `GVL_Test.ExampleStruct`)
4854
5218
  * @param value Value to write
4855
5219
  * @param targetOpts Optional target settings that override values in `settings`
4856
- * @param autoFill If true and data type is a container (`STRUCT`, `FUNCTION_BLOCK` etc.), missing properties are automatically **set to default values** (usually `0` or `''`)
5220
+ * @param autoFill If set and the data type is a container (`STRUCT`, `FUNCTION_BLOCK` etc.), missing properties are automatically set to active values read from target (kept as-is).
4857
5221
  *
4858
5222
  * @template T In Typescript, the data type of the value, for example `writeValue<number>(...)` or `writeValue<ST_TypedStruct>(...)`
5223
+ * @throws Throws an error if sending the command fails or if the target responds with an error.
4859
5224
  */
4860
5225
  async writeValue(path, value, autoFill = false, targetOpts = {}) {
4861
5226
  if (!this.connection.connected) {
@@ -4876,7 +5241,8 @@ class Client extends events_1.default {
4876
5241
  let dataType;
4877
5242
  try {
4878
5243
  this.debugD(`writeValue(): Getting data type for ${path}`);
4879
- dataType = await this.buildDataType(symbol.type, targetOpts);
5244
+ //Also passing size for TC2 pointer/pseudo type support
5245
+ dataType = await this.buildDataType(symbol.type, targetOpts, true, symbol.size);
4880
5246
  }
4881
5247
  catch (err) {
4882
5248
  this.debug(`writeValue(): Getting data type for ${path} failed: %o`, err);
@@ -4934,20 +5300,37 @@ class Client extends events_1.default {
4934
5300
  };
4935
5301
  }
4936
5302
  /**
4937
- * **TODO - DOCUMENTATION ONGOING**
5303
+ * Writes variable's value to the target system by a symbol object (acquired using `getSymbol()`).
5304
+ * Converts the value from a Javascript object to a raw value.
4938
5305
  *
4939
- * Writes a value by symbol. Converts the value from a Javascript object to a raw value.
5306
+ * Returns variable's
5307
+ * - converted value
5308
+ * - raw value
5309
+ * - data type
5310
+ * - symbol
4940
5311
  *
4941
- * Returns the converted value, the raw value, the data type and the symbol.
5312
+ * **NOTE:** Do not use `autoFill` for `UNION` types, it doesn't work correctly.
4942
5313
  *
4943
- * **NOTE:** Do not use `autoFill` for `UNION` types, it works without errors but the result isn't probably the desired one
5314
+ * **NOTE:** This requires that the target is a PLC runtime or has equivalent ADS protocol support.
5315
+ *
5316
+ * @example
5317
+ * ```js
5318
+ * try {
5319
+ * const symbol = await client.getSymbol('GVL_Read.StandardTypes.INT_');
4944
5320
  *
4945
- * @param symbol Symbol (acquired using `getSymbol()`)
5321
+ * const res = await client.writeValueBySymbol(symbol, 32767);
5322
+ * } catch (err) {
5323
+ * console.log("Error:", err);
5324
+ * }
5325
+ * ```
5326
+ *
5327
+ * @param symbol Symbol object
4946
5328
  * @param value Value to write
4947
5329
  * @param targetOpts Optional target settings that override values in `settings`
4948
- * @param autoFill If true and data type is a container (`STRUCT`, `FUNCTION_BLOCK` etc.), missing properties are automatically **set to default values** (usually `0` or `''`)
5330
+ * @param autoFill If set and the data type is a container (`STRUCT`, `FUNCTION_BLOCK` etc.), missing properties are automatically set to active values read from target (kept as-is).
4949
5331
  *
4950
5332
  * @template T In Typescript, the data type of the value, for example `writeValue<number>(...)` or `writeValue<ST_TypedStruct>(...)`
5333
+ * @throws Throws an error if sending the command fails or if the target responds with an error.
4951
5334
  */
4952
5335
  async writeValueBySymbol(symbol, value, autoFill = false, targetOpts = {}) {
4953
5336
  if (!this.connection.connected) {
@@ -4956,14 +5339,27 @@ class Client extends events_1.default {
4956
5339
  return this.writeValue(symbol.name, value, autoFill, targetOpts);
4957
5340
  }
4958
5341
  /**
4959
- * **TODO - DOCUMENTATION ONGOING**
4960
- *
4961
5342
  * Returns a default (empty) Javascript object representing provided PLC data type.
4962
5343
  *
4963
- * @param dataType Data type name in the PLC as string (such as `ST_Struct`) or `AdsDataType` object
5344
+ * @example
5345
+ * ```js
5346
+ * try {
5347
+ * const res = await client.getDefaultPlcObject('INT');
5348
+ * console.log(res); //0
5349
+
5350
+ * const res2 = await client.getDefaultPlcObject('Tc2_Standard.TON');
5351
+ * console.log(res2); //{ IN: false, PT: 0, Q: false, ET: 0, M: false, StartTime: 0 }
5352
+ *
5353
+ * } catch (err) {
5354
+ * console.log("Error:", err);
5355
+ * }
5356
+ * ```
5357
+ *
5358
+ * @param dataType Data type name in the PLC as string (such as `ST_Struct`) or data type object (acquired using {@link getDataType}())
4964
5359
  * @param targetOpts Optional target settings that override values in `settings`
4965
5360
  *
4966
- * @template T Typescript data type of the PLC data, for example `readValue<number>(...)` or `readValue<ST_TypedStruct>(...)`
5361
+ * @template T Typescript data type of the PLC data, for example `getDefaultPlcObject<number>(...)` or `getDefaultPlcObject<ST_TypedStruct>(...)`
5362
+ * @throws Throws an error if sending the command fails or if the target responds with an error.
4967
5363
  */
4968
5364
  async getDefaultPlcObject(dataType, targetOpts = {}) {
4969
5365
  if (!this.connection.connected) {
@@ -4987,15 +5383,28 @@ class Client extends events_1.default {
4987
5383
  return value;
4988
5384
  }
4989
5385
  /**
4990
- * **TODO - DOCUMENTATION ONGOING**
5386
+ * Converts raw data to a Javascript object by using the provided data type.
5387
+ *
5388
+ * @example
5389
+ * ```js
5390
+ * try {
5391
+ * const data = await client.readRaw(16448, 414816, 2);
5392
+ * console.log(data); //<Buffer ff 7f>
4991
5393
  *
4992
- * Converts a raw byte value to a Javascript object.
5394
+ * const converted = await client.convertFromRaw(data, 'INT');
5395
+ * console.log(converted); //32767
4993
5396
  *
4994
- * @param data Raw PLC data as Buffer (read for example with `readRaw()`)
4995
- * @param dataType Data type name in the PLC as string (such as `ST_Struct`) or `AdsDataType` object
5397
+ * } catch (err) {
5398
+ * console.log("Error:", err);
5399
+ * }
5400
+ * ```
5401
+ *
5402
+ * @param data Raw data (acquired for example using {@link readRaw}())
5403
+ * @param dataType Data type name in the PLC as string (such as `ST_Struct`) or data type object (acquired using {@link getDataType}())
4996
5404
  * @param targetOpts Optional target settings that override values in `settings`
4997
5405
  *
4998
5406
  * @template T Typescript data type of the PLC data, for example `convertFromRaw<number>(...)` or `convertFromRaw<ST_TypedStruct>(...)`
5407
+ * @throws Throws an error if sending the command fails or if the target responds with an error.
4999
5408
  */
5000
5409
  async convertFromRaw(data, dataType, targetOpts = {}) {
5001
5410
  if (!this.connection.connected) {
@@ -5027,18 +5436,27 @@ class Client extends events_1.default {
5027
5436
  return value;
5028
5437
  }
5029
5438
  /**
5030
- * **TODO - DOCUMENTATION ONGOING**
5439
+ * Converts a Javascript object to raw data by using the provided data type.
5031
5440
  *
5032
- * Converts a Javascript object to raw byte data.
5441
+ * **NOTE:** Do not use `autoFill` for `UNION` types, it doesn't work correctly.
5442
+
5443
+ * @example
5444
+ * ```js
5445
+ * try {
5446
+ * const data = await client.convertToRaw(32767, 'INT');
5447
+ * console.log(data); //<Buffer ff 7f>
5033
5448
  *
5034
- * **NOTE:** Do not use `autoFill` for `UNION` types, it works without errors but the result isn't probably the desired one
5449
+ * } catch (err) {
5450
+ * console.log("Error:", err);
5451
+ * }
5452
+ * ```
5035
5453
  *
5036
- * @param value Javascript object that represents the `dataType` in target system
5037
- * @param dataType Data type name in the PLC as string (such as `ST_Struct`) or `AdsDataType` object
5038
- * @param autoFill If true and data type is a container (`STRUCT`, `FUNCTION_BLOCK` etc.), missing properties are automatically **set to default values** (usually `0` or `''`)
5454
+ * @param value Value to convert
5455
+ * @param dataType Data type name in the PLC as string (such as `ST_Struct`) or data type object (acquired using {@link getDataType}())
5456
+ * @param autoFill autoFill If set and the data type is a container (`STRUCT`, `FUNCTION_BLOCK` etc.), missing properties are automatically set to default values (`0` or empty string).
5039
5457
  * @param targetOpts Optional target settings that override values in `settings`
5040
5458
  *
5041
- * @template T Typescript data type of the PLC data, for example `convertFromRaw<number>(...)` or `convertFromRaw<ST_TypedStruct>(...)`
5459
+ * @throws Throws an error if sending the command fails or if the target responds with an error.
5042
5460
  */
5043
5461
  async convertToRaw(value, dataType, autoFill = false, targetOpts = {}) {
5044
5462
  if (!this.connection.connected) {
@@ -5094,14 +5512,39 @@ class Client extends events_1.default {
5094
5512
  }
5095
5513
  }
5096
5514
  /**
5097
- * **TODO - DOCUMENTATION ONGOING**
5515
+ * Creates a handle to a variable at the target system by variable path (such as `GVL_Test.ExampleStruct`).
5098
5516
  *
5099
- * Creates a variable handle for a PLC symbol by given variable path
5517
+ * The handle can be then used for reading and writing the value.
5100
5518
  *
5101
- * Variable value can be accessed by using the handle with `readRawByHandle()` and `writeRawByHandle()`
5519
+ * Reading and writing dereferenced `POINTER` and `REFERENCE` values is also possible.
5520
+ * See {@link readRawByHandle}() and {@link writeRawByHandle}().
5102
5521
  *
5103
- * @param path Full variable path in the PLC (such as `GVL_Test.ExampleStruct`)
5104
- * @param targetOpts Optional target settings that override values in `settings` (**NOTE:** If used, no caching is available -> possible performance impact)
5522
+ * NOTE: The handle should be deleted after it's no longer needed,
5523
+ * as there is a limited amount of handles available. See {@link deleteVariableHandle}().
5524
+ *
5525
+ * @example
5526
+ * ```js
5527
+ * try {
5528
+ * //POINTER value (Note the dereference operator ^)
5529
+ * const handle1 = await client.createVariableHandle('GVL_Read.ComplexTypes.POINTER_^');
5530
+ * const value = await client.readRawByHandle(handle1);
5531
+ * await client.deleteVariableHandle(handle1);
5532
+ *
5533
+ * const handle2 = await client.createVariableHandle('GVL_Read.StandardTypes.INT_');
5534
+ * const value2 = await client.readRawByHandle(handle2);
5535
+ * await client.deleteVariableHandle(handle2);
5536
+ *
5537
+ * //Now you use convertFromRaw() to get actual values
5538
+ *
5539
+ * } catch (err) {
5540
+ * console.log("Error:", err);
5541
+ * }
5542
+ * ```
5543
+ *
5544
+ * @param path Variable path in the PLC to read (such as `GVL_Test.ExampleStruct`)
5545
+ * @param targetOpts Optional target settings that override values in `settings`
5546
+ *
5547
+ * @throws Throws an error if sending the command fails or if the target responds with an error.
5105
5548
  */
5106
5549
  async createVariableHandle(path, targetOpts = {}) {
5107
5550
  if (!this.connection.connected) {
@@ -5159,18 +5602,44 @@ class Client extends events_1.default {
5159
5602
  }
5160
5603
  }
5161
5604
  /**
5162
- * **TODO - DOCUMENTATION ONGOING**
5605
+ * Sends multiple {@link createVariableHandle}() commands in one ADS packet.
5163
5606
  *
5164
- * Sends multiple createVariableHandle() commands in one ADS packet
5607
+ * Creates a handle to a variable at the target system by variable path (such as `GVL_Test.ExampleStruct`).
5165
5608
  *
5166
- * Creates a variable handle for a PLC symbol by given variable path
5609
+ * The handle can be then used for reading and writing the value.
5167
5610
  *
5168
- * Variable value can be accessed by using the handle with `readRawByHandle()` and `writeRawByHandle()`
5611
+ * Reading and writing dereferenced `POINTER` and `REFERENCE` values is also possible.
5612
+ * See {@link readRawByHandle}() and {@link writeRawByHandle}().
5169
5613
  *
5170
- * Uses ADS sum command under the hood (better perfomance)
5614
+ * NOTE: The handle should be deleted after it's no longer needed,
5615
+ * as there is a limited amount of handles available. See {@link deleteVariableHandle}().
5616
+ *
5617
+ * Uses ADS sum command under the hood (better and faster performance).
5618
+ * See [Beckhoff Information System](https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_adsdll2/9007199379576075.html&id=9180083787138954512) for more info.
5619
+ *
5620
+ * @example
5621
+ * ```js
5622
+ * try {
5623
+ * const results = await client.createVariableHandleMulti([
5624
+ * 'GVL_Read.StandardTypes.INT_',
5625
+ * 'GVL_Read.StandardTypes.REAL_'
5626
+ * ]);
5171
5627
  *
5172
- * @param paths Array of full variable paths in the PLC (such as `GVL_Test.ExampleStruct`)
5628
+ * if(results[0].success) {
5629
+ * console.log(`First handle: ${results[0].handle}`);
5630
+ * } else {
5631
+ * console.log(`Creating first handle failed: ${results[0].errorStr}`);
5632
+ * }
5633
+ *
5634
+ * } catch (err) {
5635
+ * console.log("Error:", err);
5636
+ * }
5637
+ * ```
5638
+ *
5639
+ * @param paths Array of variable paths in the PLC to read (such as `GVL_Test.ExampleStruct`)
5173
5640
  * @param targetOpts Optional target settings that override values in `settings`
5641
+ *
5642
+ * @throws Throws an error if sending the command fails or if the target responds with an error.
5174
5643
  */
5175
5644
  async createVariableHandleMulti(paths, targetOpts = {}) {
5176
5645
  if (!this.connection.connected) {
@@ -5275,12 +5744,26 @@ class Client extends events_1.default {
5275
5744
  }
5276
5745
  }
5277
5746
  /**
5278
- * **TODO - DOCUMENTATION ONGOING**
5747
+ * Deletes a variable handle that was previously created
5748
+ * using {@link createVariableHandle}().
5749
+ *
5750
+ * @example
5751
+ * ```js
5752
+ * try {
5753
+ * const handle = createVariableHandle(...);
5279
5754
  *
5280
- * Deletes a variable handle that was previously created using `createVariableHandle()`
5755
+ * //After use, deleting the handle
5756
+ * await client.deleteVariableHandle(handle);
5757
+ *
5758
+ * } catch (err) {
5759
+ * console.log("Error:", err);
5760
+ * }
5761
+ * ```
5281
5762
  *
5282
5763
  * @param handle Variable handle to delete
5283
- * @param targetOpts Optional target settings that override values in `settings` (**NOTE:** If used, no caching is available -> possible performance impact)
5764
+ * @param targetOpts Optional target settings that override values in `settings`
5765
+ *
5766
+ * @throws Throws an error if sending the command fails or if the target responds with an error.
5284
5767
  */
5285
5768
  async deleteVariableHandle(handle, targetOpts = {}) {
5286
5769
  if (!this.connection.connected) {
@@ -5318,16 +5801,38 @@ class Client extends events_1.default {
5318
5801
  }
5319
5802
  }
5320
5803
  /**
5321
- * **TODO - DOCUMENTATION ONGOING**
5804
+ * Sends multiple {@link deleteVariableHandle}() commands in one ADS packet.
5805
+ *
5806
+ * Deletes a variable handle that was previously created
5807
+ * using {@link createVariableHandle}().
5808
+ *
5809
+ * Uses ADS sum command under the hood (better and faster performance).
5810
+ * See [Beckhoff Information System](https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_adsdll2/9007199379576075.html&id=9180083787138954512) for more info.
5322
5811
  *
5323
- * Sends multiple deleteVariableHandle() commands in one ADS packet
5812
+ * @example
5813
+ * ```js
5814
+ * try {
5815
+ * const handle1 = createVariableHandle(...);
5816
+ * const handle2 = createVariableHandle(...);
5324
5817
  *
5325
- * Deletes a variable handle that was previously created using `createVariableHandle()`
5818
+ * //After use, deleting the handles
5819
+ * const results = await client.deleteVariableHandleMulti([handle1, handle2]);
5326
5820
  *
5327
- * Uses ADS sum command under the hood (better performance)
5821
+ * if(results[0].success) {
5822
+ * console.log(`First deleted`);
5823
+ * } else {
5824
+ * console.log(`Deleting first handle failed: ${results[0].errorStr}`);
5825
+ * }
5826
+ *
5827
+ * } catch (err) {
5828
+ * console.log("Error:", err);
5829
+ * }
5830
+ * ```
5328
5831
  *
5329
5832
  * @param handles Array of variable handles to delete
5330
5833
  * @param targetOpts Optional target settings that override values in `settings`
5834
+ *
5835
+ * @throws Throws an error if sending the command fails or if the target responds with an error.
5331
5836
  */
5332
5837
  async deleteVariableHandleMulti(handles, targetOpts = {}) {
5333
5838
  if (!this.connection.connected) {
@@ -5399,13 +5904,24 @@ class Client extends events_1.default {
5399
5904
  }
5400
5905
  }
5401
5906
  /**
5402
- * **TODO - DOCUMENTATION ONGOING**
5907
+ * Reads raw data from the target system by a previously created variable handle (acquired using {@link createVariableHandle}())
5403
5908
  *
5404
- * Reads raw byte data from the target system by previously created variable handle
5909
+ * @example
5910
+ * ```js
5911
+ * try {
5912
+ * const handle = await client.createVariableHandle('GVL_Read.StandardTypes.INT_'');
5913
+ * const value = await client.readRawByHandle(handle);
5914
+ * await client.deleteVariableHandle(handle);
5405
5915
  *
5916
+ * } catch (err) {
5917
+ * console.log("Error:", err);
5918
+ * }
5919
+ * ```
5406
5920
  * @param handle Variable handle
5407
5921
  * @param size Optional data length to read (bytes) - as default, size in handle is used if available. Uses 0xFFFFFFFF as fallback.
5408
- * @param targetOpts Optional target settings that override values in `settings` (**NOTE:** If used, no caching is available -> possible performance impact)
5922
+ * @param targetOpts Optional target settings that override values in `settings`
5923
+ *
5924
+ * @throws Throws an error if sending the command fails or if the target responds with an error.
5409
5925
  */
5410
5926
  async readRawByHandle(handle, size, targetOpts = {}) {
5411
5927
  if (!this.connection.connected) {
@@ -5429,13 +5945,28 @@ class Client extends events_1.default {
5429
5945
  }
5430
5946
  }
5431
5947
  /**
5432
- * **TODO - DOCUMENTATION ONGOING**
5948
+ * Writes raw data to the target system by a previously created variable handle (acquired using {@link createVariableHandle}())
5433
5949
  *
5434
- * Writes raw byte data to the target system by previously created variable handle
5950
+ * @example
5951
+ * ```js
5952
+ * try {
5953
+ * const value = await client.convertToRaw(32767, 'INT');
5954
+ * console.log(value); //<Buffer ff 7f>
5955
+ *
5956
+ * const handle = await client.createVariableHandle('GVL_Read.StandardTypes.INT_');
5957
+ * await client.writeRawByHandle(handle, value);
5958
+ * await client.deleteVariableHandle(handle);
5959
+ *
5960
+ * } catch (err) {
5961
+ * console.log("Error:", err);
5962
+ * }
5963
+ * ```
5435
5964
  *
5436
5965
  * @param handle Variable handle
5437
5966
  * @param value Data to write
5438
- * @param targetOpts Optional target settings that override values in `settings` (**NOTE:** If used, no caching is available -> possible performance impact)
5967
+ * @param targetOpts Optional target settings that override values in `settings`
5968
+ *
5969
+ * @throws Throws an error if sending the command fails or if the target responds with an error.
5439
5970
  */
5440
5971
  async writeRawByHandle(handle, value, targetOpts = {}) {
5441
5972
  if (!this.connection.connected) {
@@ -5453,12 +5984,23 @@ class Client extends events_1.default {
5453
5984
  }
5454
5985
  }
5455
5986
  /**
5456
- * **TODO - DOCUMENTATION ONGOING**
5987
+ * Reads raw data from the target system by a symbol object (acquired using `getSymbol()`)
5457
5988
  *
5458
- * Reads raw data by symbol
5989
+ * @example
5990
+ * ```js
5991
+ * try {
5992
+ * const symbol = await client.getSymbol('GVL_Read.StandardTypes.INT_');
5993
+ * const value = await client.readRawBySymbol(symbol);
5459
5994
  *
5460
- * @param symbol Symbol (acquired using `getSymbol()`)
5461
- * @param targetOpts Optional target settings that override values in `settings` (**NOTE:** If used, no caching is available -> possible performance impact)
5995
+ * } catch (err) {
5996
+ * console.log("Error:", err);
5997
+ * }
5998
+ * ```
5999
+ *
6000
+ * @param symbol Symbol
6001
+ * @param targetOpts Optional target settings that override values in `settings`
6002
+ *
6003
+ * @throws Throws an error if sending the command fails or if the target responds with an error.
5462
6004
  */
5463
6005
  async readRawBySymbol(symbol, targetOpts = {}) {
5464
6006
  if (!this.connection.connected) {
@@ -5476,13 +6018,27 @@ class Client extends events_1.default {
5476
6018
  }
5477
6019
  }
5478
6020
  /**
5479
- * **TODO - DOCUMENTATION ONGOING**
6021
+ * Writes raw data to the target system by a symbol object (acquired using `getSymbol()`)
5480
6022
  *
5481
- * Writes raw data by symbol
6023
+ * @example
6024
+ * ```js
6025
+ * try {
6026
+ * const value = await client.convertToRaw(32767, 'INT');
6027
+ * console.log(value); //<Buffer ff 7f>
5482
6028
  *
5483
- * @param symbol Symbol (acquired using `getSymbol()`)
6029
+ * const symbol = await client.getSymbol('GVL_Read.StandardTypes.INT_');
6030
+ * await client.writeRawBySymbol(symbol, value);
6031
+ *
6032
+ * } catch (err) {
6033
+ * console.log("Error:", err);
6034
+ * }
6035
+ * ```
6036
+ *
6037
+ * @param symbol Symbol
5484
6038
  * @param value Data to write
5485
6039
  * @param targetOpts Optional target settings that override values in `settings`
6040
+ *
6041
+ * @throws Throws an error if sending the command fails or if the target responds with an error.
5486
6042
  */
5487
6043
  async writeRawBySymbol(symbol, value, targetOpts = {}) {
5488
6044
  if (!this.connection.connected) {
@@ -5499,21 +6055,40 @@ class Client extends events_1.default {
5499
6055
  }
5500
6056
  }
5501
6057
  /**
5502
- * **TODO - DOCUMENTATION ONGOING**
6058
+ * Invokes a function block RPC method on the target system.
5503
6059
  *
5504
- * Invokes/calls a function block RPC method from PLC
6060
+ * Returns the return value of the method and outputs (if any).
5505
6061
  *
5506
- * Returns method return value and/or outputs (if any)
6062
+ * NOTE: In the PLC, `{attribute 'TcRpcEnable'}` is required above the `METHOD` definition.
5507
6063
  *
5508
- * For RPC support, the method needs to have `{attribute 'TcRpcEnable'}` attribute above the `METHOD` definition
6064
+ * @example
6065
+ * ```js
6066
+ * try {
6067
+ * const res = await client.invokeRpcMethod('GVL_RPC.RpcBlock', 'Calculator', {
6068
+ * Value1: 1,
6069
+ * Value2: 123
6070
+ * });
5509
6071
  *
5510
- * @param path Full function block instance path in the PLC (such as `GVL_Test.ExampleBlock`)
5511
- * @param method Function block method name to call
5512
- * @param parameters Function block method parameters (inputs) (if any)
6072
+ * console.log(res);
6073
+ * //{
6074
+ * // returnValue: true,
6075
+ * // outputs: { Sum: 124, Product: 123, Division: 0.008130080997943878 }
6076
+ * //}
6077
+ *
6078
+ * } catch (err) {
6079
+ * console.log("Error:", err);
6080
+ * }
6081
+ * ```
6082
+ *
6083
+ * @param path Variable path in the PLC of the function block instance (such as `GVL_Test.ExampleBlock`)
6084
+ * @param method Function block method name
6085
+ * @param parameters Method parameters (inputs) (if any)
5513
6086
  * @param targetOpts Optional target settings that override values in `settings`
5514
6087
  *
5515
6088
  * @template T Typescript data type of the method return value, for example `invokeRpcMethod<number>(...)` or `invokeRpcMethod<ST_TypedStruct>(...)`
5516
6089
  * @template U Typescript data type of the method outputs object, for example `invokeRpcMethod<number, ST_TypedStruct>(...)`
6090
+ *
6091
+ * @throws Throws an error if sending the command fails or if the target responds with an error.
5517
6092
  */
5518
6093
  async invokeRpcMethod(path, method, parameters = {}, targetOpts = {}) {
5519
6094
  if (!this.connection.connected) {