jisotalo / ads-client

Unofficial Node.js ADS library for connecting to Beckhoff TwinCAT automation systems using ADS protocol.
https://jisotalo.fi/ads-client/
MIT License
80 stars 17 forks source link

Properties support #62

Closed Hopperpop closed 3 years ago

Hopperpop commented 3 years ago

Would it be possible to support reading/writing properties who have a correct monitor pragma? (https://infosys.beckhoff.com/content/1033/tc3_plc_intro/2529692299.html)

Currently it returns always a fixed value depending on the type: INT:0, LREAL;NaN, UINT:35320, BOOL:false, ... Beckhoff HMI also uses ADS and seems to be able to handle properties with a pragma.

jisotalo commented 3 years ago

Hi!

I have used the monitoring pragma but never tried to read that using ADS. It probably needs some research.

Do you know if TwinCAT.Ads.dll for C# supports it?

Hopperpop commented 3 years ago

At the moment I don't have any idea what needs to be done to get it working. And if other libraries support it. Indeed some research will be needed.

Hopperpop commented 3 years ago

I found that adding {attribute 'monitoring' := 'call'} adds a rpc call for the setter and getter function (ex. "__setMyProp"). But trying to call these methods doesn't work as it fails when getting a handle:

ads-client createVariableHandle(): Creating handle to MAIN.fbTest#__setp_bool failed: ClientException: Response with ADS error received 
    at Client.callback (C:\Users\x\source\repos\node-red-contrib-ads-client\node_modules\ads-client\src\ads-client.js:6164:25) 
    at Client._onAdsCommandReceived (C:\Users\x\source\repos\node-red-contrib-ads-client\node_modules\ads-client\src\ads-client.js:6005:29) 
    at Client._onAmsTcpPacketReceived (C:\Users\x\source\repos\node-red-contrib-ads-client\node_modules\ads-client\src\ads-client.js:5866:29) 
    at Client._parseAmsTcpPacket (C:\Users\x\source\repos\node-red-contrib-ads-client\node_modules\ads-client\src\ads-client.js:5521:27)     
    at processImmediate (internal/timers.js:461:21) { sender: '_sendAdsCommand()', adsError: true, adsErrorInfo: { adsErrorType: 'ADS error', adsErrorCode: 1808, adsErrorStr: 'Symbol not found' }, metaData: null, errorTrace: [], getInnerException: null } +5ms

I found a related question here: stackoverflow Bellow the type definition of a function block with set/get rpc calls.

{
  "name": "",
  "type": "FB_Test",
  "size": 24,
  "offset": 0,
  "adsDataType": 65,
  "adsDataTypeStr": "ADST_BIGTYPE",
  "comment": "",
  "attributes": [],
  "rpcMethods": [
    {
      "version": 1,
      "vTableIndex": 3,
      "returnSize": 1,
      "returnAlignSize": 1,
      "reserved": 0,
      "returnTypeGuid": "95190718000000000000000000000030",
      "retunAdsDataType": 33,
      "retunAdsDataTypeStr": "ADST_BIT",
      "flags": 1,
      "flagsStr": [
        "DataType"
      ],
      "nameLength": 11,
      "returnTypeLength": 4,
      "commentLength": 0,
      "parameterCount": 0,
      "name": "__getp_bool",
      "returnType": "BOOL",
      "comment": "",
      "parameters": []
    },
    {
      "version": 1,
      "vTableIndex": 7,
      "returnSize": 0,
      "returnAlignSize": 0,
      "reserved": 0,
      "returnTypeGuid": "00000000000000000000000000000000",
      "retunAdsDataType": 0,
      "retunAdsDataTypeStr": "ADST_VOID",
      "flags": 1,
      "flagsStr": [
        "DataType"
      ],
      "nameLength": 11,
      "returnTypeLength": 0,
      "commentLength": 0,
      "parameterCount": 1,
      "name": "__setp_bool",
      "returnType": "",
      "comment": "",
      "parameters": [
        {
          "size": 1,
          "alignSize": 1,
          "adsDataType": 33,
          "adsDataTypeStr": "ADST_BIT",
          "flags": 1,
          "flagsStr": [
            "In"
          ],
          "reserved": 0,
          "typeGuid": "95190718000000000000000000000030",
          "lengthIsPara": 0,
          "nameLength": 6,
          "typeLength": 4,
          "commentLength": 0,
          "name": "p_bool",
          "type": "BOOL",
          "comment": ""
        }
      ]
    },
    {
      "version": 1,
      "vTableIndex": 12,
      "returnSize": 1,
      "returnAlignSize": 1,
      "reserved": 0,
      "returnTypeGuid": "95190718000000000000000000000030",
      "retunAdsDataType": 33,
      "retunAdsDataTypeStr": "ADST_BIT",
      "flags": 1,
      "flagsStr": [
        "DataType"
      ],
      "nameLength": 8,
      "returnTypeLength": 4,
      "commentLength": 0,
      "parameterCount": 0,
      "name": "mGetBool",
      "returnType": "BOOL",
      "comment": "",
      "parameters": []
    }
  ],
  "arrayData": [],
  "subItems": [
    {
      "name": "pbool",
      "type": "BOOL",
      "size": 1,
      "offset": 16,
      "adsDataType": 33,
      "adsDataTypeStr": "ADST_BIT",
      "comment": "",
      "attributes": [
        {
          "name": "DisplayMinValue",
          "value": "0"
        },
        {
          "name": "DisplayMaxValue",
          "value": "1"
        }
      ],
      "rpcMethods": [],
      "arrayData": [],
      "subItems": []
    },
    {
      "name": "p_bool",
      "type": "BOOL",
      "size": 1,
      "offset": 0,
      "adsDataType": 33,
      "adsDataTypeStr": "ADST_BIT",
      "comment": "",
      "attributes": [
        {
          "name": "DisplayMinValue",
          "value": "0"
        },
        {
          "name": "DisplayMaxValue",
          "value": "1"
        }
      ],
      "rpcMethods": [],
      "arrayData": [],
      "subItems": []
    }
  ]
}
jisotalo commented 3 years ago

Thanks @Hopperpop!

I will check this and report

jisotalo commented 3 years ago

Been quite busy with one side project (uses TC3, ads-client and React). However I tried to work on this now.

I created a STRING property: image

I managed to use the following to read and write that property.

const handle = await client.createVariableHandle('GVL_PropertyTest.FB.Str')

//Reading property
let value = await client.convertFromRaw(await client.readRawByHandle(handle), 'STRING(80)')
console.log('Value at first: ', value)

//Writing property
await client.writeRawByHandle(handle, await client.convertToRaw('A new value!', 'STRING(80)'))
console.log('New value was written!')

//Reading property again
value = await client.convertFromRaw(await client.readRawByHandle(handle), 'STRING(80)')
console.log('Value after writing: ', value)

await client.deleteVariableHandle(handle)

However, my PC crashed randomly when testing this (running local TwinCAT)...

Edit: The following should be identical at C# and the PC won't crash. Need to do some Wiresharking:

var handle = client.CreateVariableHandle("GVL_PropertyTest.FB.Str");

var value = client.ReadAny(handle, typeof(string), new int[] { 81 });
Console.WriteLine($"Value at first: {value}");

client.WriteAny(handle, "A new value!", new int[] { 81 });
Console.WriteLine($"New value was written!");

value = client.ReadAny(handle, typeof(string), new int[] { 81 });
Console.WriteLine($"Value after writing: {value}");

client.DeleteVariableHandle(handle);

Edit2: Only difference when Wiresharking was that the C# writes only the string bytes given, and the ads-client writes all 81 bytes. And when testing ads-client with INT, no crashes happened. TC version is 4024.10.

jisotalo commented 3 years ago

@Hopperpop have you tried the code above, does it work at your system?

Hopperpop commented 3 years ago

I tried it and and seems to work correctly with LREAL. Code in the getter function is also executed. For strings I also have crashes, even when only calling "readRawByHandle". (Tc4024.12)

jisotalo commented 3 years ago

Ok! Thanks for info. The crashing is a bit strange..

jisotalo commented 3 years ago

I'm closing this issue for now. Will add somehting to the README later.