modbus-serial
Advanced tools
Comparing version 4.0.0 to 4.0.1
{ | ||
"name": "modbus-serial", | ||
"version": "4.0.0", | ||
"version": "4.0.1", | ||
"description": "A pure JavaScript implemetation of MODBUS-RTU (and TCP) for NodeJS.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -6,30 +6,9 @@ 'use strict'; | ||
var crc16 = require('./../utils/crc16'); | ||
var EXCEPTION_LENGTH = 5; | ||
/** | ||
* check if a buffer chunk can be a modbus answer | ||
* or modbus exception | ||
* | ||
* @param {RTUBufferedPort} modbus | ||
* @param {Buffer} buf the buffer to check. | ||
* @return {boolean} if the buffer can be an answer | ||
*/ | ||
function checkData(modbus, buf) { | ||
// check buffer size | ||
if (buf.length != modbus._length && buf.length != 5) return false; | ||
// calculate crc16 | ||
var crcIn = buf.readUInt16LE(buf.length - 2); | ||
// check buffer unit-id, command and crc | ||
return (buf[0] == modbus._id && | ||
(0x7f & buf[1]) == modbus._cmd && | ||
crcIn == crc16(buf.slice(0, -2))); | ||
} | ||
/** | ||
* Simulate a modbus-RTU port using buffered serial connection | ||
*/ | ||
var RTUBufferedPort = function(path, options) { | ||
var modbus = this; | ||
var self = this; | ||
@@ -49,35 +28,30 @@ // options | ||
// register the port data event | ||
this._client.on('data', function(data) { | ||
/* add data to buffer | ||
*/ | ||
modbus._buffer = Buffer.concat([modbus._buffer, data]); | ||
this._client.on('data', function onData(data) { | ||
// add data to buffer | ||
self._buffer = Buffer.concat([self._buffer, data]); | ||
/* check if buffer include a complete modbus answer | ||
*/ | ||
var length = modbus._length; | ||
var bufferLength = modbus._buffer.length ; | ||
// check if buffer include a complete modbus answer | ||
var expectedLength = self._length; | ||
var bufferLength = self._buffer.length ; | ||
// check data length | ||
if (bufferLength < 5 || length < 6) return; | ||
if (expectedLength < 6 || bufferLength < EXCEPTION_LENGTH) return; | ||
// loop and check length-sized buffer chunks | ||
for (var i = 0; i < (bufferLength - length + 1); i++) { | ||
// cut a length of bytes from buffer | ||
var _data = modbus._buffer.slice(i, i + length); | ||
var maxOffset = bufferLength - EXCEPTION_LENGTH; | ||
for (var i = 0; i <= maxOffset; i++) { | ||
var unitId = self._buffer[i]; | ||
var functionCode = self._buffer[i+1]; | ||
// check if this is the data we are waiting for | ||
if (checkData(modbus, _data)) { | ||
// adjust i to end of data chunk | ||
i = i + length; | ||
if (unitId !== self._id) continue; | ||
// emit a data signal | ||
modbus.emit('data', _data); | ||
if (functionCode === self._cmd && i + expectedLength <= bufferLength) { | ||
self._emitData(i, expectedLength); | ||
return; | ||
} | ||
if (functionCode === (0x80 | self._cmd) && i + EXCEPTION_LENGTH <= bufferLength) { | ||
self._emitData(i, EXCEPTION_LENGTH); | ||
return; | ||
} | ||
} | ||
/* cut checked data from buffer | ||
*/ | ||
if (i) { | ||
modbus._buffer = modbus._buffer.slice(i); | ||
} | ||
}); | ||
@@ -90,2 +64,18 @@ | ||
/** | ||
* Emit the received response, cut the buffer and reset the internal vars. | ||
* @param {number} start the start index of the response within the buffer | ||
* @param {number} length the length of the response | ||
* @private | ||
*/ | ||
RTUBufferedPort.prototype._emitData = function(start, length) { | ||
this.emit('data', this._buffer.slice(start, start + length)); | ||
this._buffer = this._buffer.slice(start + length); | ||
// reset internal vars | ||
this._id = 0; | ||
this._cmd = 0; | ||
this._length = 0; | ||
}; | ||
/** | ||
* Simulate successful port open | ||
@@ -92,0 +82,0 @@ */ |
@@ -6,32 +6,10 @@ 'use strict'; | ||
var crc16 = require('./../utils/crc16'); | ||
var EXCEPTION_LENGTH = 5; | ||
var TELNET_PORT = 2217; | ||
/** | ||
* check if a buffer chunk can be a modbus answer | ||
* or modbus exception | ||
* | ||
* @param {TelnetPort} modbus | ||
* @param {Buffer} buf the buffer to check. | ||
* @return {boolean} if the buffer can be an answer | ||
*/ | ||
function checkData(modbus, buf) { | ||
// check buffer size | ||
if (buf.length != modbus._length && buf.length != 5) return false; | ||
// calculate crc16 | ||
var crcIn = buf.readUInt16LE(buf.length - 2); | ||
// check buffer unit-id, command and crc | ||
return (buf[0] == modbus._id && | ||
(0x7f & buf[1]) == modbus._cmd && | ||
crcIn == crc16(buf.slice(0, -2))); | ||
} | ||
/** | ||
* Simulate a modbus-RTU port using Telent connection | ||
*/ | ||
var TelnetPort = function(ip, options) { | ||
var modbus = this; | ||
var self = this; | ||
this.ip = ip; | ||
@@ -54,43 +32,38 @@ this.openFlag = false; | ||
// register the port data event | ||
this._client.on('data', function(data) { | ||
/* add data to buffer | ||
*/ | ||
modbus._buffer = Buffer.concat([modbus._buffer, data]); | ||
this._client.on('data', function onData(data) { | ||
// add data to buffer | ||
self._buffer = Buffer.concat([self._buffer, data]); | ||
/* check if buffer include a complete modbus answer | ||
*/ | ||
var length = modbus._length; | ||
var bufferLength = modbus._buffer.length ; | ||
// check if buffer include a complete modbus answer | ||
var expectedLength = self._length; | ||
var bufferLength = self._buffer.length ; | ||
// check data length | ||
if (bufferLength < 5 || length < 6) return; | ||
if (expectedLength < 6 || bufferLength < EXCEPTION_LENGTH) return; | ||
// loop and check length-sized buffer chunks | ||
for (var i = 0; i < (bufferLength - length + 1); i++) { | ||
// cut a length of bytes from buffer | ||
var _data = modbus._buffer.slice(i, i + length); | ||
var maxOffset = bufferLength - EXCEPTION_LENGTH; | ||
for (var i = 0; i <= maxOffset; i++) { | ||
var unitId = self._buffer[i]; | ||
var functionCode = self._buffer[i+1]; | ||
// check if this is the data we are waiting for | ||
if (checkData(modbus, _data)) { | ||
// adjust i to end of data chunk | ||
i = i + length; | ||
if (unitId !== self._id) continue; | ||
// emit a data signal | ||
modbus.emit('data', _data); | ||
if (functionCode === self._cmd && i + expectedLength <= bufferLength) { | ||
self._emitData(i, expectedLength); | ||
return; | ||
} | ||
if (functionCode === (0x80 | self._cmd) && i + EXCEPTION_LENGTH <= bufferLength) { | ||
self._emitData(i, EXCEPTION_LENGTH); | ||
return; | ||
} | ||
} | ||
/* cut checked data from buffer | ||
*/ | ||
if (i) { | ||
modbus._buffer = modbus._buffer.slice(i); | ||
} | ||
}); | ||
this._client.on('connect', function() { | ||
modbus.openFlag = true; | ||
self.openFlag = true; | ||
}); | ||
this._client.on('close', function(had_error) { | ||
modbus.openFlag = false; | ||
self.openFlag = false; | ||
}); | ||
@@ -103,2 +76,18 @@ | ||
/** | ||
* Emit the received response, cut the buffer and reset the internal vars. | ||
* @param {number} start the start index of the response within the buffer | ||
* @param {number} length the length of the response | ||
* @private | ||
*/ | ||
TelnetPort.prototype._emitData = function(start, length) { | ||
this.emit('data', this._buffer.slice(start, start + length)); | ||
this._buffer = this._buffer.slice(start + length); | ||
// reset internal vars | ||
this._id = 0; | ||
this._cmd = 0; | ||
this._length = 0; | ||
}; | ||
/** | ||
* Simulate successful port open | ||
@@ -105,0 +94,0 @@ */ |
@@ -70,2 +70,19 @@ 'use strict'; | ||
}); | ||
it('should return a valid Modbus RTU exception', function(done) { | ||
port.once('data', function(data) { | ||
expect(data.toString('hex')).to.equal('1183044136'); | ||
done(); | ||
}); | ||
port.open(function() { | ||
port.write(new Buffer('1103006B00037687', 'hex')); | ||
setTimeout(function() { | ||
port._client.receive(new Buffer('11', 'hex')); | ||
port._client.receive(new Buffer('83', 'hex')); | ||
port._client.receive(new Buffer('04', 'hex')); | ||
port._client.receive(new Buffer('41', 'hex')); | ||
port._client.receive(new Buffer('36', 'hex')); | ||
}); | ||
}); | ||
}); | ||
}); | ||
@@ -72,0 +89,0 @@ |
@@ -70,2 +70,19 @@ 'use strict'; | ||
}); | ||
it('should return a valid Modbus RTU exception', function(done) { | ||
port.once('data', function(data) { | ||
expect(data.toString('hex')).to.equal('1183044136'); | ||
done(); | ||
}); | ||
port.open(function() { | ||
port.write(new Buffer('1103006B00037687', 'hex')); | ||
setTimeout(function() { | ||
port._client.receive(new Buffer('11', 'hex')); | ||
port._client.receive(new Buffer('83', 'hex')); | ||
port._client.receive(new Buffer('04', 'hex')); | ||
port._client.receive(new Buffer('41', 'hex')); | ||
port._client.receive(new Buffer('36', 'hex')); | ||
}); | ||
}); | ||
}); | ||
}); | ||
@@ -72,0 +89,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2635
107805
36