node-red-contrib-netvar-utils
Version:
Network Variable List utility nodes for node-red
164 lines • 7.61 kB
JavaScript
;
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