modbus-serial
Advanced tools
Comparing version 3.3.5 to 3.4.5
@@ -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. | ||
@@ -29,3 +29,3 @@ */ | ||
var id = this._unitID; | ||
/* the function check for a callback | ||
@@ -48,10 +48,10 @@ * if we have a callback, use it | ||
} | ||
f.bind(client)(id, address, arg, cb); | ||
}); | ||
return promise; | ||
} | ||
} | ||
return converted; | ||
@@ -66,9 +66,9 @@ } | ||
var addPromiseAPI = function(Modbus) { | ||
var cl = Modbus.prototype; | ||
// set/get unitID | ||
cl.setID = function(id) {this._unitID = id;} | ||
cl.getID = function() {return this._unitID;} | ||
// convert functions to return promises | ||
@@ -80,2 +80,3 @@ cl.readCoils = convert(cl.writeFC1); | ||
cl.writeCoil = convert(cl.writeFC5); | ||
cl.writeRegister = convert(cl.writeFC6); | ||
cl.writeRegisters = convert(cl.writeFC16); | ||
@@ -82,0 +83,0 @@ } |
199
index.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. | ||
@@ -24,7 +24,7 @@ */ | ||
* Modbus is a serial communications protocol, first used in 1979. | ||
* Modbus is simple and robust, openly published, royalty-free and | ||
* Modbus is simple and robust, openly published, royalty-free and | ||
* easy to deploy and maintain. | ||
*/ | ||
/** | ||
/** | ||
* Calculate buffer CRC16 and add it to the | ||
@@ -41,7 +41,7 @@ * end of the buffer. | ||
var tmp; | ||
// calculate crc16 | ||
for (var i = 0; i < length; i++) { | ||
crc = crc ^ buf[i]; | ||
for (var j = 0; j < 8; j++) { | ||
@@ -55,6 +55,6 @@ tmp = crc & 0x0001; | ||
} | ||
// add to end of buffer | ||
buf.writeUInt16LE(crc, length); | ||
// return the crc | ||
@@ -64,3 +64,3 @@ return crc; | ||
/** | ||
/** | ||
* Parse the data for a Modbus - | ||
@@ -75,6 +75,6 @@ * Read Coils (FC=02,01) | ||
var contents = []; | ||
for (var i = 0; i < length; i++) { | ||
var reg = data[i + 3]; | ||
for (var j = 0; j < 8; j++) { | ||
@@ -85,3 +85,3 @@ contents.push((reg & 1) == 1); | ||
} | ||
if (next) | ||
@@ -91,3 +91,3 @@ next(null, {"data": contents, "buffer": data.slice(3, 3 + length)}); | ||
/** | ||
/** | ||
* Parse the data for a Modbus - | ||
@@ -102,3 +102,3 @@ * Read Input Registers (FC=04,03) | ||
var contents = []; | ||
for (var i = 0; i < length; i += 2) { | ||
@@ -108,3 +108,3 @@ var reg = data.readUInt16BE(i + 3); | ||
} | ||
if (next) | ||
@@ -114,3 +114,3 @@ next(null, {"data": contents, "buffer": data.slice(3, 3 + length)}); | ||
/** | ||
/** | ||
* Parse the data for a Modbus - | ||
@@ -125,3 +125,3 @@ * Force Single Coil (FC=05) | ||
var state = data.readUInt16BE(4); | ||
if (next) | ||
@@ -131,4 +131,19 @@ next(null, {"address": dataAddress, "state": (state == 0xff00)}); | ||
/** | ||
/** | ||
* Parse the data for a Modbus - | ||
* Preset Single Registers (FC=06) | ||
* | ||
* @param {buffer} data the data buffer to parse. | ||
* @param {function} next the function to call next. | ||
*/ | ||
function _readFC6(data, next) { | ||
var dataAddress = data.readUInt16BE(2); | ||
var value = data.readUInt16BE(4); | ||
if (next) | ||
next(null, {"address": dataAddress, "value": value}); | ||
} | ||
/** | ||
* Parse the data for a Modbus - | ||
* Preset Multiple Registers (FC=16) | ||
@@ -142,3 +157,3 @@ * | ||
var length = data.readUInt16BE(4); | ||
if (next) | ||
@@ -156,3 +171,3 @@ next(null, {"address": dataAddress, "length": length}); | ||
this._port = port; | ||
// state variables | ||
@@ -163,3 +178,3 @@ this._nextAddress = null; // unit address of current function call. | ||
this._next = null; // the function to call on success or failure | ||
this._unitID = 1; | ||
@@ -176,3 +191,3 @@ }; | ||
var modbus = this; | ||
// open the serial port | ||
@@ -192,4 +207,4 @@ modbus._port.open(function (error) { | ||
callback(error); | ||
/* On serial port success | ||
/* On serial port success | ||
* register the modbus parser functions | ||
@@ -201,6 +216,6 @@ */ | ||
var next = modbus._next; | ||
/* check incoming data | ||
*/ | ||
/* check message length | ||
@@ -210,4 +225,5 @@ * if we do not expect this data | ||
*/ | ||
if (data.length != length) { | ||
error = "Data length error, expected " + | ||
error = "Data length error, expected " + | ||
length + " got " + data.length; | ||
@@ -218,6 +234,6 @@ if (next) | ||
} | ||
var address = data.readUInt8(0); | ||
var code = data.readUInt8(1); | ||
/* check message address and code | ||
@@ -234,3 +250,3 @@ * if we do not expect this message | ||
} | ||
// data is OK - clear state variables | ||
@@ -240,3 +256,3 @@ modbus._nextAddress = null; | ||
modbus._next = null; | ||
/* check message CRC | ||
@@ -247,3 +263,3 @@ * if CRC is bad raise an error | ||
var crc = _CRC16(data, length - 2); | ||
if (crcIn != crc) { | ||
@@ -255,6 +271,6 @@ error = "CRC error"; | ||
} | ||
/* parse incoming data | ||
*/ | ||
/* Read Coil Status (FC=01) | ||
@@ -266,3 +282,3 @@ * Read Input Status (FC=02) | ||
} | ||
/* Read Input Registers (FC=04) | ||
@@ -274,3 +290,3 @@ * Read Holding Registers (FC=03) | ||
} | ||
/* Force Single Coil (FC=05) | ||
@@ -281,3 +297,9 @@ */ | ||
} | ||
/* Preset Single Register (FC=06) | ||
*/ | ||
if (code == 6) { | ||
_readFC6(data, next); | ||
} | ||
// Preset Multiple Registers (FC=16) | ||
@@ -292,3 +314,3 @@ if (code == 16) { | ||
/** | ||
/** | ||
* Write a Modbus "Read Coil Status" (FC=01) to serial port. | ||
@@ -305,3 +327,3 @@ * | ||
/** | ||
/** | ||
* Write a Modbus "Read Input Status" (FC=02) to serial port. | ||
@@ -317,3 +339,3 @@ * | ||
if (!code) code = 2; | ||
// set state variables | ||
@@ -324,6 +346,6 @@ this._nextAddress = address; | ||
this._next = next; | ||
var codeLength = 6; | ||
var buf = new Buffer(codeLength + 2); // add 2 crc bytes | ||
buf.writeUInt8(address, 0); | ||
@@ -333,6 +355,6 @@ buf.writeUInt8(code, 1); | ||
buf.writeUInt16BE(length, 4); | ||
// add crc bytes to buffer | ||
_CRC16(buf, codeLength); | ||
// write buffer to serial port | ||
@@ -342,3 +364,3 @@ this._port.write(buf); | ||
/** | ||
/** | ||
* Write a Modbus "Read Holding Registers" (FC=03) to serial port. | ||
@@ -355,3 +377,3 @@ * | ||
/** | ||
/** | ||
* Write a Modbus "Read Input Registers" (FC=04) to serial port. | ||
@@ -367,3 +389,3 @@ * | ||
if (!code) code = 4; | ||
// set state variables | ||
@@ -374,6 +396,6 @@ this._nextAddress = address; | ||
this._next = next; | ||
var codeLength = 6; | ||
var buf = new Buffer(codeLength + 2); // add 2 crc bytes | ||
buf.writeUInt8(address, 0); | ||
@@ -383,6 +405,6 @@ buf.writeUInt8(code, 1); | ||
buf.writeUInt16BE(length, 4); | ||
// add crc bytes to buffer | ||
_CRC16(buf, codeLength); | ||
// write buffer to serial port | ||
@@ -392,3 +414,3 @@ this._port.write(buf); | ||
/** | ||
/** | ||
* Write a Modbus "Force Single Coil" (FC=05) to serial port. | ||
@@ -403,3 +425,3 @@ * | ||
var code = 5; | ||
// set state variables | ||
@@ -410,10 +432,10 @@ this._nextAddress = address; | ||
this._next = next; | ||
var codeLength = 6; | ||
var buf = new Buffer(codeLength + 2); // add 2 crc bytes | ||
buf.writeUInt8(address, 0); | ||
buf.writeUInt8(code, 1); | ||
buf.writeUInt16BE(dataAddress, 2); | ||
if (state) { | ||
@@ -424,6 +446,6 @@ buf.writeUInt16BE(0xff00, 4); | ||
} | ||
// add crc bytes to buffer | ||
_CRC16(buf, codeLength); | ||
// write buffer to serial port | ||
@@ -433,3 +455,38 @@ this._port.write(buf); | ||
/** | ||
/** | ||
* Write a Modbus "Preset Single Register " (FC=6) to serial port. | ||
* | ||
* @param {number} address the slave unit address. | ||
* @param {value} number the value to write to a specific register. | ||
* @param {function} next the function to call next. | ||
*/ | ||
ModbusRTU.prototype.writeFC6 = function (address, dataAddress, value, next) { | ||
var code = 6; | ||
// set state variables | ||
this._nextAddress = address; | ||
this._nextCode = code; | ||
this._nextLength = 8; | ||
this._next = next; | ||
var codeLength = 6; // 1B deviceAddress + 1B functionCode + 2B dataAddress + 2B value | ||
var buf = new Buffer(codeLength + 2); // add 2 crc bytes | ||
buf.writeUInt8(address, 0); | ||
buf.writeUInt8(code, 1); | ||
buf.writeUInt16BE(dataAddress, 2); | ||
buf.writeUInt16BE(value, 4); | ||
// add crc bytes to buffer | ||
_CRC16(buf, codeLength); | ||
// write buffer to serial port | ||
this._port.write(buf); | ||
} | ||
/** | ||
* Write a Modbus "Preset Multiple Registers" (FC=16) to serial port. | ||
@@ -444,3 +501,3 @@ * | ||
var code = 16; | ||
// set state variables | ||
@@ -451,6 +508,6 @@ this._nextAddress = address; | ||
this._next = next; | ||
var codeLength = 7 + 2 * array.length; | ||
var buf = new Buffer(codeLength + 2); // add 2 crc bytes | ||
buf.writeUInt8(address, 0); | ||
@@ -461,10 +518,10 @@ buf.writeUInt8(code, 1); | ||
buf.writeUInt8(array.length * 2, 6); | ||
for (var i = 0; i < array.length; i++) { | ||
buf.writeUInt16BE(array[i], 7 + 2 * i); | ||
} | ||
// add crc bytes to buffer | ||
_CRC16(buf, codeLength); | ||
// write buffer to serial port | ||
@@ -471,0 +528,0 @@ this._port.write(buf); |
{ | ||
"name": "modbus-serial", | ||
"version": "3.3.5", | ||
"version": "3.4.5", | ||
"description": "A pure JavaScript implemetation of MODBUS-RTU (and TCP) for NodeJS.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -16,7 +16,7 @@ 'use strict'; | ||
var tmp; | ||
// calculate crc16 | ||
for (var i = 0; i < length; i++) { | ||
crc = crc ^ buf[i]; | ||
for (var j = 0; j < 8; j++) { | ||
@@ -30,3 +30,3 @@ tmp = crc & 0x0001; | ||
} | ||
return crc; | ||
@@ -44,8 +44,8 @@ } | ||
if (buf.length != modbus._length) return false; | ||
// calculate crc16 | ||
var crcIn = buf.readUInt16LE(buf.length - 2); | ||
// check buffer unit-id, command and crc | ||
return (buf[0] == modbus._id && | ||
return (buf[0] == modbus._id && | ||
buf[1] == modbus._cmd && | ||
@@ -60,6 +60,6 @@ crcIn == crc16(buf)); | ||
var modbus = this; | ||
// options | ||
if (typeof(options) == 'undefined') options = {}; | ||
// internal buffer | ||
@@ -70,6 +70,6 @@ this._buffer = new Buffer(0); | ||
this._length = 0; | ||
// create the SerialPort | ||
this._client= new SerialPort(path, options); | ||
// register the port data event | ||
@@ -80,3 +80,3 @@ this._client.on('data', function(data) { | ||
modbus._buffer = Buffer.concat([modbus._buffer, data]); | ||
/* check if buffer include a complete modbus answer | ||
@@ -86,6 +86,6 @@ */ | ||
var bufferLength = modbus._buffer.length ; | ||
// check data length | ||
if (bufferLength < 6 || length < 6) return; | ||
// loop and check length-sized buffer chunks | ||
@@ -95,3 +95,3 @@ for (var i = 0; i < (bufferLength - length + 1); i++) { | ||
var _data = modbus._buffer.slice(i, i + length); | ||
// check if this is the data we are waiting for | ||
@@ -101,3 +101,3 @@ if (checkData(modbus, _data)) { | ||
i = i + length; | ||
// emit a data signal | ||
@@ -107,3 +107,3 @@ modbus.emit('data', _data); | ||
} | ||
/* cut checked data from buffer | ||
@@ -142,7 +142,7 @@ */ | ||
} | ||
// remember current unit and command | ||
this._id = data[0]; | ||
this._cmd = data[1]; | ||
// calculate expected answer length | ||
@@ -161,2 +161,3 @@ switch (this._cmd) { | ||
case 5: | ||
case 6: | ||
case 16: | ||
@@ -170,3 +171,3 @@ this._length = 6 + 2; | ||
} | ||
// send buffer to slave | ||
@@ -173,0 +174,0 @@ this._client.write(data); |
@@ -18,7 +18,7 @@ 'use strict'; | ||
var tmp; | ||
// calculate crc16 | ||
for (var i = 0; i < length; i++) { | ||
crc = crc ^ buf[i]; | ||
for (var j = 0; j < 8; j++) { | ||
@@ -32,3 +32,3 @@ tmp = crc & 0x0001; | ||
} | ||
return crc; | ||
@@ -46,8 +46,8 @@ } | ||
if (buf.length != modbus._length) return false; | ||
// calculate crc16 | ||
var crcIn = buf.readUInt16LE(buf.length - 2); | ||
// check buffer unit-id, command and crc | ||
return (buf[0] == modbus._id && | ||
return (buf[0] == modbus._id && | ||
buf[1] == modbus._cmd && | ||
@@ -63,7 +63,7 @@ crcIn == crc16(buf)); | ||
this.ip = ip; | ||
// options | ||
if (typeof(options) == 'undefined') options = {}; | ||
this.port = options.port || TELNET_PORT; // telnet server port | ||
// internal buffer | ||
@@ -74,6 +74,6 @@ this._buffer = new Buffer(0); | ||
this._length = 0; | ||
// create a socket | ||
this._client = new net.Socket(); | ||
// register the port data event | ||
@@ -84,3 +84,3 @@ this._client.on('data', function(data) { | ||
modbus._buffer = Buffer.concat([modbus._buffer, data]); | ||
/* check if buffer include a complete modbus answer | ||
@@ -90,6 +90,6 @@ */ | ||
var bufferLength = modbus._buffer.length ; | ||
// check data length | ||
if (bufferLength < 6 || length < 6) return; | ||
// loop and check length-sized buffer chunks | ||
@@ -99,3 +99,3 @@ for (var i = 0; i < (bufferLength - length + 1); i++) { | ||
var _data = modbus._buffer.slice(i, i + length); | ||
// check if this is the data we are waiting for | ||
@@ -105,3 +105,3 @@ if (checkData(modbus, _data)) { | ||
i = i + length; | ||
// emit a data signal | ||
@@ -111,3 +111,3 @@ modbus.emit('data', _data); | ||
} | ||
/* cut checked data from buffer | ||
@@ -149,7 +149,7 @@ */ | ||
} | ||
// remember current unit and command | ||
this._id = data[0]; | ||
this._cmd = data[1]; | ||
// calculate expected answer length | ||
@@ -168,2 +168,3 @@ switch (this._cmd) { | ||
case 5: | ||
case 6: | ||
case 16: | ||
@@ -177,3 +178,3 @@ this._length = 6 + 2; | ||
} | ||
// send buffer to slave | ||
@@ -180,0 +181,0 @@ this._client.write(data); |
@@ -15,9 +15,9 @@ 'use strict'; | ||
this._registers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; | ||
// simulate 14 holding registers | ||
this._holding_registers = [0,0,0,0,0,0,0,0, 0xa12b, 0xffff, 0xb21a ]; | ||
// simulate 16 coils / digital inputs | ||
this._coils = 0x0000; | ||
events.call(this); | ||
@@ -38,7 +38,7 @@ } | ||
var tmp; | ||
// calculate crc16 | ||
for (var i = 0; i < length; i++) { | ||
crc = crc ^ buf[i]; | ||
for (var j = 0; j < 8; j++) { | ||
@@ -52,3 +52,3 @@ tmp = crc & 0x0001; | ||
} | ||
return crc; | ||
@@ -78,3 +78,3 @@ } | ||
var buffer = null; | ||
// if length is too short, ignore message | ||
@@ -84,7 +84,7 @@ if (buf.length < 8) { | ||
} | ||
var unitNumber = buf[0]; | ||
var functionCode = buf[1]; | ||
var crc = buf[buf.length - 2] + buf[buf.length - 1] * 0x100; | ||
// if crc is bad, ignore message | ||
@@ -94,3 +94,3 @@ if (crc != crc16(buf)) { | ||
} | ||
// function code 1 and 2 | ||
@@ -100,3 +100,3 @@ if (functionCode == 1 || functionCode == 2) { | ||
var length = buf.readUInt16BE(4); | ||
// if length is bad, ignore message | ||
@@ -106,11 +106,11 @@ if (buf.length != 8) { | ||
} | ||
// build answer | ||
buffer = new Buffer(3 + parseInt((length - 1) / 8 + 1) + 2); | ||
buffer.writeUInt8(parseInt((length - 1) / 8 + 1), 2); | ||
// read coils | ||
buffer.writeUInt16LE(this._coils >> address, 3); | ||
} | ||
// function code 3 | ||
@@ -120,3 +120,3 @@ if (functionCode == 3) { | ||
var length = buf.readUInt16BE(4); | ||
// if length is bad, ignore message | ||
@@ -126,7 +126,7 @@ if (buf.length != 8) { | ||
} | ||
// build answer | ||
buffer = new Buffer(3 + length * 2 + 2); | ||
buffer.writeUInt8(length * 2, 2); | ||
// read registers | ||
@@ -137,3 +137,3 @@ for (var i = 0; i < length; i++) { | ||
} | ||
// function code 4 | ||
@@ -143,3 +143,3 @@ if (functionCode == 4) { | ||
var length = buf.readUInt16BE(4); | ||
// if length is bad, ignore message | ||
@@ -149,7 +149,7 @@ if (buf.length != 8) { | ||
} | ||
// build answer | ||
buffer = new Buffer(3 + length * 2 + 2); | ||
buffer.writeUInt8(length * 2, 2); | ||
// read registers | ||
@@ -160,3 +160,3 @@ for (var i = 0; i < length; i++) { | ||
} | ||
// function code 5 | ||
@@ -166,3 +166,3 @@ if (functionCode == 5) { | ||
var state = buf.readUInt16BE(4); | ||
// if length is bad, ignore message | ||
@@ -172,3 +172,3 @@ if (buf.length != 8) { | ||
} | ||
// build answer | ||
@@ -178,11 +178,30 @@ buffer = new Buffer(8); | ||
buffer.writeUInt16BE(state, 4); | ||
// write coil | ||
if (state == 0xff00) { | ||
this._coils |= 1 << address; | ||
this._coils |= 1 << address; | ||
} else { | ||
this._coils &= ~(1 << address); | ||
this._coils &= ~(1 << address); | ||
} | ||
} | ||
// function code 6 | ||
if (functionCode == 6) { | ||
var address = buf.readUInt16BE(2); | ||
var value = buf.readUInt16BE(4); | ||
// if length is bad, ignore message | ||
if (buf.length != (6 + 2)) { | ||
return; | ||
} | ||
// build answer | ||
buffer = new Buffer(8); | ||
buffer.writeUInt16BE(address, 2); | ||
buffer.writeUInt16BE(value, 4); | ||
this._holding_registers[address] = value; | ||
} | ||
// function code 16 | ||
@@ -192,3 +211,3 @@ if (functionCode == 16) { | ||
var length = buf.readUInt16BE(4); | ||
// if length is bad, ignore message | ||
@@ -198,3 +217,3 @@ if (buf.length != (7 + length * 2 + 2)) { | ||
} | ||
// build answer | ||
@@ -204,3 +223,3 @@ buffer = new Buffer(8); | ||
buffer.writeUInt16BE(length, 4); | ||
// write registers | ||
@@ -211,3 +230,3 @@ for (var i = 0; i < length; i++) { | ||
} | ||
// send data back | ||
@@ -218,7 +237,7 @@ if (buffer) { | ||
buffer.writeUInt8(functionCode, 1); | ||
// add crc | ||
crc = crc16(buffer); | ||
buffer.writeUInt16LE(crc, buffer.length - 2); | ||
// corrupt the answer | ||
@@ -242,3 +261,3 @@ switch (unitNumber) { | ||
} | ||
this.emit('data', buffer); | ||
@@ -245,0 +264,0 @@ } |
@@ -9,3 +9,3 @@ # modbus-serial | ||
Modbus is a serial communications protocol, first used in 1979. | ||
Modbus is simple and robust, openly published, royalty-free and | ||
Modbus is simple and robust, openly published, royalty-free and | ||
easy to deploy and maintain. | ||
@@ -44,3 +44,3 @@ | ||
Arduino can also talk modbus and you can control your projects and robots | ||
using modbus. | ||
using modbus. | ||
@@ -50,9 +50,9 @@ Arduino libraries for modbus slave: | ||
* https://github.com/smarmengol/Modbus-Master-Slave-for-Arduino | ||
Arduino sketch for irrigation timer with modbus support: | ||
* https://github.com/yaacov/arduino-irrigation-timer | ||
Node Modbus-WebSocket bridge: | ||
* https://github.com/yaacov/node-modbus-ws | ||
#### Compatibility | ||
@@ -67,2 +67,3 @@ | ||
* FC5 "Force Single Coil" | ||
* FC6 "Preset Single Register" | ||
* FC16 "Preset Multiple Registers" | ||
@@ -93,3 +94,3 @@ | ||
client.setID(1); | ||
client.readInputRegisters(0, 10) | ||
@@ -275,2 +276,14 @@ .then(console.log) | ||
---- | ||
---- | ||
##### .writeRegister (address, value) | ||
Writes "Preset Single Register" (FC=6) request to serial port. | ||
*address {number}:* | ||
The Data Address of the first register. | ||
*value {number}:* | ||
The value to set into the register. | ||
---- | ||
###### API Callbacks | ||
@@ -314,3 +327,3 @@ ---- | ||
*callback {function}:* (optional) | ||
Called once the unit returns an answer. The callback should be a function | ||
Called once the unit returns an answer. The callback should be a function | ||
that looks like: function (error, data) { ... } | ||
@@ -338,3 +351,3 @@ ``` | ||
*callback {function}:* (optional) | ||
Called once the unit returns an answer. The callback should be a function | ||
Called once the unit returns an answer. The callback should be a function | ||
that looks like: function (error, data) { ... } | ||
@@ -362,3 +375,3 @@ ``` | ||
*callback {function}:* (optional) | ||
Called once the unit returns an answer. The callback should be a function | ||
Called once the unit returns an answer. The callback should be a function | ||
that looks like: function (error, data) { ... } | ||
@@ -386,3 +399,3 @@ ``` | ||
*callback {function}:* (optional) | ||
Called once the unit returns an answer. The callback should be a function | ||
Called once the unit returns an answer. The callback should be a function | ||
that looks like: function (error, data) { ... } | ||
@@ -410,6 +423,23 @@ ``` | ||
*callback {function}:* (optional) | ||
Called once the unit returns an answer. The callback should be a function | ||
Called once the unit returns an answer. The callback should be a function | ||
that looks like: function (error, data) { ... } | ||
---- | ||
##### .writeFC6 (unit, address, array, callback) | ||
Writes "Preset Single Register" (FC=6) request to serial port. | ||
*unit {number}:* | ||
The slave unit address. | ||
*address {number}:* | ||
The Data Address of the first register. | ||
*value {number}:* | ||
The value to sent to unit. | ||
*callback {function}:* (optional) | ||
Called once the unit returns an answer. The callback should be a function | ||
that looks like: function (error, data) { ... } | ||
---- | ||
##### .writeFC16 (unit, address, array, callback) | ||
@@ -428,3 +458,3 @@ Writes "Preset Multiple Registers" (FC=16) request to serial port. | ||
*callback {function}:* (optional) | ||
Called once the unit returns an answer. The callback should be a function | ||
Called once the unit returns an answer. The callback should be a function | ||
that looks like: function (error, data) { ... } | ||
@@ -431,0 +461,0 @@ |
@@ -10,3 +10,3 @@ 'use strict'; | ||
describe('ModbusRTU', function() { | ||
describe('#open() - open serial port.', function () { | ||
@@ -16,3 +16,3 @@ it('should open the port without errors', function (done) { | ||
expect(err).to.be.a('null'); | ||
done(); | ||
@@ -22,3 +22,3 @@ }); | ||
}); | ||
describe('#writeFC3() - read holding registers.', function () { | ||
@@ -33,3 +33,3 @@ it('should read 3 registers [0xa12b, 0xffff, 0xb21a] without errors', function (done) { | ||
}); | ||
it('should read raw buffer "a12bffffb21a" without errors', function (done) { | ||
@@ -44,3 +44,3 @@ modbusRTU.writeFC3(1, 8, 3, function(err, data) { | ||
}); | ||
describe('#writeFC4() - read input registers.', function () { | ||
@@ -55,23 +55,23 @@ it('should read 3 registers [8, 9, 10] without errors', function (done) { | ||
}); | ||
it('should fail on short data answer', function (done) { | ||
modbusRTU.writeFC4(2, 8, 1, function(err, data) { | ||
expect(err).to.have.string('Data length error'); | ||
done() | ||
}); | ||
}); | ||
it('should fail on CRC error', function (done) { | ||
modbusRTU.writeFC4(3, 8, 1, function(err, data) { | ||
expect(err).to.have.string('CRC error'); | ||
done() | ||
}); | ||
}); | ||
it('should fail on unexpected replay', function (done) { | ||
modbusRTU.writeFC4(4, 8, 1, function(err, data) { | ||
expect(err).to.have.string('Unexpected data error'); | ||
done() | ||
@@ -81,32 +81,70 @@ }); | ||
}); | ||
describe('#writeFC6() - write single holding register.', function () { | ||
it('should write to register 1 42 without errors', function (done) { | ||
modbusRTU.writeFC6(1, 1, 42, function(err, data) { | ||
expect(err).to.be.a('null'); | ||
expect(data.address).to.equal(1); | ||
expect(data.value).to.equal(42); | ||
done() | ||
}); | ||
}); | ||
it('should fail on short data answer', function (done) { | ||
modbusRTU.writeFC6(2, 1, 42, function(err, data) { | ||
expect(err).to.have.string('Data length error'); | ||
done() | ||
}); | ||
}); | ||
it('should fail on CRC error', function (done) { | ||
modbusRTU.writeFC6(3, 1, 42, function(err, data) { | ||
expect(err).to.have.string('CRC error'); | ||
done() | ||
}); | ||
}); | ||
it('should fail on unexpected replay', function (done) { | ||
modbusRTU.writeFC6(4, 1, 42, function(err, data) { | ||
expect(err).to.have.string('Unexpected data error'); | ||
done() | ||
}); | ||
}); | ||
}); | ||
describe('#writeFC16() - write holding registers.', function () { | ||
it('should write 3 registors [42, 128, 5] without errors', function (done) { | ||
it('should write 3 registers [42, 128, 5] without errors', function (done) { | ||
modbusRTU.writeFC16(1, 8, [42, 128, 5], function(err, data) { | ||
expect(err).to.be.a('null'); | ||
done() | ||
}); | ||
}); | ||
it('should fail on short data answer', function (done) { | ||
modbusRTU.writeFC16(2, 8, [42, 128, 5], function(err, data) { | ||
expect(err).to.have.string('Data length error'); | ||
done() | ||
}); | ||
}); | ||
it('should fail on CRC error', function (done) { | ||
modbusRTU.writeFC16(3, 8, [42, 128, 5], function(err, data) { | ||
expect(err).to.have.string('CRC error'); | ||
done() | ||
}); | ||
}); | ||
it('should fail on unexpected replay', function (done) { | ||
modbusRTU.writeFC16(4, 8, [42, 128, 5], function(err, data) { | ||
expect(err).to.have.string('Unexpected data error'); | ||
done() | ||
@@ -116,3 +154,3 @@ }); | ||
}); | ||
describe('#writeFC3() - read holding registers after write.', function () { | ||
@@ -128,3 +166,3 @@ it('should read 3 registers [42, 128, 5] without errors', function (done) { | ||
}); | ||
describe('#writeFC5() - force one coil.', function () { | ||
@@ -136,3 +174,3 @@ it('should force coil 3 to be true, without errors', function (done) { | ||
expect(data.state).to.equal(true); | ||
done() | ||
@@ -142,3 +180,3 @@ }); | ||
}); | ||
describe('#writeFC1() - read coils after force coil.', function () { | ||
@@ -151,3 +189,3 @@ it('should read coil 3 to be true, without errors', function (done) { | ||
expect(data.data[3]).to.equal(false); | ||
done() | ||
@@ -157,3 +195,3 @@ }); | ||
}); | ||
describe('#writeFC1() - read inputs.', function () { | ||
@@ -166,3 +204,3 @@ it('should read input 0 to be false, without errors', function (done) { | ||
expect(data.data[3]).to.equal(true); | ||
done() | ||
@@ -172,4 +210,4 @@ }); | ||
}); | ||
}); | ||
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
77921
1740
547