UNPKG

simple-modbus

Version:

A simple library for working with Modbus with Typescript bindings.

849 lines (829 loc) 40.7 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var net = _interopDefault(require('net')); /*! ***************************************************************************** Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. ***************************************************************************** */ /* global Reflect, Promise */ 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); }; function __extends(d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } /** * This code is borrowed from Basarat Ali Syed from his Typescript Gitbook. * Licensed under Creative Commons https://creativecommons.org/licenses/by/4.0/ * * Passes through events as they happen. You will not get events from before you start listening */ var TypedEvent = /** @class */ (function () { function TypedEvent() { var _this = this; this.listeners = []; this.listenersOncer = []; this.on = function (listener) { _this.listeners.push(listener); return { dispose: function () { return _this.off(listener); } }; }; this.once = function (listener) { _this.listenersOncer.push(listener); }; this.off = function (listener) { var callbackIndex = _this.listeners.indexOf(listener); if (callbackIndex > -1) _this.listeners.splice(callbackIndex, 1); }; this.emit = function (event) { /** Update any general listeners */ _this.listeners.forEach(function (listener) { return listener(event); }); /** Clear the `once` queue */ _this.listenersOncer.forEach(function (listener) { return listener(event); }); _this.listenersOncer = []; }; this.pipe = function (te) { return _this.on(function (e) { return te.emit(e); }); }; } return TypedEvent; }()); /* istanbul ignore next */ var ModbusServer = /** @class */ (function () { function ModbusServer() { this.onReadCoilStatus = new TypedEvent(); this.onReadInputStatus = new TypedEvent(); this.onReadHoldingRegisters = new TypedEvent(); this.onReadInputRegisters = new TypedEvent(); this.onForceSingleCoil = new TypedEvent(); this.onPresetSingleRegister = new TypedEvent(); this.onForceMultipleCoils = new TypedEvent(); this.onPresetMultipleRegisters = new TypedEvent(); this.onCommandError = new TypedEvent(); this.onServerError = new TypedEvent(); } return ModbusServer; }()); // export class ModbusServerError extends Error { var ModbusCommandError = /** @class */ (function (_super) { __extends(ModbusCommandError, _super); // Impossible to get Jest to see super branch as covered, have to ignore whole constructor /* istanbul ignore next */ function ModbusCommandError(message, requestBytes) { var _this = _super.call(this, message) || this; _this.message = message; _this.name = 'ModbusCommandError'; _this.message = message; _this.stack = (new Error()).stack; _this.requestBytes = requestBytes; Object.setPrototypeOf(_this, ModbusCommandError.prototype); return _this; } ModbusCommandError.prototype.toString = function () { return this.name + ': ' + this.message; }; return ModbusCommandError; }(Error)); (function (ModbusFunctionCode) { ModbusFunctionCode[ModbusFunctionCode["READ_COIL_STATUS"] = 1] = "READ_COIL_STATUS"; ModbusFunctionCode[ModbusFunctionCode["READ_INPUT_STATUS"] = 2] = "READ_INPUT_STATUS"; ModbusFunctionCode[ModbusFunctionCode["READ_HOLDING_REGISTERS"] = 3] = "READ_HOLDING_REGISTERS"; ModbusFunctionCode[ModbusFunctionCode["READ_INPUT_REGISTERS"] = 4] = "READ_INPUT_REGISTERS"; ModbusFunctionCode[ModbusFunctionCode["FORCE_SINGLE_COIL"] = 5] = "FORCE_SINGLE_COIL"; ModbusFunctionCode[ModbusFunctionCode["PRESET_SINGLE_REGISTER"] = 6] = "PRESET_SINGLE_REGISTER"; ModbusFunctionCode[ModbusFunctionCode["FORCE_MULTIPLE_COILS"] = 15] = "FORCE_MULTIPLE_COILS"; ModbusFunctionCode[ModbusFunctionCode["PRESET_MULTIPLE_REGISTERS"] = 16] = "PRESET_MULTIPLE_REGISTERS"; })(exports.ModbusFunctionCode || (exports.ModbusFunctionCode = {})); (function (ModbusCommandException) { ModbusCommandException[ModbusCommandException["ILLEGAL_FUNCTION"] = 1] = "ILLEGAL_FUNCTION"; ModbusCommandException[ModbusCommandException["ILLEGAL_DATA_ADDRESS"] = 2] = "ILLEGAL_DATA_ADDRESS"; ModbusCommandException[ModbusCommandException["ILLEGAL_DATA_VALUE"] = 3] = "ILLEGAL_DATA_VALUE"; ModbusCommandException[ModbusCommandException["SERVER_DEVICE_FAILURE"] = 4] = "SERVER_DEVICE_FAILURE"; ModbusCommandException[ModbusCommandException["ACKNOWLEDGE"] = 5] = "ACKNOWLEDGE"; ModbusCommandException[ModbusCommandException["SERVER_DEVICE_BUSY"] = 6] = "SERVER_DEVICE_BUSY"; ModbusCommandException[ModbusCommandException["NEGATIVE_ACKNOWLEDGE"] = 7] = "NEGATIVE_ACKNOWLEDGE"; ModbusCommandException[ModbusCommandException["MEMORY_PARITY_ERROR"] = 8] = "MEMORY_PARITY_ERROR"; ModbusCommandException[ModbusCommandException["GATEWAY_PATH_UNAVAILABLE"] = 10] = "GATEWAY_PATH_UNAVAILABLE"; ModbusCommandException[ModbusCommandException["GATEWAY_TARGET_FAILED_TO_RESPOND"] = 11] = "GATEWAY_TARGET_FAILED_TO_RESPOND"; })(exports.ModbusCommandException || (exports.ModbusCommandException = {})); var CoilStatus; (function (CoilStatus) { CoilStatus[CoilStatus["ON"] = 0] = "ON"; CoilStatus[CoilStatus["OFF"] = 1] = "OFF"; })(CoilStatus || (CoilStatus = {})); var ModbusCommand = /** @class */ (function () { function ModbusCommand(rawPacket, unitIdGetter, functionCodeGetter, successGetter, failureGetter) { /** * Fires on either success or failure, with the response bytes. Mainly used by the server to send a response. */ this.onComplete = new TypedEvent(); /** * Fires on a call of the success method. */ this.onSuccess = new TypedEvent(); /** * Fires on a call of the fail method. */ this.onFailure = new TypedEvent(); this._rawPacket = rawPacket; this._unitIdGetter = unitIdGetter; this._functionCodeGetter = functionCodeGetter; this._successGetter = successGetter; this._failureGetter = failureGetter; } Object.defineProperty(ModbusCommand.prototype, "unitId", { /** * If RTU, unitId is equivalent to slaveId */ get: function () { return this._unitIdGetter(this._rawPacket); }, enumerable: true, configurable: true }); Object.defineProperty(ModbusCommand.prototype, "functionCode", { /** * Modbus function code */ get: function () { return this._functionCodeGetter(this._rawPacket); }, enumerable: true, configurable: true }); Object.defineProperty(ModbusCommand.prototype, "responsePacket", { /** * This function will give you the response packet bytes that will be sent on the emitting server. Before calling this function, the `success` or `fail` method must be called in order to set the response. * * @returns A buffer of the bytes representing the response to the server * @throws ModbusCommandError if success or fail hasn't been called yet */ get: function () { if (!this._responsePacket) { throw new ModbusCommandError('Tried to read response packet, but success or fail has not been called.', this._rawPacket); } return this._responsePacket; }, enumerable: true, configurable: true }); /** * Set a failure on this command to return an exception response to the emitting server. * * @param exception - The reason for the failure */ ModbusCommand.prototype.fail = function (exception) { this._responsePacket = this._failureGetter(this._rawPacket, exception); this.onComplete.emit(this); this.onFailure.emit(this); }; return ModbusCommand; }()); var ReadCoilStatusCommand = /** @class */ (function (_super) { __extends(ReadCoilStatusCommand, _super); /** * @hidden */ function ReadCoilStatusCommand(rawPacket, unitIdGetter, functionCodeGetter, successGetter, failureGetter, coilAddressGetter, coilLengthGetter) { var _this = _super.call(this, rawPacket, unitIdGetter, functionCodeGetter, successGetter, failureGetter) || this; _this._coilAddressGetter = coilAddressGetter; _this._coilLengthGetter = coilLengthGetter; return _this; } Object.defineProperty(ReadCoilStatusCommand.prototype, "coilStartAddress", { get: function () { return this._coilAddressGetter(this._rawPacket); }, enumerable: true, configurable: true }); Object.defineProperty(ReadCoilStatusCommand.prototype, "numberOfCoils", { get: function () { return this._coilLengthGetter(this._rawPacket); }, enumerable: true, configurable: true }); /** * Set success on this command to return a valid response to the emitting server. * * @param data - Boolean coil data, starting at `coilStartAddress`, of length `numberOfCoils`. */ ReadCoilStatusCommand.prototype.success = function (data) { // TODO: Throw error here if data length doesn't equal requested length this._responsePacket = this._successGetter(this._rawPacket, data); this.onComplete.emit(this); this.onSuccess.emit(this); }; return ReadCoilStatusCommand; }(ModbusCommand)); var ReadInputStatusCommand = /** @class */ (function (_super) { __extends(ReadInputStatusCommand, _super); /** * @hidden */ function ReadInputStatusCommand(rawPacket, unitIdGetter, functionCodeGetter, successGetter, failureGetter, inputAddressGetter, inputLengthGetter) { var _this = _super.call(this, rawPacket, unitIdGetter, functionCodeGetter, successGetter, failureGetter) || this; _this._inputAddressGetter = inputAddressGetter; _this._inputLengthGetter = inputLengthGetter; return _this; } Object.defineProperty(ReadInputStatusCommand.prototype, "inputStartAddress", { get: function () { return this._inputAddressGetter(this._rawPacket); }, enumerable: true, configurable: true }); Object.defineProperty(ReadInputStatusCommand.prototype, "numberOfInputs", { get: function () { return this._inputLengthGetter(this._rawPacket); }, enumerable: true, configurable: true }); /** * Set success on this command to return a valid response to the emitting server. * * @param data - Input status data of requested discrete inputs. `true` = ON, `false` = off */ ReadInputStatusCommand.prototype.success = function (data) { // TODO: Throw error here if data length doesn't equal requested length this._responsePacket = this._successGetter(this._rawPacket, data); this.onComplete.emit(this); this.onSuccess.emit(this); }; return ReadInputStatusCommand; }(ModbusCommand)); var ReadHoldingRegistersCommand = /** @class */ (function (_super) { __extends(ReadHoldingRegistersCommand, _super); /** * @hidden */ function ReadHoldingRegistersCommand(rawPacket, unitIdGetter, functionCodeGetter, successGetter, failureGetter, registerAddressGetter, registerLengthGetter) { var _this = _super.call(this, rawPacket, unitIdGetter, functionCodeGetter, successGetter, failureGetter) || this; _this._registerAddressGetter = registerAddressGetter; _this._registerLengthGetter = registerLengthGetter; return _this; } Object.defineProperty(ReadHoldingRegistersCommand.prototype, "registerStartAddress", { get: function () { return this._registerAddressGetter(this._rawPacket); }, enumerable: true, configurable: true }); Object.defineProperty(ReadHoldingRegistersCommand.prototype, "registerLength", { get: function () { return this._registerLengthGetter(this._rawPacket); }, enumerable: true, configurable: true }); /** * Set success on this command to return a valid response to the emitting server. * * @param data - Array of values of the requested holding registers. Register values are 16 bits. Array length must equal `registerLength`. `data[0]` should be the value of the register at `registerStartAddress`. */ ReadHoldingRegistersCommand.prototype.success = function (data) { // TODO: Throw error here if data length doesn't equal requested length this._responsePacket = this._successGetter(this._rawPacket, data); this.onComplete.emit(this); this.onSuccess.emit(this); }; return ReadHoldingRegistersCommand; }(ModbusCommand)); var ReadInputRegistersCommand = /** @class */ (function (_super) { __extends(ReadInputRegistersCommand, _super); /** * @hidden */ function ReadInputRegistersCommand(rawPacket, unitIdGetter, functionCodeGetter, successGetter, failureGetter, registerAddressGetter, registerLengthGetter) { var _this = _super.call(this, rawPacket, unitIdGetter, functionCodeGetter, successGetter, failureGetter) || this; _this._registerAddressGetter = registerAddressGetter; _this._registerLengthGetter = registerLengthGetter; return _this; } Object.defineProperty(ReadInputRegistersCommand.prototype, "registerStartAddress", { get: function () { return this._registerAddressGetter(this._rawPacket); }, enumerable: true, configurable: true }); Object.defineProperty(ReadInputRegistersCommand.prototype, "registerLength", { get: function () { return this._registerLengthGetter(this._rawPacket); }, enumerable: true, configurable: true }); /** * Set success on this command to return a valid response to the emitting server. * * @param data - Array of values of the requested input registers. Register values are 16 bits. Array length must equal `registerLength`. `data[0]` should be the value of the register at `registerStartAddress`. */ ReadInputRegistersCommand.prototype.success = function (data) { // TODO: Throw error here if data length doesn't equal requested length this._responsePacket = this._successGetter(this._rawPacket, data); this.onComplete.emit(this); this.onSuccess.emit(this); }; return ReadInputRegistersCommand; }(ModbusCommand)); var ForceSingleCoilCommand = /** @class */ (function (_super) { __extends(ForceSingleCoilCommand, _super); /** * @hidden */ function ForceSingleCoilCommand(rawPacket, unitIdGetter, functionCodeGetter, successGetter, failureGetter, coilAddressGetter, coilStatusGetter) { var _this = _super.call(this, rawPacket, unitIdGetter, functionCodeGetter, successGetter, failureGetter) || this; _this._coilAddressGetter = coilAddressGetter; _this._coilStatusGetter = coilStatusGetter; return _this; } Object.defineProperty(ForceSingleCoilCommand.prototype, "coilAddress", { get: function () { return this._coilAddressGetter(this._rawPacket); }, enumerable: true, configurable: true }); Object.defineProperty(ForceSingleCoilCommand.prototype, "coilStatus", { get: function () { return this._coilStatusGetter(this._rawPacket); }, enumerable: true, configurable: true }); Object.defineProperty(ForceSingleCoilCommand.prototype, "coilStatusAsCoilStatus", { get: function () { return this.coilStatus === true ? CoilStatus.ON : CoilStatus.OFF; }, enumerable: true, configurable: true }); /** * Set success on this command to return a valid response to the emitting server. */ ForceSingleCoilCommand.prototype.success = function () { this._responsePacket = this._successGetter(this._rawPacket); this.onComplete.emit(this); this.onSuccess.emit(this); }; return ForceSingleCoilCommand; }(ModbusCommand)); var PresetSingleRegisterCommand = /** @class */ (function (_super) { __extends(PresetSingleRegisterCommand, _super); /** * @hidden */ function PresetSingleRegisterCommand(rawPacket, unitIdGetter, functionCodeGetter, successGetter, failureGetter, registerAddressGetter, registerValueGetter) { var _this = _super.call(this, rawPacket, unitIdGetter, functionCodeGetter, successGetter, failureGetter) || this; _this._registerAddressGetter = registerAddressGetter; _this._registerValueGetter = registerValueGetter; return _this; } Object.defineProperty(PresetSingleRegisterCommand.prototype, "registerAddress", { get: function () { return this._registerAddressGetter(this._rawPacket); }, enumerable: true, configurable: true }); Object.defineProperty(PresetSingleRegisterCommand.prototype, "registerValue", { get: function () { return this._registerValueGetter(this._rawPacket); }, enumerable: true, configurable: true }); /** * Set success on this command to return a valid response to the emitting server. */ PresetSingleRegisterCommand.prototype.success = function () { this._responsePacket = this._successGetter(this._rawPacket); this.onComplete.emit(this); this.onSuccess.emit(this); }; return PresetSingleRegisterCommand; }(ModbusCommand)); var ForceMultipleCoilsCommand = /** @class */ (function (_super) { __extends(ForceMultipleCoilsCommand, _super); /** * @hidden */ function ForceMultipleCoilsCommand(rawPacket, unitIdGetter, functionCodeGetter, successGetter, failureGetter, coilAddressGetter, coilLengthGetter, coilStatusesGetter) { var _this = _super.call(this, rawPacket, unitIdGetter, functionCodeGetter, successGetter, failureGetter) || this; _this._coilAddressGetter = coilAddressGetter; _this._coilLengthGetter = coilLengthGetter; _this._coilStatusesGetter = coilStatusesGetter; return _this; } Object.defineProperty(ForceMultipleCoilsCommand.prototype, "coilStartAddress", { get: function () { return this._coilAddressGetter(this._rawPacket); }, enumerable: true, configurable: true }); Object.defineProperty(ForceMultipleCoilsCommand.prototype, "coilLength", { get: function () { return this._coilLengthGetter(this._rawPacket); }, enumerable: true, configurable: true }); Object.defineProperty(ForceMultipleCoilsCommand.prototype, "coilStatuses", { get: function () { return this._coilStatusesGetter(this._rawPacket); }, enumerable: true, configurable: true }); Object.defineProperty(ForceMultipleCoilsCommand.prototype, "coilStatusesAsCoilStatusArray", { get: function () { return this.coilStatuses.map(function (x) { return (x === true ? CoilStatus.ON : CoilStatus.OFF); }); }, enumerable: true, configurable: true }); /** * Set success on this command to return a valid response to the emitting server. */ ForceMultipleCoilsCommand.prototype.success = function () { this._responsePacket = this._successGetter(this._rawPacket); this.onComplete.emit(this); this.onSuccess.emit(this); }; return ForceMultipleCoilsCommand; }(ModbusCommand)); var PresetMultipleRegistersCommand = /** @class */ (function (_super) { __extends(PresetMultipleRegistersCommand, _super); /** * @hidden */ function PresetMultipleRegistersCommand(rawPacket, unitIdGetter, functionCodeGetter, successGetter, failureGetter, registerAddressGetter, registerLengthGetter, registerValuesGetter) { var _this = _super.call(this, rawPacket, unitIdGetter, functionCodeGetter, successGetter, failureGetter) || this; _this._registerAddressGetter = registerAddressGetter; _this._registerLengthGetter = registerLengthGetter; _this._registerValuesGetter = registerValuesGetter; return _this; } Object.defineProperty(PresetMultipleRegistersCommand.prototype, "registerStartAddress", { get: function () { return this._registerAddressGetter(this._rawPacket); }, enumerable: true, configurable: true }); Object.defineProperty(PresetMultipleRegistersCommand.prototype, "registerLength", { get: function () { return this._registerLengthGetter(this._rawPacket); }, enumerable: true, configurable: true }); Object.defineProperty(PresetMultipleRegistersCommand.prototype, "registerValues", { get: function () { return this._registerValuesGetter(this._rawPacket); }, enumerable: true, configurable: true }); Object.defineProperty(PresetMultipleRegistersCommand.prototype, "registerValuesAsUint16Array", { get: function () { return new Uint16Array(this.registerValues); }, enumerable: true, configurable: true }); /** * Set success on this command to return a valid response to the emitting server. */ PresetMultipleRegistersCommand.prototype.success = function () { this._responsePacket = this._successGetter(this._rawPacket); this.onComplete.emit(this); this.onSuccess.emit(this); }; return PresetMultipleRegistersCommand; }(ModbusCommand)); var ModbusCommandFactory = /** @class */ (function () { function ModbusCommandFactory(options) { this.simpleAddressing = true; if (options !== undefined) { if (options.simpleAddressing === false) { this.simpleAddressing = false; } } } return ModbusCommandFactory; }()); 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 ModbusCommandError('Packet length too short', packet); } var fc = this._functionCodeGetter(packet); // Determine packet type, and call appropriate constructor switch (fc) { case exports.ModbusFunctionCode.READ_COIL_STATUS: return new ReadCoilStatusCommand(packet, this._unitIdGetter, this._functionCodeGetter, this._readCoilSuccessGetter, this._failureGetter, this._coilAddressGetter, this._coilLengthGetter); case exports.ModbusFunctionCode.READ_INPUT_STATUS: return new ReadInputStatusCommand(packet, this._unitIdGetter, this._functionCodeGetter, this._readInputStatusSuccessGetter, this._failureGetter, this._inputAddressGetter, this._inputLengthGetter); case exports.ModbusFunctionCode.READ_HOLDING_REGISTERS: return new ReadHoldingRegistersCommand(packet, this._unitIdGetter, this._functionCodeGetter, this._readRegistersSuccessGetter, this._failureGetter, this._holdingRegisterAddressGetter, this._registerLengthGetter); case exports.ModbusFunctionCode.READ_INPUT_REGISTERS: return new ReadInputRegistersCommand(packet, this._unitIdGetter, this._functionCodeGetter, this._readRegistersSuccessGetter, this._failureGetter, this._inputRegisterAddressGetter, this._registerLengthGetter); case exports.ModbusFunctionCode.FORCE_SINGLE_COIL: try { this._coilStatusGetter(packet); } catch (_a) { throw new ModbusCommandError('FORCE_SINGLE_COIL - Invalid coil status received', packet); } return new ForceSingleCoilCommand(packet, this._unitIdGetter, this._functionCodeGetter, this._packetCopySuccessGetter, this._failureGetter, this._coilAddressGetter, this._coilStatusGetter); case exports.ModbusFunctionCode.PRESET_SINGLE_REGISTER: return new PresetSingleRegisterCommand(packet, this._unitIdGetter, this._functionCodeGetter, this._packetCopySuccessGetter, this._failureGetter, this._holdingRegisterAddressGetter, this._registerValueGetter); case exports.ModbusFunctionCode.FORCE_MULTIPLE_COILS: try { this._coilStatusesGetter(packet); } catch (_b) { throw new ModbusCommandError('FORCE_MULTIPLE_COILS - Invalid coil status command received', packet); } return new ForceMultipleCoilsCommand(packet, this._unitIdGetter, this._functionCodeGetter, this._forceMultipleCoilsSuccessGetter, this._failureGetter, this._coilAddressGetter, this._coilLengthGetter, this._coilStatusesGetter); case exports.ModbusFunctionCode.PRESET_MULTIPLE_REGISTERS: try { this._registerValuesGetter(packet); } catch (_c) { throw new ModbusCommandError('PRESET_MULTIPLE_REGISTERS - Invalid register command received', packet); } return new PresetMultipleRegistersCommand(packet, this._unitIdGetter, this._functionCodeGetter, this._presetMultipleRegistersSuccessGetter, this._failureGetter, this._holdingRegisterAddressGetter, this._registerLengthGetter, this._registerValuesGetter); default: throw new ModbusCommandError('Function code not implemented', packet); } }; return ModbusTcpCommandFactory; }(ModbusCommandFactory)); var ModbusTcpServer = /** @class */ (function (_super) { __extends(ModbusTcpServer, _super); function ModbusTcpServer(options) { var _this_1 = _super.call(this) || this; _this_1._commandFactory = new ModbusTcpCommandFactory(); _this_1._options = options; _this_1._commandFactory = new ModbusTcpCommandFactory(options); _this_1._tcpServer = net.createServer(function (socket) { var _this = _this_1; socket.on('data', function (data) { try { // Build object from packet var command = _this_1._commandFactory.fromPacket(data); // Listen for success or failure events being emitted from command object command.onComplete.once(function (command) { socket.write(command.responsePacket); }); // Determine packet type and emit corresponding event type switch (command.functionCode) { case exports.ModbusFunctionCode.READ_COIL_STATUS: _this.onReadCoilStatus.emit(command); break; case exports.ModbusFunctionCode.READ_INPUT_STATUS: _this.onReadInputStatus.emit(command); break; case exports.ModbusFunctionCode.READ_HOLDING_REGISTERS: _this.onReadHoldingRegisters.emit(command); break; case exports.ModbusFunctionCode.READ_INPUT_REGISTERS: _this.onReadInputRegisters.emit(command); break; case exports.ModbusFunctionCode.FORCE_SINGLE_COIL: _this.onForceSingleCoil.emit(command); break; case exports.ModbusFunctionCode.PRESET_SINGLE_REGISTER: _this.onPresetSingleRegister.emit(command); break; case exports.ModbusFunctionCode.FORCE_MULTIPLE_COILS: _this.onForceMultipleCoils.emit(command); break; case exports.ModbusFunctionCode.PRESET_MULTIPLE_REGISTERS: _this.onPresetMultipleRegisters.emit(command); break; } } catch (e) { // TODO: Explicit typeguard here, look into changing from try/catch _this.onCommandError.emit(e); } }); socket.on('error', function (e) { _this.onServerError.emit(e); }); }); return _this_1; } ModbusTcpServer.prototype.listen = function (port) { this._tcpServer.listen(port); return this; }; ModbusTcpServer.prototype.close = function () { this._tcpServer.close(); return this; }; return ModbusTcpServer; }(ModbusServer)); var index = /*#__PURE__*/Object.freeze({ Server: ModbusTcpServer, CommandFactory: ModbusTcpCommandFactory }); exports.ModbusTcp = index; //# sourceMappingURL=simple-modbus.cjs.js.map