UNPKG

node-red-contrib-netvar-utils

Version:

Network Variable List utility nodes for node-red

164 lines 7.61 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Nvl = void 0; const ajv_1 = __importDefault(require("ajv")); const nearley_1 = require("nearley"); const rfdc_1 = __importDefault(require("rfdc")); const constants_1 = require("../../shared/constants"); const util_1 = require("../../shared/util"); const compile_emitter_1 = require("./compile-emitter"); const compile_reader_1 = require("./compile-reader"); const nvl_grammar_1 = __importDefault(require("./nvl-grammar")); const util_2 = require("./util"); const ajv = new ajv_1.default(); const clone = rfdc_1.default(); class Nvl { constructor(node, config) { this.listId = parseInt(config.netvarListId); this.definitions = this.parseNetvarList(node, config.netvarList); this.template = util_1.buildNetworkVariableListJSON(this.definitions); this.schema = util_2.buildJSONSchemaFromDefinitions(this.definitions); this.expectedPackets = this.getExpectedPackets(this.definitions); this.validateJSON = ajv.compile(this.schema); this.readers = this.expectedPackets.map(packet => compile_reader_1.compilePacketReader(packet)); this.emitters = this.expectedPackets.map(packet => compile_emitter_1.compilePacketEmitter(packet, this.listId)); } createEmptyJSON() { return clone(this.template); } /** Check if received packet is expected according to given configuration */ isExpectedPacket(packet) { if (!util_1.isNvlPacket(packet)) return false; const index = packet.readUInt16LE(constants_1.OFFSET_PACKET_INDEX); const expectedPacket = this.expectedPackets[index]; return expectedPacket && this.listId === packet.readUInt16LE(constants_1.OFFSET_LIST_ID) && expectedPacket.size === packet.readUInt16LE(constants_1.OFFSET_PACKET_SIZE) && expectedPacket.variableCount === packet.readUInt16LE(constants_1.OFFSET_VAR_COUNT); } getExpectedPacketCount() { return this.expectedPackets.length; } /** Mutates target object */ readPacket(target, packet) { const index = packet.readUInt16LE(constants_1.OFFSET_PACKET_INDEX); const reader = this.readers[index]; reader(target, packet); } emitPackets(target, counter = 0) { counter = Math.floor(counter); counter %= 65535; return this.emitters.map((emitter, index) => emitter(target, counter + index)); } /** Get expected packets, their sizes and the variables they should contain by interpreting network variable list definitions */ getExpectedPackets(definitions) { const packets = []; const defineNewPacket = (index) => ({ index, size: constants_1.PACKET_HEADER_SIZE, variableCount: 0, definitions: [], }); let currentPacket = defineNewPacket(0); for (const definition of definitions) { const remainder = constants_1.MAX_PACKET_SIZE - currentPacket.size; if (definition.isArray) { const volume = definition.dimensions.reduce((a, b) => a * b); const unitSize = definition.size; const totalSize = volume * unitSize; if (remainder >= totalSize) { currentPacket.size += totalSize; currentPacket.variableCount += volume; currentPacket.definitions.push({ ...definition, begin: 0, end: volume, }); } else { let volumeIndex = Math.floor(remainder / unitSize); currentPacket.size += volumeIndex * unitSize; currentPacket.variableCount += volumeIndex; currentPacket.definitions.push({ ...definition, begin: 0, end: volumeIndex, }); packets.push(currentPacket); currentPacket = defineNewPacket(packets.length); while (volumeIndex < volume) { const remainingUnitCount = volume - volumeIndex; const remainingArraySize = remainingUnitCount * unitSize; if (constants_1.MAX_VARIABLE_SIZE < remainingArraySize) { const unitSpan = Math.floor(constants_1.MAX_VARIABLE_SIZE / unitSize); currentPacket.size += unitSpan * unitSize; currentPacket.variableCount += unitSpan; currentPacket.definitions.push({ ...definition, begin: volumeIndex, end: volumeIndex + unitSpan, }); packets.push(currentPacket); currentPacket = defineNewPacket(packets.length); volumeIndex += unitSpan; } else { currentPacket.size += remainingUnitCount * unitSize; currentPacket.variableCount += remainingUnitCount; currentPacket.definitions.push({ ...definition, begin: volumeIndex, end: volume, }); volumeIndex = volume; } } } } else { if (definition.size > remainder) { packets.push(currentPacket); currentPacket = defineNewPacket(packets.length); currentPacket.size += definition.size; currentPacket.variableCount += 1; currentPacket.definitions.push(definition); if (definition.size > constants_1.MAX_VARIABLE_SIZE) { packets.push(currentPacket); currentPacket = defineNewPacket(packets.length); } } else { currentPacket.size += definition.size; currentPacket.variableCount += 1; currentPacket.definitions.push(definition); } } } if (currentPacket.definitions.length > 0) packets.push(currentPacket); return packets; } parseNetvarList(node, nvl) { var _a; const parser = new nearley_1.Parser(nearley_1.Grammar.fromCompiled(nvl_grammar_1.default), {}); try { parser.feed(nvl.trim()); if (parser.results.length > 1) node.debug('[WARN] Network variable grammar is ambigious!'); } catch (err) { node.error(this.createNetvarSyntaxError(err)); } return ((_a = parser.results) === null || _a === void 0 ? void 0 : _a[0]) || []; } createNetvarSyntaxError(err) { const message = `Error while parsing network variable list.\n${err.message.slice(0, err.message.indexOf(' Instead'))}`; return new SyntaxError(message); } } exports.Nvl = Nvl; //# sourceMappingURL=nvl.js.map