Skip to content

Commit

Permalink
Buffered RTU FC43 Support (#353)
Browse files Browse the repository at this point in the history
* fixing Buffered RTU to actually wait for the read device identification responses and then return them

* putting back debugging stuff I removed

* unknown length as a const

* 7 bits to num of objects is now a const
  • Loading branch information
eeerin authored Aug 18, 2020
1 parent 781ea7e commit 67a3f41
Showing 1 changed file with 70 additions and 14 deletions.
84 changes: 70 additions & 14 deletions ports/rtubufferedport.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,43 @@ var modbusSerialDebug = require("debug")("modbus-serial");
var EXCEPTION_LENGTH = 5;
var MIN_DATA_LENGTH = 6;
var MAX_BUFFER_LENGTH = 256;
var CRC_LENGTH = 2;
var READ_DEVICE_IDENTIFICATION_FUNCTION_CODE = 43;
var LENGTH_UNKNOWN = "unknown";
var BITS_TO_NUM_OF_OBJECTS = 7;

// Helper function -> Bool
// BIT | TYPE
// 8 | OBJECTID
// 9 | length of OBJECTID
// 10 -> n | the object
// 10 + n + 1 | new object id
var calculateFC43Length = function(buffer, numObjects, i, bufferLength) {
var result = { hasAllData: true };
var currentByte = 8 + i; // current byte starts at object id.
if (numObjects > 0) {
for (var j = 0; j < numObjects; j++) {
if (bufferLength < currentByte) {
result.hasAllData = false;
break;
}
var objLength = buffer[currentByte + 1];
if (!objLength) {
result.hasAllData = false;
break;
}
currentByte += 2 + objLength;
}
}
if (currentByte + CRC_LENGTH > bufferLength) {
// still waiting on the CRC!
result.hasAllData = false;
}
if (result.hasAllData) {
result.bufLength = currentByte + CRC_LENGTH;
}
return result;
};

/**
* Simulate a modbus-RTU port using buffered serial connection.
Expand Down Expand Up @@ -40,14 +77,18 @@ var RTUBufferedPort = function(path, options) {
// add data to buffer
self._buffer = Buffer.concat([self._buffer, data]);

modbusSerialDebug({ action: "receive serial rtu buffered port", data: data, buffer: self._buffer });

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

modbusSerialDebug({ action: "receive serial rtu buffered port", data: data, buffer: self._buffer });

// check data length
if (expectedLength < MIN_DATA_LENGTH || bufferLength < EXCEPTION_LENGTH) return;
if (expectedLength !== LENGTH_UNKNOWN &&
expectedLength < MIN_DATA_LENGTH ||
bufferLength < EXCEPTION_LENGTH
) { return; }

// check buffer size for MAX_BUFFER_SIZE
if (bufferLength > MAX_BUFFER_LENGTH) {
Expand All @@ -57,19 +98,32 @@ var RTUBufferedPort = function(path, options) {

// loop and check length-sized buffer chunks
var maxOffset = bufferLength - EXCEPTION_LENGTH;

for (var i = 0; i <= maxOffset; i++) {
var unitId = self._buffer[i];
var functionCode = self._buffer[i + 1];

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

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;
if (functionCode === self._cmd && functionCode === READ_DEVICE_IDENTIFICATION_FUNCTION_CODE) {
if (bufferLength <= BITS_TO_NUM_OF_OBJECTS + i) {
return;
}
var numObjects = self._buffer[7 + i];
var result = calculateFC43Length(self._buffer, numObjects, i, bufferLength);
if (result.hasAllData) {
self._emitData(i, result.bufLength);
return;
}
} else {
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;
}
}

// frame header matches, but still missing bytes pending
Expand Down Expand Up @@ -102,9 +156,7 @@ util.inherits(RTUBufferedPort, EventEmitter);
*/
RTUBufferedPort.prototype._emitData = function(start, length) {
var buffer = this._buffer.slice(start, start + length);

modbusSerialDebug({ action: "emit data serial rtu buffered port", buffer: buffer });

this.emit("data", buffer);
this._buffer = this._buffer.slice(start + length);
};
Expand Down Expand Up @@ -163,8 +215,11 @@ RTUBufferedPort.prototype.write = function(data) {
this._length = 6 + 2;
break;
case 43:
modbusSerialDebug("RTUBuffered F43 not supported");
this._length = 0;
// this function is super special
// you know the format of the code response
// and you need to continuously check that all of the data has arrived before emitting
// see onData for more info.
this._length = LENGTH_UNKNOWN;
break;
default:
// raise and error ?
Expand All @@ -179,7 +234,8 @@ RTUBufferedPort.prototype.write = function(data) {
action: "send serial rtu buffered",
data: data,
unitid: this._id,
functionCode: this._cmd
functionCode: this._cmd,
length: this._length
});
};

Expand Down

0 comments on commit 67a3f41

Please sign in to comment.