Cloud-Automation / node-modbus

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

Buggy Holding Registers #202

Closed wongjasont closed 6 years ago

wongjasont commented 6 years ago

I've created a runnable test below to demonstrate the issue:

const modbus = require('jsmodbus');
const net = require('net');

let socket = new net.Socket();
let opts = {
    host: '127.0.0.1',
    port : '5440'
};
let client = new modbus.client.TCP(socket, 1, 30000);

socket.on('connect', () => {
    Promise.all([
        // FOR COILS:
        // FIRST 5 VALUES [1,0,1,0,1]
        client.writeSingleCoil(0, true),
        client.writeSingleCoil(1, false),
        client.writeSingleCoil(2, true),
        client.writeSingleCoil(3, false),
        client.writeSingleCoil(4, true),
        // NEXT 5 VALUES [1,1,1,1,1]
        client.writeMultipleCoils(5, [true, true, true, true, true], 5),

        // FOR REGISTERS:
        // FIRST 5 VALUES: [111,222,333,444,555]
        client.writeSingleRegister(0, 111),
        client.writeSingleRegister(1, 222),
        client.writeSingleRegister(2, 333),
        client.writeSingleRegister(3, 444),
        client.writeSingleRegister(4, 555),
        // NEXT 5 VALUES
        // 666,777,888,999,100
        client.writeMultipleRegisters(5, [666, 777, 888, 999, 100]),
        // NEXT 5 VALUES
        // 101,202,303,404,505
        client.writeMultipleRegisters(10, [101, 202, 303, 404, 505])
    ]).then(() => {
        Promise.all([
            client.readCoils(0, 15), // COMPLETE - [1,0,1,0,1,1,1,1,1,1,0,0,0,0,0,0]
            client.readCoils(0, 5), // FIRST 5 COILS - [1,0,1,0,1]
            client.readCoils(5, 5), // NEXT 5 COILS - [1,1,1,1,1]
            client.readCoils(10, 5), // NEXT 5 COILS - [0,0,0,0,0,0]
            client.readHoldingRegisters(0, 15), // COMPLETE - [111,222,333,444,555,666,777,888,999,100,101,202,303,404,505]
            client.readHoldingRegisters(0, 5), // FIRST 5 REGISTERS - [111,222,333,444,555]
            client.readHoldingRegisters(1, 5), // 5 REGISTERS STARTING AT 2nd - [222,333,444,555,666]
            client.readHoldingRegisters(2, 5), // 5 REGISTERS STARTING AT 3rd - [333,444,555,666,777]
            client.readHoldingRegisters(3, 5), // 5 REGISTERS STARTING AT 4th - [444,555,666,777,888]
            client.readHoldingRegisters(4, 5) // 5 REGISTERS STARTING AT 5th - [555,666,777,888,999]
        ]).then((results) => {
            results.forEach((result) => {
                console.log(JSON.stringify(result.response._body._valuesAsArray))
            })

        })
    })
});

socket.on('error', (err) => {
    console.error(err)
});

socket.connect(opts);

The results of running this (Using jsmodbus v3.0.0):

[1,0,1,0,1,1,1,1,1,1,0,0,0,0,0,0]
[1,0,1,0,1,0,0,0]
[1,1,1,1,1,0,0,0]
[0,0,0,0,0,0,0,0]
[111,222,333,444,555,666,777,888,999,100,101,202,303,404,505]
[111,222,333,444,555]
[28416,56833,19713,48130,11010]
[222,333,444,555,666]
[56833,19713,48130,11010,39427]
[333,444,555,666,777]

Seems that coils are doing fine based on the test; but the registers are not.

stefanpoeter commented 6 years ago

Mhh, i am using v3.0.0 already in an application and i don't have any flaws with the holdingRegister requests so far. What server do you use?

wongjasont commented 6 years ago

@stefanpoeter These are my dependencies:

"dependencies": {
    "commander": "^2.15.1",
    "jsmodbus": "^3.0.0",
    "net": "^1.0.2"
  }

I am using this as my server code.

        let net = require('net');
        let modbus = require('jsmodbus');
        let netServer = new net.Server()
        let server = new modbus.server.TCP(netServer);
        let socket = new net.Socket();
        let opts = {
            host: '127.0.0.1',
            port : '5440'
        };
        netServer.listen(5440);
        // OTHER LINES HERE (server.on event listeners)
        socket.connect(opts);

I've based it solely from SimpleServer.js example.

wongjasont commented 6 years ago

@stefanpoeter I traced the buffer itself and found that the function call is weird: client.readHoldingRegisters(0, 15) - Will read 15 32bits registers starting at address 0 client.readHoldingRegisters(1, 15) - Will read 15 32bits registers starting at address 1 Each address holds 16 bits. I've assumed this to be 32bits, this was the case in the simulator from https://github.com/riptideio/modbus-simulator

So in this buffer for example: <Buffer 01 02 03 04 05 06 ... > client.readHoldingRegisters(0, 1) will result to 0x0102 client.readHoldingRegisters(1, 1) will result to 0x0203

BUT mind that (111 = 0x6f, 222 = 0xde) client.writeMultipleRegisters(0, [111]) client.writeMultipleRegisters(1, [222]) will result to the buffer getting: <Buffer 00 6f 00 de ... > Meaning the expected behavior of read is quite different from write. Write will apply in 32bits while the address meant in read is in 16-bit offsets.

Is this THE correct expected behavior? If yes how come the address in write is not same as read, if you get what I mean.

stefanpoeter commented 6 years ago

@wongjasont You probably mean this section in the code

    let startByte = requestBody.start
    let endByte = requestBody.start + (requestBody.count * 2)

and you are right, the startByte should be a multiple of two. I'll put this into the 3.0.1 patch.

stefanpoeter commented 6 years ago

I'll fixed this in branch v3.1.0-dev, thanks for your contribution.