Cloud-Automation / node-modbus

Modbus TCP Client/Server implementation for Node.JS
465 stars 174 forks source link

'TypeError: "value" argument is out of bounds' error when handling request response #232

Closed paulmccarthy closed 4 years ago

paulmccarthy commented 5 years ago

I'm trying to read data from a NDMeter Rail 350 power meter via Modbus RTU. I'm using a Raspberry Pi Compute Model based system, with the following:

Node JS Version: 8.15.0 NPM Version: 6.4.1 OS Version (uname -a): Linux 13001 4.4.45-v7+ #19 SMP Fri Feb 10 12:54:17 CET 2017 armv7l GNU/Linux OS Version (/etc/os-release): PRETTY_NAME="Raspbian GNU/Linux 8 (jessie)" NAME="Raspbian GNU/Linux" VERSION_ID="8" VERSION="8 (jessie)" ID=raspbian ID_LIKE=debian HOME_URL="http://www.raspbian.org/" SUPPORT_URL="http://www.raspbian.org/RaspbianForums" BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"

The command is sent via over modbus, and data is returned, but I get the following error:

UnhandledPromiseRejectionWarning: TypeError: "value" argument is out of bounds
    at checkInt (buffer.js:1185:11)
    at Buffer.writeUInt8 (buffer.js:1233:5)
    at /home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/response/read-input-registers.js:90:15
    at Array.forEach (<anonymous>)
    at ReadInputRegistersResponseBody.createPayload (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/response/read-input-registers.js:89:18)
    at ModbusRTUClientRequestHandler.handle (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/rtu-client-request-handler.js:48:79)
    at ModbusRTUClient._onData (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/modbus-client.js:51:30)
    at emitOne (events.js:116:13)
    at SerialPort.emit (events.js:211:7)
    at addChunk (_stream_readable.js:263:12)

The issue is caused by the following code starting on line 84 insrc/response/read-input-registers.js:

createPayload () {
    const payload = Buffer.alloc(this.byteCount)

    payload.writeUInt8(this._fc, 0)
    payload.writeUInt8(this.length, 1)
    this._values.forEach(function (value, i) {
      payload.writeUInt8(value, 2 + i)
    })

    return payload
  }

This power meter returns 16 bit values, so the payload.writeUint8 function throws the error when it encounters a value > 255.

I've tried changing the code to:

createPayload () {
    const payload = Buffer.alloc(this.byteCount)

    payload.writeUInt16BE(this._fc, 0)
    payload.writeUInt16BE(this.length, 1)
    this._values.forEach(function (value, i) {
      payload.writeUInt16BE(value, 2 + i)
    })

    return payload
  }

which does return the expected values, but the then I get another error:

{ err: 'crcMismatch',
     message: 'the response payload does not match the crc' } }

This error is thrown on line 53 of src/rtu-client-request-handler.js.

DEBUG output with unchanged code:

serialport/bindings loading LinuxBinding +0ms
  serialport/stream opening path: /dev/ttyUSB4 +0ms
  serialport/binding-abstract open +0ms
  serialport/stream _read queueing _read for after open +9ms
  serialport/bindings/poller Creating poller +0ms
  serialport/stream opened path: /dev/ttyUSB4 +7ms
