UNPKG

simple-modbus

Version:

A simple library for working with Modbus with Typescript bindings.

240 lines 14.2 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); Object.defineProperty(exports, "__esModule", { value: true }); var modbus_commands_1 = require("../modbus-commands"); var modbus_errors_1 = require("../error/modbus-errors"); var modbus_command_factory_1 = require("../modbus-command-factory"); var ModbusTcpCommandFactory = /** @class */ (function (_super) { __extends(ModbusTcpCommandFactory, _super); function ModbusTcpCommandFactory(options) { var _this = _super.call(this, options) || this; _this._unitIdGetter = (function (requestPacket) { return requestPacket.readUInt8(6); }); _this._functionCodeGetter = (function (requestPacket) { return requestPacket.readUInt8(7); }); _this._packetCopySuccessGetter = (function (requestPacket) { return Buffer.from(requestPacket); }); _this._forceMultipleCoilsSuccessGetter = (function (requestPacket) { var response = Array.from(requestPacket).slice(0, 12); response[4] = 0x00; response[5] = 0x06; return Buffer.from(response); }); _this._failureGetter = (function (requestPacket, exception) { var response = []; // First 2 bytes are the Transaction Identifier response[0] = requestPacket.readUInt8(0); response[1] = requestPacket.readUInt8(1); // Next 2 bytes are protocol ID. These should always be 0x0000. But the protocol says to copy them from the request. response[2] = requestPacket.readUInt8(2); response[3] = requestPacket.readUInt8(3); // Failure length is always constant response[4] = 0x00; response[5] = 0x03; // Copy UnitId from request response[6] = requestPacket.readUInt8(6); // Function code is request function code with highest bit set response[7] = requestPacket.readUInt8(7) | 128; response[8] = exception; return Buffer.from(new Uint8Array(response)); }); _this._presetMultipleRegistersSuccessGetter = (function (requestPacket) { var response = Array.from(requestPacket).slice(0, 12); response[4] = 0x00; response[5] = 0x06; return Buffer.from(response); }); _this._readCoilSuccessGetter = function (requestPacket, data) { var response = ModbusTcpCommandFactory._stubTcpHeader(requestPacket); // Calculate number of bytes with coil data in response var coilsRequested = _this._coilLengthGetter(requestPacket); var byteLength = Math.ceil(coilsRequested / 8.0); response[8] = byteLength; // TCP byte length data response[4] = (byteLength + 3) >> 8; response[5] = (byteLength + 3) & 0xFF; // Pad array with false at end to end on an 8 bit boundary var paddedData = data.concat((new Array(8 - (coilsRequested % 8)).fill(false))); for (var i = 0; i < byteLength; i++) { // Take a slice of the array of length 8, reverse it, then fill the accumulator with it (starting from right) response[9 + i] = paddedData.slice(i * 8, 8 + (i * 8)).reduce(function (accumulator, currentValue, currentIndex) { return accumulator | ((currentValue ? 1 : 0) << currentIndex); }, 0x00); } return Buffer.from(new Uint8Array(response)); }; _this._readInputStatusSuccessGetter = function (requestPacket, data) { var response = ModbusTcpCommandFactory._stubTcpHeader(requestPacket); // Calculate number of bytes with coil data in response var inputsRequested = _this._inputLengthGetter(requestPacket); var byteLength = Math.ceil(inputsRequested / 8.0); response[8] = byteLength; // TCP byte length data response[4] = (byteLength + 3) >> 8; response[5] = (byteLength + 3) & 0xFF; // Pad array with false at end to end on an 8 bit boundary var paddedData = data.concat((new Array(8 - (inputsRequested % 8)).fill(false))); for (var i = 0; i < byteLength; i++) { // Take a slice of the array of length 8, and fill the accumulator with it (starting from right) response[9 + i] = paddedData.slice(i * 8, 8 + (i * 8)).reduce(function (accumulator, currentValue, currentIndex) { return accumulator | ((currentValue ? 1 : 0) << currentIndex); }, 0x00); } return Buffer.from(new Uint8Array(response)); }; _this._readRegistersSuccessGetter = function (requestPacket, data) { var response = ModbusTcpCommandFactory._stubTcpHeader(requestPacket); // Calculate number of bytes with coil data in response var registersRequested = _this._registerLengthGetter(requestPacket); var byteLength = registersRequested * 2; response[8] = byteLength; // TCP byte length data response[4] = (byteLength + 3) >> 8; response[5] = (byteLength + 3) & 0xFF; for (var i = 0; i < registersRequested; i++) { response[9 + (i * 2)] = data[i] >> 8; response[10 + (i * 2)] = data[i] & 0xFF; } return Buffer.from(new Uint8Array(response)); }; _this._holdingRegisterAddressGetter = (function (requestPacket) { return _this.simpleAddressing ? requestPacket.readUInt16BE(8) : requestPacket.readUInt16BE(8) + 40001; }); _this._inputRegisterAddressGetter = (function (requestPacket) { return _this.simpleAddressing ? requestPacket.readUInt16BE(8) : requestPacket.readUInt16BE(8) + 30001; }); _this._registerValueGetter = (function (requestPacket) { return requestPacket.readUInt16BE(10); }); _this._registerLengthGetter = (function (requestPacket) { return requestPacket.readUInt16BE(10); }); _this._coilAddressGetter = (function (requestPacket) { return _this.simpleAddressing ? requestPacket.readUInt16BE(8) : requestPacket.readUInt16BE(8) + 1; }); _this._coilLengthGetter = (function (requestPacket) { return requestPacket.readUInt16BE(10); }); _this._coilStatusGetter = (function (requestPacket) { var value = requestPacket.readUInt16BE(10); if (value === 0xFF00) { return true; } else if (value === 0x0000) { return false; } throw new Error('_coilStatusGetter invalid value'); }); _this._coilStatusesGetter = function (requestPacket) { var coilLength = _this._coilLengthGetter(requestPacket); var byteLength = Math.ceil(coilLength / 8.0); var packetByteLength = requestPacket.readUInt8(12); if (byteLength !== packetByteLength || requestPacket.length !== byteLength + 13) { // Malformed packet, check and throw exception throw new Error('_coilStatusesGetter invalid length'); } var coilArray = new Array(byteLength * 8); for (var i = 0; i < byteLength; i++) { var byteVal = requestPacket.readUInt8(13 + i); for (var j = 0; j < 8; j++) { coilArray[(i * 8) + j] = ((byteVal >> j) & 0x01) === 1; } } return coilArray.slice(0, coilLength); }; _this._registerValuesGetter = function (requestPacket) { var registerLength = _this._registerLengthGetter(requestPacket); var byteLength = registerLength * 2; var packetByteLength = requestPacket.readUInt8(12); if (byteLength !== packetByteLength || requestPacket.length !== byteLength + 13) { // Malformed packet, check and throw exception throw new Error('_registerValuesGetter invalidValue'); } var registerArray = new Array(registerLength); for (var i = 0; i < registerLength; i++) { registerArray[i] = requestPacket.readUInt16BE(13 + (i * 2)); } return registerArray; }; _this._inputAddressGetter = (function (requestPacket) { return _this.simpleAddressing ? requestPacket.readUInt16BE(8) : requestPacket.readUInt16BE(8) + 10001; }); _this._inputLengthGetter = (function (requestPacket) { return requestPacket.readUInt16BE(10); }); _this._options = options; return _this; } ModbusTcpCommandFactory._stubTcpHeader = function (requestPacket) { var response = []; // First 2 bytes are the Transaction Identifier response[0] = requestPacket.readUInt8(0); response[1] = requestPacket.readUInt8(1); // Next 2 bytes are protocol ID. These should always be 0x0000. But the protocol says to copy them from the request. response[2] = requestPacket.readUInt8(2); response[3] = requestPacket.readUInt8(3); // Copy UnitId from request response[6] = requestPacket.readUInt8(6); // Copy Function Code from request response[7] = requestPacket.readUInt8(7); return response; }; ModbusTcpCommandFactory.prototype.fromPacket = function (packet) { // Minimum Modbus TCP request packet size is 12 if (packet.length < 12) { throw new modbus_errors_1.ModbusCommandError('Packet length too short', packet); } var fc = this._functionCodeGetter(packet); // Determine packet type, and call appropriate constructor switch (fc) { case modbus_commands_1.ModbusFunctionCode.READ_COIL_STATUS: return new modbus_commands_1.ReadCoilStatusCommand(packet, this._unitIdGetter, this._functionCodeGetter, this._readCoilSuccessGetter, this._failureGetter, this._coilAddressGetter, this._coilLengthGetter); case modbus_commands_1.ModbusFunctionCode.READ_INPUT_STATUS: return new modbus_commands_1.ReadInputStatusCommand(packet, this._unitIdGetter, this._functionCodeGetter, this._readInputStatusSuccessGetter, this._failureGetter, this._inputAddressGetter, this._inputLengthGetter); case modbus_commands_1.ModbusFunctionCode.READ_HOLDING_REGISTERS: return new modbus_commands_1.ReadHoldingRegistersCommand(packet, this._unitIdGetter, this._functionCodeGetter, this._readRegistersSuccessGetter, this._failureGetter, this._holdingRegisterAddressGetter, this._registerLengthGetter); case modbus_commands_1.ModbusFunctionCode.READ_INPUT_REGISTERS: return new modbus_commands_1.ReadInputRegistersCommand(packet, this._unitIdGetter, this._functionCodeGetter, this._readRegistersSuccessGetter, this._failureGetter, this._inputRegisterAddressGetter, this._registerLengthGetter); case modbus_commands_1.ModbusFunctionCode.FORCE_SINGLE_COIL: try { this._coilStatusGetter(packet); } catch (_a) { throw new modbus_errors_1.ModbusCommandError('FORCE_SINGLE_COIL - Invalid coil status received', packet); } return new modbus_commands_1.ForceSingleCoilCommand(packet, this._unitIdGetter, this._functionCodeGetter, this._packetCopySuccessGetter, this._failureGetter, this._coilAddressGetter, this._coilStatusGetter); case modbus_commands_1.ModbusFunctionCode.PRESET_SINGLE_REGISTER: return new modbus_commands_1.PresetSingleRegisterCommand(packet, this._unitIdGetter, this._functionCodeGetter, this._packetCopySuccessGetter, this._failureGetter, this._holdingRegisterAddressGetter, this._registerValueGetter); case modbus_commands_1.ModbusFunctionCode.FORCE_MULTIPLE_COILS: try { this._coilStatusesGetter(packet); } catch (_b) { throw new modbus_errors_1.ModbusCommandError('FORCE_MULTIPLE_COILS - Invalid coil status command received', packet); } return new modbus_commands_1.ForceMultipleCoilsCommand(packet, this._unitIdGetter, this._functionCodeGetter, this._forceMultipleCoilsSuccessGetter, this._failureGetter, this._coilAddressGetter, this._coilLengthGetter, this._coilStatusesGetter); case modbus_commands_1.ModbusFunctionCode.PRESET_MULTIPLE_REGISTERS: try { this._registerValuesGetter(packet); } catch (_c) { throw new modbus_errors_1.ModbusCommandError('PRESET_MULTIPLE_REGISTERS - Invalid register command received', packet); } return new modbus_commands_1.PresetMultipleRegistersCommand(packet, this._unitIdGetter, this._functionCodeGetter, this._presetMultipleRegistersSuccessGetter, this._failureGetter, this._holdingRegisterAddressGetter, this._registerLengthGetter, this._registerValuesGetter); default: throw new modbus_errors_1.ModbusCommandError('Function code not implemented', packet); } }; return ModbusTcpCommandFactory; }(modbus_command_factory_1.ModbusCommandFactory)); exports.ModbusTcpCommandFactory = ModbusTcpCommandFactory; //# sourceMappingURL=modbus-tcp-command-factory.js.map