UNPKG

@zandor300/jsmodbus

Version:

Implementation for the Serial/TCP Modbus protocol.

261 lines (260 loc) 13.1 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const response_1 = require("./response"); const request_1 = require("./request"); const buffer_utils_js_1 = __importDefault(require("./buffer-utils.js")); const codes_1 = require("./codes"); const { bufferToArrayStatus, arrayStatusToBuffer } = buffer_utils_js_1.default; const Debug = require("debug"); const debug = Debug('modbus tcp response handler'); class ModbusServerResponseHandler { constructor(server, fromRequest) { this._server = server; this._fromRequest = fromRequest; } handle(request, cb) { if (!request) { return null; } if ((0, request_1.isExceptionRequestBody)(request.body)) { const responseBody = response_1.ExceptionResponseBody.fromRequest(request.body); const response = this._fromRequest(request, responseBody); cb(response.createPayload()); return response; } const fc = request.body.fc; if ((0, codes_1.isFunctionCode)(fc)) { switch (fc) { case codes_1.FC.READ_COIL: return this._handleReadCoil(request, cb); case codes_1.FC.READ_DISCRETE_INPUT: return this._handleDiscreteInput(request, cb); case codes_1.FC.READ_HOLDING_REGISTERS: return this._handleReadHoldingRegisters(request, cb); case codes_1.FC.READ_INPUT_REGISTERS: return this._handleReadInputRegisters(request, cb); case codes_1.FC.WRITE_SINGLE_COIL: return this._handleWriteSingleCoil(request, cb); case codes_1.FC.WRITE_SINGLE_HOLDING_REGISTER: return this._handleWriteSingleHoldingRegister(request, cb); case codes_1.FC.WRITE_MULTIPLE_COILS: return this._handleWriteMultipleCoils(request, cb); case codes_1.FC.WRITE_MULTIPLE_HOLDING_REGISTERS: return this._handleWriteMultipleHoldingRegisters(request, cb); } } return; } _handleReadCoil(request, cb) { if (!(0, request_1.isReadCoilsRequestBody)(request.body)) { throw new Error(`InvalidRequestClass - Expected ReadCoilsRequestBody but received ${request.body.name}`); } if (!this._server.coils) { debug('no coils buffer on server, trying readCoils handler'); this._server.emit('readCoils', request, cb); return; } this._server.emit('preReadCoils', request, cb); const responseBody = response_1.ReadCoilsResponseBody.fromRequest(request.body, this._server.coils); const response = this._fromRequest(request, responseBody); const payload = response.createPayload(); cb(payload); this._server.emit('postReadCoils', request, cb); return response; } _handleDiscreteInput(request, cb) { if (!(0, request_1.isReadDiscreteInputsRequestBody)(request.body)) { throw new Error(`InvalidRequestClass - Expected ReadDiscreteInputsRequestBody but received ${request.body.name}`); } if (!this._server.discrete) { debug('no discrete input buffer on server, trying readDiscreteInputs handler'); this._server.emit('readDiscreteInputs', request, cb); return; } this._server.emit('preReadDiscreteInputs', request, cb); const responseBody = response_1.ReadDiscreteInputsResponseBody.fromRequest(request.body, this._server.discrete); const response = this._fromRequest(request, responseBody); const payload = response.createPayload(); cb(payload); this._server.emit('postReadDiscreteInputs', request, cb); return response; } _handleReadHoldingRegisters(request, cb) { if (!(0, request_1.isReadHoldingRegistersRequestBody)(request.body)) { const msg = `InvalidRequestClass - Expected ReadHoldingRegistersRequestBody but received ${request.body.name}`; throw new Error(msg); } if (!this._server.holding) { debug('no holding register buffer on server, trying readHoldingRegisters handler'); this._server.emit('readHoldingRegisters', request, cb); return; } this._server.emit('preReadHoldingRegisters', request, cb); const responseBody = response_1.ReadHoldingRegistersResponseBody.fromRequest(request.body, this._server.holding); const response = this._fromRequest(request, responseBody); const payload = response.createPayload(); cb(payload); this._server.emit('postReadHoldingRegisters', request, cb); return response; } _handleReadInputRegisters(request, cb) { if (!(0, request_1.isReadInputRegistersRequestBody)(request.body)) { throw new Error(`InvalidRequestClass - Expected ReadInputRegistersRequestBody but received ${request.body.name}`); } if (!this._server.input) { debug('no input register buffer on server, trying readInputRegisters handler'); this._server.emit('readInputRegisters', request, cb); return; } this._server.emit('preReadInputRegisters', request, cb); const responseBody = response_1.ReadInputRegistersResponseBody.fromRequest(request.body, this._server.input); const response = this._fromRequest(request, responseBody); const payload = response.createPayload(); cb(payload); this._server.emit('postReadInputRegisters', request, cb); return response; } _handleWriteSingleCoil(request, cb) { if (!(0, request_1.isWriteSingleCoilRequestBody)(request.body)) { throw new Error(`InvalidRequestClass - Expected WriteSingleCoilRequestBody but received ${request.body.name}`); } if (!this._server.coils) { debug('no coils buffer on server, trying writeSingleCoil handler'); this._server.emit('writeSingleCoil', request, cb); return; } this._server.emit('preWriteSingleCoil', request, cb); const responseBody = response_1.WriteSingleCoilResponseBody.fromRequest(request.body); const address = request.body.address; debug('Writing value %d to address %d', request.body.value, address); const oldValue = this._server.coils.readUInt8(Math.floor(address / 8)); let newValue; if (request.body.value !== 0xFF00 && request.body.value !== 0x0000) { debug('illegal data value'); const exceptionBody = new response_1.ExceptionResponseBody(request.body.fc, 0x03); const exceptionResponse = this._fromRequest(request, exceptionBody); cb(exceptionResponse.createPayload()); return exceptionResponse; } if (request.body.value === 0xFF00) { newValue = oldValue | Math.pow(2, address % 8); } else { newValue = oldValue & ~Math.pow(2, address % 8); } if (responseBody.address / 8 > this._server.coils.length) { debug('illegal data address'); const exceptionBody = new response_1.ExceptionResponseBody(request.body.fc, 0x02); const exceptionResponse = this._fromRequest(request, exceptionBody); cb(exceptionResponse.createPayload()); return exceptionResponse; } else { this._server.coils.writeUInt8(newValue, Math.floor(address / 8)); } const response = this._fromRequest(request, responseBody); const payload = response.createPayload(); cb(payload); this._server.emit('postWriteSingleCoil', request, cb); return response; } _handleWriteSingleHoldingRegister(request, cb) { if (!(0, request_1.isWriteSingleRegisterRequestBody)(request.body)) { throw new Error(`InvalidRequestClass - Expected WriteSingleRegisterRequestBody but received ${request.body.name}`); } if (!this._server.holding) { debug('no register buffer on server, trying writeSingleRegister handler'); this._server.emit('writeSingleRegister', request, cb); return; } this._server.emit('preWriteSingleRegister', request, cb); const responseBody = response_1.WriteSingleRegisterResponseBody.fromRequest(request.body); if (responseBody.address * 2 > this._server.holding.length) { debug('illegal data address'); const exceptionBody = new response_1.ExceptionResponseBody(request.body.fc, 0x02); const exceptionResponse = this._fromRequest(request, exceptionBody); cb(exceptionResponse.createPayload()); return exceptionResponse; } else { if (request.body.value !== undefined) { this._server.holding.writeUInt16BE(request.body.value, responseBody.address * 2); } else if (request.body.buffer !== undefined) { request.body.buffer.copy(this._server.holding, responseBody.address * 2, 0, 2); } } const response = this._fromRequest(request, responseBody); const payload = response.createPayload(); cb(payload); this._server.emit('postWriteSingleRegister', request, cb); return response; } _handleWriteMultipleCoils(request, cb) { if (!(0, request_1.isWriteMultipleCoilsRequestBody)(request.body)) { throw new Error(`InvalidRequestClass - Expected WriteMultipleCoilsRequestBody but received ${request.body.name}`); } if (!this._server.coils) { debug('no coils buffer on server, trying writeMultipleCoils handler'); this._server.emit('writeMultipleCoils', request, cb); return; } this._server.emit('preWriteMultipleCoils', request, cb); const responseBody = response_1.WriteMultipleCoilsResponseBody.fromRequest(request.body); const oldStatus = bufferToArrayStatus(this._server.coils); const requestCoilValues = bufferToArrayStatus(request.body.valuesAsBuffer); const start = request.body.address; const end = start + request.body.quantity; const newStatus = oldStatus.map((byte, i) => { let value = byte; const inRange = (i >= start && i < end); if (inRange) { const newValue = requestCoilValues.shift(); value = newValue !== undefined ? newValue : byte; } return value; }); this._server.emit('writeMultipleCoils', this._server.coils, oldStatus); this._server.coils.fill(arrayStatusToBuffer(newStatus)); this._server.emit('postWriteMultipleCoils', this._server.coils, newStatus); const response = this._fromRequest(request, responseBody); const payload = response.createPayload(); cb(payload); this._server.emit('postWriteMultipleCoils', request, cb); return response; } _handleWriteMultipleHoldingRegisters(request, cb) { if (!(0, request_1.isWriteMultipleRegistersRequestBody)(request.body)) { throw new Error(`InvalidRequestClass - Expected WriteMultipleRegistersRequestBody but received ${request.body.name}`); } if (!this._server.holding) { debug('no register buffer on server, trying writeMultipleRegisters handler'); this._server.emit('writeMultipleRegisters', request, cb); return; } this._server.emit('preWriteMultipleRegisters', request, cb); const responseBody = response_1.WriteMultipleRegistersResponseBody.fromRequest(request.body); if (((request.body.address * 2) + request.body.values.length) > this._server.holding.length) { debug('illegal data address'); const exceptionBody = new response_1.ExceptionResponseBody(request.body.fc, 0x02); const exceptionResponse = this._fromRequest(request, exceptionBody); cb(exceptionResponse.createPayload()); return exceptionResponse; } else { this._server.emit('writeMultipleRegisters', this._server.holding); debug('Request Body: ', request.body); this._server.holding.fill(new Uint8Array(request.body.values), request.body.address * 2, request.body.address * 2 + request.body.values.length); this._server.emit('postWriteMultipleRegisters', this._server.holding); } const response = this._fromRequest(request, responseBody); const payload = response.createPayload(); cb(payload); this._server.emit('postWriteMultipleRegisters', request, cb); return response; } } exports.default = ModbusServerResponseHandler;