socket open
  modbus-client issuing new read input registers request +0ms
  rtu-client-request-handler registrating new request +0ms
  user-request creating new user request with timeout 5000 +0ms
  client-request-handler flushing +0ms
  client-request-handler flushing new request <Buffer 01 04 4c 00 00 20 e7 42> +5ms
  serialport/stream _write 8 bytes of data +19ms
  serialport/binding-abstract write 8 bytes +34ms
  serialport/stream _read reading +2ms
  serialport/binding-abstract read +2ms
  serialport/bindings/unixWrite Starting write 8 bytes offset 0 bytesToWrite 8 +0ms
  serialport/bindings/unixRead Starting read +0ms
  serialport/bindings/unixWrite write returned null 8 +4ms
  serialport/bindings/unixWrite wrote 8 bytes +1ms
  serialport/bindings/unixWrite Finished writing 8 bytes +0ms
  serialport/stream binding.write write finished +9ms
  client-request-handler request fully flushed, ( error: undefined ) undefined +18ms
  serialport/bindings/unixRead waiting for readable because of code: EAGAIN +5ms
  serialport/bindings/poller Polling for "readable" +33ms
  serialport/bindings/poller received "readable" +66ms
  serialport/binding-abstract read +77ms
  serialport/bindings/unixRead Starting read +69ms
  serialport/bindings/unixRead Finished read 6 bytes +0ms
  serialport/stream binding.read finished +71ms
  modbus-client received data +99ms
  rtu-response-handler receiving new data +0ms
  rtu-response-handler buffer <Buffer 01 04 40 00 00 00> +0ms
  rtu-response address 1 buffer <Buffer 01 04 40 00 00 00> +0ms
  response-factory fc 4 payload <Buffer 04 40 00 00 00> +0ms
  response-factory when NoSuchIndex Exception, the buffer does not contain a complete message +1ms
  response-factory RangeError: Index out of range
  response-factory     at checkOffset (buffer.js:977:11)
  response-factory     at Buffer.readUInt16BE (buffer.js:1031:5)
  response-factory     at Function.fromBuffer (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/response/read-input-registers.js:37:27)
  response-factory     at Function.fromBuffer (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/response/response-factory.js:45:39)
  response-factory     at Function.fromBuffer (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/rtu-response.js:28:34)
  response-factory     at ModbusRTUClientResponseHandler.handleData (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/rtu-client-response-handler.js:17:42)
  response-factory     at ModbusRTUClient._onData (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/modbus-client.js:37:27)
  response-factory     at emitOne (events.js:116:13)
  response-factory     at SerialPort.emit (events.js:211:7)
  response-factory     at addChunk (_stream_readable.js:263:12) +0ms
  rtu-response-handler not enough data available to parse +8ms
  serialport/stream _read reading +12ms
  serialport/binding-abstract read +14ms
  serialport/bindings/unixRead Starting read +14ms
  serialport/bindings/unixRead Finished read 27 bytes +1ms
  serialport/stream binding.read finished +2ms
  modbus-client received data +13ms
  rtu-response-handler receiving new data +4ms
  rtu-response-handler buffer <Buffer 01 04 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00> +0ms
  rtu-response address 1 buffer <Buffer 01 04 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00> +11ms
  response-factory fc 4 payload <Buffer 04 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00> +9ms
  response-factory when NoSuchIndex Exception, the buffer does not contain a complete message +1ms
  response-factory RangeError: Index out of range
  response-factory     at checkOffset (buffer.js:977:11)
  response-factory     at Buffer.readUInt16BE (buffer.js:1031:5)
  response-factory     at Function.fromBuffer (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/response/read-input-registers.js:37:27)
  response-factory     at Function.fromBuffer (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/response/response-factory.js:45:39)
  response-factory     at Function.fromBuffer (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/rtu-response.js:28:34)
  response-factory     at ModbusRTUClientResponseHandler.handleData (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/rtu-client-response-handler.js:17:42)
  response-factory     at ModbusRTUClient._onData (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/modbus-client.js:37:27)
  response-factory     at emitOne (events.js:116:13)
  response-factory     at SerialPort.emit (events.js:211:7)
  response-factory     at addChunk (_stream_readable.js:263:12) +0ms
  rtu-response-handler not enough data available to parse +4ms
  serialport/stream _read reading +5ms
  serialport/binding-abstract read +7ms
  serialport/bindings/unixRead Starting read +5ms
  serialport/bindings/unixRead Finished read 14 bytes +1ms
  serialport/stream binding.read finished +1ms
  modbus-client received data +6ms
  rtu-response-handler receiving new data +2ms
  rtu-response-handler buffer <Buffer 01 04 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 06 03 e8> +0ms
  rtu-response address 1 buffer <Buffer 01 04 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 06 03 e8> +5ms
  response-factory fc 4 payload <Buffer 04 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 06 03 e8> +5ms
  response-factory when NoSuchIndex Exception, the buffer does not contain a complete message +0ms
  response-factory RangeError: Index out of range
  response-factory     at checkOffset (buffer.js:977:11)
  response-factory     at Buffer.readUInt16BE (buffer.js:1031:5)
  response-factory     at Function.fromBuffer (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/response/read-input-registers.js:37:27)
  response-factory     at Function.fromBuffer (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/response/response-factory.js:45:39)
  response-factory     at Function.fromBuffer (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/rtu-response.js:28:34)
  response-factory     at ModbusRTUClientResponseHandler.handleData (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/rtu-client-response-handler.js:17:42)
  response-factory     at ModbusRTUClient._onData (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/modbus-client.js:37:27)
  response-factory     at emitOne (events.js:116:13)
  response-factory     at SerialPort.emit (events.js:211:7)
  response-factory     at addChunk (_stream_readable.js:263:12) +0ms
  rtu-response-handler not enough data available to parse +3ms
  serialport/stream _read reading +4ms
  serialport/binding-abstract read +5ms
  serialport/bindings/unixRead Starting read +5ms
  serialport/bindings/unixRead Finished read 8 bytes +0ms
  serialport/stream binding.read finished +1ms
  modbus-client received data +5ms
  rtu-response-handler receiving new data +2ms
  rtu-response-handler buffer <Buffer 01 04 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 06 03 e8 00 00 00 ... > +0ms
  rtu-response address 1 buffer <Buffer 01 04 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 06 03 e8 00 00 00 ... > +5ms
  response-factory fc 4 payload <Buffer 04 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 06 03 e8 00 00 00 00 ... > +5ms
  response-factory when NoSuchIndex Exception, the buffer does not contain a complete message +0ms
  response-factory RangeError: Index out of range
  response-factory     at checkOffset (buffer.js:977:11)
  response-factory     at Buffer.readUInt16BE (buffer.js:1031:5)
  response-factory     at Function.fromBuffer (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/response/read-input-registers.js:37:27)
  response-factory     at Function.fromBuffer (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/response/response-factory.js:45:39)
  response-factory     at Function.fromBuffer (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/rtu-response.js:28:34)
  response-factory     at ModbusRTUClientResponseHandler.handleData (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/rtu-client-response-handler.js:17:42)
  response-factory     at ModbusRTUClient._onData (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/modbus-client.js:37:27)
  response-factory     at emitOne (events.js:116:13)
  response-factory     at SerialPort.emit (events.js:211:7)
  response-factory     at addChunk (_stream_readable.js:263:12) +0ms
  rtu-response-handler not enough data available to parse +3ms
  serialport/stream _read reading +4ms
  serialport/binding-abstract read +5ms
  serialport/bindings/unixRead Starting read +5ms
  serialport/bindings/unixRead Finished read 11 bytes +0ms
  serialport/stream binding.read finished +2ms
  modbus-client received data +5ms
  rtu-response-handler receiving new data +2ms
  rtu-response-handler buffer <Buffer 01 04 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 06 03 e8 00 00 00 ... > +0ms
  rtu-response address 1 buffer <Buffer 01 04 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 06 03 e8 00 00 00 ... > +5ms
  response-factory fc 4 payload <Buffer 04 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 06 03 e8 00 00 00 00 ... > +5ms
  response-factory when NoSuchIndex Exception, the buffer does not contain a complete message +0ms
  response-factory RangeError: Index out of range
  response-factory     at checkOffset (buffer.js:977:11)
  response-factory     at Buffer.readUInt16BE (buffer.js:1031:5)
  response-factory     at Function.fromBuffer (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/response/read-input-registers.js:37:27)
  response-factory     at Function.fromBuffer (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/response/response-factory.js:45:39)
  response-factory     at Function.fromBuffer (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/rtu-response.js:28:34)
  response-factory     at ModbusRTUClientResponseHandler.handleData (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/rtu-client-response-handler.js:17:42)
  response-factory     at ModbusRTUClient._onData (/home/pi/modbus-test/jsmodbus/node_modules/jsmodbus/src/modbus-client.js:37:27)
  response-factory     at emitOne (events.js:116:13)
  response-factory     at SerialPort.emit (events.js:211:7)
  response-factory     at addChunk (_stream_readable.js:263:12) +0ms
  rtu-response-handler not enough data available to parse +3ms
  serialport/stream _read reading +3ms
  serialport/binding-abstract read +6ms
  serialport/bindings/unixRead Starting read +5ms
  serialport/bindings/unixRead Finished read 3 bytes +0ms
  serialport/stream binding.read finished +2ms
  modbus-client received data +5ms
  rtu-response-handler receiving new data +2ms
  rtu-response-handler buffer <Buffer 01 04 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 06 03 e8 00 00 00 ... > +0ms
  rtu-response address 1 buffer <Buffer 01 04 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 06 03 e8 00 00 00 ... > +6ms
  response-factory fc 4 payload <Buffer 04 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 06 03 e8 00 00 00 00 ... > +5ms
  rtu-response-handler crc 7009 +3ms
  rtu-response-handler reset buffer from 69 to 0 +0ms
  rtu-response-handler not enough data available to parse +0ms
  rtu-client-request-handler new response coming in +136ms

