netkitty
Version:
Network tools kit
792 lines • 54.1 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Goose = void 0;
const BaseHeader_1 = require("../abstracts/BaseHeader");
const node_tlv_1 = __importDefault(require("node-tlv"));
const HexToNumber_1 = require("../../helper/HexToNumber");
const NumberToBERHex_1 = require("../../helper/NumberToBERHex");
const NumberToHex_1 = require("../../helper/NumberToHex");
const StringContentEncodingEnum_1 = require("../lib/StringContentEncodingEnum");
const NumberToBERBuffer_1 = require("../../helper/NumberToBERBuffer");
const BufferToNumber_1 = require("../../helper/BufferToNumber");
const NumberToBuffer_1 = require("../../helper/NumberToBuffer");
const GetBERIntegerLengthFromBuffer_1 = require("../lib/GetBERIntegerLengthFromBuffer");
var ItemDataType;
(function (ItemDataType) {
ItemDataType["Boolean"] = "Boolean";
ItemDataType["INT8"] = "INT8";
ItemDataType["INT16"] = "INT16";
ItemDataType["INT32"] = "INT32";
ItemDataType["INT64"] = "INT64";
ItemDataType["INT8U"] = "INT8U";
ItemDataType["INT16U"] = "INT16U";
ItemDataType["INT32U"] = "INT32U";
ItemDataType["FLOAT32"] = "FLOAT32";
ItemDataType["CODEDENUM"] = "CODED-ENUM";
ItemDataType["OCTETSTRING"] = "OCTET-STRING";
ItemDataType["VISIBLESTRING"] = "VISIBLE-STRING";
ItemDataType["TimeStamp"] = "TimeStamp";
ItemDataType["Quality"] = "Quality";
ItemDataType["Structure"] = "Structure";
})(ItemDataType || (ItemDataType = {}));
class Goose extends BaseHeader_1.BaseHeader {
constructor() {
super(...arguments);
this.TLVChild = [];
this.SCHEMA = {
type: 'object',
properties: {
appid: {
type: 'integer',
minimum: 0,
maximum: 65535,
label: 'APPID',
decode: () => {
this.instance.appid.setValue((0, BufferToNumber_1.BufferToUInt16)(this.readBytes(0, 2)));
},
encode: () => {
const APPID = this.instance.appid.getValue(0, (nodePath) => this.recordError(nodePath, 'Not Found'));
this.instance.appid.setValue(APPID);
this.writeBytes(0, (0, NumberToBuffer_1.UInt16ToBuffer)(APPID));
}
},
length: {
type: 'integer',
minimum: 0,
maximum: 65535,
label: 'Length',
decode: () => {
this.instance.length.setValue((0, BufferToNumber_1.BufferToUInt16)(this.readBytes(2, 2)));
},
encode: () => {
const length = this.instance.length.getValue(0, (nodePath) => this.recordError(nodePath, 'Not Found'));
if (length > 0) {
this.instance.length.setValue(length);
this.writeBytes(2, (0, NumberToBuffer_1.UInt16ToBuffer)(length));
}
else {
this.addPostSelfEncodeHandler(() => {
const finalLength = parseInt(this.instance.length.getValue().toString());
this.writeBytes(2, (0, NumberToBuffer_1.UInt16ToBuffer)(finalLength));
});
}
}
},
reserved1: {
type: 'object',
label: 'Reserved1',
properties: {
simulated: {
type: 'boolean',
label: 'Simulated',
decode: () => {
this.instance.reserved1.simulated.setValue(!!this.readBits(4, 2, 0, 1));
},
encode: () => {
const simulated = this.instance.reserved1.simulated.getValue(false);
this.writeBits(4, 2, 0, 1, simulated ? 1 : 0);
}
},
reserved: {
type: 'number',
minimum: 0,
maximum: 32767,
label: 'Reserved',
decode: () => {
this.instance.reserved1.reserved.setValue(this.readBits(4, 2, 1, 16));
},
encode: () => {
const reserved = this.instance.reserved1.reserved.getValue(0);
this.writeBits(4, 2, 1, 16, reserved);
}
}
}
},
reserved2: {
type: 'object',
label: 'Reserved2',
properties: {
reserved: {
type: 'number',
minimum: 0,
maximum: 65535,
label: 'Reserved',
decode: () => {
this.instance.reserved2.reserved.setValue(this.readBits(4, 2, 0, 16));
},
encode: () => {
const reserved = this.instance.reserved2.reserved.getValue(0);
this.writeBits(4, 2, 0, 16, reserved);
}
}
}
},
goosePdu: {
type: 'object',
label: 'GOOSE PDU',
decode: () => {
let readTLVBufferLength = this.packet.length - this.startPos - 8;
while (!this.TLVInstance) {
try {
const buffer = this.readBytes(8, readTLVBufferLength, true);
this.TLVInstance = node_tlv_1.default.parse(buffer);
const tagWithLength = buffer.toString('hex').replace(this.TLVInstance.bValue.toString('hex'), '#').split('#');
const tagWithLengthBytes = Math.max(...tagWithLength.map((value) => Math.ceil(value.length / 2)));
const TLVBufferLength = this.TLVInstance.bValue.length + tagWithLengthBytes;
this.TLVInstance = node_tlv_1.default.parse(this.readBytes(8, TLVBufferLength, false));
}
catch (e) {
readTLVBufferLength -= 1;
if (!readTLVBufferLength)
break;
}
}
this.TLVChild = this.TLVInstance ? this.TLVInstance.getChild() : [];
},
encode: () => {
let buffers = Buffer.from([]);
this.TLVChild.forEach(item => buffers = Buffer.concat([buffers, item.bTag, item.bLength, item.bValue]));
const goosePduTLV = new node_tlv_1.default(0x61, buffers);
const goosePduBuffer = Buffer.concat([goosePduTLV.bTag, goosePduTLV.bLength, goosePduTLV.bValue]);
this.writeBytes(8, goosePduBuffer);
/**
* Update the length only if it is not set
* Update length(APPID's length + Length's length + Reserved1's length + Reserved2's length + goosePdu's length)
*/
if (this.instance.length.getValue() > 0)
return;
this.instance.length.setValue(2 + 2 + 2 + 2 + goosePduBuffer.length);
},
properties: {
gocbRef: {
type: 'string',
maxLength: 129,
label: 'GoCBReference',
contentEncoding: StringContentEncodingEnum_1.StringContentEncodingEnum.ASCII,
decode: () => {
const gocbRefTLV = this.TLVChild.find(tlv => tlv.getTag('number') === 0x80);
if (!gocbRefTLV)
return this.recordError(this.instance.goosePdu.gocbRef.getPath(), 'Not Found');
this.instance.goosePdu.gocbRef.setValue(gocbRefTLV.getValue('buffer').toString('ascii'));
},
encode: () => {
const gocbRefValue = this.instance.goosePdu.gocbRef.getValue('', (nodePath) => this.recordError(nodePath, 'Not Found'));
if (!gocbRefValue)
return;
let gocbRefBuffer = Buffer.from(gocbRefValue, 'ascii');
if (gocbRefBuffer.length > 129) {
this.recordError(this.instance.goosePdu.gocbRef.getPath(), 'This VisibleString shall have a maximum size of 129 octets');
gocbRefBuffer = gocbRefBuffer.subarray(0, 129);
}
this.TLVChild.push(new node_tlv_1.default(0x80, gocbRefBuffer));
}
},
timeAllowedtoLive: {
type: 'number',
minimum: 0,
maximum: 4294967295,
label: 'TimeAllowedtoLive',
decode: () => {
const timeAllowedtoLiveString = this.TLVChild.find(tlv => tlv.getTag('number') === 0x81)?.getValue('hex');
if (!timeAllowedtoLiveString)
return this.recordError(this.instance.goosePdu.timeAllowedtoLive.getPath(), 'Not Found');
this.instance.goosePdu.timeAllowedtoLive.setValue((0, HexToNumber_1.HexToUInt32)(timeAllowedtoLiveString));
},
encode: () => {
let timeAllowedtoLiveValue = this.instance.goosePdu.timeAllowedtoLive.getValue(-1, (nodePath) => this.recordError(nodePath, 'Not Found'));
if (timeAllowedtoLiveValue === -1)
return;
if (timeAllowedtoLiveValue < 1 || timeAllowedtoLiveValue > 4294967295) {
this.recordError(this.instance.goosePdu.timeAllowedtoLive.getPath(), 'This INTEGER value shall have a range of 1 to 4294967295');
timeAllowedtoLiveValue = 4294967295;
}
const timeAllowedtoLiveTLV = new node_tlv_1.default(0x81, (0, NumberToBERBuffer_1.UInt32ToBERBuffer)(timeAllowedtoLiveValue));
this.TLVChild.push(timeAllowedtoLiveTLV);
}
},
datSet: {
type: 'string',
maxLength: 129,
label: 'DatSet',
contentEncoding: StringContentEncodingEnum_1.StringContentEncodingEnum.ASCII,
decode: () => {
const datSetTLV = this.TLVChild.find(tlv => tlv.getTag('number') === 0x82);
if (!datSetTLV)
return this.recordError(this.instance.goosePdu.datSet.getPath(), 'Not Found');
this.instance.goosePdu.datSet.setValue(datSetTLV.getValue('buffer').toString('ascii'));
},
encode: () => {
const datSetValue = this.instance.goosePdu.datSet.getValue('', (nodePath) => this.recordError(nodePath, 'Not Found'));
if (!datSetValue)
return;
let datSetBuffer = Buffer.from(datSetValue, 'ascii');
if (datSetBuffer.length > 129) {
this.recordError(this.instance.goosePdu.datSet.getPath(), 'This VisibleString shall have a maximum size of 129 octets');
datSetBuffer = datSetBuffer.subarray(0, 129);
}
this.TLVChild.push(new node_tlv_1.default(0x82, datSetBuffer));
}
},
goID: {
type: 'string',
maxLength: 65,
label: 'GoID',
contentEncoding: StringContentEncodingEnum_1.StringContentEncodingEnum.ASCII,
decode: () => {
const goIDTLV = this.TLVChild.find(tlv => tlv.getTag('number') === 0x83);
if (!goIDTLV)
return this.recordError(this.instance.goosePdu.goID.getPath(), 'Not Found');
this.instance.goosePdu.goID.setValue(goIDTLV.getValue('buffer').toString('ascii'));
},
encode: () => {
const goIDValue = this.instance.goosePdu.goID.getValue('', (nodePath) => this.recordError(nodePath, 'Not Found'));
if (!goIDValue)
return;
let goIDBuffer = Buffer.from(goIDValue, 'ascii');
if (goIDBuffer.length > 65) {
this.recordError(this.instance.goosePdu.goID.getPath(), 'This VisibleString shall have a maximum size of 65 octets');
goIDBuffer = goIDBuffer.subarray(0, 65);
}
this.TLVChild.push(new node_tlv_1.default(0x83, goIDBuffer));
}
},
t: {
type: 'string',
label: 'TimeStamp',
contentEncoding: StringContentEncodingEnum_1.StringContentEncodingEnum.BIGINT,
decode: () => {
const tStr = this.TLVChild.find(tlv => tlv.getTag('number') === 0x84)?.getValue('hex');
if (!tStr)
return this.recordError(this.instance.goosePdu.t.getPath(), 'Not Found');
this.instance.goosePdu.t.setValue(BigInt(`0x${tStr}`).toString());
},
encode: () => {
const tStr = this.instance.goosePdu.t.getValue('', (nodePath) => this.recordError(nodePath, 'Not Found'));
if (!tStr)
return;
const tBigIntValue = BigInt(tStr);
const tTLV = new node_tlv_1.default(0x84, Buffer.from(tBigIntValue.toString(16).padStart(8 * 2, '0'), 'hex'));
this.TLVChild.push(tTLV);
}
},
stNum: {
type: 'integer',
minimum: 0,
maximum: 4294967295,
label: 'StNum',
decode: () => {
const stNumStr = this.TLVChild.find(tlv => tlv.getTag('number') === 0x85)?.getValue('hex');
if (!stNumStr)
return this.recordError(this.instance.goosePdu.stNum.getPath(), 'Not Found');
this.instance.goosePdu.stNum.setValue((0, HexToNumber_1.HexToUInt32)(stNumStr));
if (this.instance.goosePdu.stNum.getValue() < 1 || this.instance.goosePdu.stNum.getValue() > 4294967295)
this.recordError(this.instance.goosePdu.stNum.getPath(), 'This INTEGER value shall have a range of 1 to 4294967295');
},
encode: () => {
let stNumValue = this.instance.goosePdu.stNum.getValue(-1, (nodePath) => this.recordError(nodePath, 'Not Found'));
if (stNumValue < 0)
return;
if (stNumValue > 4294967295) {
stNumValue = 4294967295;
this.recordError(this.instance.goosePdu.stNum.getPath(), 'This INTEGER value shall have a range of 1 to 4294967295');
}
if (stNumValue === undefined)
return this.recordError(this.instance.goosePdu.stNum.getPath(), 'Not Found');
const stNumTLV = new node_tlv_1.default(0x85, (0, NumberToBERBuffer_1.UInt32ToBERBuffer)(stNumValue));
this.TLVChild.push(stNumTLV);
}
},
sqNum: {
type: 'integer',
minimum: 0,
maximum: 4294967295,
label: 'SqNum',
decode: () => {
const sqNumStr = this.TLVChild.find(tlv => tlv.getTag('number') === 0x86)?.getValue('hex');
if (!sqNumStr)
return this.recordError(this.instance.goosePdu.sqNum.getPath(), 'Not Found');
this.instance.goosePdu.sqNum.setValue((0, HexToNumber_1.HexToUInt32)(sqNumStr));
},
encode: () => {
let sqNumValue = this.instance.goosePdu.sqNum.getValue(-1, (nodePath) => this.recordError(nodePath, 'Not Found'));
if (sqNumValue < 0)
return;
if (sqNumValue > 4294967295) {
sqNumValue = 4294967295;
this.recordError(this.instance.goosePdu.sqNum.getPath(), 'This INTEGER value shall have a range of 1 to 4294967295');
}
if (sqNumValue === undefined)
return this.recordError(this.instance.goosePdu.sqNum.getPath(), 'Not Found');
const sqNumTLV = new node_tlv_1.default(0x86, (0, NumberToBERBuffer_1.UInt32ToBERBuffer)(sqNumValue));
this.TLVChild.push(sqNumTLV);
}
},
simulation: {
type: 'boolean',
label: 'Simulation',
decode: () => {
const simulationStr = this.TLVChild.find(tlv => tlv.getTag('number') === 0x87)?.getValue('hex');
if (!simulationStr)
return this.recordError(this.instance.goosePdu.simulation.getPath(), 'Not Found');
const simulationNum = parseInt(simulationStr, 16);
if (simulationNum > 1)
this.recordError(this.instance.goosePdu.simulation.getPath(), 'This Boolean shall have a range of TRUE, FALSE');
this.instance.goosePdu.simulation.setValue(!!simulationNum);
},
encode: () => {
const simulationValue = this.instance.goosePdu.simulation.getValue(undefined, (nodePath) => this.recordError(nodePath, 'Not Found'));
if (simulationValue === undefined)
return;
const simulationNum = simulationValue ? 1 : 0;
const simulationTLV = new node_tlv_1.default(0x87, Buffer.from(simulationNum.toString(16).padStart(2, '0'), 'hex'));
this.TLVChild.push(simulationTLV);
}
},
confRev: {
type: 'integer',
label: 'ConfRev',
decode: () => {
const confRevStr = this.TLVChild.find(tlv => tlv.getTag('number') === 0x88)?.getValue('hex');
if (!confRevStr)
return this.recordError(this.instance.goosePdu.confRev.getPath(), 'Not Found');
this.instance.goosePdu.confRev.setValue((0, HexToNumber_1.HexToUInt32)(confRevStr));
},
encode: () => {
let confRevValue = this.instance.goosePdu.confRev.getValue(-1, (nodePath) => this.recordError(nodePath, 'Not Found'));
if (confRevValue > 4294967295) {
confRevValue = 4294967295;
this.recordError(this.instance.goosePdu.confRev.getPath(), 'This INTEGER value shall have a range of 0 to 4294967295');
}
if (confRevValue === -1)
return;
const confRevTLV = new node_tlv_1.default(0x88, (0, NumberToBERBuffer_1.UInt32ToBERBuffer)(confRevValue));
this.TLVChild.push(confRevTLV);
}
},
ndsCom: {
type: 'boolean',
label: 'NdsCom',
decode: () => {
const ndsComStr = this.TLVChild.find(tlv => tlv.getTag('number') === 0x89)?.getValue('hex');
if (!ndsComStr)
return this.recordError(this.instance.goosePdu.ndsCom.getPath(), 'Not Found');
const ndsComNum = parseInt(ndsComStr, 16);
if (ndsComNum > 1)
this.recordError(this.instance.goosePdu.ndsCom.getPath(), 'This Boolean shall have a range of TRUE, FALSE');
this.instance.goosePdu.ndsCom.setValue(!!ndsComNum);
},
encode: () => {
const ndsComValue = this.instance.goosePdu.ndsCom.getValue(undefined, (nodePath) => this.recordError(nodePath, 'Not Found'));
if (ndsComValue === undefined)
return;
const ndsComNum = ndsComValue ? 1 : 0;
const ndsComTLV = new node_tlv_1.default(0x89, Buffer.from(ndsComNum.toString(16).padStart(2, '0'), 'hex'));
this.TLVChild.push(ndsComTLV);
}
},
numDatSetEntries: {
type: 'integer',
label: 'NumDatSetEntries',
decode: () => {
const numDatSetEntriesStr = this.TLVChild.find(tlv => tlv.getTag('number') === 0x8A)?.getValue('hex');
if (!numDatSetEntriesStr)
return this.recordError(this.instance.goosePdu.numDatSetEntries.getPath(), 'Not Found');
this.instance.goosePdu.numDatSetEntries.setValue(parseInt(numDatSetEntriesStr, 16));
},
encode: () => {
const numDatSetEntriesValue = this.instance.goosePdu.numDatSetEntries.getValue(undefined, (nodePath) => this.recordError(nodePath, 'Not Found'));
if (numDatSetEntriesValue === undefined)
return;
const numDatSetEntriesTLV = new node_tlv_1.default(0x8A, (0, NumberToBERBuffer_1.UInt32ToBERBuffer)(numDatSetEntriesValue));
this.TLVChild.push(numDatSetEntriesTLV);
}
},
allData: {
type: 'array',
label: 'AllData',
items: {
anyOf: [
{
type: 'object',
label: ItemDataType.Boolean,
properties: {
dataType: { type: 'string', enum: [ItemDataType.Boolean] },
value: { type: 'boolean' }
}
},
{
type: 'object',
label: ItemDataType.INT8,
properties: {
dataType: { type: 'string', enum: [ItemDataType.INT8] },
value: { type: 'integer' }
}
},
{
type: 'object',
label: ItemDataType.INT16,
properties: {
dataType: { type: 'string', enum: [ItemDataType.INT16] },
value: { type: 'integer' }
}
},
{
type: 'object',
label: ItemDataType.INT32,
properties: {
dataType: { type: 'string', enum: [ItemDataType.INT32] },
value: { type: 'integer' }
}
},
{
type: 'object',
label: ItemDataType.INT64,
properties: {
dataType: { type: 'string', enum: [ItemDataType.INT64] },
value: { type: 'string', contentEncoding: StringContentEncodingEnum_1.StringContentEncodingEnum.BIGINT }
}
},
{
type: 'object',
label: ItemDataType.INT8U,
properties: {
dataType: { type: 'string', enum: [ItemDataType.INT8U] },
value: { type: 'integer' }
}
},
{
type: 'object',
label: ItemDataType.INT16U,
properties: {
dataType: { type: 'string', enum: [ItemDataType.INT16U] },
value: { type: 'integer' }
}
},
{
type: 'object',
label: ItemDataType.INT32U,
properties: {
dataType: { type: 'string', enum: [ItemDataType.INT32U] },
value: { type: 'integer' }
}
},
{
type: 'object',
label: ItemDataType.FLOAT32,
properties: {
dataType: { type: 'string', enum: [ItemDataType.FLOAT32] },
value: { type: 'number' }
}
},
{
type: 'object',
label: ItemDataType.CODEDENUM,
properties: {
dataType: { type: 'string', enum: [ItemDataType.CODEDENUM] },
value: { type: 'integer' }
}
},
{
type: 'object',
label: ItemDataType.OCTETSTRING,
properties: {
dataType: { type: 'string', enum: [ItemDataType.OCTETSTRING] },
value: { type: 'string', contentEncoding: StringContentEncodingEnum_1.StringContentEncodingEnum.HEX }
}
},
{
type: 'object',
label: ItemDataType.VISIBLESTRING,
properties: {
dataType: { type: 'string', enum: [ItemDataType.VISIBLESTRING] },
value: { type: 'string', contentEncoding: StringContentEncodingEnum_1.StringContentEncodingEnum.ASCII }
}
},
{
type: 'object',
properties: {
dataType: { type: 'string', enum: [ItemDataType.TimeStamp] },
value: { type: 'string' }
}
},
{
type: 'object',
label: ItemDataType.Quality,
properties: {
dataType: { type: 'string', enum: [ItemDataType.Quality] },
value: { type: 'string', contentEncoding: StringContentEncodingEnum_1.StringContentEncodingEnum.BINARY }
}
},
{
type: 'object',
label: ItemDataType.Structure,
properties: {
dataType: { type: 'string', enum: [ItemDataType.Structure] },
value: {
$ref: '#/properties/goosePdu/properties/allData'
}
}
}
]
},
/**
* +-----------------------------------+-------------------+-------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
* | Data types according to IEC 61850-7-2 | ASN.1 Tag for Data | ASN.1 Length | Comments |
* +-----------------------------------+-------------------+-------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
* | Boolean | 0x83 | 1 | 8 Bit set to 0 FALSE; anything else = TRUE |
* | INT8 | 0x85 | 2 | 8 Bit Big Endian; signed |
* | INT16 | 0x85 | 3 | 16 Bit Big Endian; signed |
* | INT32 | 0x85 | 5 | 32 Bit Big Endian; signed |
* | INT64 | 0x85 | 9 | 64Bit Big Endian; signed |
* | INT8U | 0x86 | 2 | 8 Bit Big Endian; unsigned |
* | INT16U | 0x86 | 3 | 16 Bit Big Endian; unsigned |
* | INT24U | - | - | Not used |
* | INT32U | 0x86 | 5 | 32 Bit Big Endian; unsigned |
* | FLOAT32 | 0x87 | 4 | 32 Bit IEEE Floating Point (IEEE 754) |
* | CODED-ENUM | 0x84 | 2 | Bit-string; depending on CODED ENUM definition – most of the time, can be encoded with 2 bytes (1st Byte = number of unused bit, 2nd Byte = Value) |
* | OCTET-STRING | 0x89 | 20 | 20 Bytes ASCII Text, Null terminated |
* | VISIBLE-STRING | 0x8a | 35 | 35 Bytes ASCII Text, Null terminated |
* | TimeStamp | 0x91 | 8 | 64 Bit TimeStamp as defined in 8.1.3.7 IEC 6 |
* | Quality | 0x84 | 3 | Bit-string |
* +-----------------------------------+-------------------+-------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+
*/
decode: () => {
const allDataTLV = this.TLVChild.find(tlv => tlv.getTag('number') === 0xAB);
const dataTLVs = allDataTLV ? allDataTLV.getChild() : [];
const allData = this.decodeDataTLVItem(dataTLVs);
if (allData.length)
this.instance.goosePdu.allData.setValue(allData);
},
encode: () => {
const allData = this.instance.goosePdu.allData.getValue([], (nodePath) => this.recordError(nodePath, 'Not Found'));
const dataItemTLVs = this.encodeDataTLVItem(allData);
if (dataItemTLVs.length) {
const allDataTLV = new node_tlv_1.default(0xAB, Buffer.concat(dataItemTLVs.map((dataItemTLV) => Buffer.concat([dataItemTLV.bTag, dataItemTLV.bLength, dataItemTLV.bValue]))));
this.TLVChild.push(allDataTLV);
}
}
}
}
}
}
};
this.id = 'goose';
this.name = 'IEC61850 GOOSE';
this.nickname = 'GOOSE';
}
/**
* Decode data TLV items
* @param dataTLVs
* @protected
*/
decodeDataTLVItem(dataTLVs) {
const dataItems = [];
dataTLVs.forEach((dataTLV) => {
const length = dataTLV.getLength('number');
const value = dataTLV.getValue('buffer');
switch (dataTLV.getTag('number')) {
case 0x83:
{
dataItems.push({
dataType: ItemDataType.Boolean,
value: !!parseInt(value.toString('hex'), 16)
});
}
break;
case 0x84:
{
switch (length) {
case 2:
{
dataItems.push({
dataType: ItemDataType.CODEDENUM,
value: parseInt(value.toString('hex'), 16)
});
}
break;
case 3:
{
dataItems.push({
dataType: ItemDataType.Quality,
value: parseInt(value.toString('hex'), 16).toString(2).padStart(24, '0')
});
}
break;
}
}
break;
case 0x85:
{
const integerRealLength = (0, GetBERIntegerLengthFromBuffer_1.GetBERIntegerLengthFromBuffer)(value);
if (integerRealLength === 1) {
dataItems.push({
dataType: ItemDataType.INT8,
value: (0, HexToNumber_1.HexToInt8)(value.toString('hex'))
});
}
else if (integerRealLength === 2) {
dataItems.push({
dataType: ItemDataType.INT16,
value: (0, HexToNumber_1.HexToInt16)(value.toString('hex'))
});
}
else if (integerRealLength === 4) {
dataItems.push({
dataType: ItemDataType.INT32,
value: (0, HexToNumber_1.HexToInt32)(value.toString('hex'))
});
}
else if (integerRealLength === 8) {
dataItems.push({
dataType: ItemDataType.INT64,
value: (0, HexToNumber_1.HexToInt64)(value.toString('hex'))
});
}
}
break;
case 0x86:
{
const unsignedIntegerRealLength = (0, GetBERIntegerLengthFromBuffer_1.GetBERIntegerLengthFromBuffer)(value);
switch (unsignedIntegerRealLength) {
case 1:
{
dataItems.push({
dataType: ItemDataType.INT8U,
value: (0, HexToNumber_1.HexToUInt8)(value.toString('hex'))
});
}
break;
case 2:
{
dataItems.push({
dataType: ItemDataType.INT16U,
value: (0, HexToNumber_1.HexToUInt16)(value.toString('hex'))
});
}
break;
case 4:
{
dataItems.push({
dataType: ItemDataType.INT32U,
value: (0, HexToNumber_1.HexToUInt32)(value.toString('hex'))
});
}
break;
}
}
break;
case 0x87:
{
dataItems.push({
dataType: ItemDataType.FLOAT32,
value: (0, HexToNumber_1.HexToFloat32)(value.toString('hex'))
});
}
break;
case 0x89:
{
dataItems.push({
dataType: ItemDataType.OCTETSTRING,
value: value.toString('hex')
});
}
break;
case 0x8a:
{
dataItems.push({
dataType: ItemDataType.VISIBLESTRING,
value: value.toString('ascii')
});
}
break;
case 0x91:
{
dataItems.push({
dataType: ItemDataType.TimeStamp,
value: parseInt(value.toString('hex'), 16).toString()
});
}
break;
case 0xa2:
{
const subDataTLVs = node_tlv_1.default.parseList(value);
dataItems.push({
dataType: ItemDataType.Structure,
value: this.decodeDataTLVItem(subDataTLVs)
});
}
break;
}
});
return dataItems;
}
/**
* Encode data TLV items
* @param dataItems
* @protected
*/
encodeDataTLVItem(dataItems) {
return dataItems
.map((dataItem, index) => {
const errorNodePath = this.instance.goosePdu.allData.getPath(index);
switch (dataItem.dataType) {
case ItemDataType.Boolean: {
const booleanIntValue = dataItem.value ? 1 : 0;
return new node_tlv_1.default(0x83, Buffer.from(booleanIntValue.toString(16).padStart(2, '0'), 'hex'));
}
case ItemDataType.INT8: {
let intValue = dataItem.value;
if (isNaN(intValue))
this.recordError(errorNodePath, 'Invalid INT8 value');
intValue = intValue ? intValue : 0;
if (intValue < -128 || intValue > 127)
this.recordError(errorNodePath, 'Invalid INT8 value');
return new node_tlv_1.default(0x85, Buffer.from((0, NumberToBERHex_1.Int8ToBERHex)(intValue), 'hex'));
}
case ItemDataType.INT16: {
let intValue = dataItem.value;
if (isNaN(intValue))
this.recordError(errorNodePath, 'Invalid INT16 value');
intValue = intValue ? intValue : 0;
if (intValue < -32768 || intValue > 32767)
this.recordError(errorNodePath, 'Invalid INT16 value');
return new node_tlv_1.default(0x85, Buffer.from((0, NumberToBERHex_1.Int16ToBERHex)(intValue), 'hex'));
}
case ItemDataType.INT32: {
let intValue = dataItem.value;
if (isNaN(intValue))
this.recordError(errorNodePath, 'Invalid INT32 value');
intValue = intValue ? intValue : 0;
if (intValue < -2147483648 || intValue > 2147483647)
this.recordError(errorNodePath, 'Invalid INT32 value');
return new node_tlv_1.default(0x85, Buffer.from((0, NumberToBERHex_1.Int32ToBERHex)(intValue), 'hex'));
}
case ItemDataType.INT64: {
const intValue = BigInt(dataItem.value);
if (intValue < BigInt('-9223372036854775808') || intValue > BigInt('9223372036854775807'))
this.recordError(errorNodePath, 'Invalid INT64 value');
return new node_tlv_1.default(0x85, Buffer.from((0, NumberToBERHex_1.Int64ToBERHex)(intValue), 'hex'));
}
case ItemDataType.INT8U: {
let uintValue = dataItem.value;
if (isNaN(uintValue))
this.recordError(errorNodePath, 'Invalid INT8U value');
uintValue = uintValue ? uintValue : 0;
if (uintValue < 0 || uintValue > 255)
this.recordError(errorNodePath, 'Invalid INT8U value');
return new node_tlv_1.default(0x86, Buffer.from((0, NumberToBERHex_1.UInt8ToBERHex)(uintValue), 'hex'));
}
case ItemDataType.INT16U: {
let uintValue = dataItem.value;
if (isNaN(uintValue))
this.recordError(errorNodePath, 'Invalid INT16U value');
uintValue = uintValue ? uintValue : 0;
if (uintValue < 0 || uintValue > 65535)
this.recordError(errorNodePath, 'Invalid INT16U value');
return new node_tlv_1.default(0x86, Buffer.from((0, NumberToBERHex_1.UInt16ToBERHex)(uintValue), 'hex'));
}
case ItemDataType.INT32U: {
let uintValue = d