From 9d85a70407d1565f45edd15ba6d4227b9398ca4d Mon Sep 17 00:00:00 2001 From: GermanBluefox Date: Mon, 7 Nov 2016 22:36:21 +0100 Subject: [PATCH 1/3] (bluefox) better processing of TCP and Serial frames. Because one MODBUS frame is not always one TCP/Serial frame. (bluefox) add discrete inputs for TCP server. (bluefox) add modbus RTU over TCP master (bluefox) change a little bit formatting --- src/handler/client/ReadCoils.js | 6 +- src/handler/client/ReadDiscreteInputs.js | 2 +- src/handler/server/ReadCoils.js | 6 +- src/handler/server/ReadDiscreteInputs.js | 8 +- src/handler/server/ReadHoldingRegisters.js | 2 +- src/handler/server/ReadInputRegisters.js | 2 +- src/handler/server/WriteMultipleCoils.js | 2 +- src/handler/server/WriteMultipleRegisters.js | 4 +- src/handler/server/WriteSingleCoil.js | 4 +- src/handler/server/WriteSingleRegister.js | 2 +- src/modbus-serial-client.js | 78 +++++-- src/modbus-server-core.js | 56 +++-- src/modbus-tcp-client.js | 41 ++-- src/modbus-tcp-rtu-client.js | 217 +++++++++++++++++++ src/modbus-tcp-server.js | 144 +++++++----- src/modbus.js | 2 +- 16 files changed, 439 insertions(+), 137 deletions(-) create mode 100644 src/modbus-tcp-rtu-client.js diff --git a/src/handler/client/ReadCoils.js b/src/handler/client/ReadCoils.js index 361a5bb..d9f7be0 100644 --- a/src/handler/client/ReadCoils.js +++ b/src/handler/client/ReadCoils.js @@ -14,11 +14,11 @@ module.exports = Stampit() var onResponse = function (pdu, request) { - this.log.debug("handeling read coils response."); + this.log.debug("handling read coils response."); var fc = pdu.readUInt8(0), - byteCount = pdu.readUInt8(1), - bitCount = byteCount * 8; + byteCount = pdu.readUInt8(1); + //bitCount = byteCount * 8; var resp = { fc : fc, diff --git a/src/handler/client/ReadDiscreteInputs.js b/src/handler/client/ReadDiscreteInputs.js index 850eda2..51ad679 100644 --- a/src/handler/client/ReadDiscreteInputs.js +++ b/src/handler/client/ReadDiscreteInputs.js @@ -14,7 +14,7 @@ module.exports = Stampit() var onResponse = function (pdu, request) { - this.log.debug("handeling read discrete inputs response."); + this.log.debug("handling read discrete inputs response."); var fc = pdu.readUInt8(0), byteCount = pdu.readUInt8(1), diff --git a/src/handler/server/ReadCoils.js b/src/handler/server/ReadCoils.js index 1c813da..7e51ad5 100644 --- a/src/handler/server/ReadCoils.js +++ b/src/handler/server/ReadCoils.js @@ -31,7 +31,7 @@ module.exports = stampit() } - var fc = pdu.readUInt8(0), + var //fc = pdu.readUInt8(0), start = pdu.readUInt16BE(1), quantity = pdu.readUInt16BE(3); @@ -52,8 +52,8 @@ module.exports = stampit() for (var totalBitCount = start; totalBitCount < start + quantity; totalBitCount += 1) { - var buf = mem.readUInt8(Math.floor(totalBitCount / 8)) - var mask = 1 << (totalBitCount % 8) + var buf = mem.readUInt8(Math.floor(totalBitCount / 8)); + var mask = 1 << (totalBitCount % 8); if(buf & mask) { val += 1 << (thisByteBitCount % 8) diff --git a/src/handler/server/ReadDiscreteInputs.js b/src/handler/server/ReadDiscreteInputs.js index 21c6b77..d1a6352 100644 --- a/src/handler/server/ReadDiscreteInputs.js +++ b/src/handler/server/ReadDiscreteInputs.js @@ -31,13 +31,13 @@ var handler = stampit() } - var fc = pdu.readUInt8(0), + var //fc = pdu.readUInt8(0), start = pdu.readUInt16BE(1), quantity = pdu.readUInt16BE(3); this.emit('readDiscreteInputsRequest', start, quantity); - var mem = this.getInput(); + var mem = this.getDiscrete(); if (start > mem.length * 8 || start + quantity > mem.length * 8) { @@ -52,8 +52,8 @@ var handler = stampit() for (var totalBitCount = start; totalBitCount < start + quantity; totalBitCount += 1) { - var buf = mem.readUInt8(Math.floor(totalBitCount / 8)) - var mask = 1 << (totalBitCount % 8) + var buf = mem.readUInt8(Math.floor(totalBitCount / 8)); + var mask = 1 << (totalBitCount % 8); if(buf & mask) { val += 1 << (thisByteBitCount % 8) diff --git a/src/handler/server/ReadHoldingRegisters.js b/src/handler/server/ReadHoldingRegisters.js index 5595135..2bd9d39 100644 --- a/src/handler/server/ReadHoldingRegisters.js +++ b/src/handler/server/ReadHoldingRegisters.js @@ -32,7 +32,7 @@ module.exports = stampit() } - var fc = pdu.readUInt8(0), + var //fc = pdu.readUInt8(0), start = pdu.readUInt16BE(1), byteStart = start * 2, quantity = pdu.readUInt16BE(3); diff --git a/src/handler/server/ReadInputRegisters.js b/src/handler/server/ReadInputRegisters.js index 98c2eb0..574c79a 100644 --- a/src/handler/server/ReadInputRegisters.js +++ b/src/handler/server/ReadInputRegisters.js @@ -30,7 +30,7 @@ module.exports = stampit() } - var fc = pdu.readUInt8(0), + var //fc = pdu.readUInt8(0), start = pdu.readUInt16BE(1), byteStart = start * 2, quantity = pdu.readUInt16BE(3); diff --git a/src/handler/server/WriteMultipleCoils.js b/src/handler/server/WriteMultipleCoils.js index 8865f66..b9ac411 100644 --- a/src/handler/server/WriteMultipleCoils.js +++ b/src/handler/server/WriteMultipleCoils.js @@ -30,7 +30,7 @@ module.exports = stampit() } - var fc = pdu.readUInt8(0), + var //fc = pdu.readUInt8(0), start = pdu.readUInt16BE(1), quantity = pdu.readUInt16BE(3), byteCount = pdu.readUInt8(5); diff --git a/src/handler/server/WriteMultipleRegisters.js b/src/handler/server/WriteMultipleRegisters.js index 33b7992..215d1ab 100644 --- a/src/handler/server/WriteMultipleRegisters.js +++ b/src/handler/server/WriteMultipleRegisters.js @@ -30,7 +30,7 @@ module.exports = stampit() } - var fc = pdu.readUInt8(0), + var //fc = pdu.readUInt8(0), start = pdu.readUInt16BE(1), byteStart = start * 2, quantity = pdu.readUInt16BE(3), @@ -55,7 +55,7 @@ module.exports = stampit() } var response = Put().word8(0x10).word16be(start).word16be(quantity).buffer(), - j = 0, currentByte; + j = 0; for (var i = byteStart; i < byteStart + byteCount; i += 1) { diff --git a/src/handler/server/WriteSingleCoil.js b/src/handler/server/WriteSingleCoil.js index 7d71b19..b5f4b2e 100644 --- a/src/handler/server/WriteSingleCoil.js +++ b/src/handler/server/WriteSingleCoil.js @@ -30,9 +30,9 @@ module.exports = stampit() } - var fc = pdu.readUInt8(0), + var //fc = pdu.readUInt8(0), address = pdu.readUInt16BE(1), - value = pdu.readUInt16BE(3) === 0x0000?false:true; + value = (pdu.readUInt16BE(3) === 0x0000); if (pdu.readUInt16BE(3) !== 0x0000 && pdu.readUInt16BE(3) !== 0xFF00) { diff --git a/src/handler/server/WriteSingleRegister.js b/src/handler/server/WriteSingleRegister.js index 6b2290e..ee00d7d 100644 --- a/src/handler/server/WriteSingleRegister.js +++ b/src/handler/server/WriteSingleRegister.js @@ -30,7 +30,7 @@ module.exports = stampit() } - var fc = pdu.readUInt8(0), + var //fc = pdu.readUInt8(0), address = pdu.readUInt16BE(1), byteAddress = address * 2, value = pdu.readUInt16BE(3); diff --git a/src/modbus-serial-client.js b/src/modbus-serial-client.js index 1b14fff..26d2a23 100644 --- a/src/modbus-serial-client.js +++ b/src/modbus-serial-client.js @@ -10,6 +10,7 @@ module.exports = stampit() var SerialPort = require('serialport'), serialport; + var buffer = new Buffer(0); var init = function () { @@ -68,11 +69,69 @@ module.exports = stampit() }.bind(this); - var onData = function (pdu) { + function toStrArray(buf) { + if (!buf || !buf.length) return ''; + var text = ''; + for (var i = 0; i < buf.length; i++) { + text += (text ? ',' : '') + buf[i]; + } + return text; + } + + var onData = function (data) { - this.log.debug('received data'); - if( crc.crc16modbus(pdu) === 0 ) { /* PDU is valid if CRC across whole PDU equals 0, else ignore and do nothing */ - this.emit('data', pdu.slice(1)); + this.log.debug('received data ' + data.length + ' bytes'); + buffer = Buffer.concat([buffer, data]); + + while (buffer.length > 4) { + + // 1. there is no mbap + // 2. extract pdu + + // 0 - device ID + // 1 - Function CODE + // 2 - Bytes length + // 3.. Data + // checksum.(2 bytes + var len; + var pdu; + // if response for write + if (buffer[1] === 5 || buffer[1] === 6 || buffer[1] === 15 || buffer[1] === 16) { + if (buffer.length < 8) { + break; + } + pdu = buffer.slice(0, 8); // 1 byte device ID + 1 byte FC + 2 bytes address + 2 bytes value + 2 bytes CRC + } else if (buffer[1] > 0 && buffer[1] < 5){ + len = buffer[2]; + + if (buffer.length < len + 5) { + break; + } + + pdu = buffer.slice(0, len + 5); // 1 byte deviceID + 1 byte FC + 1 byte length + 2 bytes CRC + } else { + // unknown function code + this.logError('unknown function code: ' + buffer[1]); + // reset buffer and try again + buffer = []; + break; + } + + if (crc.crc16modbus(pdu) === 0) { /* PDU is valid if CRC across whole PDU equals 0, else ignore and do nothing */ + if (pdu[0] !== this.unitId) { + // answer for wrong device + this.log.debug('received answer for wrong ID ' + buffer[0] + ', expected ' + this.unitId); + } + // emit data event and let the + // listener handle the pdu + this.emit('data', pdu.slice(1, pdu.length - 2)); + } else { + this.logError('Wrong CRC for frame: ' + toStrArray(pdu)); + // reset buffer and try again + buffer = []; + break; + } + buffer = buffer.slice(pdu.length, buffer.length); } }.bind(this); @@ -90,20 +149,13 @@ module.exports = stampit() .put(pdu), buf = pkt.buffer(); - crc16 = 0; - crc16= crc.crc16modbus(buf); - pkt = pkt.word16le(crc16).buffer(); - - - for (var j = 0; j < pkt.length; j += 1) { - console.log(pkt.readUInt8(j).toString(16)); - } + var crc16 = crc.crc16modbus(buf); + pkt = pkt.word16le(crc16).buffer(); serialport.write(pkt, function (err) { if (err) { this.emit('error', err); - return; } }.bind(this)); diff --git a/src/modbus-server-core.js b/src/modbus-server-core.js index 99205d0..5bb7274 100644 --- a/src/modbus-server-core.js +++ b/src/modbus-server-core.js @@ -3,11 +3,11 @@ var stampit = require('stampit'), EventBus = require('stampit-event-bus'), Log = require('stampit-log'); - var core = stampit() +var core = stampit() .compose(EventBus, Log) .init(function () { - - var coils, holding, input, handler = { }; + + var coils, holding, input, discrete, handler = { }; var init = function () { @@ -28,71 +28,81 @@ var stampit = require('stampit'), } else { input = this.input; } - + if (!this.discrete) { + discrete = new Buffer(1024); + } else { + discrete = this.discrete; + } }.bind(this); this.onData = function (pdu, callback) { - // get fc and byteCount in advance - var fc = pdu.readUInt8(0), - byteCount = pdu.readUInt8(1); + // get fc and byteCount in advance + var fc = pdu.readUInt8(0); + //byteCount = pdu.readUInt8(1); // get the pdu handler var reqHandler = handler[fc]; if (!reqHandler) { - // write a error/exception pkt to the + // write a error/exception pkt to the // socket with error code fc + 0x80 and // exception code 0x01 (Illegal Function) - + this.log.debug('no handler for fc', fc); callback(Put().word8(fc + 0x80).word8(0x01).buffer()); return; - + } reqHandler(pdu, function (response) { - + callback(response); - + }.bind(this)); - + }.bind(this); this.setRequestHandler = function (fc, callback) { - + this.log.debug('setting request handler', fc); handler[fc] = callback; return this; - + }; this.getCoils = function () { - + return coils; - + }; this.getInput = function () { - + return input; - + }; this.getHolding = function () { - + return holding; - + + }; + + this.getDiscrete = function () { + + return discrete; + }; init(); - + }); - module.exports = core; +module.exports = core; diff --git a/src/modbus-tcp-client.js b/src/modbus-tcp-client.js index b71cdb9..313f128 100644 --- a/src/modbus-tcp-client.js +++ b/src/modbus-tcp-client.js @@ -11,7 +11,8 @@ module.exports = stampit() currentRequestId = reqId, closedOnPurpose = false, reconnect = false, - trashRequestId, + buffer = new Buffer(0), + trashRequestId, socket; var init = function () { @@ -93,41 +94,39 @@ module.exports = stampit() this.log.debug('received data'); - var cnt = 0; + buffer = Buffer.concat([buffer, data]); - while (cnt < data.length) { + while (buffer.length > 8) { // 1. extract mbap - var mbap = data.slice(cnt, cnt + 7), - id = mbap.readUInt16BE(0), - len = mbap.readUInt16BE(4); + var id = buffer.readUInt16BE(0), + len = buffer.readUInt16BE(4); - if (id === trashRequestId) { - - this.log.debug('current mbap contains trashed request id.'); - - return; + this.log.debug('MBAP extracted'); + // 2. extract pdu + if (buffer.length < 7 + len - 1) { + break; } - cnt += 7; - - this.log.debug('MBAP extracted'); + var pdu = buffer.slice(7, 7 + len - 1); - // 2. extract pdu + this.log.debug('PDU extracted'); - var pdu = data.slice(cnt, cnt + len - 1); + if (id === trashRequestId) { - cnt += pdu.length; + this.log.debug('current mbap contains trashed request id.'); - this.log.debug('PDU extracted'); + } else { - // emit data event and let the - // listener handle the pdu + // emit data event and let the + // listener handle the pdu + this.emit('data', pdu); - this.emit('data', pdu); + } + buffer = buffer.slice(pdu.length + 7, buffer.length); } }.bind(this); diff --git a/src/modbus-tcp-rtu-client.js b/src/modbus-tcp-rtu-client.js new file mode 100644 index 0000000..aef85a9 --- /dev/null +++ b/src/modbus-tcp-rtu-client.js @@ -0,0 +1,217 @@ +var stampit = require('stampit'), + Put = require('put'), + crc = require('crc'), + Net = require('net'), + ModbusCore = require('./modbus-client-core.js'); + +module.exports = stampit() + .compose(ModbusCore) + .init(function () { + + var closedOnPurpose = false, + reconnect = false, + buffer = new Buffer(0), + crc16, + socket; + + var init = function () { + + this.setState('init'); + + if (!this.unitId) { this.unitId = 0; } + if (!this.protocolVersion) { this.protocolVersion = 0; } + if (!this.port) { this.port = 502; } + if (!this.host) { this.host = 'localhost'; } + if (!this.autoReconnect) { this.autoReconnect = false; } + if (!this.reconnectTimeout) { this.reconnectTimeout = 0; } + + this.on('send', onSend); + this.on('newState_error', onError); + + this.on('stateChanged', this.log.debug); + + }.bind(this); + + var connect = function () { + + this.setState('connect'); + + if (!socket) { + + socket = new Net.Socket(); + + socket.on('connect', onSocketConnect); + socket.on('close', onSocketClose); + socket.on('error', onSocketError); + socket.on('data', onSocketData); + + } + + socket.connect(this.port, this.host); + + }.bind(this); + + var onSocketConnect = function () { + + this.emit('connect'); + this.setState('ready'); + + }.bind(this); + + var onSocketClose = function (hadErrors) { + + this.log.debug('Socket closed with error', hadErrors); + + this.setState('closed'); + this.emit('close'); + + if (!closedOnPurpose && (this.autoReconnect || reconnect)) { + + setTimeout(function () { + + reconnect = false; + + connect(); + }, this.reconnectTimeout || 0); + + } + + }.bind(this); + + var onSocketError = function (err) { + + this.logError('Socket Error', err); + + this.setState('error'); + this.emit('error', err); + + }.bind(this); + + function toStrArray(buf) { + if (!buf || !buf.length) return ''; + var text = ''; + for (var i = 0; i < buf.length; i++) { + text += (text ? ',' : '') + buf[i]; + } + return text; + } + + var onSocketData = function (data) { + + this.log.debug('received data'); + + buffer = Buffer.concat([buffer, data]); + + while (buffer.length > 4) { + + // 1. there is no mbap + // 2. extract pdu + + // 0 - device ID + // 1 - Function CODE + // 2 - Bytes length + // 3.. Data + // checksum.(2 bytes + var len; + var pdu; + // if response for write + if (buffer[1] === 5 || buffer[1] === 6 || buffer[1] === 15 || buffer[1] === 16) { + if (buffer.length < 8) break; + pdu = buffer.slice(0, 8); // 1 byte device ID + 1 byte FC + 2 bytes address + 2 bytes value + 2 bytes CRC + } else if (buffer[1] > 0 && buffer[1] < 5){ + len = buffer[2]; + if (buffer.length < len + 5) break; + pdu = buffer.slice(0, len + 5); // 1 byte deviceID + 1 byte FC + 1 byte length + 2 bytes CRC + } else { + // unknown function code + this.logError('unknown function code: ' + buffer[1]); + // reset buffer and try again + buffer = []; + break; + } + + if (crc.crc16modbus(pdu) === 0) { /* PDU is valid if CRC across whole PDU equals 0, else ignore and do nothing */ + if (pdu[0] !== this.unitId) { + // answer for wrong device + this.log.debug('received answer for wrong ID ' + buffer[0] + ', expected ' + this.unitId); + } + // emit data event and let the + // listener handle the pdu + this.emit('data', pdu.slice(1, pdu.length - 2)); + } else { + this.logError('Wrong CRC for frame: ' + toStrArray(pdu)); + // reset buffer and try again + buffer = []; + break; + } + buffer = buffer.slice(pdu.length, buffer.length); + } + }.bind(this); + + var onError = function () { + + this.logError('Client in error state.'); + + socket.destroy(); + + }.bind(this); + + + var onSend = function (pdu) { + + this.log.debug('Sending pdu to the socket.'); + + var pkt = Put() + .word8(this.unitId) // unit id + .put(pdu); // the actual pdu + + var buf = pkt.buffer(); + crc16 = crc.crc16modbus(buf); + pkt = pkt.word16le(crc16).buffer(); + + socket.write(pkt); + + }.bind(this); + + this.connect = function () { + + this.setState('connect'); + + connect(); + + return this; + + }; + + this.reconnect = function () { + + if (!this.inState('closed')) { + return this; + } + + closedOnPurpose = false; + reconnect = true; + + this.log.debug('Reconnecting client.'); + + socket.end(); + + return this; + + }; + + this.close = function () { + + closedOnPurpose = true; + + this.log.debug('Closing client on purpose.'); + + socket.end(); + + return this; + + }; + + init(); + + }); diff --git a/src/modbus-tcp-server.js b/src/modbus-tcp-server.js index f87cfc2..3d013de 100644 --- a/src/modbus-tcp-server.js +++ b/src/modbus-tcp-server.js @@ -8,12 +8,14 @@ module.exports = stampit() .compose(ModbusServerCore) .compose(StateMachine) .init(function () { - + 'use strict'; + var server, socketCount = 0, fifo = []; - var clients = [] + var clients = []; + var buffer = new Buffer(0); var init = function () { - + if (!this.port) { this.port = 502; } @@ -23,28 +25,32 @@ module.exports = stampit() } server = net.createServer(); - + server.on('connection', function (s) { this.log.debug('new connection', s.address()); - - clients.push(s) + + clients.push(s); initiateSocket(s); - + this.emit('connection', s.address()); + }.bind(this)); + server.on('disconnect', function (s) { + this.emit('close', s.address()); + }); + server.listen(this.port, this.hostname, function (err) { - + if (err) { - + this.log.debug('error while listening', err); this.emit('error', err); - return; } }.bind(this)); - + this.log.debug('server is listening on port', this.hostname + ':' + this.port); this.on('newState_ready', flush); @@ -54,48 +60,61 @@ module.exports = stampit() }.bind(this); var onSocketEnd = function (socket, socketId) { - + return function () { - + this.emit('close'); this.log.debug('connection closed, socket', socketId); - + }.bind(this); - + }.bind(this); var onSocketData = function (socket, socketId) { - + return function (data) { - this.log.debug('received data socket',socketId, data.byteLength); + this.log.debug('received data socket', socketId, data.byteLength); + + buffer = Buffer.concat([buffer, data]); + + while (buffer.length > 8) { + + // 1. extract mbap - // 1. extract mbap + var len = buffer.readUInt16BE(4); + var request = { + trans_id: buffer.readUInt16BE(0), + protocol_ver: buffer.readUInt16BE(2), + unit_id: buffer.readUInt8(6) + }; - var mbap = data.slice(0, 0 + 7), - len = mbap.readUInt16BE(4); - request = { - trans_id: mbap.readUInt16BE(0), - protocol_ver: mbap.readUInt16BE(2), - unit_id: mbap.readUInt8(6) - }; + this.log.debug('MBAP extracted'); - // 2. extract pdu + // 2. extract pdu + if (buffer.length < 7 + len - 1) { + break; // wait for next bytes + } - var pdu = data.slice(7, 7 + len - 1); + var pdu = buffer.slice(7, 7 + len - 1); - // emit data event and let the - // listener handle the pdu + this.log.debug('PDU extracted'); - fifo.push({ request : request, pdu : pdu, socket : socket }); + // emit data event and let the + // listener handle the pdu + + fifo.push({ request : request, pdu : pdu, socket : socket }); + + flush(); + + buffer = buffer.slice(pdu.length + 7, buffer.length); + } - flush(); - }.bind(this); - + }.bind(this); var flush = function () { - + if (this.inState('processing')) { return; } @@ -109,10 +128,10 @@ module.exports = stampit() var current = fifo.shift(); this.onData(current.pdu, function (response) { - + this.log.debug('sending tcp data'); - var pkt = Put() + var pkt = Put() .word16be(current.request.trans_id) // transaction id .word16be(current.request.protocol_ver) // protocol version .word16be(response.length + 1) // pdu length @@ -120,49 +139,54 @@ module.exports = stampit() .put(response) // the actual pdu .buffer(); - current.socket.write(pkt); - + current.socket.write(pkt); + this.setState('ready'); }.bind(this)); - + }.bind(this); var onSocketError = function (socket, socketCount) { - + return function (e) { - - this.logError('Socker error', e); - + this.emit('error', e); + + this.logError('Socket error', e); + }.bind(this); - - + + }.bind(this); var initiateSocket = function (socket) { - + socketCount += 1; socket.on('end', onSocketEnd(socket, socketCount)); socket.on('data', onSocketData(socket, socketCount)); socket.on('error', onSocketError(socket, socketCount)); - - }.bind(this); + + }.bind(this); this.close = function (cb) { - - for(var c in clients) { - clients[c].destroy() - } - - server.close(function() { - server.unref() - if(cb) { cb() } - }); - + + for(var c in clients) { + clients[c].destroy() + } + + server.close(function() { + server.unref(); + if(cb) { cb() } + }); + + }; + + this.getClients = function () { + return clients; }; init(); - - + + }); diff --git a/src/modbus.js b/src/modbus.js index b244338..25be15b 100644 --- a/src/modbus.js +++ b/src/modbus.js @@ -31,7 +31,7 @@ fs.readdirSync(__dirname + '/handler/client') exports.server = { tcp : { core : require('./modbus-tcp-server.js'), - complete : require('./modbus-tcp-server.js'), + complete : require('./modbus-tcp-server.js') }, handler : { } }; From 2a588edae4ccc426de70876ecfcb3eed7678cd7a Mon Sep 17 00:00:00 2001 From: GermanBluefox Date: Thu, 24 Nov 2016 15:01:59 +0100 Subject: [PATCH 2/3] (bluefox) remove rtu-client --- src/modbus-tcp-client.js | 6 +- src/modbus-tcp-rtu-client.js | 217 ----------------------------------- 2 files changed, 3 insertions(+), 220 deletions(-) delete mode 100644 src/modbus-tcp-rtu-client.js diff --git a/src/modbus-tcp-client.js b/src/modbus-tcp-client.js index 837f141..6cebca4 100644 --- a/src/modbus-tcp-client.js +++ b/src/modbus-tcp-client.js @@ -179,11 +179,11 @@ module.exports = stampit() return socket } this.setCurrentRequestId = function (id) { - currentRequestId = id + currentRequestId = id } this.registerOnSend = function (_onSend) { - this.removeListener(onSend) - this.on('send', _onSend.bind(this)) + this.removeListener(onSend) + this.on('send', _onSend.bind(this)) } } diff --git a/src/modbus-tcp-rtu-client.js b/src/modbus-tcp-rtu-client.js deleted file mode 100644 index aef85a9..0000000 --- a/src/modbus-tcp-rtu-client.js +++ /dev/null @@ -1,217 +0,0 @@ -var stampit = require('stampit'), - Put = require('put'), - crc = require('crc'), - Net = require('net'), - ModbusCore = require('./modbus-client-core.js'); - -module.exports = stampit() - .compose(ModbusCore) - .init(function () { - - var closedOnPurpose = false, - reconnect = false, - buffer = new Buffer(0), - crc16, - socket; - - var init = function () { - - this.setState('init'); - - if (!this.unitId) { this.unitId = 0; } - if (!this.protocolVersion) { this.protocolVersion = 0; } - if (!this.port) { this.port = 502; } - if (!this.host) { this.host = 'localhost'; } - if (!this.autoReconnect) { this.autoReconnect = false; } - if (!this.reconnectTimeout) { this.reconnectTimeout = 0; } - - this.on('send', onSend); - this.on('newState_error', onError); - - this.on('stateChanged', this.log.debug); - - }.bind(this); - - var connect = function () { - - this.setState('connect'); - - if (!socket) { - - socket = new Net.Socket(); - - socket.on('connect', onSocketConnect); - socket.on('close', onSocketClose); - socket.on('error', onSocketError); - socket.on('data', onSocketData); - - } - - socket.connect(this.port, this.host); - - }.bind(this); - - var onSocketConnect = function () { - - this.emit('connect'); - this.setState('ready'); - - }.bind(this); - - var onSocketClose = function (hadErrors) { - - this.log.debug('Socket closed with error', hadErrors); - - this.setState('closed'); - this.emit('close'); - - if (!closedOnPurpose && (this.autoReconnect || reconnect)) { - - setTimeout(function () { - - reconnect = false; - - connect(); - }, this.reconnectTimeout || 0); - - } - - }.bind(this); - - var onSocketError = function (err) { - - this.logError('Socket Error', err); - - this.setState('error'); - this.emit('error', err); - - }.bind(this); - - function toStrArray(buf) { - if (!buf || !buf.length) return ''; - var text = ''; - for (var i = 0; i < buf.length; i++) { - text += (text ? ',' : '') + buf[i]; - } - return text; - } - - var onSocketData = function (data) { - - this.log.debug('received data'); - - buffer = Buffer.concat([buffer, data]); - - while (buffer.length > 4) { - - // 1. there is no mbap - // 2. extract pdu - - // 0 - device ID - // 1 - Function CODE - // 2 - Bytes length - // 3.. Data - // checksum.(2 bytes - var len; - var pdu; - // if response for write - if (buffer[1] === 5 || buffer[1] === 6 || buffer[1] === 15 || buffer[1] === 16) { - if (buffer.length < 8) break; - pdu = buffer.slice(0, 8); // 1 byte device ID + 1 byte FC + 2 bytes address + 2 bytes value + 2 bytes CRC - } else if (buffer[1] > 0 && buffer[1] < 5){ - len = buffer[2]; - if (buffer.length < len + 5) break; - pdu = buffer.slice(0, len + 5); // 1 byte deviceID + 1 byte FC + 1 byte length + 2 bytes CRC - } else { - // unknown function code - this.logError('unknown function code: ' + buffer[1]); - // reset buffer and try again - buffer = []; - break; - } - - if (crc.crc16modbus(pdu) === 0) { /* PDU is valid if CRC across whole PDU equals 0, else ignore and do nothing */ - if (pdu[0] !== this.unitId) { - // answer for wrong device - this.log.debug('received answer for wrong ID ' + buffer[0] + ', expected ' + this.unitId); - } - // emit data event and let the - // listener handle the pdu - this.emit('data', pdu.slice(1, pdu.length - 2)); - } else { - this.logError('Wrong CRC for frame: ' + toStrArray(pdu)); - // reset buffer and try again - buffer = []; - break; - } - buffer = buffer.slice(pdu.length, buffer.length); - } - }.bind(this); - - var onError = function () { - - this.logError('Client in error state.'); - - socket.destroy(); - - }.bind(this); - - - var onSend = function (pdu) { - - this.log.debug('Sending pdu to the socket.'); - - var pkt = Put() - .word8(this.unitId) // unit id - .put(pdu); // the actual pdu - - var buf = pkt.buffer(); - crc16 = crc.crc16modbus(buf); - pkt = pkt.word16le(crc16).buffer(); - - socket.write(pkt); - - }.bind(this); - - this.connect = function () { - - this.setState('connect'); - - connect(); - - return this; - - }; - - this.reconnect = function () { - - if (!this.inState('closed')) { - return this; - } - - closedOnPurpose = false; - reconnect = true; - - this.log.debug('Reconnecting client.'); - - socket.end(); - - return this; - - }; - - this.close = function () { - - closedOnPurpose = true; - - this.log.debug('Closing client on purpose.'); - - socket.end(); - - return this; - - }; - - init(); - - }); From 203069714cac8ebc5825d93e15b587d1b22cfa29 Mon Sep 17 00:00:00 2001 From: GermanBluefox Date: Thu, 24 Nov 2016 15:03:11 +0100 Subject: [PATCH 3/3] (bluefox) remove let --- test/heap-test-coils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/heap-test-coils.js b/test/heap-test-coils.js index 5e11d92..0b1f5cb 100644 --- a/test/heap-test-coils.js +++ b/test/heap-test-coils.js @@ -11,7 +11,7 @@ const client = modbus.client.tcp.complete({ client.connect() client.on('connect', function () { - for (let i = 1; i < 1e5; i++) { + for (var i = 1; i < 1e5; i++) { client.readCoils(0, 13) }