DEBUG output with writeUint8 changed to writeUint16BE:

serialport/bindings loading LinuxBinding +0ms
  serialport/stream opening path: /dev/ttyUSB4 +0ms
  serialport/binding-abstract open +0ms
  serialport/stream _read queueing _read for after open +9ms
  serialport/bindings/poller Creating poller +0ms
  serialport/stream opened path: /dev/ttyUSB4 +7ms
socket open
  modbus-client issuing new read input registers request +0ms
  rtu-client-request-handler registrating new request +0ms
  user-request creating new user request with timeout 5000 +0ms
  client-request-handler flushing +0ms
  client-request-handler flushing new request <Buffer 01 04 4c 00 00 20 e7 42> +5ms
  serialport/stream _write 8 bytes of data +19ms
  serialport/binding-abstract write 8 bytes +34ms
  serialport/stream _read reading +2ms
  serialport/binding-abstract read +2ms
  serialport/bindings/unixWrite Starting write 8 bytes offset 0 bytesToWrite 8 +0ms
  serialport/bindings/unixRead Starting read +0ms
  serialport/bindings/unixWrite write returned null 8 +5ms
  serialport/bindings/unixWrite wrote 8 bytes +0ms
  serialport/bindings/unixWrite Finished writing 8 bytes +0ms
  serialport/stream binding.write write finished +8ms
  client-request-handler request fully flushed, ( error: undefined ) undefined +17ms
  serialport/bindings/unixRead waiting for readable because of code: EAGAIN +5ms
  serialport/bindings/poller Polling for "readable" +32ms
  serialport/bindings/poller received "readable" +462ms
  serialport/binding-abstract read +472ms
  serialport/bindings/unixRead Starting read +465ms
  serialport/bindings/unixRead Finished read 69 bytes +0ms
  serialport/stream binding.read finished +467ms
  modbus-client received data +494ms
  rtu-response-handler receiving new data +0ms
  rtu-response-handler buffer <Buffer 01 04 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 06 03 e8 00 00 00 ... > +0ms
  rtu-response address 1 buffer <Buffer 01 04 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 06 03 e8 00 00 00 ... > +0ms
  response-factory fc 4 payload <Buffer 04 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 06 03 e8 00 00 00 00 ... > +0ms
  rtu-response-handler crc 30089 +5ms
  rtu-response-handler reset buffer from 69 to 0 +0ms
  rtu-response-handler not enough data available to parse +1ms
  rtu-client-request-handler new response coming in +501ms
  rtu-client-request-handler create crc from response <Buffer 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 00 00 02 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... > +1ms
  rtu-client-request-handler CRC does not match 30089 !== 35447 +0ms
  serialport/stream _read reading +13ms
  serialport/binding-abstract read +16ms
  serialport/bindings/unixRead Starting read +16ms
