jisotalo/ads-client

Issue reading structs containing BIT datatype

Closed this issue · 6 comments

Hi,

I'm having an issue where I cannot subscribe to structures containing BITs. I can subscribe to everything else just fine.

For example, I cannot subscribe to the struct below:

TYPE ST_SYSTEM_STATE :
STRUCT
	//all subsystems
	bStateMachineRunning					: BIT; 
	bMotorsPowered						: BIT; 	
	bInitComplete							: BIT; 	
	bIsHoming							: BIT;	
	bHasHomed							: BIT; 	
	bIsReady								: BIT; 	
	bIsBusy								: BIT; 
	bMotorsMoving						: BIT;	
	bHasStopped							: BIT; 
	bHasPaused							: BIT;
END_STRUCT
END_TYPE

Turning on debugging in ads-client, I receive the following message:

at async \node_modules\ads-client\src\ads-client.js:6325:35 { code: 'ERR_BUFFER_OUT_OF_BOUNDS' } +4ms
  ads-client:details IO in  <------ 68 bytes +494ms
  ads-client:details _parseAmsTcpHeader(): Starting to parse AMS/TCP header +1ms
  ads-client:details _parseAmsTcpHeader(): AMS/TCP header parsed: { command: 0, commandStr: 'AMS_TCP_PORT_AMS_CMD', dataLength: 62 } +0ms
  ads-client:details _parseAmsHeader(): Starting to parse AMS header +1ms
  ads-client:details _parseAmsHeader(): AMS header parsed: { targetAmsNetId: '192.168.200.1.1.1', targetAdsPort: 33242, sourceAmsNetId: '192.168.11.2.1.1', sourceAdsPort: 851, adsCommand: 8, adsCommandStr: 'Notification', stateFlags: 4, stateFlagsStr: 'AdsCommand, Tcp, Request', dataLength: 30, errorCode: 0, invokeId: 0, error: false, errorStr:
  ads-client:details _getDataTypeInfo(): Data type requested for BIT +0ms
  ads-client:details _getDataTypeInfo(): Data type info found from cache for BIT +0ms
  ads-client:details _getDataTypeInfo(): Data type requested for BIT +0ms  ads-client:details _getDataTypeInfo(): Data type info found from cache for BIT +1ms
  ads-client _onAdsCommandReceived(): Ads notification received but parsing Javascript object failed: RangeError [ERR_BUFFER_OUT_OF_BOUNDS]: Attempt to access memory outside buffer bounds

Any help would be greatly appreciated.

Thanks!
Isaac

Hi!

Actually the BIT data type is not available/working at the moment. I thought that I had it in README but I didn't.. Basically it is in the code however handled like a BOOL and it would require some extra effort to be handled correctly.

So I would suggest to use BOOL instead if possible, or just a single WORD and then get the bits yourself. Personally I never use BITs with TwinCAT as the support is not that good.

Edit: I will keep this issue open as this certainly should work some day if it's technically doable.

Hi jisotalo,

Thanks very much for the quick reply. Good to know I wasn't going crazy! We initially were using BITs instead of BOOLs to reduce the size of the overall packets over the network, but it's not a big deal for us to change over to using BOOLs instead. I'll keep it in mind for future development not to use BITs.

Once again, I very much appreciate the time and effort you've put into this library.

Thanks!
Isaac

If you really need to read struct with BITs it's possible but needs a little work. I tested the following and it works fine!

PLC side

TYPE ST_Bits:
STRUCT
  Bit_0 : BIT;
  Bit_1 : BIT;
  Bit_2 : BIT;
  Bit_3 : BIT;
  Bit_4 : BIT;
  Bit_5 : BIT;
  Bit_6 : BIT;
  Bit_7 : BIT;
END_STRUCT
END_TYPE
//GVL_BitTest
{attribute 'qualified_only'}
VAR_GLOBAL
  Bits : ST_Bits;
END_VAR

Node.js side

const ads = require('ads-client');
const client = new ads.Client({
  targetAmsNetId: 'localhost',
  targetAdsPort: 851
});

client.connect()
  .then(async res => {   
    console.log(`Connected to the ${res.targetAmsNetId}`);
    console.log(`Router assigned us AmsNetId ${res.localAmsNetId} and port ${res.localAdsPort}`);

    //First getting the symbol info for this variable
    const info = await client.getSymbolInfo('GVL_BitTest.Bits');

    //Using symbol info to subscribe to raw data
    const sub = await client.subscribeRaw(info.indexGroup, info.indexOffset, info.size, (data, sub) => {
      //Converting Buffer to byte
      const value = data.value.readUint8();
      
      const converted = {
        bit_0: !!(value & (0x01 << 0)),
        bit_1: !!(value & (0x01 << 1)),
        bit_2: !!(value & (0x01 << 2)),
        bit_3: !!(value & (0x01 << 3)),
        bit_4: !!(value & (0x01 << 4)),
        bit_5: !!(value & (0x01 << 5)),
        bit_6: !!(value & (0x01 << 6)),
        bit_7: !!(value & (0x01 << 7)),
      }
      console.log(converted);
      /* Should print something like:
      {
        bit_0: true,
        bit_1: false,
        bit_2: true,
        bit_3: false,
        bit_4: true,
        bit_5: false,
        bit_6: true,
        bit_7: false
      }
      */
    });
  })
  .catch(err => {
    console.log('Something failed:', err);
  })

Thanks again and have a nice christmas!

Adding this to version 2.0 milestone. Let's see if it's possible easily or not.

Development ongoing, reading already works in commit f6a3724

Reading and writing BITs now works in v2 (at least in my tests) - commit c3507e2