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 3.4.6 to 3.5.0

apis/buffer_bit.js

97

apis/connection.js

@@ -5,12 +5,12 @@ 'use strict';

*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

@@ -25,6 +25,6 @@ */

var addConnctionAPI = function(Modbus) {
var cl = Modbus.prototype;
/**
/**
* Connect to a communication port, using SerialPort.

@@ -42,10 +42,10 @@ *

}
// create the SerialPort
var SerialPort = require("serialport").SerialPort;
var serialPort = new SerialPort(path, options);
// re-set the serial port to use
this._port = serialPort;
// open and call next

@@ -55,3 +55,3 @@ this.open(next);

/**
/**
* Connect to a communication port, using TcpPort.

@@ -65,3 +65,3 @@ *

var port;
// check if we have options

@@ -72,15 +72,15 @@ if (typeof(next) == 'undefined' && typeof(options) == 'function') {

}
// create the TcpPort
var TcpPort = require('../ports/tcpport');
var tcpPort = new TcpPort(ip, options);
// re-set the port to use
this._port = tcpPort;
// open and call next
this.open(next);
}
/**
/**
* Connect to a communication port, using TelnetPort.

@@ -94,3 +94,3 @@ *

var port;
// check if we have options

@@ -101,15 +101,15 @@ if (typeof(next) == 'undefined' && typeof(options) == 'function') {

}
// create the TcpPort
var TelnetPort = require('../ports/telnetport');
var telnetPort = new TelnetPort(ip, options);
// re-set the port to use
this._port = telnetPort;
// open and call next
this.open(next);
}
/**
/**
* Connect to a communication port, using C701 UDP-to-Serial bridge.

@@ -123,3 +123,3 @@ *

var port;
// check if we have options

@@ -130,15 +130,15 @@ if (typeof(next) == 'undefined' && typeof(options) == 'function') {

}
// create the TcpPort
var C701Port = require('../ports/c701port');
var c701Port = new C701Port(ip, options);
// re-set the port to use
this._port = c701Port;
// open and call next
this.open(next);
}
/**
/**
* Connect to a communication port, using Bufferd Serial port.

@@ -156,15 +156,40 @@ *

}
// create the SerialPort
var SerialPort = require('../ports/rtubufferedport');
var serialPort = new SerialPort(path, options);
// re-set the serial port to use
this._port = serialPort;
// open and call next
this.open(next);
}
/**
* Connect to a communication port, using ASCII Serial port.
*
* @param {string} path the path to the Serial Port - required.
* @param {object} options - the serial port options - optional.
* @param {function} next the function to call next.
*/
cl.connectAsciiSerial = function (path, options, next) {
// check if we have options
if (typeof(next) == 'undefined' && typeof(options) == 'function') {
next = options;
options = {};
}
// create the ASCII SerialPort
var SerialPortAscii = require('../ports/asciiport');
var serialPortAscii = new SerialPortAscii(path, options);
// re-set the serial port to use
this._port = serialPortAscii;
// open and call next
this.open(next);
}
}
module.exports = addConnctionAPI;

@@ -18,2 +18,6 @@ 'use strict';

