ads-client 1.14.2 → 1.14.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,22 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [1.14.3] - 23.09.2023
8
+ ### Changed
9
+ - Bug fix: Some TwinCAT 2 devices (such as BK9050) do not send data length if answering with error code
10
+ - This caused `RangeError: Index out of range` exception as there wasn't enough bytes received
11
+ - See [issue #116](https://github.com/jisotalo/ads-client/issues/116)
12
+ - Bug fix: If using older Node.js versions such as 8.x, connection lost could have caused unhandled exception
13
+ - Reason was `catch {}` which isn't supported in old versions
14
+ - See [issue #116](https://github.com/jisotalo/ads-client/issues/116)
15
+
16
+ ### Added
17
+ - Updated readme to include information about TypeScript types
18
+ - Thanks to [Christian Rishøj](https://github.com/crishoj)
19
+ - Updated readme with FAQ about TwinCAT 2 low-end devices
20
+ - Updated readme about v2 development
21
+ - Added option to run tests with usermode runtime AmsNetId (`192.168.4.1.1.1`) instead of localhost (`npm run test-um`)
22
+
7
23
  ## [1.14.2] - 02.05.2023
8
24
  ### Changed
9
25
  - Bug fix: `ADS_DATA_TYPE_FLAGS` (`dataType.flags`) were parsed incorrectly.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
 
4
4
  [![npm version](https://img.shields.io/npm/v/ads-client)](https://www.npmjs.org/package/ads-client)
5
- [![Donate](https://img.shields.io/badge/Donate-PayPal-yellow)](https://www.paypal.com/donate/?business=KUWBXXCVGZZME&no_recurring=0&currency_code=EUR)
5
+ [![Donate](https://img.shields.io/badge/Support-PayPal-yellow)](https://www.paypal.com/donate/?business=KUWBXXCVGZZME&no_recurring=0&currency_code=EUR)
6
6
  [![GitHub](https://img.shields.io/badge/View%20on-GitHub-brightgreen)](https://github.com/jisotalo/ads-client)
7
7
  [![License](https://img.shields.io/github/license/jisotalo/ads-client)](https://choosealicense.com/licenses/mit/)
8
8
 
@@ -10,16 +10,19 @@ Beckhoff TwinCAT ADS client library for Node.js (unofficial). Connects to Beckho
10
10
 
11
11
  Coded from scratch using [TwinCAT ADS specification](https://infosys.beckhoff.com/content/1033/tc3_ads_intro/116157835.html?id=124964102706356243) and [Beckhoff.TwinCAT.Ads nuget package](https://www.nuget.org/packages/Beckhoff.TwinCAT.Ads/5.0.0-preview6). Inspiration from similar projects like [node-ads](https://www.npmjs.com/package/node-ads), [beckhoff-js](https://www.npmjs.com/package/beckhoff-js) and [iecstruct](https://www.npmjs.com/package/iecstruct).
12
12
 
13
- There is automatically created documentation available at https://jisotalo.github.io/ads-client/
13
+ There is automatically created documentation available at https://jisotalo.fi/ads-client/
14
14
 
15
15
  # Project status
16
16
  This project is currently "ready". It's maintained actively and used in projects by the author and others (also lot's of commercial projects)
17
17
 
18
18
  Bugs are fixed if found and new features can be added. Please let me know if you have any ideas!
19
19
 
20
- And if you want you can buy me a beer using PayPal :)
20
+ If you want to support my work, you can do it using PayPal. I can provide you support in exchange.
21
21
 
22
- [![Donate](https://img.shields.io/badge/Donate%20a%20beer!-PayPal-yellow)](https://www.paypal.com/donate/?business=KUWBXXCVGZZME&no_recurring=0&currency_code=EUR)
22
+ [![Donate](https://img.shields.io/badge/Support%20my%20work!-PayPal-yellow)](https://www.paypal.com/donate/?business=KUWBXXCVGZZME&no_recurring=0&currency_code=EUR)
23
+
24
+ ## Version 2
25
+ Version 2 is under development in [`v2-dev`](https://github.com/jisotalo/ads-client/tree/v2-dev) branch. It's written in TypeScript (including all types!) and will also be more optimized. At the moment basic functions *might* work but it's not ready for production use.
23
26
 
24
27
 
25
28
  # Using Node-RED?
@@ -101,6 +104,13 @@ Install the [npm package](https://www.npmjs.com/package/ads-client) using npm co
101
104
  npm i ads-client
102
105
  ```
103
106
 
107
+ If you are using TypeScript, install unofficial types using npm command (thanks [Christian Rishøj](https://github.com/crishoj)):
108
+ ```bash
109
+ npm install --save @types/ads-client
110
+ ```
111
+
112
+ *Note: Version 2 under development will be written in 100% TypeScript*
113
+
104
114
  Include the module in your code
105
115
  ```js
106
116
  const ads = require('ads-client')
@@ -1764,12 +1774,17 @@ Solution:
1764
1774
  * When closing application, first unsubscribe from all notifications using `unsubscribeAll()`
1765
1775
  * Use router instead of direct connection, see https://github.com/jisotalo/ads-client/issues/85#issuecomment-1193098519
1766
1776
 
1777
+ ### Issues with TwinCAT 2 low-end devices (BK9050, BC9050 etc.)
1778
+ * You can only use raw commands (such as `readRaw()`, `writeRaw()`, `subscribeRaw()`) as these devices provide no symbols
1779
+ * See [issue 114](https://github.com/jisotalo/ads-client/issues/114) and [issue 116](https://github.com/jisotalo/ads-client/issues/116) for starters
1780
+
1781
+
1767
1782
  # Automatic testing
1768
1783
  Since version 1.14.0 the library has automatic testing using Jest. Idea is to run the tests before updates to make sure everything works OK (this should have been done much earlier...)
1769
1784
 
1770
1785
  Separate PLC project is required for testing, see https://github.com/jisotalo/ads-client-test-plc-project for more project and more info.
1771
1786
 
1772
- Tests are run with command `npm test` (not in npm version, please clone this repository).
1787
+ Tests are run with command `npm test` or `npm run test-um` (usermode runtime) (not in npm version, please clone this repository).
1773
1788
 
1774
1789
  # Documentation
1775
1790
 
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "ads-client",
3
- "version": "1.14.2",
3
+ "version": "1.14.3",
4
4
  "description": "Beckhoff TwinCAT ADS client library for Node.js (unofficial). Connects to Beckhoff TwinCAT automation systems using ADS protocol.",
5
5
  "main": "./src/ads-client.js",
6
6
  "scripts": {
7
7
  "test": "jest --runInBand",
8
+ "test-um": "set ADS_CLIENT_TEST_AMS=192.168.4.1.1.1 && jest --runInBand",
8
9
  "generate-docs": "jsdoc ./src/ads-client.js ./README.md -c ./jsdoc-conf.json -d ./docs/ -t ./node_modules/docdash/"
9
10
  },
10
11
  "keywords": [
package/src/ads-client.js CHANGED
@@ -894,7 +894,7 @@ class Client extends EventEmitter {
894
894
  } catch (err) {
895
895
  return reject(new ClientException(this, 'readSymbol()', `Reading symbol ${variableName} failed: Reading data type failed`, err))
896
896
  }
897
-
897
+
898
898
  //4. Parse the data to javascript object
899
899
  let data = {}
900
900
  try {
@@ -3658,7 +3658,7 @@ function _reconnect(forceDisconnect = false, isReconnecting = false) {
3658
3658
 
3659
3659
  debug(`_reconnect(): Connection and some subscriptions reinitialized. Connection is back.`)
3660
3660
  })
3661
-
3661
+
3662
3662
  this.emit('reconnect')
3663
3663
 
3664
3664
  resolve(res)
@@ -3945,7 +3945,9 @@ async function _onConnectionLost(socketFailure = false) {
3945
3945
  _console.call(this, 'WARNING: Connection was lost and setting autoReconnect=false. Quiting.')
3946
3946
  try {
3947
3947
  await this.disconnect(true)
3948
- } catch { }
3948
+ } catch (err) {
3949
+ debugD(`_onConnectionLost(): Error during disconnecting. Quiting.`)
3950
+ }
3949
3951
 
3950
3952
  return
3951
3953
  }
@@ -3965,7 +3967,7 @@ async function _onConnectionLost(socketFailure = false) {
3965
3967
  //Try to reconnect
3966
3968
  _reconnect.call(this, socketFailure, true)
3967
3969
  .then(res => {
3968
-
3970
+
3969
3971
  //Success -> remove timer
3970
3972
  _clearTimer(this._internals.reconnectionTimer)
3971
3973
 
@@ -3974,7 +3976,7 @@ async function _onConnectionLost(socketFailure = false) {
3974
3976
  //Reconnecting failed
3975
3977
  if (firstTime)
3976
3978
  _console.call(this, `WARNING: Reconnecting failed. Keeping trying in the background every ${this.settings.reconnectInterval} ms...`)
3977
-
3979
+
3978
3980
  //If this is still a valid timer, start over again
3979
3981
  if (this._internals.reconnectionTimer.id === timerId) {
3980
3982
  //Creating a new timer with the same id
@@ -4018,7 +4020,7 @@ function _clearTimer(timerObject) {
4018
4020
  //Increasing timer id
4019
4021
  timerObject.id = timerObject.id < Number.MAX_SAFE_INTEGER ? timerObject.id + 1 : 0;
4020
4022
  }
4021
-
4023
+
4022
4024
 
4023
4025
 
4024
4026
 
@@ -4294,7 +4296,7 @@ function _systemManagerStatePoller() {
4294
4296
  let oldState = this.metaData.systemManagerState
4295
4297
 
4296
4298
  //If the timer has changed, quit here
4297
- if (this._internals.systemManagerStatePoller.id !== timerId){
4299
+ if (this._internals.systemManagerStatePoller.id !== timerId) {
4298
4300
  return
4299
4301
  }
4300
4302
 
@@ -4353,7 +4355,7 @@ function _systemManagerStatePoller() {
4353
4355
  () => poller(this._internals.systemManagerStatePoller.id),
4354
4356
  this.settings.checkStateInterval
4355
4357
  )
4356
-
4358
+
4357
4359
  }
4358
4360
 
4359
4361
 
@@ -5241,7 +5243,7 @@ function _parseJsObjectToBuffer(value, dataType, objectPathStr = '', isArraySubI
5241
5243
  //Struct or array subitem - Go through each subitem
5242
5244
  if ((dataType.arrayData.length === 0 || isArraySubItem) && dataType.subItems.length > 0) {
5243
5245
  buffer = Buffer.alloc(dataType.size)
5244
-
5246
+
5245
5247
  for (const subItem of dataType.subItems) {
5246
5248
  //Try the find the subitem from javascript object
5247
5249
  let key = null
@@ -6040,11 +6042,16 @@ function _parseAdsData(packet, data) {
6040
6042
  case ADS.ADS_COMMAND.ReadWrite:
6041
6043
  case ADS.ADS_COMMAND.Read:
6042
6044
 
6043
-
6044
6045
  //0..3 Ads error number
6045
6046
  ads.errorCode = data.readUInt32LE(pos)
6046
6047
  pos += 4
6047
6048
 
6049
+ if (data.byteLength <= 4) {
6050
+ ads.dataLength = 0
6051
+ ads.data = Buffer.alloc(0)
6052
+ break
6053
+ }
6054
+
6048
6055
  //4..7 Data length (bytes)
6049
6056
  ads.dataLength = data.readUInt32LE(pos)
6050
6057
  pos += 4
@@ -6055,8 +6062,6 @@ function _parseAdsData(packet, data) {
6055
6062
 
6056
6063
  break
6057
6064
 
6058
-
6059
-
6060
6065
  //-------------- Write ---------------
6061
6066
  case ADS.ADS_COMMAND.Write:
6062
6067
 
@@ -6066,8 +6071,6 @@ function _parseAdsData(packet, data) {
6066
6071
 
6067
6072
  break
6068
6073
 
6069
-
6070
-
6071
6074
  //-------------- Device info ---------------
6072
6075
  case ADS.ADS_COMMAND.ReadDeviceInfo:
6073
6076
 
@@ -6077,6 +6080,10 @@ function _parseAdsData(packet, data) {
6077
6080
 
6078
6081
  ads.data = {}
6079
6082
 
6083
+ if (data.byteLength <= 4) {
6084
+ break
6085
+ }
6086
+
6080
6087
  //4 Major version
6081
6088
  ads.data.majorVersion = data.readUInt8(pos)
6082
6089
  pos += 1
@@ -6094,10 +6101,6 @@ function _parseAdsData(packet, data) {
6094
6101
 
6095
6102
  break
6096
6103
 
6097
-
6098
-
6099
-
6100
-
6101
6104
  //-------------- Device status ---------------
6102
6105
  case ADS.ADS_COMMAND.ReadState:
6103
6106
 
@@ -6107,6 +6110,10 @@ function _parseAdsData(packet, data) {
6107
6110
 
6108
6111
  ads.data = {}
6109
6112
 
6113
+ if (data.byteLength <= 4) {
6114
+ break
6115
+ }
6116
+
6110
6117
  //4..5 ADS state
6111
6118
  ads.data.adsState = data.readUInt16LE(pos)
6112
6119
  ads.data.adsStateStr = ADS.ADS_STATE.toString(ads.data.adsState)
@@ -6118,9 +6125,6 @@ function _parseAdsData(packet, data) {
6118
6125
 
6119
6126
  break
6120
6127
 
6121
-
6122
-
6123
-
6124
6128
  //-------------- Add notification ---------------
6125
6129
  case ADS.ADS_COMMAND.AddNotification:
6126
6130
 
@@ -6130,15 +6134,16 @@ function _parseAdsData(packet, data) {
6130
6134
 
6131
6135
  ads.data = {}
6132
6136
 
6137
+ if (data.byteLength <= 4) {
6138
+ break
6139
+ }
6140
+
6133
6141
  //4..7 Notification handle
6134
6142
  ads.data.notificationHandle = data.readUInt32LE(pos)
6135
6143
  pos += 4
6136
6144
 
6137
6145
  break
6138
6146
 
6139
-
6140
-
6141
-
6142
6147
  //-------------- Delete notification ---------------
6143
6148
  case ADS.ADS_COMMAND.DeleteNotification:
6144
6149
 
@@ -6148,8 +6153,6 @@ function _parseAdsData(packet, data) {
6148
6153
 
6149
6154
  break
6150
6155
 
6151
-
6152
-
6153
6156
  //-------------- Notification ---------------
6154
6157
  case ADS.ADS_COMMAND.Notification:
6155
6158
 
@@ -6157,8 +6160,6 @@ function _parseAdsData(packet, data) {
6157
6160
 
6158
6161
  break
6159
6162
 
6160
-
6161
-
6162
6163
  //-------------- WriteControl ---------------
6163
6164
  case ADS.ADS_COMMAND.WriteControl:
6164
6165
 
@@ -6168,7 +6169,6 @@ function _parseAdsData(packet, data) {
6168
6169
 
6169
6170
  break
6170
6171
 
6171
-
6172
6172
  default:
6173
6173
  //Unknown command, return a custom error
6174
6174
  debug(`_parseAdsResponse: Unknown ads command in response: ${packet.ams.adsCommand}`)