-
Notifications
You must be signed in to change notification settings - Fork 179
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #94 from Cloud-Automation/chopped-data-packets
Chopped data packets
- Loading branch information
Showing
5 changed files
with
220 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
'use strict' | ||
var stampit = require('stampit') | ||
var logger = require('stampit-log') | ||
|
||
module.exports = stampit() | ||
.compose(logger) | ||
.init(function () { | ||
let buffer = Buffer.alloc(0) | ||
|
||
let init = function () { | ||
if (!this.socket || this.socketId === undefined || !this.onRequest) { | ||
throw new Error('No Socket defined.') | ||
} | ||
|
||
this.socket.on('end', this.onSocketEnd) | ||
this.socket.on('data', this.onSocketData) | ||
this.socket.on('error', this.onSocketError) | ||
}.bind(this) | ||
|
||
this.onSocketEnd = function () { | ||
if (this.onEnd) { | ||
this.onEnd() | ||
} | ||
|
||
this.log.debug('connection closed, socket', this.socketId) | ||
}.bind(this) | ||
|
||
this.onSocketData = function (data) { | ||
this.log.debug('received data socket', this.socketId, data.byteLength) | ||
|
||
buffer = Buffer.concat([buffer, data]) | ||
|
||
while (buffer.length > 8) { | ||
// 1. extract mbap | ||
|
||
let len = buffer.readUInt16BE(4) | ||
let request = { | ||
trans_id: buffer.readUInt16BE(0), | ||
protocol_ver: buffer.readUInt16BE(2), | ||
unit_id: buffer.readUInt8(6) | ||
} | ||
|
||
// 2. extract pdu | ||
|
||
/* received data is not complete yet. | ||
* break loop and wait for more data. */ | ||
|
||
if (buffer.length < 7 + len - 1) { | ||
break | ||
} | ||
|
||
let pdu = buffer.slice(7, 7 + len) | ||
|
||
// emit data event and let the | ||
// listener handle the pdu | ||
|
||
this.log.debug('PDU extracted.') | ||
|
||
this.onRequest({ request: request, pdu: pdu, socket: this.socket }) | ||
|
||
buffer = buffer.slice(pdu.length + 7, buffer.length) | ||
} | ||
}.bind(this) | ||
|
||
this.onSocketError = function (e) { | ||
this.logError('Socker error', e) | ||
} | ||
|
||
init() | ||
}) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
/* global describe, it */ | ||
'use strict' | ||
var assert = require('assert') | ||
var EventEmitter = require('events') | ||
|
||
describe('Modbus TCP Tests.', 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') | ||
|
||
it('should handle a chopped data request fine.', function (done) { | ||
var em = new EventEmitter() | ||
var requests = [Buffer.from([0x00, 0x01]), // Transaction Identifier | ||
Buffer.from([0x00, 0x00]), // Protocol | ||
Buffer.from([0x00, 0x05]), // Length | ||
Buffer.from([0x01]), // Unit identifier | ||
Buffer.from([0x01]), // PDU Function Code | ||
Buffer.from([0x00, 0x0A]), // Start Address | ||
Buffer.from([0x00, 0x15])] // Quantitiy | ||
|
||
var exRequest = { | ||
request: { | ||
trans_id: 1, | ||
protocol_ver: 0, | ||
unit_id: 1 | ||
}, | ||
pdu: Buffer.from([0x01, 0x00, 0x0A, 0x00, 0x15]), | ||
socket: em } | ||
|
||
var callbackCounter = 0 | ||
var handler = function (req) { | ||
assert.deepEqual(req, exRequest) | ||
callbackCounter += 1 | ||
assert.equal(callbackCounter, 1) | ||
done() | ||
} | ||
|
||
ClientSocket({ | ||
socket: em, | ||
socketId: 1, | ||
onRequest: handler | ||
}) | ||
|
||
requests.forEach(function (b) { | ||
em.emit('data', b) | ||
}) | ||
}) | ||
}) | ||
|
||
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])) | ||
}) | ||
}) | ||
}) |