stefanpoeter commented 5 years ago

Can you post the code where you call the readInputRegisters method.

paulmccarthy commented 5 years ago

Thanks for replying. My code is below:

const modbus = require('jsmodbus');
const SerialPort = require('serialport');

const socket = new SerialPort('/dev/ttyUSB4', {
    baudRate: 19200
});

const client = new modbus.client.RTU(socket, 1);

socket.on('open', function () {
    console.log('socket open');

    client.readInputRegisters(19456, 32)
        .then((resp) => {
            console.log(resp.response.body.valuesAsArray);
            socket.end();
            process.exit();
        }).catch(function () {
            console.error('readInputRegisters error', arguments);
            socket.end();
            process.exit(1);
        });
});

socket.on('socket error', function() {
    console.error('socket error', arguments);
    process.exit(1);
});
stefanpoeter commented 5 years ago

Thanks for the code.

Changing the writeUint8 into a writeUint16 does not do any good and doesn't make sense. It seems like the payload buffer is not initiated with the right size. Can you add a log message for the byteCount like below and try again?

createPayload () {
    console.log('BYTE_COUNT:', this.byteCount)
    const payload = Buffer.alloc(this.byteCount)

    payload.writeUInt8(this._fc, 0)
    payload.writeUInt8(this.length, 1)
    this._values.forEach(function (value, i) {
      payload.writeUInt8(value, 2 + i)
    })

    return payload
  }
stefanpoeter commented 5 years ago

Any progress?

dpham314 commented 5 years ago

I had a similar issue with reading a 16 bit ModbusRTU register, but with read-holding-registers. The values when createPayload ran were:

this._values = [2019, 4] this._valuesAsBuffer = [7, 227, 0, 4] this.byteCount = 6

Since 2019 > 255, it gives an error. It works when I change this._values to this._valuesAsBuffer in the createPayload function.

  createPayload () {
    if (this._values instanceof Buffer) {
      let payload = Buffer.alloc(2)
      payload.writeUInt8(this._fc, 0)
      payload.writeUInt8(this._byteCount, 1)
      payload = Buffer.concat([payload, this._values])
      return payload
    }

    if (this._values instanceof Array) {
      const payload = Buffer.alloc(this.byteCount)
      payload.writeUInt8(this._fc, 0)
      payload.writeUInt8(this._byteCount, 1)
      this._valuesAsBuffer.forEach(function (value, i) {
        payload.writeUInt8(value, 2 + i)
      })

      return payload
    }
  }

So the createPayload function in read-input-registers would be

  createPayload () {
    const payload = Buffer.alloc(this.byteCount)

    payload.writeUInt8(this._fc, 0)
    payload.writeUInt8(this.length, 1)
    this._valuesAsBuffer.forEach(function (value, i) {
      payload.writeUInt8(value, 2 + i)
    })

    return payload
  }

245

dvankuren commented 5 years ago

I also ran into this in read-holding-registers when the register value exceeded max UInt8. The suggestion provided by @dpham314 indeed resolved the problem.

stefanpoeter commented 4 years ago

@dvankuren Should be resolved in the lates version. Can you check that? Version 3.1.4