diff --git a/src/modbus-tcp-client.js b/src/modbus-tcp-client.js index 6cebca4..f120deb 100644 --- a/src/modbus-tcp-client.js +++ b/src/modbus-tcp-client.js @@ -1,17 +1,15 @@ 'use strict' var stampit = require('stampit') -var Net = require('net') -var ModbusCore = require('./modbus-client-core.js') module.exports = stampit() - .compose(ModbusCore) .init(function () { var reqId = 0 var currentRequestId = reqId var closedOnPurpose = false var reconnect = false var trashRequestId + var buffer = Buffer.alloc(0) var socket var init = function () { @@ -35,8 +33,13 @@ module.exports = stampit() this.setState('connect') if (!socket) { - socket = new Net.Socket() - + /* for testing you are able to inject a mocking object + * a simple event object should do the trick */ + if (this.injectedSocket) { + socket = this.injectedSocket + } else { + socket = require('net').Socket() + } socket.on('connect', onSocketConnect) socket.on('close', onSocketClose) socket.on('error', onSocketError) @@ -76,14 +79,13 @@ module.exports = stampit() var onSocketData = function (data) { this.log.debug('received data') - var cnt = 0 + buffer = Buffer.concat([buffer, data]) - while (cnt < data.length) { + while (buffer.length > 7) { // 1. extract mbap - var mbap = data.slice(cnt, cnt + 7) - var id = mbap.readUInt16BE(0) - var len = mbap.readUInt16BE(4) + var id = buffer.readUInt16BE(0) + var len = buffer.readUInt16BE(4) if (id === trashRequestId) { this.log.debug('current mbap contains trashed request id.') @@ -91,15 +93,14 @@ module.exports = stampit() return } - cnt += 7 - - this.log.debug('MBAP extracted') + /* Not all data received yet. */ + if (buffer.length < 7 + len - 1) { + break + } // 2. extract pdu - var pdu = data.slice(cnt, cnt + len - 1) - - cnt += pdu.length + var pdu = buffer.slice(7, 7 + len - 1) this.log.debug('PDU extracted') @@ -107,6 +108,8 @@ module.exports = stampit() // listener handle the pdu this.emit('data', pdu) + + buffer = buffer.slice(pdu.length + 7, buffer.length) } }.bind(this) diff --git a/src/modbus-tcp-server.js b/src/modbus-tcp-server.js index c490874..f7f576d 100644 --- a/src/modbus-tcp-server.js +++ b/src/modbus-tcp-server.js @@ -81,12 +81,12 @@ module.exports = stampit() var initiateSocket = function (socket) { let socketId = socketList.length - let requestHandler = function (req) { + var requestHandler = function (req) { fifo.push(req) flush() } - let removeHandler = function () { + var removeHandler = function () { socketList[socketId] = undefined /* remove undefined on the end of the array */ for (let i = socketList.length - 1; i >= 0; i -= 1) { @@ -97,8 +97,8 @@ module.exports = stampit() socketList.splice(i, 1) } - console.log(socketList) - } + this.log.debug('Client connection closed, remaining clients. ', socketList.length) + }.bind(this) let clientSocket = ClientSocket({ socket: socket, @@ -108,7 +108,7 @@ module.exports = stampit() }) socketList.push(clientSocket) - } + }.bind(this) this.close = function (cb) { for (var c in clients) { diff --git a/src/modbus.js b/src/modbus.js index 33d2736..2299862 100644 --- a/src/modbus.js +++ b/src/modbus.js @@ -2,11 +2,13 @@ var fs = require('fs') var path = require('path') +var ModbusCore = require('./modbus-client-core.js') +var ModbusTcpClient = require('./modbus-tcp-client.js') exports.client = { tcp: { - core: require('./modbus-tcp-client.js'), - complete: require('./modbus-tcp-client.js') + core: ModbusCore.compose(ModbusTcpClient), + complete: ModbusCore.compose(ModbusTcpClient) }, serial: { core: require('./modbus-serial-client.js'), diff --git a/test/modbus-tcp.test.js b/test/modbus-tcp.test.js index 61a034d..ddba189 100644 --- a/test/modbus-tcp.test.js +++ b/test/modbus-tcp.test.js @@ -4,7 +4,7 @@ var assert = require('assert') var EventEmitter = require('events') describe('Modbus TCP Tests.', function () { - describe('Chopped Data Tests (Server Side).', function () { + describe('Server Tests.', function () { /* We are using the read coils request for the chopped data tests. */ let ClientSocket = require('../src/modbus-tcp-server-client.js') @@ -47,4 +47,46 @@ describe('Modbus TCP Tests.', function () { }) }) }) + + describe('Client Tests.', function () { + var stampit = require('stampit') + var StateMachine = require('stampit-state-machine') + var Logger = require('stampit-log') + + it('should handle a chopped data request fine.', function (done) { + var ModbusTcpClient = require('../src/modbus-tcp-client.js') + var injectedSocket = new EventEmitter() + var exResponse = Buffer.from([0x01, 0x02, 0x055, 0x01]) + + /* dummy method */ + injectedSocket.connect = function () { } + + /* create the client by composing + * logger, state machine and the tcp client, + * normally the logger and the state machine + * come with the modbus client core. */ + var client = stampit() + .compose(Logger) + .compose(StateMachine) + .compose(ModbusTcpClient)({ + injectedSocket: injectedSocket + }) + + /* connect to whatever and confirm */ + client.connect() + + injectedSocket.emit('connect') + + /* fetch send data and compare */ + client.on('data', function (data) { + assert.equal(data.compare(exResponse), 0) + done() + }) + + /* Send header data */ + injectedSocket.emit('data', Buffer.from([0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x01])) + /* emitting a read coils request (start = 0, count = 10) */ + injectedSocket.emit('data', Buffer.from([0x01, 0x02, 0x55, 0x01])) + }) + }) })