/* Add bit operation functions to Buffer
*/
require('./apis/buffer_bit')();
/**

@@ -63,3 +67,3 @@ * @fileoverview ModbusRTU module, exports the ModbusRTU class.

* Parse the data for a Modbus -
* Read Coils (FC=02,01)
* Read Coils (FC=02, 01)
*

@@ -88,3 +92,3 @@ * @param {buffer} data the data buffer to parse.

* Parse the data for a Modbus -
* Read Input Registers (FC=04,03)
* Read Input Registers (FC=04, 03)
*

@@ -139,3 +143,3 @@ * @param {buffer} data the data buffer to parse.

* Parse the data for a Modbus -
* Preset Multiple Registers (FC=16)
* Preset Multiple Registers (FC=15, 16)
*

@@ -206,2 +210,39 @@ * @param {buffer} data the data buffer to parse.

/* check minimal length
*/
if (data.length < 5) {
error = "Data length error, expected " +
length + " got " + data.length;
if (next)
next(error);
return;
}
/* check message CRC
* if CRC is bad raise an error
*/
var crcIn = data.readUInt16LE(data.length - 2);
var crc = _CRC16(data, data.length - 2);
if (crcIn != crc) {
error = "CRC error";
if (next)
next(error);
return;
}
// if crc is OK, read address and function code
var address = data.readUInt8(0);
var code = data.readUInt8(1);
/* check for modbus exception
*/
if (data.length == 5 &&
code == (0x80 | modbus._nextCode)) {
error = "Modbus exception " + data.readUInt8(2);
if (next)
next(error);
return;
}
/* check message length

@@ -211,3 +252,2 @@ * if we do not expect this data

*/
if (data.length != length) {

@@ -221,5 +261,2 @@ error = "Data length error, expected " +

var address = data.readUInt8(0);
var code = data.readUInt8(1);
/* check message address and code

@@ -242,48 +279,33 @@ * if we do not expect this message

/* check message CRC
* if CRC is bad raise an error
*/
var crcIn = data.readUInt16LE(length - 2);
var crc = _CRC16(data, length - 2);
if (crcIn != crc) {
error = "CRC error";
if (next)
next(error);
return;
}
/* parse incoming data
*/
/* Read Coil Status (FC=01)
* Read Input Status (FC=02)
*/
if (code == 2 || code == 1) {
_readFC2(data, next);
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)
_readFC4(data, next);
break;
case 5:
// Force Single Coil
_readFC5(data, next);
break;
case 6:
// Preset Single Register
_readFC6(data, next);
break;
case 15:
case 16:
// Force Multiple Coils
// Preset Multiple Registers
_readFC16(data, next);
break;
}
/* Read Input Registers (FC=04)
* Read Holding Registers (FC=03)
*/
if (code == 4 || code == 3) {
_readFC4(data, next);
}
/* Force Single Coil (FC=05)
*/
if (code == 5) {
_readFC5(data, next);
}
/* Preset Single Register (FC=06)
*/
if (code == 6) {
_readFC6(data, next);
}
// Preset Multiple Registers (FC=16)
if (code == 16) {
_readFC16(data, next);
}
});

@@ -388,4 +410,4 @@ }

* @param {number} address the slave unit address.
* @param {number} dataAddress the Data Address of the first register.
* @param {number} state the state to write to the coil (true / false).
* @param {number} dataAddress the Data Address of the coil.
* @param {number} state the boolean state to write to the coil (true / false).
* @param {function} next the function to call next.

@@ -422,3 +444,2 @@ */

