Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

modbus-serial

Package Overview
Dependencies
Maintainers
1
Versions
123
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

modbus-serial - npm Package Compare versions

Comparing version 8.0.11 to 8.0.12

examples/server_serial.js

22

apis/connection.js

@@ -63,2 +63,3 @@ "use strict";

this._enronTables = options.enronTables;
this._encapsulatedRTU = options.encapsulatedRTU;
}

@@ -101,2 +102,3 @@

this._enronTables = options.enronTables;
this._encapsulatedRTU = options.encapsulatedRTU;
}

@@ -330,2 +332,3 @@

this._enronTables = options.enronTables;
this._encapsulatedRTU = options.encapsulatedRTU;
}

@@ -388,3 +391,20 @@

*/
cl.connectRTUSocket = function(socket, next) {
cl.connectRTUSocket = function(socket, options, next) {
if (options) {
this._enron = options.enron;
this._enronTables = options.enronTables;
this._encapsulatedRTU = options.encapsulatedRTU;
}
// check if we have options
if (typeof next === "undefined" && typeof options === "function") {
next = options;
options = {};
}
// check if we have options
if (typeof options === "undefined") {
options = {};
}
const thisModbus = this;

@@ -391,0 +411,0 @@ this._port = socket;

428

index.js

@@ -354,187 +354,297 @@ "use strict";

// set locale helpers variables
const transaction = modbus._transactions[modbus._port._transactionIdRead];
let next;
// the _transactionIdRead can be missing, ignore wrong transaction it's
if (!transaction) {
return;
}
/* check enron options are valid
*/
function validateEnron() {
if (modbus._enron) {
const example = {
enronTables: {
booleanRange: [1001, 1999],
shortRange: [3001, 3999],
longRange: [5001, 5999],
floatRange: [7001, 7999]
}
};
if (transaction.responses) {
/* Stash what we received */
transaction.responses.push(Uint8Array.prototype.slice.call(data));
if (typeof modbus._enronTables === "undefined" ||
modbus._enronTables.shortRange.length !== 2 ||
modbus._enronTables.shortRange[0] >= modbus._enronTables.shortRange[1]) {
next(new Error("Enron table definition missing from options. Example: " + JSON.stringify(example)));
return;
}
}
}
/* What do we do next? */
const next = function(err, res) {
if (transaction.next) {
/* Include request/response data if enabled */
if (transaction.request && transaction.responses) {
if (err) {
err.modbusRequest = transaction.request;
err.modbusResponses = transaction.responses;
}
if (modbus._encapsulatedRTU === true) {
let finished = false;
let dataLength = data.readUInt8(2);
let transaction = modbus._transactions[modbus._port._transactionIdRead];
modbus._port._transactionIdRead += 1;
if (res) {
res.request = transaction.request;
res.responses = transaction.responses;
}
/* What do we do next? */
next = function(err, res) {
if (transaction && transaction.next) {
return transaction.next(err, res);
}
};
/* Pass the data on */
return transaction.next(err, res);
}
};
validateEnron();
/* cancel the timeout */
_cancelTimeout(transaction._timeoutHandle);
transaction._timeoutHandle = undefined;
let messageBuf;
let offset = 0;
/* check if the timeout fired */
if (transaction._timeoutFired === true) {
// we have already called back with an error, so don't generate a new callback
return;
}
while (!finished) {
// do stuff
messageBuf = Buffer.alloc(dataLength + 5);
/* check incoming data
*/
data.copy(messageBuf, 0, offset, offset + dataLength + 5);
/* check minimal length
*/
if (!transaction.lengthUnknown && data.length < 5) {
error = "Data length error, expected " +
transaction.nextLength + " got " + data.length;
next(new Error(error));
return;
}
const crcIn = messageBuf.readUInt16LE(messageBuf.length - 2);
/* check message CRC
* if CRC is bad raise an error
*/
const crcIn = data.readUInt16LE(data.length - 2);
if (crcIn !== crc16(data.slice(0, -2))) {
error = "CRC error";
next(new Error(error));
return;
}
if (crcIn !== crc16(messageBuf.slice(0, -2))) {
error = "CRC error";
return;
}
// if crc is OK, read address and function code
const address = data.readUInt8(0);
const code = data.readUInt8(1);
// if crc is OK, read address and function code
const address = messageBuf.readUInt8(0);
const code = messageBuf.readUInt8(1);
/* check for modbus exception
*/
if (data.length >= 5 &&
code === (0x80 | transaction.nextCode)) {
const errorCode = data.readUInt8(2);
if (transaction.next) {
error = new Error("Modbus exception " + errorCode + ": " + (modbusErrorMessages[errorCode] || "Unknown error"));
error.modbusCode = errorCode;
next(error);
/* check for modbus exception
*/
if (messageBuf.length >= 5 &&
code === (0x80 | code)) {
const errorCode = messageBuf.readUInt8(2);
error = new Error("Modbus exception " + errorCode + ": " + (modbusErrorMessages[errorCode] || "Unknown error"));
error.modbusCode = errorCode;
return;
}
switch (code) {
case 1:
case 2:
// Read Coil Status (FC=01)
// Read Input Status (FC=02)
_readFC2(messageBuf, next);
break;
case 3:
case 4:
// Read Input Registers (FC=04)
// Read Holding Registers (FC=03)
if (modbus._enron && !(address >= modbus._enronTables.shortRange[0] && address <= modbus._enronTables.shortRange[1])) {
_readFC3or4Enron(messageBuf, next);
} else {
_readFC3or4(messageBuf, next);
}
break;
case 5:
// Force Single Coil
_readFC5(messageBuf, next);
break;
case 6:
// Preset Single Register
if (modbus._enron && !(address >= modbus._enronTables.shortRange[0] && address <= modbus._enronTables.shortRange[1])) {
_readFC6Enron(messageBuf, next);
} else {
_readFC6(messageBuf, next);
}
break;
case 15:
case 16:
// Force Multiple Coils
// Preset Multiple Registers
_readFC16(messageBuf, next);
break;
case 17:
_readFC17(messageBuf, next);
break;
case 20:
_readFC20(messageBuf, transaction.next);
break;
case 43:
// read device identification
_readFC43(messageBuf, modbus, next);
}
// move on to next
offset += 5 + dataLength;
if (offset + 2 > data.length) {
finished = true;
} else {
dataLength = data.readUInt8(offset + 2);
transaction = modbus._transactions[modbus._port._transactionIdRead];
modbus._port._transactionIdRead += 1;
}
}
return;
}
} else {
// set locale helpers variables
const transaction = modbus._transactions[modbus._port._transactionIdRead];
/* check enron options are valid
*/
if (modbus._enron) {
const example = {
enronTables: {
booleanRange: [1001, 1999],
shortRange: [3001, 3999],
longRange: [5001, 5999],
floatRange: [7001, 7999]
// the _transactionIdRead can be missing, ignore wrong transaction it's
if (!transaction) {
return;
}
if (transaction.responses) {
/* Stash what we received */
transaction.responses.push(Uint8Array.prototype.slice.call(data));
}
/* What do we do next? */
next = function(err, res) {
if (transaction.next) {
/* Include request/response data if enabled */
if (transaction.request && transaction.responses) {
if (err) {
err.modbusRequest = transaction.request;
err.modbusResponses = transaction.responses;
}
if (res) {
res.request = transaction.request;
res.responses = transaction.responses;
}
}
/* Pass the data on */
return transaction.next(err, res);
}
};
if (typeof modbus._enronTables === "undefined" ||
modbus._enronTables.shortRange.length !== 2 ||
modbus._enronTables.shortRange[0] >= modbus._enronTables.shortRange[1]) {
next(new Error("Enron table definition missing from options. Example: " + JSON.stringify(example)));
validateEnron();
/* cancel the timeout */
_cancelTimeout(transaction._timeoutHandle);
transaction._timeoutHandle = undefined;
/* check if the timeout fired */
if (transaction._timeoutFired === true) {
// we have already called back with an error, so don't generate a new callback
return;
}
}
/* check message length
* if we do not expect this data
* raise an error
*/
if (!transaction.lengthUnknown && data.length !== transaction.nextLength) {
error = "Data length error, expected " +
transaction.nextLength + " got " + data.length;
next(new Error(error));
return;
}
/* check incoming data
*/
/* check message address
* if we do not expect this message
* raise an error
*/
if (address !== transaction.nextAddress) {
error = "Unexpected data error, expected " +
"address " + transaction.nextAddress + " got " + address;
if (transaction.next)
/* check minimal length
*/
if (!transaction.lengthUnknown && data.length < 5) {
error = "Data length error, expected " +
transaction.nextLength + " got " + data.length;
next(new Error(error));
return;
}
return;
}
/* check message code
* if we do not expect this message
* raise an error
*/
if (code !== transaction.nextCode) {
error = "Unexpected data error, expected " +
"code " + transaction.nextCode + " got " + code;
if (transaction.next)
/* check message CRC
* if CRC is bad raise an error
*/
const crcIn = data.readUInt16LE(data.length - 2);
if (crcIn !== crc16(data.slice(0, -2))) {
error = "CRC error";
next(new Error(error));
return;
}
return;
}
/* parse incoming data
*/
// if crc is OK, read address and function code
const address = data.readUInt8(0);
const code = data.readUInt8(1);
switch (code) {
case 1:
case 2:
// Read Coil Status (FC=01)
// Read Input Status (FC=02)
_readFC2(data, next);
break;
case 3:
case 4:
// Read Input Registers (FC=04)
// Read Holding Registers (FC=03)
if (modbus._enron && !(transaction.nextDataAddress >= modbus._enronTables.shortRange[0] && transaction.nextDataAddress <= modbus._enronTables.shortRange[1])) {
_readFC3or4Enron(data, next);
} else {
_readFC3or4(data, next);
/* check for modbus exception
*/
if (data.length >= 5 &&
code === (0x80 | transaction.nextCode)) {
const errorCode = data.readUInt8(2);
if (transaction.next) {
error = new Error("Modbus exception " + errorCode + ": " + (modbusErrorMessages[errorCode] || "Unknown error"));
error.modbusCode = errorCode;
next(error);
}
break;
case 5:
// Force Single Coil
_readFC5(data, next);
break;
case 6:
// Preset Single Register
if (modbus._enron && !(transaction.nextDataAddress >= modbus._enronTables.shortRange[0] && transaction.nextDataAddress <= modbus._enronTables.shortRange[1])) {
_readFC6Enron(data, next);
} else {
_readFC6(data, next);
}
break;
case 15:
case 16:
// Force Multiple Coils
// Preset Multiple Registers
_readFC16(data, next);
break;
case 17:
_readFC17(data, next);
break;
case 20:
_readFC20(data, transaction.next);
break;
case 43:
// read device identification
_readFC43(data, modbus, next);
return;
}
/* check message length
* if we do not expect this data
* raise an error
*/
if (!transaction.lengthUnknown && data.length !== transaction.nextLength) {
error = "Data length error, expected " +
transaction.nextLength + " got " + data.length;
next(new Error(error));
return;
}
/* check message address
* if we do not expect this message
* raise an error
*/
if (address !== transaction.nextAddress) {
error = "Unexpected data error, expected " +
"address " + transaction.nextAddress + " got " + address;
if (transaction.next)
next(new Error(error));
return;
}
/* check message code
* if we do not expect this message
* raise an error
*/
if (code !== transaction.nextCode) {
error = "Unexpected data error, expected " +
"code " + transaction.nextCode + " got " + code;
if (transaction.next)
next(new Error(error));
return;
}
/* parse incoming data
*/
switch (code) {
case 1:
case 2:
// Read Coil Status (FC=01)
// Read Input Status (FC=02)
_readFC2(data, next);
break;
case 3:
case 4:
// Read Input Registers (FC=04)
// Read Holding Registers (FC=03)
if (modbus._enron && !(transaction.nextDataAddress >= modbus._enronTables.shortRange[0] && transaction.nextDataAddress <= modbus._enronTables.shortRange[1])) {
_readFC3or4Enron(data, next);
} else {
_readFC3or4(data, next);
}
break;
case 5:
// Force Single Coil
_readFC5(data, next);
break;
case 6:
// Preset Single Register
if (modbus._enron && !(transaction.nextDataAddress >= modbus._enronTables.shortRange[0] && transaction.nextDataAddress <= modbus._enronTables.shortRange[1])) {
_readFC6Enron(data, next);
} else {
_readFC6(data, next);
}
break;
case 15:
case 16:
// Force Multiple Coils
// Preset Multiple Registers
_readFC16(data, next);
break;
case 17:
_readFC17(data, next);
break;
case 20:
_readFC20(data, transaction.next);
break;
case 43:
// read device identification
_readFC43(data, modbus, next);
}
}

@@ -774,3 +884,2 @@ }

}
// set state variables

@@ -781,3 +890,3 @@ this._transactions[this._port._transactionIdWrite] = {

nextCode: code,
nextLength: 3 + (valueSize * length) + 2,
nextLength: 3 + (valueSize * length) + 2, // response size: unitID, FC, length, data, CRC
next: next

@@ -799,2 +908,4 @@ };

_writeBufferToPort.call(this, buf, this._port._transactionIdWrite);
this._port._transactionIdWrite += 1;
}

@@ -1179,4 +1290,5 @@

module.exports.Server = require("./servers/server");
module.exports.ServerTCP = require("./servers/servertcp");
module.exports.ServerSerial = require("./servers/serverserial");
module.exports.default = module.exports;

@@ -48,4 +48,4 @@ import { Socket } from 'net';

linkTelnet(socket: Socket, options: TelnetPortOptions): Promise<void>;
connectRTUSocket(socket: Socket, next: Function): void;
connectRTUSocket(socket: Socket): Promise<void>;
connectRTUSocket(socket: Socket, options: SocketOptions, next: Function): void;
connectRTUSocket(socket: Socket, options: SocketOptions): Promise<void>;

@@ -156,2 +156,5 @@ // Promise API

export interface SocketOptions {
}
export interface TelnetPortOptions {

@@ -158,0 +161,0 @@ port?: number;

{
"name": "modbus-serial",
"version": "8.0.11",
"version": "8.0.12",
"description": "A pure JavaScript implemetation of MODBUS-RTU (Serial and TCP) for NodeJS.",

@@ -44,4 +44,4 @@ "main": "index.js",

"debug": "^4.1.1",
"serialport": "^10.4.0"
"serialport": "^11.0.0"
}
}

@@ -64,10 +64,11 @@ # modbus-serial

| FC2 "Read Input Status" | `readDiscreteInputs(addr, arg)` |
| FC3 "Read Holding Registers" | `readHoldingRegisters(addr, len) ` |
| FC3 "Read Holding Registers" | `readHoldingRegisters(addr, len)`, `readRegistersEnron(addr, len)`* |
| FC4 "Read Input Registers" | `readInputRegisters(addr, len) ` |
| FC5 "Force Single Coil" | `writeCoil(coil, binary) //NOT setCoil` |
| FC6 "Preset Single Register" | `writeRegister(addr, value)` |
| FC15 "Force Multiple Coil" | `writeCoils(addr, valueAry)` |
| FC16 "Preset Multiple Registers" | `writeRegisters(addr, valueAry)` |
| FC15 "Force Multiple Coil" | `writeCoils(addr, valueAry)` |
| FC16 "Preset Multiple Registers" | `writeRegisters(addr, valueAry)`, `writeRegistersEnron(addr, valueAry)`* |
| FC43/14 "Read Device Identification" (supported ports: TCP, RTU) | `readDeviceIdentification(id, obj)` |
\* See examples/server_enron.js for enron configuration example.
###### Client Serial:

@@ -88,5 +89,6 @@

* modbus-TCP (ServerTCP): Over TCP/IP line.
* modbus-TCP ServerTCP(): Encapsulated TCP/IP.
* modbus-RTU Server(): RTU over TCP/IP Socket.
* modbus-Serial ServerSerial(): Over serial.
#### Examples

@@ -232,3 +234,3 @@

----
###### ModbusTCP Server
###### Modbus TCP Server
``` javascript

@@ -289,2 +291,87 @@ // create an empty modbus client

----
###### Modbus Serial Server
``` javascript
const ModbusRTU = require("..");
const holdingRegisters = {};
const coils = {};
const inputRegisters = {};
const discreteInputs = {};
const vector = {
getInputRegister: function(addr) {
return inputRegisters[addr];
},
getMultipleInputRegisters: function(startAddr, length) {
const values = [];
for (let i = 0; i < length; i++) {
values[i] = inputRegisters[startAddr + i];
}
return values;
},
getDiscreteInput: function(addr) {
return discreteInputs[addr];
},
getHoldingRegister: function(addr) {
return holdingRegisters[addr];
},
setRegister: function(addr, value) {
holdingRegisters[addr] = value;
return;
},
getMultipleHoldingRegisters: function(startAddr, length) {
const values = [];
for (let i = 0; i < length; i++) {
values[i] = holdingRegisters[startAddr + i];
}
return values;
},
getCoil: function(addr) {
return coils[addr];
},
setCoil: function(addr, value) {
coils[addr] = value;
return coils[addr];
},
readDeviceIdentification: function() {
return {
0x00: "MyVendorName",
0x01: "MyProductCode",
0x02: "MyMajorMinorRevision",
0x05: "MyModelName",
0x97: "MyExtendedObject1",
0xab: "MyExtendedObject2"
};
}
};
// set the server to answer for modbus requests
const serverSerial = new ModbusRTU.ServerSerial(
vector,
{
port: "/tmp/ttyp0",
debug: true,
unitID: 1
// enron: true,
// enronTables: {
// booleanRange: [1001, 1999],
// shortRange: [3001, 3999],
// longRange: [5001, 5999],
// floatRange: [7001, 7999]
// }
},
{
baudRate: 9600,
dataBits: 8,
stopBits: 1,
parity: "even"
}
);
serverSerial.on("error", function(err) {
// Handle socket error if needed, can be ignored
console.error(err);
});
```
----
###### Read and Write Modbus ASCII

@@ -291,0 +378,0 @@ ``` javascript

@@ -71,2 +71,5 @@ "use strict";

debug: true
},
{
baudRate: 9600
});

@@ -262,2 +265,5 @@ });

unitID: 4
},
{
baudRate: 9600
});

@@ -323,2 +329,5 @@ });

unitID: 4
},
{
baudRate: 9600
});

@@ -325,0 +334,0 @@ });

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc