Cloud-Automation / node-modbus

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

Server Example seems to be broken #269

Closed Byorun closed 3 years ago

Byorun commented 4 years ago

If I try to run the simple-server example my IDE and node (when executed)

image

this error is thrown for

Byorun commented 4 years ago

I put togther a code snippet to test all events (according to modbus-server)

import * as Modbus from "jsmodbus"
import {Server} from 'net'

const netServer = new Server()
const initialHoldingRegisters = Buffer.alloc(10000)
const server = new Modbus.server.TCP(netServer, {
    holding: initialHoldingRegisters
})

server.on('connection', (client) => {
    console.log('connection')
})
server.on('readCoils', (request, cb) => {
    console.log('readCoils')
})
server.on('preReadCoils', (request, cb) => {
    console.log('preReadCoils')
})
server.on('postReadCoils', (request, cb) => {
    console.log('postReadCoils')
})
server.on('readDiscreteInputs', (request, cb) => {
    console.log('readDiscreteInputs')
})
server.on('preReadDiscreteInputs', (request, cb) => {
    console.log('preReadDiscreteInputs')
})
server.on('postReadDiscreteInputs', (request, cb) => {
    console.log('postReadDiscreteInputs')
})
server.on('readHoldingRegisters', (request, cb) => {
    console.log('readHoldingRegisters')
})
server.on('preReadHoldingRegisters', (request, cb) => {
    console.log('preReadHoldingRegisters')
})
server.on('postReadHoldingRegisters', (request, cb) => {
    console.log('postReadHoldingRegisters')
})
server.on('readInputRegisters', (request, cb) => {
    console.log('readInputRegisters')
})
server.on('preReadInputRegisters', (request, cb) => {
    console.log('preReadInputRegisters')
})
server.on('postReadInputRegisters', (request, cb) => {
    console.log('postReadInputRegisters')
})
server.on('writeSingleCoil', (request, cb) => {
    console.log('writeSingleCoil')
})
server.on('preWriteSingleCoil', (request, cb) => {
    console.log('preWriteSingleCoil')
})
server.on('postWriteSingleCoil', (request, cb) => {
    console.log('postWriteSingleCoil')
})
server.on('writeSingleRegister', (request, cb) => {
    console.log('writeSingleRegister')
})
server.on('preWriteSingleRegister', (request, cb) => {
    console.log('preWriteSingleRegister')
})
server.on('postWriteSingleRegister', (request, cb) => {
    console.log('postWriteSingleRegister')
})
server.on('writeMultipleCoils', (request, cb) => {
    console.log('writeMultipleCoils')
})
server.on('preWriteMultipleCoils', (request, cb) => {
    console.log('preWriteMultipleCoils')
})
server.on('writeMultipleCoils', (coils, oldStatus) => {
    console.log('writeMultipleCoils')
})
server.on('postWriteMultipleCoils', (coils, newStatus) => {
    console.log('postWriteMultipleCoils')
})
server.on('postWriteMultipleCoils', (request, cb) => {
    console.log('postWriteMultipleCoils')
})
server.on('writeMultipleRegisters', (request, cb) => {
    console.log('writeMultipleRegisters')
})
server.on('preWriteMultipleRegisters', (request, cb) => {
    console.log('preWriteMultipleRegisters')
})
server.on('writeMultipleRegisters', (holdingRegisters) => {
    console.log('writeMultipleRegisters')
})
server.on('postWriteMultipleRegisters', (holdingRegisters) => {
    console.log('postWriteMultipleRegisters')
})
server.on('postWriteMultipleRegisters', (request, cb) => {
    console.log('postWriteMultipleRegisters')
})

netServer.listen(502)

connection preReadCoils postReadCoils preReadDiscreteInputs postReadDiscreteInputs preReadHoldingRegisters postReadHoldingRegisters preReadInputRegisters postReadInputRegisters preWriteSingleCoil postWriteSingleCoil preWriteSingleRegister postWriteSingleRegister preWriteMultipleRegisters writeMultipleRegisters writeMultipleRegisters postWriteMultipleRegisters postWriteMultipleRegisters postWriteMultipleRegisters postWriteMultipleRegisters preWriteMultipleCoils writeMultipleCoils writeMultipleCoils postWriteMultipleCoils postWriteMultipleCoils postWriteMultipleCoils postWriteMultipleCoils

In addition it is not clear (for me at least) how I should use the BufferCB while handling the event

alexbuczynsky commented 4 years ago

This seems to be a bug caused by the on(event) overload for the "connection" event: https://github.com/Cloud-Automation/node-modbus/blob/f348a56c9e0a33149d7c465abfbb7abcdf7e9579/src/modbus-server.ts#L65

https://github.com/Cloud-Automation/node-modbus/blob/f348a56c9e0a33149d7c465abfbb7abcdf7e9579/src/modbus-server.ts#L94

The type overload needs to be investigated. I will do that and report back here

alexbuczynsky commented 4 years ago

In addition it is not clear (for me at least) how I should use the BufferCB while handling the event From my understanding, the callback can be optionally called to send a response back to the client for that request. You can use this as an interceptor to prevent users from writing invalid data to specific portions of the buffer for example.

It is used by the ModbusServerClient to send the payload from a read / write request back to the socket: https://github.com/Cloud-Automation/node-modbus/blob/f348a56c9e0a33149d7c465abfbb7abcdf7e9579/src/modbus-server-client.ts#L55-L59

@stefanpoeter could maybe provide more insight.

stefanpoeter commented 4 years ago

Well that makes no sense to me either.

In addition it is not clear (for me at least) how I should use the BufferCB while handling the event From my understanding, the callback can be optionally called to send a response back to the client for that request. You can use this as an interceptor to prevent users from writing invalid data to specific portions of the buffer for example.

The main Idea is that you can react to the request but cannot alter them. The ability to alter the response is probably a good addition. For example one should be able to throw an exception in the listener and therefor changing the response. The buffer in the callback and the callback itself makes no sense, don't know how this got there :-). I think that was an attempt to async the request but went totally wrong.

This might be a possible extension for the listener


  private _handleReadCoil (request: ModbusAbstractRequest, cb: (buffer: Buffer) => void) {

    ...

  try {
   this._server.emit('preReadCoils', request)
  } catch (e) {
    //send alternative payload with an error response body.
    return;
  }

    const responseBody = ReadCoilsResponseBody.fromRequest(request.body, this._server.coils)
    const response = this._fromRequest(request, responseBody)
    const payload = response.createPayload()
    cb(payload)

    // throwing an exception does not make sense here since the resonse has already been issued
    this._server.emit('postReadCoils', request)

  }

For writing the main events from WriteSingleCoil and WriteSingleRegister are missing

Should be fixed easily.

stif commented 4 years ago

I also experienced this bug (only pre and post events fired):

preReadDiscreteInputs postReadDiscreteInputs

unfortunately it is not clear to me how to fix it, so i will move on an try another module..

robot2045 commented 4 years ago

I'm also experiencing this problem, any solution ? @alexbuczynsky @stefanpoeter server.on('readCoils', function (request, response, send) is never reached