ads-client 2.0.0-beta.5 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,30 +1,31 @@
1
1
  # ads-client
2
2
 
3
-
4
3
  [![npm version](https://img.shields.io/npm/v/ads-client)](https://www.npmjs.org/package/ads-client)
5
4
  [![GitHub](https://img.shields.io/badge/View%20on-GitHub-brightgreen)](https://github.com/jisotalo/ads-client)
6
5
  [![License](https://img.shields.io/github/license/jisotalo/ads-client)](https://choosealicense.com/licenses/mit/)
7
6
 
8
-
9
7
  Beckhoff TwinCAT ADS client library for Node.js (unofficial).
10
8
 
11
9
  Connect to a Beckhoff TwinCAT automation system using the ADS protocol from a Node.js app.
12
10
 
13
11
  If you are using Node-RED, check out the [node-red-contrib-ads-client](https://www.npmjs.com/package/node-red-contrib-ads-client).
14
12
 
15
- # Project status
13
+ There is automatically created documentation available at https://jisotalo.fi/ads-client/
16
14
 
17
- <u><b>NOTE: DOCUMENTATION LINKS ARE NOT WORKING UNTIL RELEASED - CLONE REPOSITORY FOR DOCS</b></u>
15
+ # Project status
18
16
 
19
- Version 2 is almost ready!
17
+ 14.12.2024 - version 2 released!
20
18
 
21
19
  - Rewritten in Typescript
22
20
  - See [CHANGELOG.md](https://github.com/jisotalo/ads-client/blob/v2-dev/CHANGELOG.md) for details.
23
- - See [MIGRATION.md](https://github.com/jisotalo/ads-client/blob/v2-dev/MIGRATION.md) for guide of migrating v1 -> v2 (breaking changes!)
24
- - See the new [documentation](TODO-DOC-URL-HERE/classes/Client.html)
21
+ - See [MIGRATION.md](https://github.com/jisotalo/ads-client/blob/v2-dev/MIGRATION.md) for guide of migrating v1 -> v2 (**breaking changes!**)
22
+ - See the new [documentation](https://jisotalo.fi/ads-client/classes/Client.html)
23
+
24
+ See [`legacy-v1` branch](https://github.com/jisotalo/ads-client/tree/legacy-v1) for previous/legacy version 1.4.4.
25
25
 
26
26
  # Features
27
27
  - Supports TwinCAT 2 and 3
28
+ - Supports connecting to the local TwinCAT 3 runtime
28
29
  - Supports any kind of target systems with ADS protocol (local runtime, PLC, EtherCAT I/O...)
29
30
  - Supports multiple connections from the same host
30
31
  - Reading and writing any kind of variables
@@ -35,8 +36,13 @@ Version 2 is almost ready!
35
36
  - Automatic byte alignment support (all pack-modes automatically supported)
36
37
 
37
38
  # Table of contents
39
+ - [ads-client](#ads-client)
40
+ - [Project status](#project-status)
41
+ - [Features](#features)
42
+ - [Table of contents](#table-of-contents)
38
43
  - [Support](#support)
39
44
  - [Installing](#installing)
45
+ - [Minimal example (TLDR)](#minimal-example-tldr)
40
46
  - [Connection setup](#connection-setup)
41
47
  - [Setup 1 - Connect from Windows](#setup-1---connect-from-windows)
42
48
  - [Setup 2 - Connect from Linux/Windows](#setup-2---connect-from-linuxwindows)
@@ -66,22 +72,35 @@ Version 2 is almost ready!
66
72
  - [Raw data](#raw-data)
67
73
  - [Unsubscribing](#unsubscribing)
68
74
  - [Using variable handles](#using-variable-handles)
75
+ - [Reading a value using a variable handle](#reading-a-value-using-a-variable-handle)
76
+ - [Writing a value using a variable handle](#writing-a-value-using-a-variable-handle)
69
77
  - [Calling function block RPC methods](#calling-function-block-rpc-methods)
70
- - [Converting from/to raw data](#converting-fromto-raw-data)
78
+ - [Things to note when using RPC Methods](#things-to-note-when-using-rpc-methods)
79
+ - [About examples](#about-examples)
80
+ - [RPC method with standard data types](#rpc-method-with-standard-data-types)
81
+ - [RPC method with struct](#rpc-method-with-struct)
82
+ - [Converting data between raw data and Javascript objects](#converting-data-between-raw-data-and-javascript-objects)
83
+ - [Converting a raw value to a Javascript object](#converting-a-raw-value-to-a-javascript-object)
84
+ - [Converting a Javascript object to a raw value](#converting-a-javascript-object-to-a-raw-value)
71
85
  - [Other features](#other-features)
86
+ - [ADS sum commands](#ads-sum-commands)
87
+ - [Starting and stopping a PLC](#starting-and-stopping-a-plc)
88
+ - [Starting and stopping TwinCAT system](#starting-and-stopping-twincat-system)
89
+ - [Client events](#client-events)
90
+ - [Debugging](#debugging)
72
91
  - [Disconnecting](#disconnecting)
73
- - [FAQ](#faq)
74
- - [Lot's of connection issues and timeouts](#lots-of-connection-issues-and-timeouts)
92
+ - [Common issues and questions](#common-issues-and-questions)
93
+ - [There are lot's of connection issues and timeouts](#there-are-lots-of-connection-issues-and-timeouts)
75
94
  - [Getting `TypeError: Do not know how to serialize a BigInt`](#getting-typeerror-do-not-know-how-to-serialize-a-bigint)
76
95
  - [Can I connect from Raspberry Pi to TwinCAT?](#can-i-connect-from-raspberry-pi-to-twincat)
77
96
  - [Receiving ADS error 1808 `Symbol not found` even when it should be found](#receiving-ads-error-1808-symbol-not-found-even-when-it-should-be-found)
78
97
  - [Having timeouts or 'mailbox is full' errors](#having-timeouts-or-mailbox-is-full-errors)
79
98
  - [Having problems to connect from OSX or Raspberry Pi to target PLC](#having-problems-to-connect-from-osx-or-raspberry-pi-to-target-plc)
80
99
  - [A data type is not found even when it should be](#a-data-type-is-not-found-even-when-it-should-be)
81
- - [ClientException: Connection failed: Device system manager state read failed](#clientexception-connection-failed-device-system-manager-state-read-failed)
100
+ - [Connection failed - failed to set PLC connection](#connection-failed---failed-to-set-plc-connection)
82
101
  - [Connection failed (error EADDRNOTAVAIL)](#connection-failed-error-eaddrnotavail)
83
102
  - [Problems running ads-client with docker](#problems-running-ads-client-with-docker)
84
- - [How to connect to PLC that is in CONFIG mode?](#how-to-connect-to-plc-that-is-in-config-mode)
103
+ - [How to connect to a PLC that is in CONFIG mode?](#how-to-connect-to-a-plc-that-is-in-config-mode)
85
104
  - [Issues with TwinCAT 2 low-end devices (BK9050, BC9050 etc.)](#issues-with-twincat-2-low-end-devices-bk9050-bc9050-etc)
86
105
  - [External links](#external-links)
87
106
  - [Library testing](#library-testing)
@@ -110,7 +129,7 @@ If you need help with integrating the ads-client, I'm available for coding work
110
129
  Install the [npm package](https://www.npmjs.com/package/ads-client):
111
130
 
112
131
  ```
113
- npm install ads-client@beta
132
+ npm install ads-client
114
133
  ```
115
134
 
116
135
  Include the module in your code:
@@ -125,11 +144,53 @@ import { Client } from 'ads-client';
125
144
 
126
145
  You can also clone the repository and run `npm run build`. After that, the library is available at `./dist/`
127
146
 
147
+ # Minimal example (TLDR)
148
+
149
+ This connects to a local PLC runtime, reads a value, writes a value, reads it again and then disconnects. The value is a string and it's located in `GVL_Global.StringValue`.
150
+
151
+ ```js
152
+ const { Client } = require('ads-client');
153
+
154
+ const client = new Client({
155
+ targetAmsNetId: 'localhost',
156
+ targetAdsPort: 851
157
+ });
158
+
159
+ client.connect()
160
+ .then(async (res) => {
161
+ console.log(`Connected to the ${res.targetAmsNetId}`);
162
+ console.log(`Router assigned us AmsNetId ${res.localAmsNetId} and port ${res.localAdsPort}`);
163
+
164
+ try {
165
+ //Reading a value
166
+ const read = await client.readValue('GVL_Global.StringValue');
167
+ console.log('Value read (before):', read.value);
168
+
169
+ //Writing a value
170
+ await client.writeValue('GVL_Global.StringValue', 'This is a new value');
171
+
172
+ //Reading a value
173
+ const read2 = await client.readValue('GVL_Global.StringValue');
174
+ console.log('Value read (after):', read2.value);
175
+
176
+ } catch (err) {
177
+ console.log('Something failed:', err);
178
+ }
179
+
180
+ //Disconnecting
181
+ await client.disconnect();
182
+ console.log('Disconnected');
183
+
184
+ }).catch(err => {
185
+ console.log('Error:', err);
186
+ });
187
+ ```
188
+
128
189
  # Connection setup
129
190
 
130
191
  The ads-client can be used with multiple system configurations.
131
192
 
132
- [![ads-client-setups](https://user-images.githubusercontent.com/13457157/82724547-8dde0800-9cdf-11ea-8dd1-0a1f06f8559f.PNG)](https://user-images.githubusercontent.com/13457157/82724547-8dde0800-9cdf-11ea-8dd1-0a1f06f8559f.PNG)
193
+ ![ads-client-setups](https://raw.githubusercontent.com/jisotalo/ads-client/refs/heads/v2-dev/img/connection_setup.png)
133
194
 
134
195
 
135
196
  ## Setup 1 - Connect from Windows
@@ -357,7 +418,7 @@ await client.readSymbol('.ExampleSTRUCT') //TwinCAT 2
357
418
 
358
419
  ## Documentation
359
420
 
360
- The documentation is available at [https://jisotalo.fi/ads-client](TODO-DOC-URL-HERE/classes/Client.html) and `./docs` folder.
421
+ The documentation is available at [https://jisotalo.fi/ads-client](https://jisotalo.fi/ads-client/classes/Client.html) and `./docs` folder.
361
422
 
362
423
  Examples in the getting started are based on a PLC project from [https://github.com/jisotalo/ads-client-test-plc-project](https://github.com/jisotalo/ads-client-test-plc-project).
363
424
 
@@ -367,67 +428,63 @@ You can use the test PLC project as reference together with the [ads-client.test
367
428
 
368
429
  Click a method to open it's documentation.
369
430
 
370
- | Method | Description |
371
- | ------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
372
- | [`cacheDataTypes()`](TODO-DOC-URL-HERE/classes/Client.html#cacheDataTypes) | Caches all data types from the target PLC runtime. |
373
- | [`cacheSymbols()`](TODO-DOC-URL-HERE/classes/Client.html#cacheSymbols) | Caches all symbols from the target PLC runtime. |
374
- | [`connect()`](TODO-DOC-URL-HERE/classes/Client.html#connect) | Connects to the target. |
375
- | [`convertFromRaw()`](TODO-DOC-URL-HERE/classes/Client.html#convertFromRaw) | Converts raw data to a Javascript object by using the provided data type. |
376
- | [`convertToRaw()`](TODO-DOC-URL-HERE/classes/Client.html#convertToRaw) | Converts a Javascript object to raw data by using the provided data type. |
377
- | [`createVariableHandle()`](TODO-DOC-URL-HERE/classes/Client.html#createVariableHandle) | Creates a handle to a variable at the target system by variable path (such as `GVL_Test.ExampleStruct`). |
378
- | [`createVariableHandleMulti()`](TODO-DOC-URL-HERE/classes/Client.html#createVariableHandleMulti) | Sends multiple `createVariableHandle()` commands in one ADS packet (ADS sum command). |
379
- | [`deleteVariableHandle()`](TODO-DOC-URL-HERE/classes/Client.html#deleteVariableHandle) | Deletes a variable handle that was previously created using `createVariableHandle()`. |
380
- | [`deleteVariableHandleMulti()`](TODO-DOC-URL-HERE/classes/Client.html#deleteVariableHandleMulti) | Sends multiple `deleteVariableHandle()` commands in one ADS packet (ADS sum command). |
381
- | [`disconnect()`](TODO-DOC-URL-HERE/classes/Client.html#disconnect) | Disconnects from the target and closes active connection. |
382
- | [`getDataType()`](TODO-DOC-URL-HERE/classes/Client.html#getDataType) | Returns full data type declaration for requested data type (such as `ST_Struct`). |
383
- | [`getDataTypes()`](TODO-DOC-URL-HERE/classes/Client.html#getDataTypes) | Returns all target PLC runtime data types. |
384
- | [`getDefaultPlcObject()`](TODO-DOC-URL-HERE/classes/Client.html#getDefaultPlcObject) | Returns a default (empty) Javascript object representing provided PLC data type. |
385
- | [`getSymbol()`](TODO-DOC-URL-HERE/classes/Client.html#getSymbol) | Returns a symbol object for given variable path (such as `GVL_Test.ExampleStruct`). |
386
- | [`getSymbols()`](TODO-DOC-URL-HERE/classes/Client.html#getSymbols) | Returns all symbols from the target PLC runtime. |
387
- | [`invokeRpcMethod()`](TODO-DOC-URL-HERE/classes/Client.html#invokeRpcMethod) | Invokes a function block RPC method on the target system. |
388
- | [`readDeviceInfo()`](TODO-DOC-URL-HERE/classes/Client.html#readDeviceInfo) | Reads target device information. |
389
- | [`readPlcRuntimeState()`](TODO-DOC-URL-HERE/classes/Client.html#readPlcRuntimeState) | Reads target PLC runtime state (`Run`, `Stop` etc.) |
390
- | [`readPlcSymbolVersion()`](TODO-DOC-URL-HERE/classes/Client.html#readPlcSymbolVersion) | Reads target PLC runtime symbol version. |
391
- | [`readPlcUploadInfo()`](TODO-DOC-URL-HERE/classes/Client.html#readPlcUploadInfo) | Reads target PLC runtime upload information. |
392
- | [`readRaw()`](TODO-DOC-URL-HERE/classes/Client.html#readRaw) | Reads raw data from the target system by a raw ADS address (index group, index offset and data length). |
393
- | [`readRawByHandle()`](TODO-DOC-URL-HERE/classes/Client.html#readRawByHandle) | Reads raw data from the target system by a previously created variable handle (acquired using `createVariableHandle()`). |
394
- | [`readRawByPath()`](TODO-DOC-URL-HERE/classes/Client.html#readRawByPath) | Reads raw data from the target system by variable path (such as `GVL_Test.ExampleStruct`). |
395
- | [`readRawBySymbol()`](TODO-DOC-URL-HERE/classes/Client.html#readRawBySymbol) | Reads raw data from the target system by a symbol object (acquired using `getSymbol()`). |
396
- | [`readRawMulti()`](TODO-DOC-URL-HERE/classes/Client.html#readRawMulti) | Sends multiple `readRaw()` commands in one ADS packet (ADS sum command). |
397
- | [`readState()`](TODO-DOC-URL-HERE/classes/Client.html#readState) | Reads target ADS state. |
398
- | [`readTcSystemState()`](TODO-DOC-URL-HERE/classes/Client.html#readTcSystemState) | Reads target TwinCAT system state from ADS port 10000 (usually `Run` or `Config`). |
399
- | [`readValue()`](TODO-DOC-URL-HERE/classes/Client.html#readValue) | Reads variable's value from the target system by a variable path (such as `GVL_Test.ExampleStruct`) and returns the value as a Javascript object. |
400
- | [`readValueBySymbol()`](TODO-DOC-URL-HERE/classes/Client.html#readValueBySymbol) | Reads variable's value from the target system by a symbol object (acquired using `getSymbol()`) and returns the value as a Javascript object. |
401
- | [`readWriteRaw()`](TODO-DOC-URL-HERE/classes/Client.html#readWriteRaw) | Writes raw data to the target system by a raw ADS address (index group, index offset) and reads the result as raw data. |
402
- | [`readWriteRawMulti()`](TODO-DOC-URL-HERE/classes/Client.html#readWriteRawMulti) | Sends multiple `readWriteRaw()` commands in one ADS packet (ADS sum command). |
403
- | [`reconnect()`](TODO-DOC-URL-HERE/classes/Client.html#reconnect) | Reconnects to the target (disconnects and then connects again). |
404
- | [`resetPlc()`](TODO-DOC-URL-HERE/classes/Client.html#resetPlc) | Resets the target PLC runtime. Same as reset cold in TwinCAT XAE. |
405
- | [`restartPlc()`](TODO-DOC-URL-HERE/classes/Client.html#restartPlc) | Restarts the PLC runtime. Same as calling `resetPlc()` and then `startPlc()`. |
406
- | [`restartTcSystem()`](TODO-DOC-URL-HERE/classes/Client.html#restartTcSystem) | Restarts the target TwinCAT system. |
407
- | [`sendAdsCommand()`](TODO-DOC-URL-HERE/classes/Client.html#sendAdsCommand) | Sends a raw ADS command to the target. |
408
- | [`setDebugLevel()`](TODO-DOC-URL-HERE/classes/Client.html#setDebugLevel) | Sets active debug level. |
409
- | [`setTcSystemToConfig()`](TODO-DOC-URL-HERE/classes/Client.html#setTcSystemToConfig) | Sets the target TwinCAT system to config mode. Same as `Restart TwinCAT (Config mode)` in TwinCAT XAE. |
410
- | [`setTcSystemToRun()`](TODO-DOC-URL-HERE/classes/Client.html#setTcSystemToRun) | Sets the target TwinCAT system to run mode. Same as `Restart TwinCAT system` in TwinCAT XAE. |
411
- | [`startPlc()`](TODO-DOC-URL-HERE/classes/Client.html#startPlc) | Starts the target PLC runtime. Same as pressing the green play button in TwinCAT XAE. |
412
- | [`stopPlc()`](TODO-DOC-URL-HERE/classes/Client.html#stopPlc) | Stops the target PLC runtime. Same as pressing the red stop button in TwinCAT XAE. |
413
- | [`subscribe()`](TODO-DOC-URL-HERE/classes/Client.html#subscribe) | Subscribes to value change notifications (ADS notifications) by variable path (such as `GVL_Test.ExampleStruct`) or raw ADS address (index group, index offset and data length). |
414
- | [`subscribeRaw()`](TODO-DOC-URL-HERE/classes/Client.html#subscribeRaw) | Subscribes to raw value change notifications (ADS notifications) by a raw ADS address (index group, index offset and data length). |
415
- | [`subscribeValue()`](TODO-DOC-URL-HERE/classes/Client.html#subscribeValue) | Subscribes to value change notifications (ADS notifications) by a variable path, such as `GVL_Test.ExampleStruct`. |
416
- | [`unsubscribe()`](TODO-DOC-URL-HERE/classes/Client.html#unsubscribe) | Unsubscribes a subscription (deletes ADS notification). |
417
- | [`unsubscribeAll()`](TODO-DOC-URL-HERE/classes/Client.html#unsubscribeAll) | Unsubscribes all active subscription (deletes all ADS notifications). |
418
- | [`writeControl()`](TODO-DOC-URL-HERE/classes/Client.html#writeControl) | Sends an ADS `WriteControl` command to the target. |
419
- | [`writeRaw()`](TODO-DOC-URL-HERE/classes/Client.html#writeRaw) | Writes raw data to the target system by a raw ADS address (index group, index offset and data length). |
420
- | [`writeRawByHandle()`](TODO-DOC-URL-HERE/classes/Client.html#writeRawByHandle) | Writes raw data to the target system by a previously created variable handle (acquired using `createVariableHandle()`). |
421
- | [`writeRawByPath()`](TODO-DOC-URL-HERE/classes/Client.html#writeRawByPath) | Writes raw data to the target system by variable path (such as `GVL_Test.ExampleStruct`). |
422
- | [`writeRawBySymbol()`](TODO-DOC-URL-HERE/classes/Client.html#writeRawBySymbol) | Writes raw data to the target system by a symbol object (acquired using `getSymbol()`). |
423
- | [`writeRawMulti()`](TODO-DOC-URL-HERE/classes/Client.html#writeRawMulti) | Sends multiple `writeRaw()` commands in one ADS packet (ADS sum command). |
424
- | [`writeValue()`](TODO-DOC-URL-HERE/classes/Client.html#writeValue) | Writes variable's value to the target system by a variable path (such as `GVL_Test.ExampleStruct`). Converts the value from a Javascript object to a raw value. |
425
- | [`writeValueBySymbol()`](TODO-DOC-URL-HERE/classes/Client.html#writeValueBySymbol) | Writes variable's value to the target system by a symbol object (acquired using `getSymbol()`). Converts the value from a Javascript object to a raw value. |
426
-
427
-
428
-
429
-
430
-
431
+ | Method | Description |
432
+ | --------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
433
+ | [`cacheDataTypes()`](https://jisotalo.fi/ads-client/classes/Client.html#cacheDataTypes) | Caches all data types from the target PLC runtime. |
434
+ | [`cacheSymbols()`](https://jisotalo.fi/ads-client/classes/Client.html#cacheSymbols) | Caches all symbols from the target PLC runtime. |
435
+ | [`connect()`](https://jisotalo.fi/ads-client/classes/Client.html#connect) | Connects to the target. |
436
+ | [`convertFromRaw()`](https://jisotalo.fi/ads-client/classes/Client.html#convertFromRaw) | Converts raw data to a Javascript object by using the provided data type. |
437
+ | [`convertToRaw()`](https://jisotalo.fi/ads-client/classes/Client.html#convertToRaw) | Converts a Javascript object to raw data by using the provided data type. |
438
+ | [`createVariableHandle()`](https://jisotalo.fi/ads-client/classes/Client.html#createVariableHandle) | Creates a handle to a variable at the target system by variable path (such as `GVL_Test.ExampleStruct`). |
439
+ | [`createVariableHandleMulti()`](https://jisotalo.fi/ads-client/classes/Client.html#createVariableHandleMulti) | Sends multiple `createVariableHandle()` commands in one ADS packet (ADS sum command). |
440
+ | [`deleteVariableHandle()`](https://jisotalo.fi/ads-client/classes/Client.html#deleteVariableHandle) | Deletes a variable handle that was previously created using `createVariableHandle()`. |
441
+ | [`deleteVariableHandleMulti()`](https://jisotalo.fi/ads-client/classes/Client.html#deleteVariableHandleMulti) | Sends multiple `deleteVariableHandle()` commands in one ADS packet (ADS sum command). |
442
+ | [`disconnect()`](https://jisotalo.fi/ads-client/classes/Client.html#disconnect) | Disconnects from the target and closes active connection. |
443
+ | [`getDataType()`](https://jisotalo.fi/ads-client/classes/Client.html#getDataType) | Returns full data type declaration for requested data type (such as `ST_Struct`). |
444
+ | [`getDataTypes()`](https://jisotalo.fi/ads-client/classes/Client.html#getDataTypes) | Returns all target PLC runtime data types. |
445
+ | [`getDefaultPlcObject()`](https://jisotalo.fi/ads-client/classes/Client.html#getDefaultPlcObject) | Returns a default (empty) Javascript object representing provided PLC data type. |
446
+ | [`getSymbol()`](https://jisotalo.fi/ads-client/classes/Client.html#getSymbol) | Returns a symbol object for given variable path (such as `GVL_Test.ExampleStruct`). |
447
+ | [`getSymbols()`](https://jisotalo.fi/ads-client/classes/Client.html#getSymbols) | Returns all symbols from the target PLC runtime. |
448
+ | [`invokeRpcMethod()`](https://jisotalo.fi/ads-client/classes/Client.html#invokeRpcMethod) | Invokes a function block RPC method on the target system. |
449
+ | [`readDeviceInfo()`](https://jisotalo.fi/ads-client/classes/Client.html#readDeviceInfo) | Reads target device information. |
450
+ | [`readPlcRuntimeState()`](https://jisotalo.fi/ads-client/classes/Client.html#readPlcRuntimeState) | Reads target PLC runtime state (`Run`, `Stop` etc.) |
451
+ | [`readPlcSymbolVersion()`](https://jisotalo.fi/ads-client/classes/Client.html#readPlcSymbolVersion) | Reads target PLC runtime symbol version. |
452
+ | [`readPlcUploadInfo()`](https://jisotalo.fi/ads-client/classes/Client.html#readPlcUploadInfo) | Reads target PLC runtime upload information. |
453
+ | [`readRaw()`](https://jisotalo.fi/ads-client/classes/Client.html#readRaw) | Reads raw data from the target system by a raw ADS address (index group, index offset and data length). |
454
+ | [`readRawByHandle()`](https://jisotalo.fi/ads-client/classes/Client.html#readRawByHandle) | Reads raw data from the target system by a previously created variable handle (acquired using `createVariableHandle()`). |
455
+ | [`readRawByPath()`](https://jisotalo.fi/ads-client/classes/Client.html#readRawByPath) | Reads raw data from the target system by variable path (such as `GVL_Test.ExampleStruct`). |
456
+ | [`readRawBySymbol()`](https://jisotalo.fi/ads-client/classes/Client.html#readRawBySymbol) | Reads raw data from the target system by a symbol object (acquired using `getSymbol()`). |
457
+ | [`readRawMulti()`](https://jisotalo.fi/ads-client/classes/Client.html#readRawMulti) | Sends multiple `readRaw()` commands in one ADS packet (ADS sum command). |
458
+ | [`readState()`](https://jisotalo.fi/ads-client/classes/Client.html#readState) | Reads target ADS state. |
459
+ | [`readTcSystemState()`](https://jisotalo.fi/ads-client/classes/Client.html#readTcSystemState) | Reads target TwinCAT system state from ADS port 10000 (usually `Run` or `Config`). |
460
+ | [`readValue()`](https://jisotalo.fi/ads-client/classes/Client.html#readValue) | Reads variable's value from the target system by a variable path (such as `GVL_Test.ExampleStruct`) and returns the value as a Javascript object. |
461
+ | [`readValueBySymbol()`](https://jisotalo.fi/ads-client/classes/Client.html#readValueBySymbol) | Reads variable's value from the target system by a symbol object (acquired using `getSymbol()`) and returns the value as a Javascript object. |
462
+ | [`readWriteRaw()`](https://jisotalo.fi/ads-client/classes/Client.html#readWriteRaw) | Writes raw data to the target system by a raw ADS address (index group, index offset) and reads the result as raw data. |
463
+ | [`readWriteRawMulti()`](https://jisotalo.fi/ads-client/classes/Client.html#readWriteRawMulti) | Sends multiple `readWriteRaw()` commands in one ADS packet (ADS sum command). |
464
+ | [`reconnect()`](https://jisotalo.fi/ads-client/classes/Client.html#reconnect) | Reconnects to the target (disconnects and then connects again). |
465
+ | [`resetPlc()`](https://jisotalo.fi/ads-client/classes/Client.html#resetPlc) | Resets the target PLC runtime. Same as reset cold in TwinCAT XAE. |
466
+ | [`restartPlc()`](https://jisotalo.fi/ads-client/classes/Client.html#restartPlc) | Restarts the PLC runtime. Same as calling `resetPlc()` and then `startPlc()`. |
467
+ | [`restartTcSystem()`](https://jisotalo.fi/ads-client/classes/Client.html#restartTcSystem) | Restarts the target TwinCAT system. |
468
+ | [`sendAdsCommand()`](https://jisotalo.fi/ads-client/classes/Client.html#sendAdsCommand) | Sends a raw ADS command to the target. |
469
+ | [`sendAdsCommandWithFallback()`](https://jisotalo.fi/ads-client/classes/Client.html#sendAdsCommandWithFallback) | Sends a raw ADS command to the target. If it fails to specific ADS error codes, sends the fallback ADS command. |
470
+ | [`setDebugLevel()`](https://jisotalo.fi/ads-client/classes/Client.html#setDebugLevel) | Sets active debug level. |
471
+ | [`setTcSystemToConfig()`](https://jisotalo.fi/ads-client/classes/Client.html#setTcSystemToConfig) | Sets the target TwinCAT system to config mode. Same as `Restart TwinCAT (Config mode)` in TwinCAT XAE. |
472
+ | [`setTcSystemToRun()`](https://jisotalo.fi/ads-client/classes/Client.html#setTcSystemToRun) | Sets the target TwinCAT system to run mode. Same as `Restart TwinCAT system` in TwinCAT XAE. |
473
+ | [`startPlc()`](https://jisotalo.fi/ads-client/classes/Client.html#startPlc) | Starts the target PLC runtime. Same as pressing the green play button in TwinCAT XAE. |
474
+ | [`stopPlc()`](https://jisotalo.fi/ads-client/classes/Client.html#stopPlc) | Stops the target PLC runtime. Same as pressing the red stop button in TwinCAT XAE. |
475
+ | [`subscribe()`](https://jisotalo.fi/ads-client/classes/Client.html#subscribe) | Subscribes to value change notifications (ADS notifications) by variable path (such as `GVL_Test.ExampleStruct`) or raw ADS address (index group, index offset and data length). |
476
+ | [`subscribeRaw()`](https://jisotalo.fi/ads-client/classes/Client.html#subscribeRaw) | Subscribes to raw value change notifications (ADS notifications) by a raw ADS address (index group, index offset and data length). |
477
+ | [`subscribeValue()`](https://jisotalo.fi/ads-client/classes/Client.html#subscribeValue) | Subscribes to value change notifications (ADS notifications) by a variable path, such as `GVL_Test.ExampleStruct`. |
478
+ | [`unsubscribe()`](https://jisotalo.fi/ads-client/classes/Client.html#unsubscribe) | Unsubscribes a subscription (deletes ADS notification). |
479
+ | [`unsubscribeAll()`](https://jisotalo.fi/ads-client/classes/Client.html#unsubscribeAll) | Unsubscribes all active subscription (deletes all ADS notifications). |
480
+ | [`writeControl()`](https://jisotalo.fi/ads-client/classes/Client.html#writeControl) | Sends an ADS `WriteControl` command to the target. |
481
+ | [`writeRaw()`](https://jisotalo.fi/ads-client/classes/Client.html#writeRaw) | Writes raw data to the target system by a raw ADS address (index group, index offset and data length). |
482
+ | [`writeRawByHandle()`](https://jisotalo.fi/ads-client/classes/Client.html#writeRawByHandle) | Writes raw data to the target system by a previously created variable handle (acquired using `createVariableHandle()`). |
483
+ | [`writeRawByPath()`](https://jisotalo.fi/ads-client/classes/Client.html#writeRawByPath) | Writes raw data to the target system by variable path (such as `GVL_Test.ExampleStruct`). |
484
+ | [`writeRawBySymbol()`](https://jisotalo.fi/ads-client/classes/Client.html#writeRawBySymbol) | Writes raw data to the target system by a symbol object (acquired using `getSymbol()`). |
485
+ | [`writeRawMulti()`](https://jisotalo.fi/ads-client/classes/Client.html#writeRawMulti) | Sends multiple `writeRaw()` commands in one ADS packet (ADS sum command). |
486
+ | [`writeValue()`](https://jisotalo.fi/ads-client/classes/Client.html#writeValue) | Writes variable's value to the target system by a variable path (such as `GVL_Test.ExampleStruct`). Converts the value from a Javascript object to a raw value. |
487
+ | [`writeValueBySymbol()`](https://jisotalo.fi/ads-client/classes/Client.html#writeValueBySymbol) | Writes variable's value to the target system by a symbol object (acquired using `getSymbol()`). Converts the value from a Javascript object to a raw value. |
431
488
 
432
489
  ## Creating a client
433
490
 
@@ -456,15 +513,21 @@ const { Client } = require('ads-client');
456
513
  const client = new Client({
457
514
  targetAmsNetId: 'localhost',
458
515
  targetAdsPort: 851
459
- })
516
+ });
460
517
 
461
518
  client.connect()
462
- .then(res => {
463
- console.log(`Connected to the ${res.targetAmsNetId}`)
464
- console.log(`Router assigned us AmsNetId ${res.localAmsNetId} and port ${res.localAdsPort}`)
519
+ .then(async (res) => {
520
+ console.log(`Connected to the ${res.targetAmsNetId}`);
521
+ console.log(`Router assigned us AmsNetId ${res.localAmsNetId} and port ${res.localAdsPort}`);
522
+ //Connected
523
+
524
+ //...
525
+
526
+ //Disconnecting
527
+ await client.disconnect();
465
528
 
466
529
  }).catch(err => {
467
- console.log('Error:', err)
530
+ console.log('Error:', err);
468
531
  });
469
532
  ```
470
533
 
@@ -472,73 +535,85 @@ client.connect()
472
535
 
473
536
  ### Reading any value
474
537
 
475
- Use [`readValue()`](TODO-DOC-URL-HERE/classes/Client.html#readValue) to read any PLC value as a Javascript object. If using Typescript, the type of the PLC variable can be passed as well (`readValue<T>()`).
538
+ Use [`readValue()`](https://jisotalo.fi/ads-client/classes/Client.html#readValue) to read any PLC value.
476
539
 
477
540
  The only exception is the dereferenced value of a reference/pointer, see [Reading reference/pointer](#reading-referencepointer).
478
541
 
542
+ **Reading INT**
543
+
479
544
  ```js
480
- try {
481
- let res;
482
-
483
- //Example: INT
484
- res = await client.readValue('GVL_Read.StandardTypes.INT_');
485
- console.log(res.value);
486
- // 32767
487
-
488
- //Example: STRING
489
- res = await client.readValue('GVL_Read.StandardTypes.STRING_');
490
- console.log(res.value);
491
- // A test string ääöö!!@@
492
-
493
- //Example: DT
494
- res = await client.readValue('GVL_Read.StandardTypes.DT_');
495
- console.log(res.value);
496
- // 2106-02-06T06:28:15.000Z (Date object)
497
-
498
- //Example: STRUCT
499
- res = await client.readValue('GVL_Read.ComplexTypes.STRUCT_');
500
- console.log(res.value);
501
- /*
502
- {
503
- BOOL_: true,
504
- BOOL_2: false,
505
- BYTE_: 255,
506
- WORD_: 65535,
507
- //...and so on
508
- }
509
- */
510
-
511
- //Example: FUNCTION_BLOCK
512
- res = await client.readValue('GVL_Read.ComplexTypes.BLOCK_2'); //TON
513
- console.log(res.value);
514
- // { IN: false, PT: 2500, Q: false, ET: 0, M: false, StartTime: 0 }
515
-
516
- //Example: ARRAY
517
- res = await client.readValue('GVL_Read.StandardArrays.REAL_3');
518
- console.log(res.value);
519
- // [ 75483.546875, 0, -75483.546875 ]
520
-
521
- //Example: ENUM
522
- res = await client.readValue('GVL_Read.ComplexTypes.ENUM_');
523
- console.log(res.value);
524
- // { name: 'Running', value: 100 }
525
-
526
- } catch (err) {
527
- console.log("Error:", err);
545
+ const res = await client.readValue('GVL_Read.StandardTypes.INT_');
546
+ console.log(res.value);
547
+ // 32767
548
+ ```
549
+
550
+ **Reading STRING**
551
+
552
+ ```js
553
+ const res = await client.readValue('GVL_Read.StandardTypes.STRING_');
554
+ console.log(res.value);
555
+ // A test string ääöö!!@@
556
+ ```
557
+
558
+ **Reading DT**
559
+
560
+ ```js
561
+ const res = await client.readValue('GVL_Read.StandardTypes.DT_');
562
+ console.log(res.value);
563
+ // 2106-02-06T06:28:15.000Z (Date object)
564
+ ```
565
+
566
+ **Reading STRUCT**
567
+
568
+ ```js
569
+ const res = await client.readValue('GVL_Read.ComplexTypes.STRUCT_');
570
+ console.log(res.value);
571
+ /*
572
+ {
573
+ BOOL_: true,
574
+ BOOL_2: false,
575
+ BYTE_: 255,
576
+ WORD_: 65535,
577
+ //...and so on
528
578
  }
579
+ */
529
580
  ```
530
581
 
531
- **Typescript example**:
582
+ **Reading FUNCTION_BLOCK**
532
583
 
533
- ```ts
534
- let res;
584
+ ```js
585
+ const res = await client.readValue('GVL_Read.ComplexTypes.BLOCK_2'); //TON
586
+ console.log(res.value);
587
+ // { IN: false, PT: 2500, Q: false, ET: 0, M: false, StartTime: 0 }
588
+ ```
589
+
590
+ **Reading ARRAY**
591
+
592
+ ```js
593
+ const res = await client.readValue('GVL_Read.StandardArrays.REAL_3');
594
+ console.log(res.value);
595
+ // [ 75483.546875, 0, -75483.546875 ]
596
+ ```
597
+
598
+ **Reading ENUM**
599
+
600
+ ```js
601
+ const res = await client.readValue('GVL_Read.ComplexTypes.ENUM_');
602
+ console.log(res.value);
603
+ // { name: 'Running', value: 100 }
604
+ ```
605
+
606
+ **Typescript example: Reading INT**
535
607
 
536
- //Example: INT
537
- res = await client.readValue<number>('GVL_Read.StandardTypes.INT_');
608
+ ```ts
609
+ const res = await client.readValue<number>('GVL_Read.StandardTypes.INT_');
538
610
  console.log(res.value); //res.value is typed as number
539
611
  // 32767
612
+ ```
613
+
614
+ **Typescript example: Reading STRUCT**
540
615
 
541
- //Example: STRUCT
616
+ ```ts
542
617
  interface ST_ComplexTypes {
543
618
  BOOL_: boolean,
544
619
  BOOL_2: boolean,
@@ -547,7 +622,7 @@ interface ST_ComplexTypes {
547
622
  //..and so on
548
623
  }
549
624
 
550
- res = await client.readValue<ST_ComplexTypes>('GVL_Read.ComplexTypes.STRUCT_');
625
+ const res = await client.readValue<ST_ComplexTypes>('GVL_Read.ComplexTypes.STRUCT_');
551
626
  console.log(res.value); //res.value is typed as ST_ComplexTypes
552
627
  /*
553
628
  {
@@ -562,382 +637,436 @@ console.log(res.value); //res.value is typed as ST_ComplexTypes
562
637
 
563
638
  ### Reading raw data
564
639
 
565
- Use [`readRaw()`](TODO-DOC-URL-HERE/classes/Client.html#readRaw) to read any PLC value as raw data. Raw data is a `Buffer` object, containing the data as bytes.
640
+ Use [`readRaw()`](https://jisotalo.fi/ads-client/classes/Client.html#readRaw) or [`readRawByPath()`](https://jisotalo.fi/ads-client/classes/Client.html#readRawByPath) to read any PLC value as raw data. The raw data in this context means received bytes (a `Buffer` object).
566
641
 
567
642
  The only exception is the dereferenced value of a reference/pointer, see [Reading reference/pointer](#reading-referencepointer).
568
643
 
569
- The `indexGroup` and `indexOffset` can be acquired for example by using [`getSymbol()`](TODO-DOC-URL-HERE/classes/Client.html#getSymbol).
644
+ For converting the data between raw data and Javascript object, see [Converting data between raw data and Javascript objects](#converting-data-between-raw-data-and-javascript-objects).
570
645
 
571
- ```js
572
- try {
573
- //Example: Reading raw data by index offset and index group
574
- //and converting it to a Javascript object manually
575
- const data = await client.readRaw(16448, 414816, 2);
576
- console.log(data); //<Buffer ff 7f>
646
+ **readRaw()**
577
647
 
578
- const converted = await client.convertFromRaw(data, 'INT');
579
- console.log(converted); //32767
648
+ The `indexGroup` and `indexOffset` can be acquired by using [`getSymbol()`](https://jisotalo.fi/ads-client/classes/Client.html#getSymbol).
580
649
 
581
- } catch (err) {
582
- console.log("Error:", err);
583
- }
650
+
651
+ ```js
652
+ //Read 2 bytes from indexGroup 16448 and indexOffset 414816
653
+ const data = await client.readRaw(16448, 414816, 2);
654
+ console.log(data); //<Buffer ff 7f>
584
655
  ```
585
656
 
586
- [`readRawByPath()`](TODO-DOC-URL-HERE/classes/Client.html#readRawByPath) can be used to read raw data by a variable path.
657
+ **readRawByPath()**
587
658
 
588
659
  ```js
589
- try {
590
- //Example: Reading raw data by variable path
591
- //and converting it to a Javascript object manually
592
- const data = await client.readRawByPath('GVL_Read.StandardTypes.INT_');
593
- console.log(data); //<Buffer ff 7f>
660
+ const data = await client.readRawByPath('GVL_Read.StandardTypes.INT_');
661
+ console.log(data); //<Buffer ff 7f>
662
+ ```
663
+
664
+
665
+ ### Reading reference/pointer
594
666
 
595
- const converted = await client.convertFromRaw(data, 'INT');
596
- console.log(converted); //32767
667
+ The dereferenced value of a reference (`REFERENCE TO`) or a pointer (`POINTER TO`) can be read with [`readRawByPath()`](https://jisotalo.fi/ads-client/classes/Client.html#readRawByPath) or by using [variable handles](https://jisotalo.fi/ads-client/classes/Client.html#createVariableHandle).
597
668
 
598
- } catch (err) {
599
- console.log("Error:", err);
669
+ **Reading POINTER (readRawByPath())**
670
+
671
+ ```js
672
+ //Reading a raw POINTER value (Note the dereference operator ^)
673
+ const value = await client.readRawByPath('GVL_Read.ComplexTypes.POINTER_^');
674
+
675
+ //Converting to a Javascript object
676
+ const value = await client.convertFromRaw(rawValue, 'ST_StandardTypes');
677
+ console.log(value);
678
+ /*
679
+ {
680
+ BOOL_: true,
681
+ BOOL_2: false,
682
+ BYTE_: 255,
683
+ WORD_: 65535,
684
+ //..and so on
600
685
  }
686
+ */
601
687
  ```
602
688
 
603
- ### Reading reference/pointer
604
-
605
- The dereferenced value of a reference (`REFERENCE TO`) or a pointer (`POINTER TO`) can be read
606
- using [`readRawByPath()`](TODO-DOC-URL-HERE/classes/Client.html#readRawByPath).
689
+ **Reading REFERENCE (readRawByPath())**
607
690
 
608
691
  ```js
609
- try {
610
- //Reading a raw POINTER value (Note the dereference operator ^)
611
- const rawPtrValue = await client.readRawByPath('GVL_Read.ComplexTypes.POINTER_^');
692
+ //Reading a raw REFERENCE value
693
+ const rawValue = await client.readRawByPath('GVL_Read.ComplexTypes.REFERENCE_');
612
694
 
613
- //Converting to a Javascript object
614
- const ptrValue = await client.convertFromRaw(rawPtrValue, 'ST_StandardTypes');
615
- console.log(ptrValue);
695
+ //Converting to a Javascript object
696
+ const value = await client.convertFromRaw(rawValue, 'ST_StandardTypes');
697
+ console.log(value);
698
+ /*
699
+ {
700
+ BOOL_: true,
701
+ BOOL_2: false,
702
+ BYTE_: 255,
703
+ WORD_: 65535,
704
+ //..and so on
705
+ }
706
+ */
707
+ ```
616
708
 
617
- //Reading a raw REFERENCE value
618
- const rawRefValue = await client.readRawByPath('GVL_Read.ComplexTypes.REFERENCE_');
619
-
620
- //Converting to a Javascript object
621
- const refValue = await client.convertFromRaw(rawRefValue, 'ST_StandardTypes');
622
- console.log(refValue);
623
-
624
- //Short version:
625
- const refValue2 = await client.convertFromRaw(
626
- await client.readRawByPath('GVL_Read.ComplexTypes.REFERENCE_'),
627
- 'ST_StandardTypes'
628
- );
629
-
630
- } catch (err) {
631
- console.log("Error:", err);
709
+ **Reading POINTER (variable handle)**
710
+
711
+ ```js
712
+ //Reading a POINTER value (Note the dereference operator ^)
713
+ const handle = await client.createVariableHandle('GVL_Read.ComplexTypes.POINTER_^');
714
+ const rawValue = await client.readRawByHandle(handle);
715
+ await client.deleteVariableHandle(handle);
716
+
717
+ //Converting to a Javascript object
718
+ const value = await client.convertFromRaw(rawValue, 'ST_StandardTypes');
719
+ console.log(value);
720
+ /*
721
+ {
722
+ BOOL_: true,
723
+ BOOL_2: false,
724
+ BYTE_: 255,
725
+ WORD_: 65535,
726
+ //..and so on
632
727
  }
728
+ */
633
729
  ```
634
730
 
635
- Another way is to use [variable handles](TODO-DOC-URL-HERE/classes/Client.html#createVariableHandle).
731
+ **Reading REFERENCE (variable handle)**
636
732
 
637
733
  ```js
638
- try {
639
- //Reading a POINTER value (Note the dereference operator ^)
640
- const ptrHandle = await client.createVariableHandle('GVL_Read.ComplexTypes.POINTER_^');
641
- const rawPtrValue = await client.readRawByHandle(ptrHandle);
642
- await client.deleteVariableHandle(ptrHandle);
643
-
644
- //Converting to a Javascript object
645
- const ptrValue = await client.convertFromRaw(rawPtrValue, 'ST_StandardTypes');
646
- console.log(ptrValue);
647
-
648
- //Reading a REFERENCE value
649
- const refHandle = await client.createVariableHandle('GVL_Read.ComplexTypes.REFERENCE_');
650
- const rawRefValue = await client.readRawByHandle(refHandle);
651
- await client.deleteVariableHandle(refHandle);
652
-
653
- //Converting to a Javascript object
654
- const refValue = await client.convertFromRaw(rawRefValue, 'ST_StandardTypes');
655
- console.log(refValue);
656
-
657
- } catch (err) {
658
- console.log("Error:", err);
734
+ //Reading a REFERENCE value
735
+ const handle = await client.createVariableHandle('GVL_Read.ComplexTypes.REFERENCE_');
736
+ const rawValue = await client.readRawByHandle(handle);
737
+ await client.deleteVariableHandle(handle);
738
+
739
+ //Converting to a Javascript object
740
+ const value = await client.convertFromRaw(rawValue, 'ST_StandardTypes');
741
+ console.log(value);
742
+ /*
743
+ {
744
+ BOOL_: true,
745
+ BOOL_2: false,
746
+ BYTE_: 255,
747
+ WORD_: 65535,
748
+ //..and so on
659
749
  }
750
+ */
660
751
  ```
661
752
 
662
753
  ## Writing values
663
754
 
664
755
  ### Writing any value
665
756
 
666
- Use [`writeValue()`](TODO-DOC-URL-HERE/classes/Client.html#writeValue) to write any PLC value.
757
+ Use [`writeValue()`](https://jisotalo.fi/ads-client/classes/Client.html#writeValue) to write any PLC value.
667
758
 
668
759
  The only exception is the dereferenced value of a reference/pointer, see [Writing reference/pointer](#writing-referencepointer).
669
760
 
761
+ **Writing INT**
762
+
670
763
  ```js
671
- try {
672
- //Example: INT
673
- await client.writeValue('GVL_Write.StandardTypes.INT_', 32767);
764
+ const res = await client.writeValue('GVL_Write.StandardTypes.INT_', 32767);
765
+ console.log(res.value);
766
+ // 32767
767
+ ```
674
768
 
675
- //Example: STRING
676
- await client.writeValue('GVL_Write.StandardTypes.STRING_', 'This is a test');
677
-
678
- //Example: DT
679
- await client.writeValue('GVL_Write.StandardTypes.DT_', new Date());
680
-
681
- //Example: STRUCT (all properties)
682
- await client.writeValue('GVL_Write.ComplexTypes.STRUCT_', {
683
- BOOL_: true,
684
- BOOL_2: false,
685
- BYTE_: 255,
686
- WORD_: 65535,
687
- //...and so on
688
- });
769
+ **Writing STRING**
689
770
 
690
- //Example: STRUCT (only some properties)
691
- await client.writeValue('GVL_Write.ComplexTypes.STRUCT_', {
692
- WORD_: 65535
693
- }, true); //<-- NOTE: autoFill set
694
-
695
- //Example: FUNCTION_BLOCK (all properties)
696
- await client.writeValue('GVL_Write.ComplexTypes.BLOCK_2', {
697
- IN: false,
698
- PT: 2500,
699
- Q: false,
700
- ET: 0,
701
- M: false,
702
- StartTime: 0
703
- });
771
+ ```js
772
+ await client.writeValue('GVL_Write.StandardTypes.STRING_', 'This is a test');
773
+ ```
704
774
 
705
- //Example: FUNCTION_BLOCK (only some properties)
706
- await client.writeValue('GVL_Write.ComplexTypes.BLOCK_2', {
707
- IN: true
708
- }, true); //<-- NOTE: autoFill set
709
-
710
- //Example: ARRAY
711
- await client.writeValue('GVL_Write.StandardArrays.REAL_3', [
712
- 75483.546875,
713
- 0,
714
- -75483.546875
715
- ]);
716
-
717
- //Example: ENUM
718
- res = await client.writeValue('GVL_Write.ComplexTypes.ENUM_', 'Running');
719
- //...or...
720
- res = await client.writeValue('GVL_Write.ComplexTypes.ENUM_', 100);
721
-
722
- } catch (err) {
723
- console.log("Error:", err);
724
- }
775
+ **Writing DT**
776
+
777
+ ```js
778
+ await client.writeValue('GVL_Write.StandardTypes.DT_', new Date());
725
779
  ```
726
780
 
727
- ### Writing raw data
781
+ **Writing STRUCT (all properties)**
728
782
 
729
- Use [`writeRaw()`](TODO-DOC-URL-HERE/classes/Client.html#writeRaw) to write any PLC value using raw data. Raw data is a `Buffer` object, containing the data as bytes.
783
+ ```js
784
+ await client.writeValue('GVL_Write.ComplexTypes.STRUCT_', {
785
+ BOOL_: true,
786
+ BOOL_2: false,
787
+ BYTE_: 255,
788
+ WORD_: 65535,
789
+ //...and so on
790
+ });
791
+ ```
730
792
 
731
- The only exception is the dereferenced value of a reference/pointer, see [Reading reference/pointer](#reading-referencepointer).
793
+ **Writing STRUCT (some properties only)**
732
794
 
733
- The `indexGroup` and `indexOffset` can be acquired for example by using [`getSymbol()`](TODO-DOC-URL-HERE/classes/Client.html#getSymbol).
795
+ All other properties will keep their values. The client reads the active value first and then makes changes.
734
796
 
735
797
  ```js
736
- try {
737
- //Example: Writing a INT variable by index offset and index group using raw data
738
- const data = await client.convertToRaw(32767, 'INT');
739
- console.log(data); //<Buffer ff 7f>
798
+ await client.writeValue('GVL_Write.ComplexTypes.STRUCT_', {
799
+ WORD_: 65535
800
+ }, true); //<-- NOTE: autoFill set
801
+ ```
740
802
 
741
- await client.writeRaw(16448, 414816, data);
803
+ **Writing FUNCTION_BLOCK (all properties)**
742
804
 
743
- } catch (err) {
744
- console.log("Error:", err);
745
- }
805
+ ```js
806
+ const timerBlock = {
807
+ IN: false,
808
+ PT: 2500,
809
+ Q: false,
810
+ ET: 0,
811
+ M: false,
812
+ StartTime: 0
813
+ };
814
+
815
+ await client.writeValue('GVL_Write.ComplexTypes.BLOCK_2', timerBlock);
746
816
  ```
747
817
 
748
- [`writeRawByPath()`](TODO-DOC-URL-HERE/classes/Client.html#writeRawByPath) can be used to write raw data by a variable path.
818
+ **Writing FUNCTION_BLOCK (some properties only)**
819
+
820
+ All other properties will keep their values. The client reads the active value first and then makes changes.
749
821
 
750
822
  ```js
751
- try {
752
- //Example: Writing a INT variable by its variable path using raw data
753
- const data = await client.convertToRaw(32767, 'INT');
754
- console.log(data); //<Buffer ff 7f>
823
+ await client.writeValue('GVL_Write.ComplexTypes.BLOCK_2', {
824
+ IN: true
825
+ }, true); //<-- NOTE: autoFill set
826
+ ```
755
827
 
756
- await client.writeRawByPath('GVL_Write.StandardTypes.INT_', data);
828
+ **Writing ARRAY**
757
829
 
758
- } catch (err) {
759
- console.log("Error:", err);
760
- }
830
+ ```js
831
+ const data = [
832
+ 75483.546875,
833
+ 0,
834
+ -75483.546875
835
+ ];
836
+
837
+ await client.writeValue('GVL_Write.StandardArrays.REAL_3', data);
838
+ ```
839
+
840
+ **Writing ENUM**
841
+
842
+ ```js
843
+ await client.writeValue('GVL_Write.ComplexTypes.ENUM_', 'Running');
844
+ //...or...
845
+ await client.writeValue('GVL_Write.ComplexTypes.ENUM_', 100);
846
+ ```
847
+
848
+ ### Writing raw data
849
+
850
+ Use [`writeRaw()`](https://jisotalo.fi/ads-client/classes/Client.html#writeRaw) or [`writeRawByPath()`](https://jisotalo.fi/ads-client/classes/Client.html#writeRawByPath) to write any PLC value using raw data. The raw data in this context means bytes (a `Buffer` object).
851
+
852
+ The only exception is the dereferenced value of a reference/pointer, see [Reading reference/pointer](#reading-referencepointer).
853
+
854
+ For converting the data between raw data and Javascript object, see [Converting data between raw data and Javascript objects](#converting-data-between-raw-data-and-javascript-objects).
855
+
856
+ **writeRaw()**
857
+ ```js
858
+ //Creating raw data of an INT
859
+ const data = await client.convertToRaw(32767, 'INT');
860
+ console.log(data); //<Buffer ff 7f>
861
+
862
+ //Writing the value to indexGroup 16448 and indexOffset 414816
863
+ await client.writeRaw(16448, 414816, data);
864
+ ```
865
+
866
+ **writeRawByPath()**
867
+
868
+ ```js
869
+ //Creating raw data of an INT
870
+ const data = await client.convertToRaw(32767, 'INT');
871
+ console.log(data); //<Buffer ff 7f>
872
+
873
+ await client.writeRawByPath('GVL_Write.StandardTypes.INT_', data);
761
874
  ```
762
875
 
763
876
  ### Writing reference/pointer
764
877
 
765
878
  The dereferenced value of a reference (`REFERENCE TO`) or a pointer (`POINTER TO`) can be written
766
- using [`writeRawByPath()`](TODO-DOC-URL-HERE/classes/Client.html#writeRawByPath).
879
+ with [`writeRawByPath()`](https://jisotalo.fi/ads-client/classes/Client.html#writeRawByPath) or by using [variable handles](https://jisotalo.fi/ads-client/classes/Client.html#createVariableHandle).
880
+
881
+ **Writing POINTER (writeRawByPath())**
767
882
 
768
883
  ```js
769
- try {
770
- //Writing a POINTER value
771
- const ptrValue = {...} //some value
772
- const rawPtrValue = await client.convertToRaw(ptrValue, 'ST_StandardTypes');
884
+ const value = {
885
+ BOOL_: true,
886
+ BOOL_2: false,
887
+ BYTE_: 255,
888
+ WORD_: 65535,
889
+ //...and so on
890
+ };
891
+ const rawValue = await client.convertToRaw(value, 'ST_StandardTypes');
773
892
 
774
- await client.writeRawByPath('GVL_Write.ComplexTypes.POINTER_^', rawPtrValue);
893
+ //Writing a raw POINTER value (Note the dereference operator ^)
894
+ await client.writeRawByPath('GVL_Write.ComplexTypes.POINTER_^', rawValue);
895
+ ```
775
896
 
776
- //Writing a REFERENCE value
777
- const refValue = {...} //some value
778
- const rawRefValue = await client.convertToRaw(refValue, 'ST_StandardTypes');
779
- await client.writeRawByPath('GVL_Write.ComplexTypes.REFERENCE_', rawRefValue);
897
+ **Writing REFERENCE (writeRawByPath())**
780
898
 
781
- } catch (err) {
782
- console.log("Error:", err);
783
- }
899
+ ```js
900
+ const value = {
901
+ BOOL_: true,
902
+ BOOL_2: false,
903
+ BYTE_: 255,
904
+ WORD_: 65535,
905
+ //...and so on
906
+ };
907
+ const rawValue = await client.convertToRaw(value, 'ST_StandardTypes');
908
+
909
+ //Writing a raw REFERENCE value
910
+ await client.writeRawByPath('GVL_Write.ComplexTypes.REFERENCE_', rawValue);
784
911
  ```
785
912
 
786
- Another way is to use [variable handles](TODO-DOC-URL-HERE/classes/Client.html#createVariableHandle).
913
+ **Writing POINTER (variable handle)**
787
914
 
788
915
  ```js
789
- try {
790
- //Writing a POINTER value (Note the dereference operator ^)
791
- const ptrValue = {...} //some value
792
- const rawPtrValue = await client.convertToRaw(ptrValue, 'ST_StandardTypes');
916
+ const value = {
917
+ BOOL_: true,
918
+ BOOL_2: false,
919
+ BYTE_: 255,
920
+ WORD_: 65535,
921
+ //...and so on
922
+ };
923
+ const rawValue = await client.convertToRaw(value, 'ST_StandardTypes');
793
924
 
794
- const ptrHandle = await client.createVariableHandle('GVL_Write.ComplexTypes.POINTER_^');
795
- await client.writeRawByHandle(ptrHandle, rawPtrValue);
796
- await client.deleteVariableHandle(ptrHandle);
925
+ //Writing a raw POINTER value (Note the dereference operator ^)
926
+ const handle = await client.createVariableHandle('GVL_Write.ComplexTypes.POINTER_^');
927
+ await client.writeRawByHandle(handle, rawValue);
928
+ await client.deleteVariableHandle(handle);
929
+ ```
797
930
 
798
- //Writing a REFERENCE value
799
- const refValue = {...} //some value
800
- const rawRefValue = await client.convertToRaw(refValue, 'ST_StandardTypes');
931
+ **Writing REFERENCE (variable handle)**
801
932
 
802
- const refHandle = await client.createVariableHandle('GVL_Write.ComplexTypes.REFERENCE_');
803
- await client.writeRawByHandle(refHandle, rawRefValue);
804
- await client.deleteVariableHandle(refHandle);
933
+ ```js
934
+ const value = {
935
+ BOOL_: true,
936
+ BOOL_2: false,
937
+ BYTE_: 255,
938
+ WORD_: 65535,
939
+ //...and so on
940
+ };
941
+ const rawValue = await client.convertToRaw(value, 'ST_StandardTypes');
805
942
 
806
- } catch (err) {
807
- console.log("Error:", err);
808
- }
943
+ //Writing a raw REFERENCE value
944
+ const handle = await client.createVariableHandle('GVL_Write.ComplexTypes.POINTER_');
945
+ await client.writeRawByHandle(handle, rawValue);
946
+ await client.deleteVariableHandle(handle);
809
947
  ```
810
948
 
811
949
  ## Subscribing to value changes
812
950
 
813
- In ads-client, subscriptions are used to handle ADS notifications.
951
+ In ads-client, subscriptions are used to handle ADS notifications. ADS notifications are data sent by PLC automatically without request. For example, the latest value of a variable every second.
814
952
 
815
- By subscribing to a variable value changes, the target system (PLC) will send ADS notifications when the value changes (or every x milliseconds). The client then receives these notifications and calls the callback function with the latest value.
953
+ By subscribing to a variable value changes, the target system (PLC) will send ADS notifications when the value changes (or every x milliseconds). The client then receives these notifications and calls the user callback function with the latest value.
816
954
 
817
955
  More information about ADS notifications at [Beckhoff Infosys: Use of ADS Notifications](https://infosys.beckhoff.com/content/1033/tc3_ads.net/9407523595.html?id=431879546285476216).
818
956
 
819
957
  ### Any value
820
958
 
821
- Use [`subscribeValue()`](TODO-DOC-URL-HERE/classes/Client.html#subscribeValue) or [`subscribe()`](TODO-DOC-URL-HERE/classes/Client.html#subscribe) to subscribe to PLC variable value changes.
959
+ Use [`subscribeValue()`](https://jisotalo.fi/ads-client/classes/Client.html#subscribeValue) or [`subscribe()`](https://jisotalo.fi/ads-client/classes/Client.html#subscribe) to subscribe to PLC variable value changes.
960
+
961
+ **Example**
962
+
963
+ Subscribing to changes of `GVL_Subscription.NumericValue_10ms`. The callback is called when the PLC value changes (at maximum every 100 milliseconds).
822
964
 
823
- Example: Subscribe to changes of `GVL_Subscription.NumericValue_10ms`. The callback is called when the PLC value changes (at maximum every 100 milliseconds).
824
965
  ```js
825
- try {
826
- const sub = await client.subscribeValue(
827
- 'GVL_Subscription.NumericValue_10ms',
828
- (data, subscription) => {
829
- console.log(`Value of ${subscription.symbol.name} has changed: ${data.value}`);
830
- },
831
- 100
832
- );
833
-
834
- } catch (err) {
835
- console.log("Error:", err);
966
+ const onValueChanged = (data, subscription) => {
967
+ console.log(`Value of ${subscription.symbol.name} has changed: ${data.value}`);
836
968
  }
969
+
970
+ const subscription = await client.subscribeValue(
971
+ 'GVL_Subscription.NumericValue_10ms',
972
+ onValueChanged,
973
+ 100
974
+ );
837
975
  ```
838
976
 
839
- Example: Subscribe to value of `GVL_Subscription.NumericValue_1000ms`. The callback is called with the latest value every 100 milliseconds (changed or not).
977
+ **Example**
978
+
979
+ Subscribing to value of `GVL_Subscription.NumericValue_1000ms`. The callback is called with the latest value every 100 milliseconds (doesn't matter if the value has changed or not).
840
980
 
841
981
  ```js
842
- try {
843
- const valueChanged = (data, subscription) => {
844
- console.log(`Value of ${subscription.symbol.name}: ${data.value}`);
845
- }
982
+ const onValueReceived = (data, subscription) => {
983
+ console.log(`Value of ${subscription.symbol.name} is: ${data.value}`);
984
+ }
846
985
 
847
- const sub = await client.subscribeValue(
848
- 'GVL_Subscription.NumericValue_1000ms',
849
- valueChanged,
850
- 100,
851
- false
852
- );
986
+ const subscription = await client.subscribeValue(
987
+ 'GVL_Subscription.NumericValue_1000ms',
988
+ onValueReceived,
989
+ 100,
990
+ false
991
+ );
853
992
 
854
- } catch (err) {
855
- console.log("Error:", err);
856
- }
857
993
  ```
858
994
 
859
- Example: Same as previous example but using [`subscribe()`](TODO-DOC-URL-HERE/classes/Client.html#subscribe) and Typescript type for the variable value. A type can be provided for `subscribeValue<T>()` as well.
995
+ **Typescript example**
860
996
 
861
- ```js
862
- //NOTE: Typescript
863
- try {
864
- const valueChanged = (data, subscription) => {
865
- //data.value is typed as "number" instead of "any" (see subscribe() call below)
866
- console.log(`Value of ${subscription.symbol.name}: ${data.value}`);
867
- }
868
-
869
- const sub = await client.subscribe<number>({
870
- target: 'GVL_Subscription.NumericValue_1000ms',
871
- callback: valueChanged,
872
- cycleTime: 100,
873
- sendOnChange: false
874
- });
997
+ Same as previous example, but with [`subscribe()`](https://jisotalo.fi/ads-client/classes/Client.html#subscribe) instead. A type can be provided for `subscribeValue<T>()` as well.
875
998
 
876
- } catch (err) {
877
- console.log("Error:", err);
878
- }
999
+ ```js
1000
+ const subscription = await client.subscribe<number>({
1001
+ target: 'GVL_Subscription.NumericValue_1000ms',
1002
+ callback: (data, subscription) => {
1003
+ //data.value is typed as "number" instead of "any"
1004
+ console.log(`Value of ${subscription.symbol.name} is: ${data.value}`);
1005
+ },
1006
+ cycleTime: 100,
1007
+ sendOnChange: false
1008
+ });
879
1009
  ```
880
1010
 
881
1011
  ### Raw data
882
1012
 
883
- Use [`subscribeRaw()`](TODO-DOC-URL-HERE/classes/Client.html#subscribeRaw) or [`subscribe()`](TODO-DOC-URL-HERE/classes/Client.html#subscribe) to subscribe to raw value changes.
1013
+ Use [`subscribeRaw()`](https://jisotalo.fi/ads-client/classes/Client.html#subscribeRaw) or [`subscribe()`](https://jisotalo.fi/ads-client/classes/Client.html#subscribe) to subscribe to raw value changes.
1014
+
1015
+ The `indexGroup` and `indexOffset` can be acquired by using [`getSymbol()`](https://jisotalo.fi/ads-client/classes/Client.html#getSymbol).
884
1016
 
885
- The `indexGroup` and `indexOffset` can be acquired for example by using [`getSymbol()`](TODO-DOC-URL-HERE/classes/Client.html#getSymbol).
1017
+ **Example**
886
1018
 
887
- Example: Subscribe to raw address of `indexGroup` = 16448, `indexOffset` = 414816 and `size` = 2 bytes.
1019
+ Subscribing to raw address of `indexGroup` = 16448 and `indexOffset` = 414816 (2 bytes).
888
1020
 
889
1021
  ```js
890
- try {
891
- await client.subscribeRaw(16448, 414816, 2, (data, subscription) => {
892
- console.log(`Value has changed: ${data.value.toString('hex')}`);
893
- }, 100);
894
-
895
- } catch (err) {
896
- console.log("Error:", err);
897
- }
1022
+ await client.subscribeRaw(16448, 414816, 2, (data, subscription) => {
1023
+ console.log(`Value has changed: ${data.value.toString('hex')}`);
1024
+ }, 100);
898
1025
  ```
899
1026
 
900
- Same using [`subscribe()`](TODO-DOC-URL-HERE/classes/Client.html#subscribe):
901
- ```js
902
- try {
903
- await client.subscribe({
904
- target: {
905
- indexGroup: 16448,
906
- indexOffset: 414816,
907
- size: 2
908
- },
909
- callback: (data, subscription) => {
910
- console.log(`Value has changed: ${data.value.toString('hex')}`);
911
- },
912
- cycleTime: 100
913
- });
1027
+ **Example**
1028
+
1029
+ Same as previous example, but with [`subscribe()`](https://jisotalo.fi/ads-client/classes/Client.html#subscribe) instead.
914
1030
 
915
- } catch (err) {
916
- console.log("Error:", err);
1031
+ ```js
1032
+ const onValueChanged = (data, subscription) => {
1033
+ console.log(`Value has changed: ${data.value.toString('hex')}`);
917
1034
  }
1035
+
1036
+ await client.subscribe({
1037
+ target: {
1038
+ indexGroup: 16448,
1039
+ indexOffset: 414816,
1040
+ size: 2
1041
+ },
1042
+ callback: onValueChanged,
1043
+ cycleTime: 100
1044
+ });
918
1045
  ```
919
1046
 
920
1047
  ### Unsubscribing
921
1048
 
922
- Subscriptions should always be cancelled when no longer needed (to save PLC resources). Use [`unsubscribe()`](TODO-DOC-URL-HERE/classes/Client.html#unsubscribe) or subscription object's [`ActiveSubscription.unsubscribe()`](TODO-DOC-URL-HERE/interfaces/ActiveSubscription.html#unsubscribe) to unsubscribe.
1049
+ Subscriptions should always be cancelled when no longer needed (to save PLC resources).
1050
+
1051
+ To unsubscribe, use [`unsubscribe()`](https://jisotalo.fi/ads-client/classes/Client.html#unsubscribe) or subscription object's [`ActiveSubscription.unsubscribe()`](https://jisotalo.fi/ads-client/interfaces/ActiveSubscription.html#unsubscribe).
923
1052
 
924
1053
  ```js
925
- const sub = await client.subscribeValue(...);
1054
+ const subscription = await client.subscribeValue(...);
926
1055
 
927
1056
  //Later when no longer needed
928
- await sub.unsubscribe();
929
- //or await client.unsubscribe(sub);
1057
+ await subscription.unsubscribe();
1058
+
1059
+ //Or alternatively
1060
+ await client.unsubscribe(subscription);
930
1061
  ```
931
1062
 
932
1063
  ## Using variable handles
933
1064
 
934
- Variable handles are another alternative to read and write raw data.
1065
+ Using variable handles is an another way to read and write raw data.
935
1066
 
936
- A handle is created to a specific PLC variable and after that, read and write operations are available.
937
- There is no need to use `indexGroup` or `indexOffset`.
1067
+ First, a handle is created to a specific PLC variable by the variable path. After that, read and write operations are available.
938
1068
 
939
1069
  Handles should always be deleted after no longer needed, as the PLC has limited number of handles.
940
- However, it's a perfectly valid practice to keep the handles open as long as needed.
941
1070
 
942
1071
  Handles can also be used to read/write reference and pointer values, see [Reading reference/pointer](#reading-referencepointer).
943
1072
 
@@ -978,49 +1107,277 @@ await client.deleteVariableHandle(handle);
978
1107
 
979
1108
  ## Calling function block RPC methods
980
1109
 
981
- If a function block method has pragma `{attribute 'TcRpcEnable'}`, the method can be called from ads-client.
1110
+ If a function block method has pragma `{attribute 'TcRpcEnable'}`,
1111
+ the method can be called from ads-client.
982
1112
 
983
1113
  Read more at [Beckhoff Infosys: Attribute 'TcRpcEnable'](https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_plc_intro/7145472907.html).
984
1114
 
985
1115
  ### Things to note when using RPC Methods
986
1116
 
1117
+ These are my own observations.
1118
+
987
1119
  - Do not use online change if you change RPC method parameters or return data types
988
1120
  - Make sure that parameters and return value have no pack-mode pragmas defined, otherwise data might be corrupted
989
1121
  - Do not use `ARRAY` values directly in parameters or return value, encapsulate arrays inside struct and use the struct instead
990
- - The feature isn't well documented by Bechkhoff, so there might be some things that aren't taken into account
1122
+ - The feature isn't well documented by Beckhoff, so there might be some things that aren't taken into account
1123
+
1124
+ ### About examples
1125
+
1126
+ These examples use `FB_RPC` from the test PLC project at [https://github.com/jisotalo/ads-client-test-plc-project](https://github.com/jisotalo/ads-client-test-plc-project).
1127
+
1128
+ ![](https://raw.githubusercontent.com/jisotalo/ads-client/refs/heads/v2-dev/img/fb_rpc.png)
1129
+
1130
+ There is an instance of the function block at `GVL_RPC.RpcBlock`.
1131
+
1132
+ ### RPC method with standard data types
1133
+
1134
+ The `Calculator()` method calculates sum, product and division of the input values. The method returns `true`, if all calculations were successful.
1135
+ ```
1136
+ {attribute 'TcRpcEnable'}
1137
+ METHOD Calculator : BOOL
1138
+ VAR_INPUT
1139
+ Value1 : REAL;
1140
+ Value2 : REAL;
1141
+ END_VAR
1142
+ VAR_OUTPUT
1143
+ Sum : REAL;
1144
+ Product : REAL;
1145
+ Division : REAL;
1146
+ END_VAR
1147
+
1148
+ //--- Code starts ---
1149
+
1150
+ //Return TRUE if all success
1151
+ Calculator := TRUE;
1152
+
1153
+ Sum := Value1 + Value2;
1154
+ Product := Value1 * Value2;
1155
+
1156
+ IF Value2 <> 0 THEN
1157
+ Division := Value1 / Value2;
1158
+ ELSE
1159
+ Division := 0;
1160
+ Calculator := FALSE;
1161
+ END_IF
1162
+ ```
1163
+
1164
+ Example call:
1165
+
1166
+ ```js
1167
+ const res = await client.invokeRpcMethod('GVL_RPC.RpcBlock', 'Calculator', {
1168
+ Value1: 1,
1169
+ Value2: 123
1170
+ });
1171
+
1172
+ console.log(res);
1173
+ /*
1174
+ {
1175
+ returnValue: true,
1176
+ outputs: {
1177
+ Sum: 124,
1178
+ Product: 123,
1179
+ Division: 0.008130080997943878
1180
+ }
1181
+ }
1182
+ */
1183
+ ```
1184
+
1185
+ ### RPC method with struct
1186
+
1187
+ The `Structs()` method takes a struct value as input, changes its values and then returns the result.
1188
+
1189
+ ```
1190
+ {attribute 'TcRpcEnable'}
1191
+ METHOD Structs : ST_Struct
1192
+ VAR_INPUT
1193
+ Input : ST_Struct;
1194
+ END_VAR
991
1195
 
992
- ### Simple RPC method example
1196
+ //--- Code starts ---
993
1197
 
994
- ### RPC methods with structs
1198
+ Structs.SomeText := CONCAT('Response: ', Input.SomeText);
1199
+ Structs.SomeReal := Input.SomeReal * 10.0;
1200
+ Structs.SomeDate := Input.SomeDate + T#24H;
1201
+ ```
1202
+
1203
+ Example call:
1204
+
1205
+ ```js
1206
+ const res = await client.invokeRpcMethod('GVL_RPC.RpcBlock', 'Structs', {
1207
+ Input: {
1208
+ SomeText: 'Hello ads-client',
1209
+ SomeReal: 3.14,
1210
+ SomeDate: new Date('2024-12-24T00:00:00.000Z')
1211
+ }
1212
+ });
1213
+
1214
+ console.log(res);
1215
+ /*
1216
+ {
1217
+ returnValue: {
1218
+ SomeText: 'Response: Hello ads-client',
1219
+ SomeReal: 31.4,
1220
+ SomeDate: 2024-12-24T01:00:00.000Z
1221
+ },
1222
+ outputs: {}
1223
+ }
1224
+ */
1225
+ ```
1226
+
1227
+ ## Converting data between raw data and Javascript objects
1228
+
1229
+ The raw data in this context means sent or received bytes (a `Buffer` object).
1230
+
1231
+ When using methods such as [`readValue()`](https://jisotalo.fi/ads-client/classes/Client.html#readValue), [`writeValue()`](https://jisotalo.fi/ads-client/classes/Client.html#writeValue) and [`subscribeValue()`](https://jisotalo.fi/ads-client/classes/Client.html#subscribeValue),
1232
+ the client converts data automatically. The conversion can be done manually as well, by using [`convertFromRaw()`](https://jisotalo.fi/ads-client/classes/Client.html#convertFromRaw) and [`convertToRaw()`](https://jisotalo.fi/ads-client/classes/Client.html#convertToRaw).
1233
+
1234
+ See my other library [iec-61131-3](https://github.com/jisotalo/iec-61131-3) for other possibilities to convert data between Javascript and IEC 61131-3 types.
1235
+
1236
+ ### Converting a raw value to a Javascript object
1237
+
1238
+ Use [`convertFromRaw()`](https://jisotalo.fi/ads-client/classes/Client.html#convertFromRaw) to convert raw data to Javascript object.
1239
+
1240
+ **Converting INT**
1241
+
1242
+ ```js
1243
+ const data = await client.readRaw(16448, 414816, 2);
1244
+ console.log(data); //<Buffer ff 7f>
995
1245
 
996
- ## Converting from/to raw data
1246
+ const converted = await client.convertFromRaw(data, 'INT');
1247
+ console.log(converted); //32767
1248
+ ```
997
1249
 
998
- README in progress.
1250
+ **Converting STRUCT**
1251
+
1252
+ ```js
1253
+ const converted = await client.convertFromRaw(data, 'ST_StandardTypes');
1254
+ console.log(converted);
1255
+ /*
1256
+ {
1257
+ BOOL_: true,
1258
+ BOOL_2: false,
1259
+ BYTE_: 255,
1260
+ WORD_: 65535,
1261
+ //..and so on
1262
+ }
1263
+ */
1264
+ ```
1265
+
1266
+
1267
+ ### Converting a Javascript object to a raw value
1268
+
1269
+ Use [`convertToRaw()`](https://jisotalo.fi/ads-client/classes/Client.html#convertToRaw) to convert Javascript object to raw data.
1270
+
1271
+ **Converting INT**
1272
+
1273
+ ```js
1274
+ const data = await client.convertToRaw(12345, 'INT');
1275
+ console.log(data); //<Buffer 39 30>
1276
+ ```
1277
+
1278
+ **Converting STRUCT**
1279
+
1280
+ ```js
1281
+ const value = {
1282
+ BOOL_: true,
1283
+ BOOL_2: false,
1284
+ BYTE_: 255,
1285
+ WORD_: 65535,
1286
+ //...and so on
1287
+ };
1288
+
1289
+ const data = await client.convertToRaw(value, 'ST_StandardTypes');
1290
+ console.log(data); //<Buffer ...>
1291
+ ```
1292
+
1293
+ **Converting STRUCT (some properties only)**
1294
+
1295
+ All other (missing) properties are set to default values (zero / empty string).
1296
+ ```js
1297
+ const value = {
1298
+ WORD_: 65535
1299
+ };
1300
+
1301
+ const data = await client.convertToRaw(value, 'ST_StandardTypes', true); //<-- NOTE: autoFill set
1302
+ console.log(data); //<Buffer ...>
1303
+ ```
999
1304
 
1000
1305
  ## Other features
1001
1306
 
1002
- README in progress.
1307
+ ### ADS sum commands
1308
+
1309
+ ADS sum commands can be used to have multiple ADS commands in one request. This can be useful for efficiency reasons.
1310
+
1311
+ See [Beckhoff Information System](https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_adsdll2/9007199379576075.html&id=9180083787138954512) for more info.
1312
+
1313
+ - [`createVariableHandleMulti()`](https://jisotalo.fi/ads-client/classes/Client.html#createVariableHandleMulti)
1314
+ - [`deleteVariableHandleMulti()`](https://jisotalo.fi/ads-client/classes/Client.html#deleteVariableHandleMulti)
1315
+ - [`readRawMulti()`](https://jisotalo.fi/ads-client/classes/Client.html#readRawMulti)
1316
+ - [`writeRawMulti()`](https://jisotalo.fi/ads-client/classes/Client.html#writeRawMulti)
1317
+ - [`readWriteRawMulti()`](https://jisotalo.fi/ads-client/classes/Client.html#readWriteRawMulti)
1318
+
1319
+ ### Starting and stopping a PLC
1320
+
1321
+ - [`startPlc()`](https://jisotalo.fi/ads-client/classes/Client.html#startPlc)
1322
+ - [`stopPlc()`](https://jisotalo.fi/ads-client/classes/Client.html#stopPlc)
1323
+ - [`resetPlc()`](https://jisotalo.fi/ads-client/classes/Client.html#resetPlc)
1324
+ - [`restartPlc()`](https://jisotalo.fi/ads-client/classes/Client.html#restartPlc)
1325
+
1326
+ ### Starting and stopping TwinCAT system
1327
+
1328
+ - [`setTcSystemToConfig()`](https://jisotalo.fi/ads-client/classes/Client.html#setTcSystemToConfig)
1329
+ - [`setTcSystemToRun()`](https://jisotalo.fi/ads-client/classes/Client.html#setTcSystemToRun)
1330
+ - [`restartTcSystem()`](https://jisotalo.fi/ads-client/classes/Client.html#restartTcSystem)
1331
+
1332
+ ### Client events
1333
+
1334
+ See [`AdsClientEvents`](https://jisotalo.fi/ads-client/interfaces/AdsClientEvents.html) for all available events, their descriptions and examples.
1335
+
1336
+ ```js
1337
+ client.on('connect', (connection) => {
1338
+ console.log('Connected:', connection);
1339
+ });
1340
+ ```
1341
+
1342
+ ### Debugging
1343
+
1344
+ Use [`setDebugLevel()`](https://jisotalo.fi/ads-client/classes/Client.html#setDebugLevel) to change debug level.
1345
+
1346
+ ```js
1347
+ client.setDebugLevel(1);
1348
+ ```
1349
+
1350
+ - 0: no debugging (default)
1351
+ - 1: basic debugging (`$env:DEBUG='ads-client'`)
1352
+ - 2: detailed debugging (`$env:DEBUG='ads-client,ads-client:details'`)
1353
+ - 3: detailed debugging with raw I/O data (`$env:DEBUG='ads-client,ads-client:details,ads-client:raw-data'`)
1354
+
1355
+ Debug data is available in the console (See [Debug](https://www.npmjs.com/package/debug) library for more).
1356
+
1003
1357
 
1004
1358
  ## Disconnecting
1005
1359
 
1006
- After the client is no more used, always use [`disconnect()`](TODO-DOC-URL-HERE/classes/Client.html#disconnect) to release all subscription handles and other resources.
1360
+ After the client is no more used, always use [`disconnect()`](https://jisotalo.fi/ads-client/classes/Client.html#disconnect) to release all subscription handles and other resources.
1007
1361
 
1008
1362
  ```js
1009
1363
  await client.disconnect();
1010
1364
  ```
1011
1365
 
1012
- ## FAQ
1366
+ ## Common issues and questions
1013
1367
 
1014
- ### Lot's of connection issues and timeouts
1368
+ ### There are lot's of connection issues and timeouts
1015
1369
  Things to try:
1016
1370
  - Remove all TwinCAT routes and create them again (yes, really)
1017
- - Increase value of [`timeoutDelay`](TODO-DOC-URL-HERE/interfaces/AdsClientSettings.html#timeoutDelay) setting
1018
- - Cache all data types and symbols straight after connecting using [`cacheDataTypes`](TODO-DOC-URL-HERE/classes/Client.html#cacheDataTypes) and [`cacheSymbols`](TODO-DOC-URL-HERE/classes/Client.html#cacheSymbols)
1371
+ - Increase value of [`timeoutDelay`](https://jisotalo.fi/ads-client/interfaces/AdsClientSettings.html#timeoutDelay) setting
1372
+ - Cache all data types and symbols straight after connecting using [`cacheDataTypes`](https://jisotalo.fi/ads-client/classes/Client.html#cacheDataTypes) and [`cacheSymbols`](https://jisotalo.fi/ads-client/classes/Client.html#cacheSymbols)
1019
1373
 
1020
1374
  ### Getting `TypeError: Do not know how to serialize a BigInt`
1021
1375
  - `JSON.stringify` doesn't understand BigInt values (such as `LINT` or similar 64 bit PLC values)
1022
- - Check [this Github issue](https://github.com/GoogleChromeLabs/jsbi/issues/30#issuecomment-953187833) for a patch
1023
- - `BigInt.prototype.toJSON = function() { return this.toString() }`
1376
+ - Check [this Github issue](https://github.com/GoogleChromeLabs/jsbi/issues/30#issuecomment-953187833) for the following patch:
1377
+
1378
+ ```js
1379
+ BigInt.prototype.toJSON = function() { return this.toString() }
1380
+ ```
1024
1381
 
1025
1382
  ### Can I connect from Raspberry Pi to TwinCAT?
1026
1383
 
@@ -1033,6 +1390,7 @@ Yes, for example using [Setup 3 - Connect from any Node.js system](#setup-3---co
1033
1390
 
1034
1391
  - Make sure you have updated the latest PLC software using *download*. Sometimes online change causes this.
1035
1392
  - If you are using TwinCAT 2, see chapter [Differences when using with TwinCAT 2](#differences-when-using-with-twincat-2)
1393
+ - Double check variable path for typos
1036
1394
 
1037
1395
  ### Having timeouts or 'mailbox is full' errors
1038
1396
 
@@ -1040,11 +1398,12 @@ Yes, for example using [Setup 3 - Connect from any Node.js system](#setup-3---co
1040
1398
  - Other possible reason is that operating system TCP window is full because of large number of requests.
1041
1399
  - Solution:
1042
1400
  - Use structs or arrays to send data in larger packets
1043
- - Try raw/multi commands to decrease data usage
1401
+ - Try raw commands or sum commands to decrease data usage
1044
1402
 
1045
1403
  ### Having problems to connect from OSX or Raspberry Pi to target PLC
1046
1404
 
1047
- - You need to connect to the PLC AMS router instead
1405
+ - The local machine has no AMS router
1406
+ - You need to connect to the PLC's AMS router instead
1048
1407
  - See [this issue comment](https://github.com/jisotalo/ads-client/issues/51#issuecomment-758016428)
1049
1408
 
1050
1409
  ### A data type is not found even when it should be
@@ -1057,9 +1416,9 @@ For example, when copying a variable name from TwinCAT online view using CTRL+C,
1057
1416
  - --> **This causes error!**
1058
1417
  - The real data type name that needs to be used is `ARRAY [0..1,0..1] OF ST_Example` (note no whitespace between array dimensions)
1059
1418
 
1060
- If you have problems, try to read the symbol object using `getSymbol()`. The final solution is to read all data types using `getDataTypes()` and manually finding the correct type.
1419
+ If you have problems, try to read the symbol object using `getSymbol()`. The final solution is to read all data types using `getDataTypes()` and manually locate the correct type.
1061
1420
 
1062
- ### ClientException: Connection failed: Device system manager state read failed
1421
+ ### Connection failed - failed to set PLC connection
1063
1422
 
1064
1423
  - The `targetAmsNetId` didn't contain a system manager service (port `10000`)
1065
1424
  - The target is not a PLC and `rawClient` setting is not set
@@ -1077,7 +1436,7 @@ See also https://github.com/jisotalo/ads-client/issues/82
1077
1436
 
1078
1437
  - EADDRNOTAVAIL: See above and https://github.com/jisotalo/ads-client/issues/82
1079
1438
 
1080
- ### How to connect to PLC that is in CONFIG mode?
1439
+ ### How to connect to a PLC that is in CONFIG mode?
1081
1440
  As default, the ads-client checks if the target has PLC runtime at given port. However, when target system manager is at config mode, there is none. The client will throw an error during connecting:
1082
1441
 
1083
1442
  `Connection failed - failed to set PLC connection. If target is not PLC runtime, use setting "rawClient". If system is in config mode or there is no PLC software yet, you might want to use setting "allowHalfOpen"`
@@ -1094,7 +1453,13 @@ Another option is to use setting `rawClient: true` - see [Connecting to targets
1094
1453
 
1095
1454
  ## External links
1096
1455
 
1097
- README in progress.
1456
+ | Description | Link |
1457
+ | -------------------------------------------- | ------------------------------------------------------- |
1458
+ | ADS client for Node-RED | https://github.com/jisotalo/node-red-contrib-ads-client |
1459
+ | ADS server for Node.js | https://github.com/jisotalo/ads-server |
1460
+ | IEC 61131-3 PLC data type helper for Node.js | https://github.com/jisotalo/iec-61131-3/ |
1461
+ | Codesys client for Node.js | https://github.com/jisotalo/codesys-client/ |
1462
+
1098
1463
 
1099
1464
  ## Library testing
1100
1465
 
@@ -1110,494 +1475,10 @@ PLC projects for running test suites are located in the following repository:
1110
1475
 
1111
1476
  Tests are run with command `npm run test-tc3`. TwinCAT 3 test PLC projects needs to be running in the target system.
1112
1477
 
1113
- **Results 28.09.2024:**
1114
-
1115
- <details>
1116
- <summary>Click to show test results</summary>
1117
- <pre>
1118
- PASS test/TC3/ads-client.test.js (24.801 s)
1119
- √ IMPORTANT NOTE: This test requires running a specific TwinCAT 3 PLC project (https://github.com/jisotalo/ads-client-test-plc-project) (1 ms)
1120
- connection
1121
- √ client is not connected at beginning (1 ms)
1122
- √ checking ads client settings (1 ms)
1123
- √ connecting to the target (41 ms)
1124
- √ checking that test PLC project is active (13 ms)
1125
- √ checking that test PLC project version is correct (10 ms)
1126
- √ checking 32/64 bitness (4 ms)
1127
- √ caching of symbols and data types
1128
- √ reconnecting (34 ms)
1129
- resetting PLC to original state
1130
- √ resetting PLC (514 ms)
1131
- √ checking that reset was successful (8 ms)
1132
- √ checking that PLC is not running (11 ms)
1133
- √ setting IsReset to false (6 ms)
1134
- √ starting PLC (7 ms)
1135
- √ checking that test PLC project is running (505 ms)
1136
- testing PLC runtime stop, start, restart
1137
- √ stopping PLC (15 ms)
1138
- √ starting PLC (14 ms)
1139
- √ restarting PLC (528 ms)
1140
- system state, PLC runtime states and device information
1141
- √ reading TwinCAT system state (5 ms)
1142
- √ reading PLC runtime (port 851) state (3 ms)
1143
- √ reading PLC runtime (port 852) state (3 ms)
1144
- √ reading PLC runtime device info (3 ms)
1145
- √ reading TwinCAT system device info (5 ms)
1146
- √ reading PLC runtime symbol version (4 ms)
1147
- symbols and data types
1148
- √ reading upload info (4 ms)
1149
- √ reading all symbols (16 ms)
1150
- √ reading single symbol information (1 ms)
1151
- √ reading all data type information (19 ms)
1152
- √ reading single data type information (2 ms)
1153
- data conversion
1154
- √ converting a raw PLC value to a Javascript variable (4 ms)
1155
- √ converting a Javascript value to a raw PLC value (40 ms)
1156
- reading values
1157
- reading standard values
1158
- √ reading BOOL (16 ms)
1159
- √ reading BYTE (8 ms)
1160
- √ reading WORD (9 ms)
1161
- √ reading DWORD (7 ms)
1162
- √ reading SINT (15 ms)
1163
- √ reading USINT (7 ms)
1164
- √ reading INT (14 ms)
1165
- √ reading UINT (7 ms)
1166
- √ reading DINT (13 ms)
1167
- √ reading UDINT (7 ms)
1168
- √ reading REAL (31 ms)
1169
- √ reading STRING (16 ms)
1170
- √ reading DATE (7 ms)
1171
- √ reading DT (14 ms)
1172
- √ reading TOD (16 ms)
1173
- √ reading TIME (8 ms)
1174
- √ reading LWORD (8 ms)
1175
- √ reading LINT (13 ms)
1176
- √ reading ULINT (7 ms)
1177
- √ reading LREAL (31 ms)
1178
- √ reading WSTRING (16 ms)
1179
- √ reading LDATE (---- TODO: Needs TC 3.1.4026 ----)
1180
- √ reading LDT (---- TODO: Needs TC 3.1.4026 ----) (1 ms)
1181
- √ reading LTOD (---- TODO: Needs TC 3.1.4026 ----)
1182
- √ reading LTIME (9 ms)
1183
- reading standard array values
1184
- √ reading ARRAY OF BOOL (14 ms)
1185
- √ reading ARRAY OF BYTE (8 ms)
1186
- √ reading ARRAY OF WORD (9 ms)
1187
- √ reading ARRAY OF DWORD (8 ms)
1188
- √ reading ARRAY OF SINT (13 ms)
1189
- √ reading ARRAY OF USINT (7 ms)
1190
- √ reading ARRAY OF INT (13 ms)
1191
- √ reading ARRAY OF UINT (8 ms)
1192
- √ reading ARRAY OF DINT (16 ms)
1193
- √ reading ARRAY OF UDINT (7 ms)
1194
- √ reading ARRAY OF REAL (31 ms)
1195
- √ reading ARRAY OF STRING (15 ms)
1196
- √ reading ARRAY OF DATE (8 ms)
1197
- √ reading ARRAY OF DT (15 ms)
1198
- √ reading ARRAY OF TOD (14 ms)
1199
- √ reading ARRAY OF TIME (5 ms)
1200
- √ reading ARRAY OF LWORD (8 ms)
1201
- √ reading ARRAY OF LINT (16 ms)
1202
- √ reading ARRAY OF ULINT (7 ms)
1203
- √ reading ARRAY OF LREAL (26 ms)
1204
- √ reading ARRAY OF WSTRING (13 ms)
1205
- √ reading ARRAY OF LDATE (---- TODO: Needs TC 3.1.4026 ----)
1206
- √ reading ARRAY OF LDT (---- TODO: Needs TC 3.1.4026 ----)
1207
- √ reading ARRAY OF LTOD (---- TODO: Needs TC 3.1.4026 ----)
1208
- √ reading ARRAY OF LTIME (6 ms)
1209
- reading complex values
1210
- √ reading STRUCT (14 ms)
1211
- √ reading ALIAS (7 ms)
1212
- √ reading ENUM (44 ms)
1213
- √ reading POINTER (address) (8 ms)
1214
- √ reading SUBRANGE (8 ms)
1215
- √ reading UNION (22 ms)
1216
- √ reading FUNCTION_BLOCK (28 ms)
1217
- √ reading INTERFACE (8 ms)
1218
- reading complex array values
1219
- √ reading ARRAY OF STRUCT (19 ms)
1220
- √ reading ARRAY OF ALIAS (9 ms)
1221
- √ reading ARRAY OF ENUM (38 ms)
1222
- √ reading ARRAY OF POINTER (address) (6 ms)
1223
- √ reading ARRAY OF SUBRANGE (6 ms)
1224
- √ reading ARRAY OF UNION (8 ms)
1225
- √ reading ARRAY OF FUNCTION_BLOCK (27 ms)
1226
- √ reading ARRAY OF INTERFACE (6 ms)
1227
- reading special types / cases
1228
- √ reading ARRAY with negative index (9 ms)
1229
- √ reading multi-dimensional ARRAY (9 ms)
1230
- √ reading ARRAY OF ARRAY (7 ms)
1231
- √ reading STRUCT with pragma: {attribute 'pack_mode' := '1'} (8 ms)
1232
- √ reading STRUCT with pragma: {attribute 'pack_mode' := '8'} (8 ms)
1233
- √ reading an empty FUNCTION_BLOCK (7 ms)
1234
- √ reading an empty STRUCT (8 ms)
1235
- √ reading an empty ARRAY (9 ms)
1236
- √ reading a single BIT (15 ms)
1237
- √ reading a struct with BIT types (8 ms)
1238
- reading dereferenced POINTER and REFERENCE values
1239
- √ reading POINTER (value) (8 ms)
1240
- √ reading REFERENCE (value) (5 ms)
1241
- reading raw data
1242
- √ reading a raw value (4 ms)
1243
- √ reading a raw value using symbol (3 ms)
1244
- √ reading a raw value using path (4 ms)
1245
- √ reading multiple raw values (multi/sum command) (5 ms)
1246
- reading (misc)
1247
- √ reading a value using symbol (3 ms)
1248
- writing values
1249
- writing standard values
1250
- √ writing BOOL (22 ms)
1251
- √ writing BYTE (12 ms)
1252
- √ writing WORD (12 ms)
1253
- √ writing DWORD (12 ms)
1254
- √ writing SINT (24 ms)
1255
- √ writing USINT (10 ms)
1256
- √ writing INT (23 ms)
1257
- √ writing UINT (11 ms)
1258
- √ writing DINT (25 ms)
1259
- √ writing UDINT (11 ms)
1260
- √ writing REAL (46 ms)
1261
- √ writing STRING (21 ms)
1262
- √ writing DATE (11 ms)
1263
- √ writing DT (22 ms)
1264
- √ writing TOD (22 ms)
1265
- √ writing TIME (11 ms)
1266
- √ writing LWORD (7 ms)
1267
- √ writing LINT (24 ms)
1268
- √ writing ULINT (9 ms)
1269
- √ writing LREAL (44 ms)
1270
- √ writing WSTRING (22 ms)
1271
- √ writing LDATE (---- TODO: Needs TC 3.1.4026 ----)
1272
- √ writing LDT (---- TODO: Needs TC 3.1.4026 ----) (1 ms)
1273
- √ writing LTOD (---- TODO: Needs TC 3.1.4026 ----)
1274
- √ writing LTIME (7 ms)
1275
- writing standard array values
1276
- √ writing ARRAY OF BOOL (24 ms)
1277
- √ writing ARRAY OF BYTE (13 ms)
1278
- √ writing ARRAY OF WORD (12 ms)
1279
- √ writing ARRAY OF DWORD (13 ms)
1280
- √ writing ARRAY OF SINT (22 ms)
1281
- √ writing ARRAY OF USINT (12 ms)
1282
- √ writing ARRAY OF INT (19 ms)
1283
- √ writing ARRAY OF UINT (11 ms)
1284
- √ writing ARRAY OF DINT (22 ms)
1285
- √ writing ARRAY OF UDINT (12 ms)
1286
- √ writing ARRAY OF REAL (44 ms)
1287
- √ writing ARRAY OF STRING (23 ms)
1288
- √ writing ARRAY OF DATE (11 ms)
1289
- √ writing ARRAY OF DT (20 ms)
1290
- √ writing ARRAY OF TOD (22 ms)
1291
- √ writing ARRAY OF TIME (11 ms)
1292
- √ writing ARRAY OF LWORD (12 ms)
1293
- √ writing ARRAY OF LINT (21 ms)
1294
- √ writing ARRAY OF ULINT (12 ms)
1295
- √ writing ARRAY OF LREAL (46 ms)
1296
- √ writing ARRAY OF WSTRING (22 ms)
1297
- √ writing ARRAY OF LDATE (---- TODO: Needs TC 3.1.4026 ----) (1 ms)
1298
- √ writing ARRAY OF LDT (---- TODO: Needs TC 3.1.4026 ----) (1 ms)
1299
- √ writing ARRAY OF LTOD (---- TODO: Needs TC 3.1.4026 ----)
1300
- √ writing ARRAY OF LTIME (10 ms)
1301
- writing complex values
1302
- √ writing STRUCT (26 ms)
1303
- √ writing ALIAS (11 ms)
1304
- √ writing ENUM (49 ms)
1305
- √ writing POINTER (address) (14 ms)
1306
- √ writing SUBRANGE (17 ms)
1307
- √ writing UNION (46 ms)
1308
- √ writing FUNCTION_BLOCK (46 ms)
1309
- √ writing INTERFACE (13 ms)
1310
- writing complex array values
1311
- √ writing ARRAY OF STRUCT (24 ms)
1312
- √ writing ARRAY OF ALIAS (10 ms)
1313
- √ writing ARRAY OF ENUM (57 ms)
1314
- √ writing ARRAY OF POINTER (address) (12 ms)
1315
- √ writing ARRAY OF SUBRANGE (11 ms)
1316
- √ writing ARRAY OF UNION (16 ms)
1317
- √ writing ARRAY OF FUNCTION_BLOCK (48 ms)
1318
- √ writing ARRAY OF INTERFACE (16 ms)
1319
- writing special types / cases
1320
- √ writing ARRAY with negative index (14 ms)
1321
- √ writing multi-dimensional ARRAY (15 ms)
1322
- √ writing ARRAY OF ARRAY (16 ms)
1323
- √ writing STRUCT with pragma: {attribute 'pack_mode' := '1'} (14 ms)
1324
- √ writing STRUCT with pragma: {attribute 'pack_mode' := '8'} (16 ms)
1325
- √ writing an empty FUNCTION_BLOCK (8 ms)
1326
- √ writing an empty STRUCT (7 ms)
1327
- √ writing an empty ARRAY (7 ms)
1328
- √ writing a single BIT (36 ms)
1329
- √ writing a struct with BIT types (11 ms)
1330
- writing dereferenced POINTER and REFERENCE values
1331
- √ writing POINTER (value) (22 ms)
1332
- √ writing REFERENCE (value) (23 ms)
1333
- writing raw data
1334
- √ writing a raw value (6 ms)
1335
- √ writing a raw value using symbol (7 ms)
1336
- √ writing a raw value using path (11 ms)
1337
- √ writing multiple raw values (multi/sum command) (20 ms)
1338
- writing (misc)
1339
- √ writing a value using symbol (8 ms)
1340
- variable handles
1341
- √ creating and deleting a varible handle (14 ms)
1342
- √ reading value using a variable handle (12 ms)
1343
- √ writing value using a variable handle (30 ms)
1344
- √ creating and deleting multiple varible handles (multi/sum command) (9 ms)
1345
- subscriptions (ADS notifications)
1346
- √ subscribing and unsubscribing successfully (2033 ms)
1347
- √ subscribing to a changing value (10 ms) with default cycle time (3023 ms)
1348
- √ subscribing to a changing value (10 ms) with 10 ms cycle time (28 ms)
1349
- √ subscribing to a constant value with maximum delay of 2000 ms (2016 ms)
1350
- √ subscribing to a raw ADS address (222 ms)
1351
- √ subscribing using subscribeValue() (2030 ms)
1352
- √ subscribing to a raw ADS address using subscribeRaw() (219 ms)
1353
- remote procedure calls (RPC methods)
1354
- √ calling a RPC method (13 ms)
1355
- √ calling a RPC method with struct parameters (9 ms)
1356
- √ calling a RPC method without return value and without parameters (11 ms)
1357
- miscellaneous
1358
- √ sending read write ADS command (6 ms)
1359
- √ sending multiple read write ADS commands (multi/sum command) (12 ms)
1360
- issue specific tests
1361
- issue 103 (https://github.com/jisotalo/ads-client/issues/103)
1362
- √ calling unsubscribeAll() multiple times (should not crash to unhandled exception) (50 ms)
1363
- disconnecting
1364
- √ disconnecting client (9 ms)
1365
- controlling TwinCAT system service
1366
- √ connecting (1 ms)
1367
- √ setting TwinCAT system to config (4024 ms)
1368
- √ setting TwinCAT system to run (4018 ms)
1369
- √ disconnecting (2 ms)
1370
- handling unknown/stale ADS notifications
1371
- √ connecting (27 ms)
1372
- √ creating an unknown notification handle by forced disconnecting (1040 ms)
1373
- √ deleting an unknown notification handle automatically (1034 ms)
1374
- √ disconnecting (1 ms)
1375
-
1376
- Test Suites: 1 passed, 1 total
1377
- Tests: 223 passed, 223 total
1378
- Snapshots: 0 total
1379
- Time: 24.889 s, estimated 25 s
1380
- Ran all test suites matching /TC3\\ads-client.test.js/i.
1381
- </pre>
1382
- </details>
1383
-
1384
1478
  ### TwinCAT 2 tests
1385
1479
 
1386
1480
  Tests are run with command `npm run test-tc2`. TwinCAT 2 test PLC projects needs to be running in the target system.
1387
1481
 
1388
- TwinCAT 2 tests only have features that are supported by TC2.
1389
-
1390
- **Results 28.09.2024:**
1391
-
1392
- <details>
1393
- <summary>Click to show test results</summary>
1394
- <pre>
1395
- PASS test/TC2/ads-client.test.js (26.971 s)
1396
- √ IMPORTANT NOTE: This test requires running a specific TwinCAT 2 PLC project (https://github.com/jisotalo/ads-client-test-plc-project)
1397
- connection
1398
- √ client is not connected at beginning
1399
- √ checking ads client settings
1400
- √ connecting to the target (35 ms)
1401
- √ checking that test PLC project is active (58 ms)
1402
- √ checking that test PLC project version is correct (9 ms)
1403
- √ checking 32/64 bitness (2 ms)
1404
- √ caching of symbols and data types (1 ms)
1405
- √ reconnecting (22 ms)
1406
- resetting PLC to original state
1407
- √ resetting PLC (507 ms)
1408
- √ checking that reset was successful (5 ms)
1409
- √ checking that PLC is not running (8 ms)
1410
- √ setting IsReset to false (3 ms)
1411
- √ starting PLC (5 ms)
1412
- √ checking that test PLC project is running (506 ms)
1413
- testing PLC runtime stop, start, restart
1414
- √ stopping PLC (13 ms)
1415
- √ starting PLC (10 ms)
1416
- √ restarting PLC (523 ms)
1417
- system state, PLC runtime states and device information
1418
- √ reading TwinCAT system state (2 ms)
1419
- √ reading PLC runtime (port 801) state (2 ms)
1420
- √ reading PLC runtime device info (2 ms)
1421
- √ reading TwinCAT system device info (2 ms)
1422
- √ reading PLC runtime symbol version (2 ms)
1423
- symbols and data types
1424
- √ reading upload info (2 ms)
1425
- √ reading all symbols (15 ms)
1426
- √ reading single symbol information
1427
- √ reading all data type information (33 ms)
1428
- √ reading single data type information (9 ms)
1429
- data conversion
1430
- √ converting a raw PLC value to a Javascript variable (7 ms)
1431
- √ converting a Javascript value to a raw PLC value (41 ms)
1432
- reading values
1433
- reading standard values
1434
- √ reading BOOL (12 ms)
1435
- √ reading BYTE (6 ms)
1436
- √ reading WORD (6 ms)
1437
- √ reading DWORD (7 ms)
1438
- √ reading SINT (11 ms)
1439
- √ reading USINT (7 ms)
1440
- √ reading INT (11 ms)
1441
- √ reading UINT (7 ms)
1442
- √ reading DINT (13 ms)
1443
- √ reading UDINT (6 ms)
1444
- √ reading REAL (19 ms)
1445
- √ reading STRING (10 ms)
1446
- √ reading DATE (4 ms)
1447
- √ reading DT (9 ms)
1448
- √ reading TOD (8 ms)
1449
- √ reading TIME (6 ms)
1450
- √ reading LREAL (26 ms)
1451
- reading standard array values
1452
- √ reading ARRAY OF BOOL (9 ms)
1453
- √ reading ARRAY OF BYTE (5 ms)
1454
- √ reading ARRAY OF WORD (5 ms)
1455
- √ reading ARRAY OF DWORD (4 ms)
1456
- √ reading ARRAY OF SINT (10 ms)
1457
- √ reading ARRAY OF USINT (6 ms)
1458
- √ reading ARRAY OF INT (9 ms)
1459
- √ reading ARRAY OF UINT (6 ms)
1460
- √ reading ARRAY OF DINT (10 ms)
1461
- √ reading ARRAY OF UDINT (3 ms)
1462
- √ reading ARRAY OF REAL (18 ms)
1463
- √ reading ARRAY OF STRING (9 ms)
1464
- √ reading ARRAY OF DATE (7 ms)
1465
- √ reading ARRAY OF DT (11 ms)
1466
- √ reading ARRAY OF TOD (9 ms)
1467
- √ reading ARRAY OF TIME (4 ms)
1468
- √ reading ARRAY OF LREAL (24 ms)
1469
- reading complex values
1470
- √ reading STRUCT (15 ms)
1471
- √ reading ALIAS (8 ms)
1472
- √ reading ENUM (16 ms)
1473
- √ reading POINTER (address) (6 ms)
1474
- √ reading SUBRANGE (6 ms)
1475
- √ reading FUNCTION_BLOCK (23 ms)
1476
- reading complex array values
1477
- √ reading ARRAY OF STRUCT (12 ms)
1478
- √ reading ARRAY OF ALIAS (6 ms)
1479
- √ reading ARRAY OF ENUM (20 ms)
1480
- √ reading ARRAY OF POINTER (address) (5 ms)
1481
- √ reading ARRAY OF SUBRANGE (3 ms)
1482
- √ reading ARRAY OF FUNCTION_BLOCK (22 ms)
1483
- reading special types / cases
1484
- √ reading ARRAY with negative index (8 ms)
1485
- √ reading multi-dimensional ARRAY (5 ms)
1486
- √ reading ARRAY OF ARRAY (5 ms)
1487
- reading dereferenced POINTER values
1488
- √ reading POINTER (value) (5 ms)
1489
- reading raw data
1490
- √ reading a raw value (3 ms)
1491
- √ reading a raw value using symbol (2 ms)
1492
- √ reading a raw value using path (2 ms)
1493
- √ reading multiple raw values (multi/sum command) (4 ms)
1494
- reading (misc)
1495
- √ reading a value using symbol (3 ms)
1496
- writing values
1497
- writing standard values
1498
- √ writing BOOL (22 ms)
1499
- √ writing BYTE (10 ms)
1500
- √ writing WORD (8 ms)
1501
- √ writing DWORD (10 ms)
1502
- √ writing SINT (18 ms)
1503
- √ writing USINT (6 ms)
1504
- √ writing INT (16 ms)
1505
- √ writing UINT (8 ms)
1506
- √ writing DINT (13 ms)
1507
- √ writing UDINT (7 ms)
1508
- √ writing REAL (30 ms)
1509
- √ writing STRING (14 ms)
1510
- √ writing DATE (6 ms)
1511
- √ writing DT (15 ms)
1512
- √ writing TOD (15 ms)
1513
- √ writing TIME (8 ms)
1514
- √ writing LREAL (28 ms)
1515
- writing standard array values
1516
- √ writing ARRAY OF BOOL (14 ms)
1517
- √ writing ARRAY OF BYTE (7 ms)
1518
- √ writing ARRAY OF WORD (7 ms)
1519
- √ writing ARRAY OF DWORD (9 ms)
1520
- √ writing ARRAY OF SINT (13 ms)
1521
- √ writing ARRAY OF USINT (7 ms)
1522
- √ writing ARRAY OF INT (15 ms)
1523
- √ writing ARRAY OF UINT (7 ms)
1524
- √ writing ARRAY OF DINT (13 ms)
1525
- √ writing ARRAY OF UDINT (9 ms)
1526
- √ writing ARRAY OF REAL (25 ms)
1527
- √ writing ARRAY OF STRING (17 ms)
1528
- √ writing ARRAY OF DATE (7 ms)
1529
- √ writing ARRAY OF DT (18 ms)
1530
- √ writing ARRAY OF TOD (18 ms)
1531
- √ writing ARRAY OF TIME (10 ms)
1532
- √ writing ARRAY OF LREAL (35 ms)
1533
- writing complex values
1534
- √ writing STRUCT (19 ms)
1535
- √ writing ALIAS (10 ms)
1536
- √ writing ENUM (25 ms)
1537
- √ writing POINTER (address) (13 ms)
1538
- √ writing SUBRANGE (12 ms)
1539
- √ writing FUNCTION_BLOCK (39 ms)
1540
- writing complex array values
1541
- √ writing ARRAY OF STRUCT (24 ms)
1542
- √ writing ARRAY OF ALIAS (11 ms)
1543
- √ writing ARRAY OF ENUM (28 ms)
1544
- √ writing ARRAY OF POINTER (address) (14 ms)
1545
- √ writing ARRAY OF SUBRANGE (11 ms)
1546
- √ writing ARRAY OF FUNCTION_BLOCK (48 ms)
1547
- writing special types / cases
1548
- √ writing ARRAY with negative index (18 ms)
1549
- √ writing multi-dimensional ARRAY (13 ms)
1550
- √ writing ARRAY OF ARRAY (12 ms)
1551
- √ writing an empty FUNCTION_BLOCK (7 ms)
1552
- writing dereferenced POINTER and REFERENCE values
1553
- √ writing POINTER (value) (15 ms)
1554
- writing raw data
1555
- √ writing a raw value (7 ms)
1556
- √ writing a raw value using symbol (4 ms)
1557
- √ writing a raw value using path (10 ms)
1558
- √ writing multiple raw values (multi/sum command) (11 ms)
1559
- writing (misc)
1560
- √ writing a value using symbol (5 ms)
1561
- variable handles
1562
- √ creating and deleting a varible handle (12 ms)
1563
- √ reading value using a variable handle (6 ms)
1564
- √ writing value using a variable handle (19 ms)
1565
- √ creating and deleting multiple varible handles (multi/sum command) (5 ms)
1566
- subscriptions (ADS notifications)
1567
- √ subscribing and unsubscribing successfully (2010 ms)
1568
- √ subscribing to a changing value (10 ms) with default cycle time (3018 ms)
1569
- √ subscribing to a changing value (10 ms) with 10 ms cycle time (30 ms)
1570
- √ subscribing to a constant value with maximum delay of 2000 ms (2010 ms)
1571
- √ subscribing to a raw ADS address (220 ms)
1572
- √ subscribing using subscribeValue() (2010 ms)
1573
- √ subscribing to a raw ADS address using subscribeRaw() (218 ms)
1574
- miscellaneous
1575
- √ sending read write ADS command (7 ms)
1576
- √ sending multiple read write ADS commands (multi/sum command) (10 ms)
1577
- issue specific tests
1578
- issue 103 (https://github.com/jisotalo/ads-client/issues/103)
1579
- √ calling unsubscribeAll() multiple times (should not crash to unhandled exception) (28 ms)
1580
- disconnecting
1581
- √ disconnecting client (6 ms)
1582
- controlling TwinCAT system service
1583
- √ connecting (2 ms)
1584
- √ setting TwinCAT system to config (5248 ms)
1585
- √ setting TwinCAT system to run (6303 ms)
1586
- √ disconnecting (1 ms)
1587
- handling unknown/stale ADS notifications
1588
- √ connecting (23 ms)
1589
- √ creating an unknown notification handle by forced disconnecting (1033 ms)
1590
- √ deleting an unknown notification handle automatically (1021 ms)
1591
- √ disconnecting (1 ms)
1592
-
1593
- Test Suites: 1 passed, 1 total
1594
- Tests: 164 passed, 164 total
1595
- Snapshots: 0 total
1596
- Time: 27.056 s
1597
- Ran all test suites matching /TC2\\ads-client.test.js/i.
1598
- </pre>
1599
- </details>
1600
-
1601
1482
  # License
1602
1483
 
1603
1484
  Licensed under [MIT License](http://www.opensource.org/licenses/MIT).