/**

@@ -456,4 +477,40 @@ * Write a Modbus "Preset Single Register " (FC=6) to serial port.

/**
* Write a Modbus "Force Multiple Coils" (FC=15) to serial port.
*
* @param {number} address the slave unit address.
* @param {number} dataAddress the Data Address of the first coil.
* @param {array} array the array of boolean states to write to coils.
* @param {function} next the function to call next.
*/
ModbusRTU.prototype.writeFC15 = function (address, dataAddress, array, next) {
var code = 15;
// set state variables
this._nextAddress = address;
this._nextCode = code;
this._nextLength = 8;
this._next = next;
var dataBytes = Math.ceil(array.length / 8);
var codeLength = 7 + dataBytes;
var buf = new Buffer(codeLength + 2); // add 2 crc bytes
buf.writeUInt8(address, 0);
buf.writeUInt8(code, 1);
buf.writeUInt16BE(dataAddress, 2);
buf.writeUInt16BE(array.length, 4);
buf.writeUInt8(dataBytes, 6);
for (var i = 0; i < array.length; i++) {
buf.writeBit(array[i], i, 7);
}
// add crc bytes to buffer
_CRC16(buf, codeLength);
// write buffer to serial port
this._port.write(buf);
}
/**

@@ -460,0 +517,0 @@ * Write a Modbus "Preset Multiple Registers" (FC=16) to serial port.

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

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -22,3 +22,3 @@ 'use strict';

crc = crc ^ buf[i];
for (var j = 0; j < 8; j++) {

@@ -38,2 +38,3 @@ tmp = crc & 0x0001;

* check if a buffer chunk can be a modbus answer
* or modbus exception
*

@@ -45,4 +46,4 @@ * @param {buffer} buf the buffer to check.

// check buffer size
if (buf.length != modbus._length) return false;
if (buf.length != modbus._length && buf.length != 5) return false;
// calculate crc16

@@ -52,4 +53,4 @@ var crcIn = buf.readUInt16LE(buf.length - 2);

// check buffer unit-id, command and crc
return (buf[0] == modbus._id &&
buf[1] == modbus._cmd &&
return (buf[0] == modbus._id &&
(0x7f & buf[1]) == modbus._cmd &&
crcIn == crc16(buf));

@@ -78,3 +79,3 @@ }

// check message length
if (data.length < (116 + modbus.length)) return;
if (data.length < (116 + 5)) return;

@@ -84,2 +85,3 @@ // check the C701 packet magic

// check for modbus valid answer
// get the serial data from the C701 packet

@@ -91,3 +93,14 @@ var buffer = data.slice(data.length - modbus._length);

modbus.emit('data', buffer);
return;
}
// check for modbus exception
// get the serial data from the C701 packet
var buffer = data.slice(data.length - 5);
//check the serial data
if (checkData(modbus, buffer)) {
modbus.emit('data', buffer);
return;
}
});

@@ -144,2 +157,3 @@

case 6:
case 15:
case 16:

@@ -146,0 +160,0 @@ this._length = 6 + 2;

@@ -35,2 +35,3 @@ 'use strict';

* check if a buffer chunk can be a modbus answer
* or modbus exception
*

@@ -42,3 +43,3 @@ * @param {buffer} buf the buffer to check.

// check buffer size
if (buf.length != modbus._length) return false;
if (buf.length != modbus._length && buf.length != 5) return false;

@@ -50,3 +51,3 @@ // calculate crc16

return (buf[0] == modbus._id &&
buf[1] == modbus._cmd &&
(0x7f & buf[1]) == modbus._cmd &&
crcIn == crc16(buf));

@@ -85,3 +86,3 @@ }

// check data length
if (bufferLength < 6 || length < 6) return;
if (bufferLength < 5 || length < 6) return;

@@ -155,2 +156,3 @@ // loop and check length-sized buffer chunks

case 6:
case 15:
case 16:

@@ -157,0 +159,0 @@ this._length = 6 + 2;

@@ -37,2 +37,3 @@ 'use strict';

* check if a buffer chunk can be a modbus answer
* or modbus exception
*

@@ -44,3 +45,3 @@ * @param {buffer} buf the buffer to check.

// check buffer size
if (buf.length != modbus._length) return false;
if (buf.length != modbus._length && buf.length != 5) return false;

@@ -52,3 +53,3 @@ // calculate crc16

return (buf[0] == modbus._id &&
buf[1] == modbus._cmd &&
(0x7f & buf[1]) == modbus._cmd &&
crcIn == crc16(buf));

@@ -89,3 +90,3 @@ }

// check data length
if (bufferLength < 6 || length < 6) return;
if (bufferLength < 5 || length < 6) return;

@@ -162,2 +163,3 @@ // loop and check length-sized buffer chunks

case 6:
case 15:
case 16:

@@ -164,0 +166,0 @@ this._length = 6 + 2;

@@ -5,2 +5,6 @@ 'use strict';

/* Add bit operation functions to Buffer
*/
require('../apis/buffer_bit')();
/**

@@ -14,6 +18,6 @@ * Simulate a serial port with 4 modbus-rtu slaves connected

var TestPort = function() {
// simulate 14 input registers
// simulate 11 input registers
this._registers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// simulate 14 holding registers
// simulate 11 holding registers
this._holding_registers = [0,0,0,0,0,0,0,0, 0xa12b, 0xffff, 0xb21a ];

@@ -167,3 +171,3 @@

if (state == 0xff00) {
this._coils |= 1 << address;
this._coils |= (1 << address);
} else {

@@ -191,4 +195,29 @@ this._coils &= ~(1 << address);

// function code 15
if (functionCode == 15) {
var address = buf.readUInt16BE(2);
var length = buf.readUInt16BE(4);
// if length is bad, ignore message
if (buf.length != 7 + Math.ceil(length / 8) + 2) {
return;
}
// build answer
buffer = new Buffer(8);
buffer.writeUInt16BE(address, 2);
buffer.writeUInt16BE(length, 4);
// write coils
for (var i = 0; i < length; i++) {
var state = buf.readBit(i, 7);
if (state) {
this._coils |= (1 << (address + i));
} else {
this._coils &= ~(1 << (address + i));
}
}
}
// function code 16

@@ -221,6 +250,2 @@ if (functionCode == 16) {

// add crc
crc = crc16(buffer);
buffer.writeUInt16LE(crc, buffer.length - 2);
// corrupt the answer

@@ -235,6 +260,2 @@ switch (unitNumber) {

break;
case 3:
// unit 3: answers with bad crc
buffer.writeUInt16LE(crc + 1, buffer.length - 2);
break;
case 4:

@@ -246,2 +267,11 @@ // unit 4: answers with bad unit number

// add crc
crc = crc16(buffer);
buffer.writeUInt16LE(crc, buffer.length - 2);
// unit 3: answers with bad crc
if (unitNumber == 3) {
buffer.writeUInt16LE(crc + 1, buffer.length - 2);
}
this.emit('data', buffer);

@@ -248,0 +278,0 @@ }

# modbus-serial
A pure JavaScript implemetation of MODBUS-RTU (and TCP) for NodeJS
[![NPM Version](https://img.shields.io/npm/v/gm.svg?style=flat)](https://www.npmjs.com/package/modbus-serial)
[![npm](https://img.shields.io/npm/v/npm.svg)](https://www.npmjs.com/package/modbus-serial)

@@ -65,2 +65,3 @@ This class makes ModbusRTU (and TCP) calls fun and easy.

* FC6 "Preset Single Register"
* FC15 "Force Multiple Coil"
* FC16 "Preset Multiple Registers"

@@ -70,3 +71,4 @@

* Modbus-RTU (modbus-rtu): Over serial line [require node serialport].
* modbus-RTU (modbus-rtu): Over serial line [require node serialport].
* modbus-ASCII (modbus-ascii): Over serial line [require node serialport].
* modbus-TCP (modbus-tcp): Over TCP/IP line.

@@ -263,2 +265,12 @@ * modbus-RTU (telnet): Over Telnet server, TCP/IP serial bridge.

----
##### .writeCoils(address, array)
Writes "Force Multiple Coils" (FC=15) request to serial port.
*address {number}:*
The Data Address of the first register.
*array {array}:*
The array of states to force into the coils.
----
##### .writeRegisters (address, array)

@@ -420,3 +432,20 @@ Writes "Preset Multiple Registers" (FC=16) request to serial port.

----
##### .writeFC6 (unit, address, array, callback)
##### .writeFC15 (unit, address, array, callback)
Writes "Force Multiple Coils" (FC=15) request to serial port.
*unit {number}:*
The slave unit address.
*address {number}:*
The Data Address of the first register.
*array {array}:*
The array of states to send to unit.
*callback {function}:* (optional)
Called once the unit returns an answer. The callback should be a function
that looks like: function (error, data) { ... }
----
##### .writeFC6 (unit, address, value, callback)
Writes "Preset Single Register" (FC=6) request to serial port.

@@ -551,1 +580,14 @@

Called once the client is connected.
----
##### .connectAsciiSerial (path, options, callback)
Connect using serial port with ASCII encoding.
*path {string}:*
The port path (e.g. "/dev/ttyS0")
*options {object}:* (optional)
The options for this connection.
*callback {function}:* (optional)
Called once the client is connected.

@@ -27,2 +27,3 @@ 'use strict';

expect(data.data.toString()).to.equal([0xa12b, 0xffff, 0xb21a].toString());
done()

@@ -37,2 +38,3 @@ });

expect(data.buffer.toString('hex')).to.equal("a12bffffb21a");
done()

@@ -49,2 +51,3 @@ });

expect(data.data.toString()).to.equal([8, 9, 10].toString());
done()

@@ -115,4 +118,50 @@ });

describe('#writeFC15() - force multiple coils.', function () {
it('should write 3 coils [true, false, true] without errors', function (done) {
modbusRTU.writeFC15(1, 8, [true, false, true], function(err, data) {
expect(err).to.be.a('null');
done()
});
});
it('should fail on short data answer', function (done) {
modbusRTU.writeFC15(2, 8, [true, false, true], function(err, data) {
expect(err).to.have.string('Data length error');
done()
});
});
it('should fail on CRC error', function (done) {
modbusRTU.writeFC15(3, 8, [true, false, true], function(err, data) {
expect(err).to.have.string('CRC error');
done()
});
});
it('should fail on unexpected replay', function (done) {
modbusRTU.writeFC15(4, 8, [true, false, true], function(err, data) {
expect(err).to.have.string('Unexpected data error');
done()
});
});
});
describe('#writeFC1() - read coils after force multiple coils.', function () {
it('should read coil 8, 9 ,10 to be true, false, true', function (done) {
modbusRTU.writeFC1(1, 8, 4, function(err, data) {
expect(err).to.be.a('null');
expect(data).to.have.property('data');
expect(data.data[0]).to.equal(true);
expect(data.data[1]).to.equal(false);
expect(data.data[2]).to.equal(true);
done()
});
});
});
describe('#writeFC16() - write holding registers.', function () {

@@ -158,2 +207,3 @@ it('should write 3 registers [42, 128, 5] without errors', function (done) {

expect(data.data.toString()).to.equal([42, 128, 5].toString());
done()

@@ -160,0 +210,0 @@ });

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