Cloud-Automation / node-modbus

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

Unable to write negative values to Int16 data type #192

Closed moonhead closed 6 years ago

moonhead commented 6 years ago

I am working with an Automation Direct P2-550, which supports a data type of Int16 (i.e. signed). I am unable to write negative values to the register containing these values using jsmodbus 3.0.0. I could with v2.4.0.

I am seeing the following error:

Error: InvalidValue
    at new WriteSingleRegisterRequestBody (<redacted>/node_modules/jsmodbus/src/request/write-single-register.js:34)
    at ModbusTCPClient.writeSingleRegister (<redacted>/node_modules/jsmodbus/src/modbus-client.js:189)

My calling code looks like this:

this.client.writeSingleRegister(register, Number( value ) ).then(function (resp) {
    console.log(resp);
}, console.error);

Which works if the value is postive, but throws the above error if negative.

In version 2.4.0 I created a buffer as follows to make negative numbers work:

var s16_buffer = new ArrayBuffer( 2 );
var s16_view = new DataView( s16_buffer );
s16_view.setInt16( 0, value );
this.client.writeSingleRegister(register, Buffer.from( s16_buffer )  ).then(function (resp) {
    console.log(resp);
}, console.error);

My suggestion is to again accept a Buffer as a value parameter in writeSingleRegister (although I do really like the experience of just passing in the value.)

As a workaround, we will simply use int32 in the cases where we need negative numbers (as those work in 3.0.0), but I wanted to bring the issue to your attention.

In general, I have loved working with this package, so thank you!

stefanpoeter commented 6 years ago

Hi @moonhead,

you can still do that:

let s16_buffer = Buffer.alloc( 2 ).writeInt16BE(value, 0);

this.client.writeSingleRegister(register, s16.readUInt16BE(0).then(function (resp) {
    console.log(resp);
}, console.error);

Hope that helps.

moonhead commented 6 years ago

Awesome! Thank you! It is non-intuitive (for me) that we read an unsigned int out of the buffer to write a negative, but it works!

For posterity, here is the code that worked for me.

let s16_buffer = Buffer.alloc( 2 );
s16_buffer.writeInt16BE(value, 0);

this.client.writeSingleRegister(register, s16_buffer.readUInt16BE(0)  ).then(function (resp) {
    console.log(resp);
}, console.error);