Skip to content

Commit

Permalink
- tested tcp buffered with PLC Simulator
Browse files Browse the repository at this point in the history
- new example for tcp buffered
  • Loading branch information
biancode committed Mar 3, 2017
1 parent c5ccab4 commit 63e5ec8
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 82 deletions.
2 changes: 1 addition & 1 deletion apis/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ var addConnctionAPI = function (Modbus) {
* Connect to a communication port, using TcpRTUBufferedPort.
*
* @param {string} ip the ip of the TCP Port - required.
* @param {Object} options - the serial port options - optional.
* @param {Object} options - the serial tcp port options - optional.
* @param {Function} next the function to call next.
*/
cl.connectTcpRTUBuffered = function (ip, options, next) {
Expand Down
1 change: 0 additions & 1 deletion examples/buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ function setClient() {
}

function run() {
// read the 4 registers starting at address 5
client.readInputRegisters(4, 12)
.then(function(d) {
floatA = d.buffer.readFloatBE(0);
Expand Down
42 changes: 42 additions & 0 deletions examples/buffertcp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// create an empty modbus client
//var ModbusRTU = require("modbus-serial");
var ModbusRTU = require("../index");
var client = new ModbusRTU();

// NPort Gateway 801D NetPort
// client.connectTcpRTUBuffered("192.168.1.73", {port: 502, removeCrc: true})
// client.connectTcpRTUBuffered("192.168.1.73", {port: 502, removeCrc: false
client.connectTcpRTUBuffered("192.168.1.20", {port: 502, removeCrc: false})
.then(setClient)
.then(function () {
console.log("Connected");
})
.catch(function (e) {
console.log(e.message);
});

function setClient() {
// set the client's unit id
// set a timout for requests default is null (no timeout)
client.setID(1);
client.setTimeout(2000);

// run program
run();
}

function run() {
// read the 4 registers starting at address 5
client.readHoldingRegisters(5, 4)
.then(function (d) {
console.log("Receive:", d.data);
})
.catch(function (e) {
console.log(e.message);
})
.then(close);
}

function close() {
client.close();
}
32 changes: 19 additions & 13 deletions examples/simple.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ var client = new ModbusRTU();

// open connection to a serial port
//client.connectRTU("/dev/ttyUSB0", {baudrate: 9600})
client.connectTCP("127.0.0.1", {port: 8502})
client.connectTCP("192.168.1.20", {port: 502})
// client.connectTCP("192.168.1.73", {port: 502})
// client.connectTCP("127.0.0.1", {port: 8502})
.then(setClient)
.then(function() {
console.log("Connected"); })
.catch(function(e) {
console.log(e.message); });
.then(function () {
console.log("Connected");
})
.catch(function (e) {
console.log(e.message);
});

function setClient() {
// set the client's unit id
Expand All @@ -23,15 +27,17 @@ function setClient() {
}

function run() {
// read the 4 registers starting at address 5
client.readHoldingRegisters(5, 4)
.then(function(d) {
console.log("Receive:", d.data); })
.catch(function(e) {
console.log(e.message); })
.then(close);
// read the 4 registers starting at address 5
client.readHoldingRegisters(5, 4)
.then(function (d) {
console.log("Receive:", d.data);
})
.catch(function (e) {
console.log(e.message);
})
.then(close);
}

function close() {
client.close();
client.close();
}
2 changes: 1 addition & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ declare namespace ModbusRTU {

interface TcpRTUPortOptions {
port?: number;
removeCRC?: boolean;
removeCrc?: boolean;
}

interface TelnetPortOptions {
Expand Down
6 changes: 3 additions & 3 deletions ports/tcpport.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ var TcpPort = function(ip, options) {
// update transaction id
modbus._transactionId = data.readUInt16BE(0);

modbusSerialDebug( {action: 'receive', data: buffer});
modbusSerialDebug( {action: 'receive', data: data, buffer: buffer});

// emit debug message
if (modbus.debug) { modbus.emit('debug', {action: 'receive', data: buffer}); }
Expand Down Expand Up @@ -129,10 +129,10 @@ TcpPort.prototype.write = function (data) {
// send buffer to slave
this._client.write(buffer);

modbusSerialDebug(JSON.stringify({action: 'send tcp', data: buffer}));
modbusSerialDebug(JSON.stringify({action: 'send tcp', data: data, buffer: buffer}));

// emit debug message
if (this.debug) { this.emit('debug', {action: 'send', data: buffer}); }
if (this.debug) { this.emit('debug', {action: 'send', data: data, buffer: buffer}); }
};

module.exports = TcpPort;
89 changes: 49 additions & 40 deletions ports/tcprtubufferedport.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ var EXCEPTION_LENGTH = 5;
var MIN_DATA_LENGTH = 6;
var MIN_MBAP_LENGTH = 6;
var MAX_TRANSACTIONS = 64; // maximum transaction to wait for
var CRC_LENGTH = 2;

var MODBUS_PORT = 502;

/**
* Simulate a modbus-RTU port using TCP connection
*/
var TcpRTUBufferedPort = function(ip, options) {
var TcpRTUBufferedPort = function (ip, options) {
var self = this;
this.ip = ip;
this.openFlag = false;
Expand All @@ -27,7 +28,7 @@ var TcpRTUBufferedPort = function(ip, options) {
// options
if (typeof(options) == 'undefined') options = {};
this.port = options.port || MODBUS_PORT;
this.removeCRC = options.removeCRC || true;
this.removeCrc = options.removeCrc;

// internal buffer
this._buffer = new Buffer(0);
Expand All @@ -38,7 +39,7 @@ var TcpRTUBufferedPort = function(ip, options) {

// handle callback - call a callback function only once, for the first event
// it will triger
var handleCallback = function(had_error) {
var handleCallback = function (had_error) {
if (self.callback) {
self.callback(had_error);
self.callback = null;
Expand All @@ -50,19 +51,32 @@ var TcpRTUBufferedPort = function(ip, options) {

// register the port data event
this._client.on('data', function onData(data) {
modbusSerialDebug(JSON.stringify({data: data}));

var buffer;
var crc;

// check data length
if (data.length < MIN_MBAP_LENGTH) return; // missing mbap on tcp
if (data.length < MIN_MBAP_LENGTH) return;

// cut 6 bytes of mbap
var buffer = new Buffer(data.length - 6);
data.copy(buffer, 0, 6);
buffer = new Buffer(data.length - MIN_MBAP_LENGTH);
data.copy(buffer, 0, MIN_MBAP_LENGTH);

// add data (PDU / ADU) to buffer
// add data to buffer
self._buffer = Buffer.concat([self._buffer, buffer]);

modbusSerialDebug({action: 'receive', data: data, buffer: buffer});
modbusSerialDebug(JSON.stringify({action: 'receive strings', data: data, buffer: buffer}));

// emit debug message
if (self.debug) {
self.emit('debug', {action: 'receive', data: data, buffer: buffer});
}

// check if buffer include a complete modbus answer
var expectedLength = self._length;
var bufferLength = self._buffer.length;
var bufferLength = self._buffer.length + CRC_LENGTH;

modbusSerialDebug('on data expected length:' + expectedLength + ' buffer length:' + bufferLength);

Expand All @@ -73,7 +87,7 @@ var TcpRTUBufferedPort = function(ip, options) {
var maxOffset = bufferLength - EXCEPTION_LENGTH;
for (var i = 0; i <= maxOffset; i++) {
var unitId = self._buffer[i];
var functionCode = self._buffer[i+1];
var functionCode = self._buffer[i + 1];

if (unitId !== self._id) continue;

Expand All @@ -88,17 +102,17 @@ var TcpRTUBufferedPort = function(ip, options) {
}
});

this._client.on('connect', function() {
this._client.on('connect', function () {
self.openFlag = true;
handleCallback();
});

this._client.on('close', function(had_error) {
this._client.on('close', function (had_error) {
self.openFlag = false;
handleCallback(had_error);
});

this._client.on('error', function(had_error) {
this._client.on('error', function (had_error) {
self.openFlag = false;
handleCallback(had_error);
});
Expand All @@ -113,29 +127,25 @@ util.inherits(TcpRTUBufferedPort, EventEmitter);
* @param {number} length the length of the response
* @private
*/
TcpRTUBufferedPort.prototype._emitData = function(start, length) {
TcpRTUBufferedPort.prototype._emitData = function (start, length) {

var data = this._buffer.slice(start, start + length);
this._buffer = this._buffer.slice(start + length);

// update transaction id
this._transactionId = data.readUInt16BE(0);

if(data.length > 0) {
var buffer;
if(this.removeCRC) {
buffer = Buffer.alloc(data.length + 2);
data.copy(buffer, 0);

// add crc
var crc = crc16(buffer.slice(0, -2));
buffer.writeUInt16LE(crc, buffer.length - 2);
} else {
buffer = Buffer.alloc(data.length);
data.copy(buffer, 0);
}
if (data.length > 0) {
var buffer = Buffer.alloc(data.length + CRC_LENGTH);
data.copy(buffer, 0);

// add crc
var crc = crc16(buffer.slice(0, -CRC_LENGTH));
buffer.writeUInt16LE(crc, buffer.length - CRC_LENGTH);

this.emit('data', buffer);
} else {
modbusSerialDebug({action: 'emit data to short', data: data})
}

// reset internal vars
Expand Down Expand Up @@ -163,15 +173,15 @@ TcpRTUBufferedPort.prototype.close = function (callback) {
/**
* Check if port is open
*/
TcpRTUBufferedPort.prototype.isOpen = function() {
TcpRTUBufferedPort.prototype.isOpen = function () {
return this.openFlag;
};

/**
* Send data to a modbus slave via telnet server
*/
TcpRTUBufferedPort.prototype.write = function (data) {
if(data.length < MIN_DATA_LENGTH) {
if (data.length < MIN_DATA_LENGTH) {
modbusSerialDebug('expected length of data is to small - minimum is ' + MIN_DATA_LENGTH);
return;
}
Expand All @@ -180,7 +190,7 @@ TcpRTUBufferedPort.prototype.write = function (data) {
this._id = data[0];
this._cmd = data[1];

// calculate expected answer length of PDU / ADU
// calculate expected answer length
switch (this._cmd) {
case 1:
case 2:
Expand All @@ -207,24 +217,23 @@ TcpRTUBufferedPort.prototype.write = function (data) {
// get next transaction id
var transactionsId = (this._transactionId + 1) % MAX_TRANSACTIONS;

// add mbap
var buffer = new Buffer(data.length + 6 - 2);
// remove crc and add mbap
var buffer = new Buffer(data.length + MIN_MBAP_LENGTH - CRC_LENGTH);
buffer.writeUInt16BE(transactionsId, 0);
buffer.writeUInt16BE(0, 2);

if(this.removeCRC) {
buffer.writeUInt16BE(data.length - 2, 4); /* overwrite CRC */
}

data.copy(buffer, 6);

modbusSerialDebug(JSON.stringify({action: 'send rtu serial over tcp', data: buffer}));
buffer.writeUInt16BE(data.length - CRC_LENGTH, 4);
data.copy(buffer, MIN_MBAP_LENGTH);

// send buffer to slave
this._client.write(buffer);

modbusSerialDebug({action: 'send tcp', data: data, buffer: buffer});
modbusSerialDebug(JSON.stringify({action: 'send tcp strings', data: data, buffer: buffer}));

// emit debug message
if (this.debug) { this.emit('debug', {action: 'send', data: buffer}); }
if (this.debug) {
this.emit('debug', {action: 'send', data: data, buffer: buffer});
}
};

module.exports = TcpRTUBufferedPort;
Loading

0 comments on commit 63e5ec8

Please sign in to comment.