@bitpoolos/edge-bacnet 1.6.9 → 1.6.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/package.json +1 -1
  3. package/resources/node-bacstack-ts/dist/index.js +3 -0
  4. package/resources/node-bacstack-ts/dist/lib/apdu.js +193 -0
  5. package/resources/node-bacstack-ts/dist/lib/asn1.js +1671 -0
  6. package/resources/node-bacstack-ts/dist/lib/bvlc.js +47 -0
  7. package/resources/node-bacstack-ts/dist/lib/client.js +1679 -0
  8. package/resources/node-bacstack-ts/dist/lib/enum.js +2114 -0
  9. package/resources/node-bacstack-ts/dist/lib/npdu.js +112 -0
  10. package/resources/node-bacstack-ts/dist/lib/services/add-list-element.js +58 -0
  11. package/resources/node-bacstack-ts/dist/lib/services/alarm-acknowledge.js +93 -0
  12. package/resources/node-bacstack-ts/dist/lib/services/alarm-summary.js +42 -0
  13. package/resources/node-bacstack-ts/dist/lib/services/atomic-read-file.js +157 -0
  14. package/resources/node-bacstack-ts/dist/lib/services/atomic-write-file.js +136 -0
  15. package/resources/node-bacstack-ts/dist/lib/services/cov-notify.js +119 -0
  16. package/resources/node-bacstack-ts/dist/lib/services/create-object.js +104 -0
  17. package/resources/node-bacstack-ts/dist/lib/services/delete-object.js +21 -0
  18. package/resources/node-bacstack-ts/dist/lib/services/device-communication-control.js +46 -0
  19. package/resources/node-bacstack-ts/dist/lib/services/error.js +27 -0
  20. package/resources/node-bacstack-ts/dist/lib/services/event-information.js +100 -0
  21. package/resources/node-bacstack-ts/dist/lib/services/event-notify-data.js +219 -0
  22. package/resources/node-bacstack-ts/dist/lib/services/get-enrollment-summary.js +172 -0
  23. package/resources/node-bacstack-ts/dist/lib/services/get-event-information.js +135 -0
  24. package/resources/node-bacstack-ts/dist/lib/services/i-am-broadcast.js +59 -0
  25. package/resources/node-bacstack-ts/dist/lib/services/i-have-broadcast.js +34 -0
  26. package/resources/node-bacstack-ts/dist/lib/services/index.js +32 -0
  27. package/resources/node-bacstack-ts/dist/lib/services/life-safety-operation.js +40 -0
  28. package/resources/node-bacstack-ts/dist/lib/services/private-transfer.js +43 -0
  29. package/resources/node-bacstack-ts/dist/lib/services/read-property-multiple.js +44 -0
  30. package/resources/node-bacstack-ts/dist/lib/services/read-property.js +122 -0
  31. package/resources/node-bacstack-ts/dist/lib/services/read-range.js +201 -0
  32. package/resources/node-bacstack-ts/dist/lib/services/reinitialize-device.js +35 -0
  33. package/resources/node-bacstack-ts/dist/lib/services/subscribe-cov.js +55 -0
  34. package/resources/node-bacstack-ts/dist/lib/services/subscribe-property.js +93 -0
  35. package/resources/node-bacstack-ts/dist/lib/services/time-sync.js +31 -0
  36. package/resources/node-bacstack-ts/dist/lib/services/who-has.js +56 -0
  37. package/resources/node-bacstack-ts/dist/lib/services/who-is.js +45 -0
  38. package/resources/node-bacstack-ts/dist/lib/services/write-property-multiple.js +105 -0
  39. package/resources/node-bacstack-ts/dist/lib/services/write-property.js +90 -0
  40. package/resources/node-bacstack-ts/dist/lib/transport.js +86 -0
  41. package/resources/node-bacstack-ts/dist/lib/types.js +2 -0
@@ -0,0 +1,1671 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.decodeContextCharacterString = exports.bacappEncodeContextTimestamp = exports.bacappEncodeTimestamp = exports.decodeReadAccessSpecification = exports.decodeApplicationTime = exports.decodeBacnetTime = exports.decodeApplicationDate = exports.decodeDate = exports.decodeBitstring = exports.decodeCharacterString = exports.decodeOctetString = exports.decodeReal = exports.decodeSigned = exports.decodeReadAccessResult = exports.encodeReadAccessResult = exports.bacappDecodeApplicationData = exports.decodeTagNumberAndValue = exports.decodeObjectId = exports.decodeIsOpeningTag = exports.decodeIsClosingTag = exports.decodeIsClosingTagNumber = exports.decodeIsOpeningTagNumber = exports.decodeIsContextTag = exports.decodeTagNumber = exports.encodeContextSigned = exports.encodeContextBitstring = exports.bacappEncodePropertyState = exports.bacappEncodeContextDeviceObjPropertyRef = exports.bacappEncodeApplicationData = exports.encodeContextBoolean = exports.encodeReadAccessSpecification = exports.encodeClosingTag = exports.encodeOpeningTag = exports.encodeContextObjectId = exports.encodeApplicationTime = exports.encodeApplicationDate = exports.encodeApplicationBitstring = exports.encodeApplicationSigned = exports.encodeApplicationEnumerated = exports.encodeApplicationUnsigned = exports.encodeApplicationObjectId = exports.encodeApplicationBoolean = exports.encodeApplicationOctetString = exports.encodeContextEnumerated = exports.encodeContextUnsigned = exports.encodeContextReal = exports.encodeTag = exports.encodeBacnetObjectId = exports.decodeEnumerated = exports.decodeUnsigned = void 0;
4
+ exports.encodeContextCharacterString = exports.encodeApplicationCharacterString = exports.decodeContextObjectId = void 0;
5
+ const iconv = require("iconv-lite");
6
+ const baEnum = require("./enum");
7
+ const getBuffer = () => ({
8
+ buffer: Buffer.alloc(1472),
9
+ offset: 0
10
+ });
11
+ const getSignedLength = (value) => {
12
+ if ((value >= -128) && (value < 128))
13
+ return 1;
14
+ else if ((value >= -32768) && (value < 32768))
15
+ return 2;
16
+ else if ((value > -8388608) && (value < 8388608))
17
+ return 3;
18
+ else
19
+ return 4;
20
+ };
21
+ const getUnsignedLength = (value) => {
22
+ if (value < 0x100)
23
+ return 1;
24
+ else if (value < 0x10000)
25
+ return 2;
26
+ else if (value < 0x1000000)
27
+ return 3;
28
+ else
29
+ return 4;
30
+ };
31
+ const getEncodingType = (encoding, decodingBuffer, decodingOffset) => {
32
+ switch (encoding) {
33
+ case baEnum.CharacterStringEncoding.UTF_8:
34
+ return 'utf8';
35
+ case baEnum.CharacterStringEncoding.UCS_2:
36
+ if (decodingBuffer && decodingBuffer[decodingOffset] === 0xFF && decodingBuffer[decodingOffset + 1] === 0xFE) {
37
+ return 'ucs2';
38
+ }
39
+ return 'UTF-16BE'; // Default to big-endian
40
+ case baEnum.CharacterStringEncoding.ISO_8859_1:
41
+ return 'latin1';
42
+ case baEnum.CharacterStringEncoding.UCS_4:
43
+ return 'utf8'; // HACK: There is currently no support for UTF-32
44
+ case baEnum.CharacterStringEncoding.MICROSOFT_DBCS:
45
+ return 'cp850';
46
+ case baEnum.CharacterStringEncoding.JIS_X_0208:
47
+ return 'Shift_JIS';
48
+ default:
49
+ return 'utf8';
50
+ }
51
+ };
52
+ const encodeUnsigned = (buffer, value, length) => {
53
+ buffer.buffer.writeUIntBE(value, buffer.offset, length);
54
+ buffer.offset += length;
55
+ };
56
+ const encodeBacnetUnsigned = (buffer, value) => {
57
+ encodeUnsigned(buffer, value, getUnsignedLength(value));
58
+ };
59
+ const encodeSigned = (buffer, value, length) => {
60
+ buffer.buffer.writeIntBE(value, buffer.offset, length);
61
+ buffer.offset += length;
62
+ };
63
+ const encodeBacnetSigned = (buffer, value) => {
64
+ encodeSigned(buffer, value, getSignedLength(value));
65
+ };
66
+ const encodeBacnetReal = (buffer, value) => {
67
+ buffer.buffer.writeFloatBE(value, buffer.offset);
68
+ buffer.offset += 4;
69
+ };
70
+ const encodeBacnetDouble = (buffer, value) => {
71
+ buffer.buffer.writeDoubleBE(value, buffer.offset);
72
+ buffer.offset += 8;
73
+ };
74
+ const decodeUnsigned = (buffer, offset, length) => ({
75
+ len: length,
76
+ value: length === 0 ? 0 : buffer.readUIntBE(offset, length)
77
+ });
78
+ exports.decodeUnsigned = decodeUnsigned;
79
+ const decodeEnumerated = (buffer, offset, lenValue) => {
80
+ return (0, exports.decodeUnsigned)(buffer, offset, lenValue);
81
+ };
82
+ exports.decodeEnumerated = decodeEnumerated;
83
+ const encodeBacnetObjectId = (buffer, objectType, instance) => {
84
+ const value = (((objectType & baEnum.ASN1_MAX_OBJECT) << baEnum.ASN1_INSTANCE_BITS) | (instance & baEnum.ASN1_MAX_INSTANCE)) >>> 0;
85
+ encodeUnsigned(buffer, value, 4);
86
+ };
87
+ exports.encodeBacnetObjectId = encodeBacnetObjectId;
88
+ const encodeTag = (buffer, tagNumber, contextSpecific, lenValueType) => {
89
+ let len = 1;
90
+ const tmp = new Array(3);
91
+ tmp[0] = 0;
92
+ if (contextSpecific) {
93
+ tmp[0] |= 0x8;
94
+ }
95
+ if (tagNumber <= 14) {
96
+ tmp[0] |= (tagNumber << 4);
97
+ }
98
+ else {
99
+ tmp[0] |= 0xF0;
100
+ tmp[1] = tagNumber;
101
+ len++;
102
+ }
103
+ if (lenValueType <= 4) {
104
+ tmp[0] |= lenValueType;
105
+ Buffer.from(tmp).copy(buffer.buffer, buffer.offset, 0, len);
106
+ buffer.offset += len;
107
+ }
108
+ else {
109
+ tmp[0] |= 5;
110
+ if (lenValueType <= 253) {
111
+ tmp[len++] = lenValueType;
112
+ Buffer.from(tmp).copy(buffer.buffer, buffer.offset, 0, len);
113
+ buffer.offset += len;
114
+ }
115
+ else if (lenValueType <= 65535) {
116
+ tmp[len++] = 254;
117
+ Buffer.from(tmp).copy(buffer.buffer, buffer.offset, 0, len);
118
+ buffer.offset += len;
119
+ encodeUnsigned(buffer, lenValueType, 2);
120
+ }
121
+ else {
122
+ tmp[len++] = 255;
123
+ Buffer.from(tmp).copy(buffer.buffer, buffer.offset, 0, len);
124
+ buffer.offset += len;
125
+ encodeUnsigned(buffer, lenValueType, 4);
126
+ }
127
+ }
128
+ };
129
+ exports.encodeTag = encodeTag;
130
+ const encodeBacnetEnumerated = (buffer, value) => {
131
+ encodeBacnetUnsigned(buffer, value);
132
+ };
133
+ const isExtendedTagNumber = (x) => {
134
+ return (x & 0xF0) === 0xF0;
135
+ };
136
+ const isExtendedValue = (x) => {
137
+ return (x & 0x07) === 5;
138
+ };
139
+ const isContextSpecific = (x) => {
140
+ return (x & 0x8) === 0x8;
141
+ };
142
+ const isOpeningTag = (x) => {
143
+ return (x & 0x07) === 6;
144
+ };
145
+ const isClosingTag = (x) => {
146
+ return (x & 0x07) === 7;
147
+ };
148
+ const encodeContextReal = (buffer, tagNumber, value) => {
149
+ (0, exports.encodeTag)(buffer, tagNumber, true, 4);
150
+ encodeBacnetReal(buffer, value);
151
+ };
152
+ exports.encodeContextReal = encodeContextReal;
153
+ const encodeContextUnsigned = (buffer, tagNumber, value) => {
154
+ (0, exports.encodeTag)(buffer, tagNumber, true, getUnsignedLength(value));
155
+ encodeBacnetUnsigned(buffer, value);
156
+ };
157
+ exports.encodeContextUnsigned = encodeContextUnsigned;
158
+ const encodeContextEnumerated = (buffer, tagNumber, value) => {
159
+ (0, exports.encodeContextUnsigned)(buffer, tagNumber, value);
160
+ };
161
+ exports.encodeContextEnumerated = encodeContextEnumerated;
162
+ const encodeOctetString = (buffer, octetString, octetOffset, octetCount) => {
163
+ if (octetString) {
164
+ for (let i = octetOffset; i < (octetOffset + octetCount); i++) {
165
+ buffer.buffer[buffer.offset++] = octetString[i];
166
+ }
167
+ }
168
+ };
169
+ const encodeApplicationOctetString = (buffer, octetString, octetOffset, octetCount) => {
170
+ (0, exports.encodeTag)(buffer, baEnum.ApplicationTags.OCTET_STRING, false, octetCount);
171
+ encodeOctetString(buffer, octetString, octetOffset, octetCount);
172
+ };
173
+ exports.encodeApplicationOctetString = encodeApplicationOctetString;
174
+ const encodeApplicationNull = (buffer) => {
175
+ buffer.buffer[buffer.offset++] = baEnum.ApplicationTags.NULL;
176
+ };
177
+ const encodeApplicationBoolean = (buffer, booleanValue) => {
178
+ (0, exports.encodeTag)(buffer, baEnum.ApplicationTags.BOOLEAN, false, booleanValue ? 1 : 0);
179
+ };
180
+ exports.encodeApplicationBoolean = encodeApplicationBoolean;
181
+ const encodeApplicationReal = (buffer, value) => {
182
+ (0, exports.encodeTag)(buffer, baEnum.ApplicationTags.REAL, false, 4);
183
+ encodeBacnetReal(buffer, value);
184
+ };
185
+ const encodeApplicationDouble = (buffer, value) => {
186
+ (0, exports.encodeTag)(buffer, baEnum.ApplicationTags.DOUBLE, false, 8);
187
+ encodeBacnetDouble(buffer, value);
188
+ };
189
+ const bitstringBytesUsed = (bitString) => {
190
+ let len = 0;
191
+ if (bitString.bitsUsed > 0) {
192
+ const lastBit = bitString.bitsUsed - 1;
193
+ const usedBytes = (lastBit / 8) + 1;
194
+ len = Math.floor(usedBytes);
195
+ }
196
+ return len;
197
+ };
198
+ const encodeApplicationObjectId = (buffer, objectType, instance) => {
199
+ const tmp = getBuffer();
200
+ (0, exports.encodeBacnetObjectId)(tmp, objectType, instance);
201
+ (0, exports.encodeTag)(buffer, baEnum.ApplicationTags.OBJECTIDENTIFIER, false, tmp.offset);
202
+ tmp.buffer.copy(buffer.buffer, buffer.offset, 0, tmp.offset);
203
+ buffer.offset += tmp.offset;
204
+ };
205
+ exports.encodeApplicationObjectId = encodeApplicationObjectId;
206
+ const encodeApplicationUnsigned = (buffer, value) => {
207
+ const tmp = getBuffer();
208
+ encodeBacnetUnsigned(tmp, value);
209
+ (0, exports.encodeTag)(buffer, baEnum.ApplicationTags.UNSIGNED_INTEGER, false, tmp.offset);
210
+ tmp.buffer.copy(buffer.buffer, buffer.offset, 0, tmp.offset);
211
+ buffer.offset += tmp.offset;
212
+ };
213
+ exports.encodeApplicationUnsigned = encodeApplicationUnsigned;
214
+ const encodeApplicationEnumerated = (buffer, value) => {
215
+ const tmp = getBuffer();
216
+ encodeBacnetEnumerated(tmp, value);
217
+ (0, exports.encodeTag)(buffer, baEnum.ApplicationTags.ENUMERATED, false, tmp.offset);
218
+ tmp.buffer.copy(buffer.buffer, buffer.offset, 0, tmp.offset);
219
+ buffer.offset += tmp.offset;
220
+ };
221
+ exports.encodeApplicationEnumerated = encodeApplicationEnumerated;
222
+ const encodeApplicationSigned = (buffer, value) => {
223
+ const tmp = getBuffer();
224
+ encodeBacnetSigned(tmp, value);
225
+ (0, exports.encodeTag)(buffer, baEnum.ApplicationTags.SIGNED_INTEGER, false, tmp.offset);
226
+ tmp.buffer.copy(buffer.buffer, buffer.offset, 0, tmp.offset);
227
+ buffer.offset += tmp.offset;
228
+ };
229
+ exports.encodeApplicationSigned = encodeApplicationSigned;
230
+ const byteReverseBits = (inByte) => {
231
+ let outByte = 0;
232
+ if ((inByte & 1) > 0) {
233
+ outByte |= 0x80;
234
+ }
235
+ if ((inByte & 2) > 0) {
236
+ outByte |= 0x40;
237
+ }
238
+ if ((inByte & 4) > 0) {
239
+ outByte |= 0x20;
240
+ }
241
+ if ((inByte & 8) > 0) {
242
+ outByte |= 0x10;
243
+ }
244
+ if ((inByte & 16) > 0) {
245
+ outByte |= 0x8;
246
+ }
247
+ if ((inByte & 32) > 0) {
248
+ outByte |= 0x4;
249
+ }
250
+ if ((inByte & 64) > 0) {
251
+ outByte |= 0x2;
252
+ }
253
+ if ((inByte & 128) > 0) {
254
+ outByte |= 1;
255
+ }
256
+ return outByte;
257
+ };
258
+ const bitstringOctet = (bitString, octetIndex) => {
259
+ let octet = 0;
260
+ if (bitString.value) {
261
+ if (octetIndex < baEnum.ASN1_MAX_BITSTRING_BYTES) {
262
+ octet = bitString.value[octetIndex];
263
+ }
264
+ }
265
+ return octet;
266
+ };
267
+ const encodeBitstring = (buffer, bitString) => {
268
+ if (bitString.bitsUsed === 0) {
269
+ buffer.buffer[buffer.offset++] = 0;
270
+ }
271
+ else {
272
+ const usedBytes = bitstringBytesUsed(bitString);
273
+ const remainingUsedBits = bitString.bitsUsed - ((usedBytes - 1) * 8);
274
+ buffer.buffer[buffer.offset++] = 8 - remainingUsedBits;
275
+ for (let i = 0; i < usedBytes; i++) {
276
+ buffer.buffer[buffer.offset++] = byteReverseBits(bitstringOctet(bitString, i));
277
+ }
278
+ }
279
+ };
280
+ const encodeApplicationBitstring = (buffer, bitString) => {
281
+ let bitStringEncodedLength = 1;
282
+ bitStringEncodedLength += bitstringBytesUsed(bitString);
283
+ (0, exports.encodeTag)(buffer, baEnum.ApplicationTags.BIT_STRING, false, bitStringEncodedLength);
284
+ encodeBitstring(buffer, bitString);
285
+ };
286
+ exports.encodeApplicationBitstring = encodeApplicationBitstring;
287
+ const encodeBacnetDate = (buffer, value) => {
288
+ if (value === new Date(1, 1, 1)) {
289
+ buffer.buffer[buffer.offset++] = 0xFF;
290
+ buffer.buffer[buffer.offset++] = 0xFF;
291
+ buffer.buffer[buffer.offset++] = 0xFF;
292
+ buffer.buffer[buffer.offset++] = 0xFF;
293
+ return;
294
+ }
295
+ if (value.getFullYear() >= 1900) {
296
+ buffer.buffer[buffer.offset++] = (value.getFullYear() - 1900);
297
+ }
298
+ else if (value.getFullYear() < 0x100) {
299
+ buffer.buffer[buffer.offset++] = value.getFullYear();
300
+ }
301
+ else {
302
+ return;
303
+ }
304
+ buffer.buffer[buffer.offset++] = value.getMonth();
305
+ buffer.buffer[buffer.offset++] = value.getDate();
306
+ buffer.buffer[buffer.offset++] = (value.getDay() === 0) ? 7 : value.getDay();
307
+ };
308
+ const encodeApplicationDate = (buffer, value) => {
309
+ (0, exports.encodeTag)(buffer, baEnum.ApplicationTags.DATE, false, 4);
310
+ encodeBacnetDate(buffer, value);
311
+ };
312
+ exports.encodeApplicationDate = encodeApplicationDate;
313
+ const encodeBacnetTime = (buffer, value) => {
314
+ buffer.buffer[buffer.offset++] = value.getHours();
315
+ buffer.buffer[buffer.offset++] = value.getMinutes();
316
+ buffer.buffer[buffer.offset++] = value.getSeconds();
317
+ buffer.buffer[buffer.offset++] = value.getMilliseconds() / 10;
318
+ };
319
+ const encodeApplicationTime = (buffer, value) => {
320
+ (0, exports.encodeTag)(buffer, baEnum.ApplicationTags.TIME, false, 4);
321
+ encodeBacnetTime(buffer, value);
322
+ };
323
+ exports.encodeApplicationTime = encodeApplicationTime;
324
+ const bacappEncodeDatetime = (buffer, value) => {
325
+ if (value !== new Date(1, 1, 1)) {
326
+ (0, exports.encodeApplicationDate)(buffer, value);
327
+ (0, exports.encodeApplicationTime)(buffer, value);
328
+ }
329
+ };
330
+ const encodeContextObjectId = (buffer, tagNumber, objectType, instance) => {
331
+ (0, exports.encodeTag)(buffer, tagNumber, true, 4);
332
+ (0, exports.encodeBacnetObjectId)(buffer, objectType, instance);
333
+ };
334
+ exports.encodeContextObjectId = encodeContextObjectId;
335
+ const encodeOpeningTag = (buffer, tagNumber) => {
336
+ let len = 1;
337
+ const tmp = new Array(2);
338
+ tmp[0] = 0x8;
339
+ if (tagNumber <= 14) {
340
+ tmp[0] |= (tagNumber << 4);
341
+ }
342
+ else {
343
+ tmp[0] |= 0xF0;
344
+ tmp[1] = tagNumber;
345
+ len++;
346
+ }
347
+ tmp[0] |= 6;
348
+ Buffer.from(tmp).copy(buffer.buffer, buffer.offset, 0, len);
349
+ buffer.offset += len;
350
+ };
351
+ exports.encodeOpeningTag = encodeOpeningTag;
352
+ const encodeClosingTag = (buffer, tagNumber) => {
353
+ let len = 1;
354
+ const tmp = new Array(2);
355
+ tmp[0] = 0x8;
356
+ if (tagNumber <= 14) {
357
+ tmp[0] |= (tagNumber << 4);
358
+ }
359
+ else {
360
+ tmp[0] |= 0xF0;
361
+ tmp[1] = tagNumber;
362
+ len++;
363
+ }
364
+ tmp[0] |= 7;
365
+ Buffer.from(tmp).copy(buffer.buffer, buffer.offset, 0, len);
366
+ buffer.offset += len;
367
+ };
368
+ exports.encodeClosingTag = encodeClosingTag;
369
+ const encodeReadAccessSpecification = (buffer, value) => {
370
+ (0, exports.encodeContextObjectId)(buffer, 0, value.objectId.type, value.objectId.instance);
371
+ (0, exports.encodeOpeningTag)(buffer, 1);
372
+ value.properties.forEach((p) => {
373
+ (0, exports.encodeContextEnumerated)(buffer, 0, p.id);
374
+ if (p.index && p.index !== baEnum.ASN1_ARRAY_ALL) {
375
+ (0, exports.encodeContextUnsigned)(buffer, 1, p.index);
376
+ }
377
+ });
378
+ (0, exports.encodeClosingTag)(buffer, 1);
379
+ };
380
+ exports.encodeReadAccessSpecification = encodeReadAccessSpecification;
381
+ const encodeContextBoolean = (buffer, tagNumber, booleanValue) => {
382
+ (0, exports.encodeTag)(buffer, tagNumber, true, 1);
383
+ buffer.buffer.writeUInt8(booleanValue ? 1 : 0, buffer.offset);
384
+ buffer.offset += 1;
385
+ };
386
+ exports.encodeContextBoolean = encodeContextBoolean;
387
+ const encodeCovSubscription = (buffer, value) => {
388
+ (0, exports.encodeOpeningTag)(buffer, 0);
389
+ (0, exports.encodeOpeningTag)(buffer, 0);
390
+ (0, exports.encodeOpeningTag)(buffer, 1);
391
+ (0, exports.encodeApplicationUnsigned)(buffer, value.recipient.network);
392
+ if (value.recipient.network === 0xFFFF) {
393
+ (0, exports.encodeApplicationOctetString)(buffer, [0], 0, 0);
394
+ }
395
+ else {
396
+ (0, exports.encodeApplicationOctetString)(buffer, value.recipient.address, 0, value.recipient.address.length);
397
+ }
398
+ (0, exports.encodeClosingTag)(buffer, 1);
399
+ (0, exports.encodeClosingTag)(buffer, 0);
400
+ (0, exports.encodeContextUnsigned)(buffer, 1, value.subscriptionProcessId);
401
+ (0, exports.encodeClosingTag)(buffer, 0);
402
+ (0, exports.encodeOpeningTag)(buffer, 1);
403
+ (0, exports.encodeContextObjectId)(buffer, 0, value.monitoredObjectId.type, value.monitoredObjectId.instance);
404
+ (0, exports.encodeContextEnumerated)(buffer, 1, value.monitoredProperty.id);
405
+ if (value.monitoredProperty.index !== baEnum.ASN1_ARRAY_ALL) {
406
+ (0, exports.encodeContextUnsigned)(buffer, 2, value.monitoredProperty.index);
407
+ }
408
+ (0, exports.encodeClosingTag)(buffer, 1);
409
+ (0, exports.encodeContextBoolean)(buffer, 2, value.issueConfirmedNotifications);
410
+ (0, exports.encodeContextUnsigned)(buffer, 3, value.timeRemaining);
411
+ if (value.covIncrement > 0) {
412
+ (0, exports.encodeContextReal)(buffer, 4, value.covIncrement);
413
+ }
414
+ };
415
+ const bacappEncodeApplicationData = (buffer, value) => {
416
+ if (value.value === null) {
417
+ value.type = baEnum.ApplicationTags.NULL;
418
+ }
419
+ switch (value.type) {
420
+ case baEnum.ApplicationTags.NULL:
421
+ encodeApplicationNull(buffer);
422
+ break;
423
+ case baEnum.ApplicationTags.BOOLEAN:
424
+ (0, exports.encodeApplicationBoolean)(buffer, value.value);
425
+ break;
426
+ case baEnum.ApplicationTags.UNSIGNED_INTEGER:
427
+ (0, exports.encodeApplicationUnsigned)(buffer, value.value);
428
+ break;
429
+ case baEnum.ApplicationTags.SIGNED_INTEGER:
430
+ (0, exports.encodeApplicationSigned)(buffer, value.value);
431
+ break;
432
+ case baEnum.ApplicationTags.REAL:
433
+ encodeApplicationReal(buffer, value.value);
434
+ break;
435
+ case baEnum.ApplicationTags.DOUBLE:
436
+ encodeApplicationDouble(buffer, value.value);
437
+ break;
438
+ case baEnum.ApplicationTags.OCTET_STRING:
439
+ (0, exports.encodeApplicationOctetString)(buffer, value.value, 0, value.value.length);
440
+ break;
441
+ case baEnum.ApplicationTags.CHARACTER_STRING:
442
+ (0, exports.encodeApplicationCharacterString)(buffer, value.value, value.encoding);
443
+ break;
444
+ case baEnum.ApplicationTags.BIT_STRING:
445
+ (0, exports.encodeApplicationBitstring)(buffer, value.value);
446
+ break;
447
+ case baEnum.ApplicationTags.ENUMERATED:
448
+ (0, exports.encodeApplicationEnumerated)(buffer, value.value);
449
+ break;
450
+ case baEnum.ApplicationTags.DATE:
451
+ (0, exports.encodeApplicationDate)(buffer, value.value);
452
+ break;
453
+ case baEnum.ApplicationTags.TIME:
454
+ (0, exports.encodeApplicationTime)(buffer, value.value);
455
+ break;
456
+ case baEnum.ApplicationTags.TIMESTAMP:
457
+ (0, exports.bacappEncodeTimestamp)(buffer, value.value);
458
+ break;
459
+ case baEnum.ApplicationTags.DATETIME:
460
+ bacappEncodeDatetime(buffer, value.value);
461
+ break;
462
+ case baEnum.ApplicationTags.OBJECTIDENTIFIER:
463
+ (0, exports.encodeApplicationObjectId)(buffer, value.value.type, value.value.instance);
464
+ break;
465
+ case baEnum.ApplicationTags.COV_SUBSCRIPTION:
466
+ encodeCovSubscription(buffer, value.value);
467
+ break;
468
+ case baEnum.ApplicationTags.READ_ACCESS_RESULT:
469
+ (0, exports.encodeReadAccessResult)(buffer, value.value);
470
+ break;
471
+ case baEnum.ApplicationTags.READ_ACCESS_SPECIFICATION:
472
+ (0, exports.encodeReadAccessSpecification)(buffer, value.value);
473
+ break;
474
+ default:
475
+ throw new Error('Unknown type');
476
+ }
477
+ };
478
+ exports.bacappEncodeApplicationData = bacappEncodeApplicationData;
479
+ const bacappEncodeDeviceObjPropertyRef = (buffer, value) => {
480
+ (0, exports.encodeContextObjectId)(buffer, 0, value.objectId.type, value.objectId.instance);
481
+ (0, exports.encodeContextEnumerated)(buffer, 1, value.id);
482
+ if (value.arrayIndex !== baEnum.ASN1_ARRAY_ALL) {
483
+ (0, exports.encodeContextUnsigned)(buffer, 2, value.arrayIndex);
484
+ }
485
+ if (value.deviceIndentifier.type === baEnum.ObjectType.DEVICE) {
486
+ (0, exports.encodeContextObjectId)(buffer, 3, value.deviceIndentifier.type, value.deviceIndentifier.instance);
487
+ }
488
+ };
489
+ const bacappEncodeContextDeviceObjPropertyRef = (buffer, tagNumber, value) => {
490
+ (0, exports.encodeOpeningTag)(buffer, tagNumber);
491
+ bacappEncodeDeviceObjPropertyRef(buffer, value);
492
+ (0, exports.encodeClosingTag)(buffer, tagNumber);
493
+ };
494
+ exports.bacappEncodeContextDeviceObjPropertyRef = bacappEncodeContextDeviceObjPropertyRef;
495
+ const bacappEncodePropertyState = (buffer, value) => {
496
+ switch (value.type) {
497
+ case baEnum.PropertyStates.BOOLEAN_VALUE:
498
+ (0, exports.encodeContextBoolean)(buffer, 0, value.state === 1 ? true : false);
499
+ break;
500
+ case baEnum.PropertyStates.BINARY_VALUE:
501
+ (0, exports.encodeContextEnumerated)(buffer, 1, value.state);
502
+ break;
503
+ case baEnum.PropertyStates.EVENT_TYPE:
504
+ (0, exports.encodeContextEnumerated)(buffer, 2, value.state);
505
+ break;
506
+ case baEnum.PropertyStates.POLARITY:
507
+ (0, exports.encodeContextEnumerated)(buffer, 3, value.state);
508
+ break;
509
+ case baEnum.PropertyStates.PROGRAM_CHANGE:
510
+ (0, exports.encodeContextEnumerated)(buffer, 4, value.state);
511
+ break;
512
+ case baEnum.PropertyStates.PROGRAM_STATE:
513
+ (0, exports.encodeContextEnumerated)(buffer, 5, value.state);
514
+ break;
515
+ case baEnum.PropertyStates.REASON_FOR_HALT:
516
+ (0, exports.encodeContextEnumerated)(buffer, 6, value.state);
517
+ break;
518
+ case baEnum.PropertyStates.RELIABILITY:
519
+ (0, exports.encodeContextEnumerated)(buffer, 7, value.state);
520
+ break;
521
+ case baEnum.PropertyStates.STATE:
522
+ (0, exports.encodeContextEnumerated)(buffer, 8, value.state);
523
+ break;
524
+ case baEnum.PropertyStates.SYSTEM_STATUS:
525
+ (0, exports.encodeContextEnumerated)(buffer, 9, value.state);
526
+ break;
527
+ case baEnum.PropertyStates.UNITS:
528
+ (0, exports.encodeContextEnumerated)(buffer, 10, value.state);
529
+ break;
530
+ case baEnum.PropertyStates.UNSIGNED_VALUE:
531
+ (0, exports.encodeContextUnsigned)(buffer, 11, value.state);
532
+ break;
533
+ case baEnum.PropertyStates.LIFE_SAFETY_MODE:
534
+ (0, exports.encodeContextEnumerated)(buffer, 12, value.state);
535
+ break;
536
+ case baEnum.PropertyStates.LIFE_SAFETY_STATE:
537
+ (0, exports.encodeContextEnumerated)(buffer, 13, value.state);
538
+ break;
539
+ default:
540
+ break;
541
+ }
542
+ };
543
+ exports.bacappEncodePropertyState = bacappEncodePropertyState;
544
+ const encodeContextBitstring = (buffer, tagNumber, bitString) => {
545
+ const bitStringEncodedLength = bitstringBytesUsed(bitString) + 1;
546
+ (0, exports.encodeTag)(buffer, tagNumber, true, bitStringEncodedLength);
547
+ encodeBitstring(buffer, bitString);
548
+ };
549
+ exports.encodeContextBitstring = encodeContextBitstring;
550
+ const encodeContextSigned = (buffer, tagNumber, value) => {
551
+ (0, exports.encodeTag)(buffer, tagNumber, true, getSignedLength(value));
552
+ encodeBacnetSigned(buffer, value);
553
+ };
554
+ exports.encodeContextSigned = encodeContextSigned;
555
+ const encodeContextTime = (buffer, tagNumber, value) => {
556
+ (0, exports.encodeTag)(buffer, tagNumber, true, 4);
557
+ encodeBacnetTime(buffer, value);
558
+ };
559
+ const bacappEncodeContextDatetime = (buffer, tagNumber, value) => {
560
+ if (value !== new Date(1, 1, 1)) {
561
+ (0, exports.encodeOpeningTag)(buffer, tagNumber);
562
+ bacappEncodeDatetime(buffer, value);
563
+ (0, exports.encodeClosingTag)(buffer, tagNumber);
564
+ }
565
+ };
566
+ const decodeTagNumber = (buffer, offset) => {
567
+ let len = 1;
568
+ let tagNumber;
569
+ if (isExtendedTagNumber(buffer[offset])) {
570
+ tagNumber = buffer[offset + 1];
571
+ len++;
572
+ }
573
+ else {
574
+ tagNumber = buffer[offset] >> 4;
575
+ }
576
+ return {
577
+ len: len,
578
+ tagNumber: tagNumber
579
+ };
580
+ };
581
+ exports.decodeTagNumber = decodeTagNumber;
582
+ const decodeIsContextTag = (buffer, offset, tagNumber) => {
583
+ const result = (0, exports.decodeTagNumber)(buffer, offset);
584
+ return isContextSpecific(buffer[offset]) && result.tagNumber === tagNumber;
585
+ };
586
+ exports.decodeIsContextTag = decodeIsContextTag;
587
+ const decodeIsOpeningTagNumber = (buffer, offset, tagNumber) => {
588
+ const result = (0, exports.decodeTagNumber)(buffer, offset);
589
+ return isOpeningTag(buffer[offset]) && result.tagNumber === tagNumber;
590
+ };
591
+ exports.decodeIsOpeningTagNumber = decodeIsOpeningTagNumber;
592
+ const decodeIsClosingTagNumber = (buffer, offset, tagNumber) => {
593
+ const result = (0, exports.decodeTagNumber)(buffer, offset);
594
+ return isClosingTag(buffer[offset]) && result.tagNumber === tagNumber;
595
+ };
596
+ exports.decodeIsClosingTagNumber = decodeIsClosingTagNumber;
597
+ const decodeIsClosingTag = (buffer, offset) => {
598
+ return (buffer[offset] & 0x07) === 7;
599
+ };
600
+ exports.decodeIsClosingTag = decodeIsClosingTag;
601
+ const decodeIsOpeningTag = (buffer, offset) => {
602
+ return (buffer[offset] & 0x07) === 6;
603
+ };
604
+ exports.decodeIsOpeningTag = decodeIsOpeningTag;
605
+ const decodeObjectId = (buffer, offset) => {
606
+ const result = (0, exports.decodeUnsigned)(buffer, offset, 4);
607
+ const objectType = (result.value >> baEnum.ASN1_INSTANCE_BITS) & baEnum.ASN1_MAX_OBJECT;
608
+ const instance = result.value & baEnum.ASN1_MAX_INSTANCE;
609
+ return {
610
+ len: result.len,
611
+ objectType: objectType,
612
+ instance: instance
613
+ };
614
+ };
615
+ exports.decodeObjectId = decodeObjectId;
616
+ const decodeObjectIdSafe = (buffer, offset, lenValue) => {
617
+ if (lenValue !== 4) {
618
+ return {
619
+ len: 0,
620
+ objectType: 0,
621
+ instance: 0
622
+ };
623
+ }
624
+ else {
625
+ return (0, exports.decodeObjectId)(buffer, offset);
626
+ }
627
+ };
628
+ const decodeTagNumberAndValue = (buffer, offset) => {
629
+ let value;
630
+ const tag = (0, exports.decodeTagNumber)(buffer, offset);
631
+ let len = tag.len;
632
+ if (isExtendedValue(buffer[offset])) {
633
+ if (buffer[offset + len] === 255) {
634
+ len++;
635
+ const result = (0, exports.decodeUnsigned)(buffer, offset + len, 4);
636
+ len += result.len;
637
+ value = result.value;
638
+ }
639
+ else if (buffer[offset + len] === 254) {
640
+ len++;
641
+ const result = (0, exports.decodeUnsigned)(buffer, offset + len, 2);
642
+ len += result.len;
643
+ value = result.value;
644
+ }
645
+ else {
646
+ value = buffer[offset + len];
647
+ len++;
648
+ }
649
+ }
650
+ else if (isOpeningTag(buffer[offset])) {
651
+ value = 0;
652
+ }
653
+ else if (isClosingTag(buffer[offset])) {
654
+ value = 0;
655
+ }
656
+ else {
657
+ value = buffer[offset] & 0x07;
658
+ }
659
+ return {
660
+ len: len,
661
+ tagNumber: tag.tagNumber,
662
+ value: value
663
+ };
664
+ };
665
+ exports.decodeTagNumberAndValue = decodeTagNumberAndValue;
666
+ const bacappDecodeApplicationData = (buffer, offset, maxOffset, objectType, propertyId) => {
667
+ if (!isContextSpecific(buffer[offset])) {
668
+ const tag = (0, exports.decodeTagNumberAndValue)(buffer, offset);
669
+ if (tag) {
670
+ const len = tag.len;
671
+ const result = bacappDecodeData(buffer, offset + len, maxOffset, tag.tagNumber, tag.value);
672
+ if (!result)
673
+ return;
674
+ let resObj = {
675
+ len: len + result.len,
676
+ type: result.type,
677
+ value: result.value
678
+ };
679
+ if (result.originalBitString) {
680
+ //protocols supported addition
681
+ resObj.originalBitString = result.originalBitString;
682
+ }
683
+ // HACK: Drop string specific handling ASAP
684
+ if (result.encoding !== undefined)
685
+ resObj.encoding = result.encoding;
686
+ return resObj;
687
+ }
688
+ }
689
+ else {
690
+ return bacappDecodeContextApplicationData(buffer, offset, maxOffset, objectType, propertyId);
691
+ }
692
+ };
693
+ exports.bacappDecodeApplicationData = bacappDecodeApplicationData;
694
+ const encodeReadAccessResult = (buffer, value) => {
695
+ (0, exports.encodeContextObjectId)(buffer, 0, value.objectId.type, value.objectId.instance);
696
+ (0, exports.encodeOpeningTag)(buffer, 1);
697
+ value.values.forEach((item) => {
698
+ (0, exports.encodeContextEnumerated)(buffer, 2, item.property.id);
699
+ if (item.property.index !== baEnum.ASN1_ARRAY_ALL) {
700
+ (0, exports.encodeContextUnsigned)(buffer, 3, item.property.index);
701
+ }
702
+ if (item.value && item.value[0] && item.value[0].value && item.value[0].value.type === 'BacnetError') {
703
+ (0, exports.encodeOpeningTag)(buffer, 5);
704
+ (0, exports.encodeApplicationEnumerated)(buffer, item.value[0].value.errorClass);
705
+ (0, exports.encodeApplicationEnumerated)(buffer, item.value[0].value.errorCode);
706
+ (0, exports.encodeClosingTag)(buffer, 5);
707
+ }
708
+ else {
709
+ (0, exports.encodeOpeningTag)(buffer, 4);
710
+ item.value.forEach((subItem) => (0, exports.bacappEncodeApplicationData)(buffer, subItem));
711
+ (0, exports.encodeClosingTag)(buffer, 4);
712
+ }
713
+ });
714
+ (0, exports.encodeClosingTag)(buffer, 1);
715
+ };
716
+ exports.encodeReadAccessResult = encodeReadAccessResult;
717
+ const decodeReadAccessResult = (buffer, offset, apduLen) => {
718
+ let len = 0;
719
+ const value = {};
720
+ if (!(0, exports.decodeIsContextTag)(buffer, offset + len, 0))
721
+ return;
722
+ len++;
723
+ let result = (0, exports.decodeObjectId)(buffer, offset + len);
724
+ value.objectId = {
725
+ type: result.objectType,
726
+ instance: result.instance
727
+ };
728
+ len += result.len;
729
+ if (!(0, exports.decodeIsOpeningTagNumber)(buffer, offset + len, 1))
730
+ return;
731
+ len++;
732
+ const values = [];
733
+ while ((apduLen - len) > 0) {
734
+ const newEntry = {};
735
+ if ((0, exports.decodeIsClosingTagNumber)(buffer, offset + len, 1)) {
736
+ len++;
737
+ break;
738
+ }
739
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
740
+ len += result.len;
741
+ if (result.tagNumber !== 2)
742
+ return;
743
+ result = (0, exports.decodeEnumerated)(buffer, offset + len, result.value);
744
+ newEntry.id = result.value;
745
+ len += result.len;
746
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
747
+ if (result.tagNumber === 3) {
748
+ len += result.len;
749
+ result = (0, exports.decodeUnsigned)(buffer, offset + len, result.value);
750
+ newEntry.index = result.value;
751
+ len += result.len;
752
+ }
753
+ else {
754
+ newEntry.index = baEnum.ASN1_ARRAY_ALL;
755
+ }
756
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
757
+ len += result.len;
758
+ if (result.tagNumber === 4) {
759
+ const localValues = [];
760
+ while ((len + offset) <= buffer.length && !(0, exports.decodeIsClosingTagNumber)(buffer, offset + len, 4)) {
761
+ const localResult = (0, exports.bacappDecodeApplicationData)(buffer, offset + len, apduLen + offset - 1, value.objectId.type, newEntry.id);
762
+ if (!localResult)
763
+ return;
764
+ len += localResult.len;
765
+ const resObj = {
766
+ value: localResult.value,
767
+ type: localResult.type
768
+ };
769
+ // HACK: Drop string specific handling ASAP
770
+ if (localResult.encoding !== undefined)
771
+ resObj.encoding = localResult.encoding;
772
+ localValues.push(resObj);
773
+ }
774
+ if (!(0, exports.decodeIsClosingTagNumber)(buffer, offset + len, 4))
775
+ return;
776
+ if ((localValues.length === 2) && (localValues[0].type === baEnum.ApplicationTags.DATE) && (localValues[1].type === baEnum.ApplicationTags.TIME)) {
777
+ const date = localValues[0].value;
778
+ const time = localValues[1].value;
779
+ const bdatetime = new Date(date.year, date.month, date.day, time.hour, time.minute, time.second, time.millisecond);
780
+ newEntry.value = [{ type: baEnum.ApplicationTags.DATETIME, value: bdatetime }];
781
+ }
782
+ else {
783
+ newEntry.value = localValues;
784
+ }
785
+ len++;
786
+ }
787
+ else if (result.tagNumber === 5) {
788
+ const err = {};
789
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
790
+ len += result.len;
791
+ result = (0, exports.decodeEnumerated)(buffer, offset + len, result.value);
792
+ len += result.len;
793
+ err.errorClass = result.value;
794
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
795
+ len += result.len;
796
+ result = (0, exports.decodeEnumerated)(buffer, offset + len, result.value);
797
+ len += result.len;
798
+ err.errorCode = result.value;
799
+ if (!(0, exports.decodeIsClosingTagNumber)(buffer, offset + len, 5))
800
+ return;
801
+ len++;
802
+ newEntry.value = [{
803
+ type: baEnum.ApplicationTags.ERROR,
804
+ value: err
805
+ }];
806
+ }
807
+ values.push(newEntry);
808
+ }
809
+ value.values = values;
810
+ return {
811
+ len: len,
812
+ value: value
813
+ };
814
+ };
815
+ exports.decodeReadAccessResult = decodeReadAccessResult;
816
+ const decodeSigned = (buffer, offset, length) => ({
817
+ len: length,
818
+ value: length === 0 ? 0 : buffer.readIntBE(offset, length)
819
+ });
820
+ exports.decodeSigned = decodeSigned;
821
+ const decodeReal = (buffer, offset) => ({
822
+ len: 4,
823
+ value: buffer.readFloatBE(offset)
824
+ });
825
+ exports.decodeReal = decodeReal;
826
+ const decodeRealSafe = (buffer, offset, lenValue) => {
827
+ if (lenValue !== 4) {
828
+ return {
829
+ len: lenValue,
830
+ value: 0
831
+ };
832
+ }
833
+ else {
834
+ return (0, exports.decodeReal)(buffer, offset);
835
+ }
836
+ };
837
+ const decodeDouble = (buffer, offset) => ({
838
+ len: 8,
839
+ value: buffer.readDoubleBE(offset)
840
+ });
841
+ const decodeDoubleSafe = (buffer, offset, lenValue) => {
842
+ if (lenValue !== 8) {
843
+ return {
844
+ len: lenValue,
845
+ value: 0
846
+ };
847
+ }
848
+ else {
849
+ return decodeDouble(buffer, offset);
850
+ }
851
+ };
852
+ const decodeOctetString = (buffer, offset, maxLength, octetStringOffset, octetStringLength) => {
853
+ const octetString = [];
854
+ for (let i = octetStringOffset; i < (octetStringOffset + octetStringLength); i++) {
855
+ octetString.push(buffer[offset + i]);
856
+ }
857
+ return {
858
+ len: octetStringLength,
859
+ value: octetString
860
+ };
861
+ };
862
+ exports.decodeOctetString = decodeOctetString;
863
+ const multiCharsetCharacterstringDecode = (buffer, offset, maxLength, encoding, length) => {
864
+ const stringBuf = Buffer.alloc(length);
865
+ buffer.copy(stringBuf, 0, offset, offset + length);
866
+ return {
867
+ value: iconv.decode(stringBuf, getEncodingType(encoding, buffer, offset)),
868
+ len: length + 1,
869
+ encoding: encoding
870
+ };
871
+ };
872
+ const decodeCharacterString = (buffer, offset, maxLength, lenValue) => {
873
+ return multiCharsetCharacterstringDecode(buffer, offset + 1, maxLength, buffer[offset], lenValue - 1);
874
+ };
875
+ exports.decodeCharacterString = decodeCharacterString;
876
+ const bitstringSetBitsUsed = (bitString, bytesUsed, unusedBits) => {
877
+ bitString.bitsUsed = bytesUsed * 8;
878
+ bitString.bitsUsed -= unusedBits;
879
+ };
880
+ const decodeBitstring = (buffer, offset, lenValue) => {
881
+ let len = 0;
882
+ const bitString = { value: [], bitsUsed: 0 };
883
+ const originalBitString = { value: [] };
884
+ if (lenValue > 0) {
885
+ const bytesUsed = lenValue - 1;
886
+ if (bytesUsed <= baEnum.ASN1_MAX_BITSTRING_BYTES) {
887
+ len = 1;
888
+ for (let i = 0; i < bytesUsed; i++) {
889
+ originalBitString.value.push(buffer[offset + len]);
890
+ bitString.value.push(byteReverseBits(buffer[offset + len++]));
891
+ }
892
+ const unusedBits = buffer[offset] & 0x07;
893
+ bitstringSetBitsUsed(bitString, bytesUsed, unusedBits);
894
+ }
895
+ }
896
+ return {
897
+ len: len,
898
+ value: bitString,
899
+ originalBitString: originalBitString
900
+ };
901
+ };
902
+ exports.decodeBitstring = decodeBitstring;
903
+ const decodeDate = (buffer, offset) => {
904
+ let date;
905
+ const year = buffer[offset] + 1900;
906
+ const month = buffer[offset + 1];
907
+ const day = buffer[offset + 2];
908
+ const wday = buffer[offset + 3];
909
+ if (month === 0xFF && day === 0xFF && wday === 0xFF && (year - 1900) === 0xFF) {
910
+ date = new Date(1, 1, 1);
911
+ }
912
+ else {
913
+ date = new Date(year, month, day);
914
+ }
915
+ return {
916
+ len: 4,
917
+ value: date
918
+ };
919
+ };
920
+ exports.decodeDate = decodeDate;
921
+ const decodeDateSafe = (buffer, offset, lenValue) => {
922
+ if (lenValue !== 4) {
923
+ return {
924
+ len: lenValue,
925
+ value: new Date(1, 1, 1)
926
+ };
927
+ }
928
+ else {
929
+ return (0, exports.decodeDate)(buffer, offset);
930
+ }
931
+ };
932
+ const decodeApplicationDate = (buffer, offset) => {
933
+ const result = (0, exports.decodeTagNumber)(buffer, offset);
934
+ if (result.tagNumber === baEnum.ApplicationTags.DATE) {
935
+ const value = (0, exports.decodeDate)(buffer, offset + 1);
936
+ return {
937
+ len: value.len + 1,
938
+ value: value.value
939
+ };
940
+ }
941
+ };
942
+ exports.decodeApplicationDate = decodeApplicationDate;
943
+ const decodeBacnetTime = (buffer, offset) => {
944
+ let value;
945
+ const hour = buffer[offset + 0];
946
+ const min = buffer[offset + 1];
947
+ const sec = buffer[offset + 2];
948
+ let hundredths = buffer[offset + 3];
949
+ if (hour === 0xFF && min === 0xFF && sec === 0xFF && hundredths === 0xFF) {
950
+ value = new Date(1, 1, 1);
951
+ }
952
+ else {
953
+ if (hundredths > 100)
954
+ hundredths = 0;
955
+ value = new Date(1, 1, 1, hour, min, sec, hundredths * 10);
956
+ }
957
+ return {
958
+ len: 4,
959
+ value: value
960
+ };
961
+ };
962
+ exports.decodeBacnetTime = decodeBacnetTime;
963
+ const decodeBacnetTimeSafe = (buffer, offset, len) => {
964
+ if (len !== 4) {
965
+ return { len, value: new Date(1, 1, 1) };
966
+ }
967
+ else {
968
+ return (0, exports.decodeBacnetTime)(buffer, offset);
969
+ }
970
+ };
971
+ const decodeApplicationTime = (buffer, offset) => {
972
+ const result = (0, exports.decodeTagNumber)(buffer, offset);
973
+ if (result.tagNumber === baEnum.ApplicationTags.TIME) {
974
+ const value = (0, exports.decodeBacnetTime)(buffer, offset + 1);
975
+ return {
976
+ len: value.len + 1,
977
+ value: value.value
978
+ };
979
+ }
980
+ };
981
+ exports.decodeApplicationTime = decodeApplicationTime;
982
+ const decodeBacnetDatetime = (buffer, offset) => {
983
+ let len = 0;
984
+ const rawDate = (0, exports.decodeApplicationDate)(buffer, offset + len);
985
+ len += rawDate.len;
986
+ const date = rawDate.value;
987
+ const rawTime = (0, exports.decodeApplicationTime)(buffer, offset + len);
988
+ len += rawTime.len;
989
+ const time = rawTime.value;
990
+ return {
991
+ len: len,
992
+ value: new Date(date.getFullYear(), date.getMonth(), date.getDay(), time.getHours(), time.getMinutes(), time.getSeconds(), time.getMilliseconds())
993
+ };
994
+ };
995
+ const bacappDecodeData = (buffer, offset, maxLength, tagDataType, lenValueType) => {
996
+ let result;
997
+ const value = {
998
+ len: 0,
999
+ type: tagDataType
1000
+ };
1001
+ switch (tagDataType) {
1002
+ case baEnum.ApplicationTags.NULL:
1003
+ value.value = null;
1004
+ break;
1005
+ case baEnum.ApplicationTags.BOOLEAN:
1006
+ value.value = lenValueType > 0 ? true : false;
1007
+ break;
1008
+ case baEnum.ApplicationTags.UNSIGNED_INTEGER:
1009
+ result = (0, exports.decodeUnsigned)(buffer, offset, lenValueType);
1010
+ value.len += result.len;
1011
+ value.value = result.value;
1012
+ break;
1013
+ case baEnum.ApplicationTags.SIGNED_INTEGER:
1014
+ result = (0, exports.decodeSigned)(buffer, offset, lenValueType);
1015
+ value.len += result.len;
1016
+ value.value = result.value;
1017
+ break;
1018
+ case baEnum.ApplicationTags.REAL:
1019
+ result = decodeRealSafe(buffer, offset, lenValueType);
1020
+ value.len += result.len;
1021
+ value.value = result.value;
1022
+ break;
1023
+ case baEnum.ApplicationTags.DOUBLE:
1024
+ result = decodeDoubleSafe(buffer, offset, lenValueType);
1025
+ value.len += result.len;
1026
+ value.value = result.value;
1027
+ break;
1028
+ case baEnum.ApplicationTags.OCTET_STRING:
1029
+ result = (0, exports.decodeOctetString)(buffer, offset, maxLength, 0, lenValueType);
1030
+ value.len += result.len;
1031
+ value.value = result.value;
1032
+ break;
1033
+ case baEnum.ApplicationTags.CHARACTER_STRING:
1034
+ result = (0, exports.decodeCharacterString)(buffer, offset, maxLength, lenValueType);
1035
+ value.len += result.len;
1036
+ value.value = result.value;
1037
+ value.encoding = result.encoding;
1038
+ break;
1039
+ case baEnum.ApplicationTags.BIT_STRING:
1040
+ result = (0, exports.decodeBitstring)(buffer, offset, lenValueType);
1041
+ value.len += result.len;
1042
+ value.value = result.value;
1043
+ if (result.originalBitString) {
1044
+ //protocols supported addition
1045
+ value.originalBitString = result.originalBitString;
1046
+ }
1047
+ break;
1048
+ case baEnum.ApplicationTags.ENUMERATED:
1049
+ result = (0, exports.decodeEnumerated)(buffer, offset, lenValueType);
1050
+ value.len += result.len;
1051
+ value.value = result.value;
1052
+ break;
1053
+ case baEnum.ApplicationTags.DATE:
1054
+ result = decodeDateSafe(buffer, offset, lenValueType);
1055
+ value.len += result.len;
1056
+ value.value = result.value;
1057
+ break;
1058
+ case baEnum.ApplicationTags.TIME:
1059
+ result = decodeBacnetTimeSafe(buffer, offset, lenValueType);
1060
+ value.len += result.len;
1061
+ value.value = result.value;
1062
+ break;
1063
+ case baEnum.ApplicationTags.OBJECTIDENTIFIER:
1064
+ result = decodeObjectIdSafe(buffer, offset, lenValueType);
1065
+ value.len += result.len;
1066
+ value.value = { type: result.objectType, instance: result.instance };
1067
+ break;
1068
+ default:
1069
+ break;
1070
+ }
1071
+ return value;
1072
+ };
1073
+ const bacappContextTagType = (property, tagNumber) => {
1074
+ let tag = 0;
1075
+ switch (property) {
1076
+ case baEnum.PropertyIdentifier.ACTUAL_SHED_LEVEL:
1077
+ case baEnum.PropertyIdentifier.REQUESTED_SHED_LEVEL:
1078
+ case baEnum.PropertyIdentifier.EXPECTED_SHED_LEVEL:
1079
+ switch (tagNumber) {
1080
+ case 0:
1081
+ case 1:
1082
+ tag = baEnum.ApplicationTags.UNSIGNED_INTEGER;
1083
+ break;
1084
+ case 2:
1085
+ tag = baEnum.ApplicationTags.REAL;
1086
+ break;
1087
+ default:
1088
+ break;
1089
+ }
1090
+ break;
1091
+ case baEnum.PropertyIdentifier.ACTION:
1092
+ switch (tagNumber) {
1093
+ case 0:
1094
+ case 1:
1095
+ tag = baEnum.ApplicationTags.OBJECTIDENTIFIER;
1096
+ break;
1097
+ case 2:
1098
+ tag = baEnum.ApplicationTags.ENUMERATED;
1099
+ break;
1100
+ case 3:
1101
+ case 5:
1102
+ case 6:
1103
+ tag = baEnum.ApplicationTags.UNSIGNED_INTEGER;
1104
+ break;
1105
+ case 7:
1106
+ case 8:
1107
+ tag = baEnum.ApplicationTags.BOOLEAN;
1108
+ break;
1109
+ default:
1110
+ break;
1111
+ }
1112
+ break;
1113
+ case baEnum.PropertyIdentifier.LIST_OF_GROUP_MEMBERS:
1114
+ switch (tagNumber) {
1115
+ case 0:
1116
+ tag = baEnum.ApplicationTags.OBJECTIDENTIFIER;
1117
+ break;
1118
+ default:
1119
+ break;
1120
+ }
1121
+ break;
1122
+ case baEnum.PropertyIdentifier.EXCEPTION_SCHEDULE:
1123
+ switch (tagNumber) {
1124
+ case 1:
1125
+ tag = baEnum.ApplicationTags.OBJECTIDENTIFIER;
1126
+ break;
1127
+ case 3:
1128
+ tag = baEnum.ApplicationTags.UNSIGNED_INTEGER;
1129
+ break;
1130
+ default:
1131
+ break;
1132
+ }
1133
+ break;
1134
+ case baEnum.PropertyIdentifier.LOG_DEVICE_OBJECT_PROPERTY:
1135
+ switch (tagNumber) {
1136
+ case 0:
1137
+ case 3:
1138
+ tag = baEnum.ApplicationTags.OBJECTIDENTIFIER;
1139
+ break;
1140
+ case 1:
1141
+ tag = baEnum.ApplicationTags.ENUMERATED;
1142
+ break;
1143
+ case 2:
1144
+ tag = baEnum.ApplicationTags.UNSIGNED_INTEGER;
1145
+ break;
1146
+ default:
1147
+ break;
1148
+ }
1149
+ break;
1150
+ case baEnum.PropertyIdentifier.SUBORDINATE_LIST:
1151
+ switch (tagNumber) {
1152
+ case 0:
1153
+ case 1:
1154
+ tag = baEnum.ApplicationTags.OBJECTIDENTIFIER;
1155
+ break;
1156
+ default:
1157
+ break;
1158
+ }
1159
+ break;
1160
+ case baEnum.PropertyIdentifier.RECIPIENT_LIST:
1161
+ switch (tagNumber) {
1162
+ case 0:
1163
+ tag = baEnum.ApplicationTags.OBJECTIDENTIFIER;
1164
+ break;
1165
+ default:
1166
+ break;
1167
+ }
1168
+ break;
1169
+ case baEnum.PropertyIdentifier.ACTIVE_COV_SUBSCRIPTIONS:
1170
+ switch (tagNumber) {
1171
+ case 0:
1172
+ case 1:
1173
+ break;
1174
+ case 2:
1175
+ tag = baEnum.ApplicationTags.BOOLEAN;
1176
+ break;
1177
+ case 3:
1178
+ tag = baEnum.ApplicationTags.UNSIGNED_INTEGER;
1179
+ break;
1180
+ case 4:
1181
+ tag = baEnum.ApplicationTags.REAL;
1182
+ break;
1183
+ default:
1184
+ break;
1185
+ }
1186
+ break;
1187
+ default:
1188
+ break;
1189
+ }
1190
+ return tag;
1191
+ };
1192
+ const decodeDeviceObjPropertyRef = (buffer, offset) => {
1193
+ let len = 0;
1194
+ let arrayIndex = baEnum.ASN1_ARRAY_ALL;
1195
+ if (!(0, exports.decodeIsContextTag)(buffer, offset + len, 0))
1196
+ return;
1197
+ len++;
1198
+ let objectId = (0, exports.decodeObjectId)(buffer, offset + len);
1199
+ len += objectId.len;
1200
+ let result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1201
+ len += result.len;
1202
+ if (result.tagNumber !== 1)
1203
+ return;
1204
+ const id = (0, exports.decodeEnumerated)(buffer, offset + len, result.value);
1205
+ len += id.len;
1206
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1207
+ if (result.tagNumber === 2) {
1208
+ len += result.len;
1209
+ // FIXME: This doesn't seem to be used
1210
+ arrayIndex = (0, exports.decodeUnsigned)(buffer, offset + len, result.value);
1211
+ len += arrayIndex.len;
1212
+ }
1213
+ if ((0, exports.decodeIsContextTag)(buffer, offset + len, 3)) {
1214
+ if (!isClosingTag(buffer[offset + len])) {
1215
+ len++;
1216
+ objectId = (0, exports.decodeObjectId)(buffer, offset + len);
1217
+ len += objectId.len;
1218
+ }
1219
+ }
1220
+ return {
1221
+ len: len,
1222
+ value: {
1223
+ objectId: objectId,
1224
+ id: id
1225
+ }
1226
+ };
1227
+ };
1228
+ const decodeReadAccessSpecification = (buffer, offset, apduLen) => {
1229
+ let len = 0;
1230
+ const value = {};
1231
+ if (!(0, exports.decodeIsContextTag)(buffer, offset + len, 0))
1232
+ return;
1233
+ len++;
1234
+ let decodedValue = (0, exports.decodeObjectId)(buffer, offset + len);
1235
+ value.objectId = {
1236
+ type: decodedValue.objectType,
1237
+ instance: decodedValue.instance
1238
+ };
1239
+ len += decodedValue.len;
1240
+ if (!(0, exports.decodeIsOpeningTagNumber)(buffer, offset + len, 1))
1241
+ return;
1242
+ len++;
1243
+ const propertyIdAndArrayIndex = [];
1244
+ while ((apduLen - len) > 1 && !(0, exports.decodeIsClosingTagNumber)(buffer, offset + len, 1)) {
1245
+ const propertyRef = {};
1246
+ if (!isContextSpecific(buffer[offset + len]))
1247
+ return;
1248
+ const result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1249
+ len += result.len;
1250
+ if (result.tagNumber !== 0)
1251
+ return;
1252
+ if ((len + result.value) >= apduLen)
1253
+ return;
1254
+ decodedValue = (0, exports.decodeEnumerated)(buffer, offset + len, result.value);
1255
+ propertyRef.id = decodedValue.value;
1256
+ len += decodedValue.len;
1257
+ propertyRef.index = baEnum.ASN1_ARRAY_ALL;
1258
+ if (isContextSpecific(buffer[offset + len]) && !isClosingTag(buffer[offset + len])) {
1259
+ const tmp = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1260
+ if (tmp.tagNumber === 1) {
1261
+ len += tmp.len;
1262
+ if ((len + tmp.value) >= apduLen)
1263
+ return;
1264
+ decodedValue = (0, exports.decodeUnsigned)(buffer, offset + len, tmp.value);
1265
+ propertyRef.index = decodedValue.value;
1266
+ len += decodedValue.len;
1267
+ }
1268
+ }
1269
+ propertyIdAndArrayIndex.push(propertyRef);
1270
+ }
1271
+ if (!(0, exports.decodeIsClosingTagNumber)(buffer, offset + len, 1))
1272
+ return;
1273
+ len++;
1274
+ value.properties = propertyIdAndArrayIndex;
1275
+ return {
1276
+ len: len,
1277
+ value: value
1278
+ };
1279
+ };
1280
+ exports.decodeReadAccessSpecification = decodeReadAccessSpecification;
1281
+ const decodeCovSubscription = (buffer, offset, apduLen) => {
1282
+ let len = 0;
1283
+ const value = {};
1284
+ let result;
1285
+ let decodedValue;
1286
+ value.recipient = {};
1287
+ if (!(0, exports.decodeIsOpeningTagNumber)(buffer, offset + len, 0))
1288
+ return;
1289
+ len++;
1290
+ if (!(0, exports.decodeIsOpeningTagNumber)(buffer, offset + len, 0))
1291
+ return;
1292
+ len++;
1293
+ if (!(0, exports.decodeIsOpeningTagNumber)(buffer, offset + len, 1))
1294
+ return;
1295
+ len++;
1296
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1297
+ len += result.len;
1298
+ if (result.tagNumber !== baEnum.ApplicationTags.UNSIGNED_INTEGER)
1299
+ return;
1300
+ decodedValue = (0, exports.decodeUnsigned)(buffer, offset + len, result.value);
1301
+ len += decodedValue.len;
1302
+ value.recipient.net = decodedValue.value;
1303
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1304
+ len += result.len;
1305
+ if (result.tagNumber !== baEnum.ApplicationTags.OCTET_STRING)
1306
+ return;
1307
+ decodedValue = (0, exports.decodeOctetString)(buffer, offset + len, apduLen, 0, result.value);
1308
+ len += decodedValue.len;
1309
+ value.recipient.adr = decodedValue.value;
1310
+ if (!(0, exports.decodeIsClosingTagNumber)(buffer, offset + len, 1))
1311
+ return;
1312
+ len++;
1313
+ if (!(0, exports.decodeIsClosingTagNumber)(buffer, offset + len, 0))
1314
+ return;
1315
+ len++;
1316
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1317
+ len += result.len;
1318
+ if (result.tagNumber !== 1)
1319
+ return;
1320
+ decodedValue = (0, exports.decodeUnsigned)(buffer, offset + len, result.value);
1321
+ len += decodedValue.len;
1322
+ value.subscriptionProcessId = decodedValue.value;
1323
+ if (!(0, exports.decodeIsClosingTagNumber)(buffer, offset + len, 0))
1324
+ return;
1325
+ len++;
1326
+ if (!(0, exports.decodeIsOpeningTagNumber)(buffer, offset + len, 1))
1327
+ return;
1328
+ len++;
1329
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1330
+ len += result.len;
1331
+ if (result.tagNumber !== 0)
1332
+ return;
1333
+ decodedValue = (0, exports.decodeObjectId)(buffer, offset + len);
1334
+ len += decodedValue.len;
1335
+ value.monitoredObjectId = {
1336
+ type: decodedValue.objectType,
1337
+ instance: decodedValue.instance
1338
+ };
1339
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1340
+ len += result.len;
1341
+ if (result.tagNumber !== 1)
1342
+ return;
1343
+ decodedValue = (0, exports.decodeEnumerated)(buffer, offset + len, result.value);
1344
+ len += decodedValue.len;
1345
+ value.monitoredProperty = {};
1346
+ value.monitoredProperty.id = decodedValue.value;
1347
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1348
+ if (result.tagNumber === 2) {
1349
+ len += result.len;
1350
+ decodedValue = (0, exports.decodeUnsigned)(buffer, offset + len, result.value);
1351
+ len += decodedValue.len;
1352
+ value.monitoredProperty.index = decodedValue.value;
1353
+ }
1354
+ else {
1355
+ value.monitoredProperty.index = baEnum.ASN1_ARRAY_ALL;
1356
+ }
1357
+ if (!(0, exports.decodeIsClosingTagNumber)(buffer, offset + len, 1))
1358
+ return;
1359
+ len++;
1360
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1361
+ len += result.len;
1362
+ if (result.tagNumber !== 2)
1363
+ return;
1364
+ value.issueConfirmedNotifications = buffer[offset + len] > 0 ? true : false;
1365
+ len++;
1366
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1367
+ len += result.len;
1368
+ if (result.tagNumber !== 3)
1369
+ return;
1370
+ decodedValue = (0, exports.decodeUnsigned)(buffer, offset + len, result.value);
1371
+ len += decodedValue.len;
1372
+ value.timeRemaining = decodedValue.value;
1373
+ if (len < apduLen && !isClosingTag(buffer[offset + len])) {
1374
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1375
+ len += result.len;
1376
+ if (result.tagNumber !== 4)
1377
+ return;
1378
+ decodedValue = (0, exports.decodeReal)(buffer, offset + len);
1379
+ len += decodedValue.len;
1380
+ value.covIncrement = decodedValue.value;
1381
+ }
1382
+ return {
1383
+ len: len,
1384
+ value: value
1385
+ };
1386
+ };
1387
+ const decodeCalendarDate = (buffer, offset) => ({
1388
+ len: 4,
1389
+ year: buffer[offset],
1390
+ month: buffer[offset + 1],
1391
+ day: buffer[offset + 2],
1392
+ wday: buffer[offset + 3]
1393
+ });
1394
+ const decodeCalendarDateRange = (buffer, offset) => {
1395
+ let len = 1;
1396
+ const startDate = (0, exports.decodeDate)(buffer, offset + len);
1397
+ len += startDate.len + 1;
1398
+ const endDate = (0, exports.decodeDate)(buffer, offset + len);
1399
+ len += endDate.len + 1;
1400
+ return {
1401
+ len: len,
1402
+ startDate: startDate,
1403
+ endDate: endDate
1404
+ };
1405
+ };
1406
+ const decodeCalendarWeekDay = (buffer, offset) => ({
1407
+ len: 3,
1408
+ month: buffer[offset],
1409
+ week: buffer[offset + 1],
1410
+ wday: buffer[offset + 2]
1411
+ });
1412
+ const decodeCalendar = (buffer, offset, apduLen) => {
1413
+ let len = 0;
1414
+ const entries = [];
1415
+ while (len < apduLen) {
1416
+ const result = (0, exports.decodeTagNumber)(buffer, offset + len);
1417
+ len += result.len;
1418
+ switch (result.tagNumber) {
1419
+ case 0: {
1420
+ const decodedValue = decodeCalendarDate(buffer, offset + len);
1421
+ len += decodedValue.len;
1422
+ entries.push(decodedValue);
1423
+ break;
1424
+ }
1425
+ case 1: {
1426
+ const decodedValue = decodeCalendarDateRange(buffer, offset + len);
1427
+ len += decodedValue.len;
1428
+ entries.push(decodedValue);
1429
+ break;
1430
+ }
1431
+ case 2: {
1432
+ const decodedValue = decodeCalendarWeekDay(buffer, offset + len);
1433
+ len += decodedValue.len;
1434
+ entries.push(decodedValue);
1435
+ break;
1436
+ }
1437
+ default:
1438
+ return {
1439
+ len: len - 1,
1440
+ value: entries
1441
+ };
1442
+ }
1443
+ }
1444
+ };
1445
+ const bacappDecodeContextApplicationData = (buffer, offset, maxOffset, objectType, propertyId) => {
1446
+ let len = 0;
1447
+ if (isContextSpecific(buffer[offset])) {
1448
+ if (propertyId === baEnum.PropertyIdentifier.LIST_OF_GROUP_MEMBERS) {
1449
+ const result = (0, exports.decodeReadAccessSpecification)(buffer, offset, maxOffset);
1450
+ if (!result)
1451
+ return;
1452
+ return {
1453
+ type: baEnum.ApplicationTags.READ_ACCESS_SPECIFICATION,
1454
+ value: result.value,
1455
+ len: result.len
1456
+ };
1457
+ }
1458
+ else if (propertyId === baEnum.PropertyIdentifier.ACTIVE_COV_SUBSCRIPTIONS) {
1459
+ const result = decodeCovSubscription(buffer, offset, maxOffset);
1460
+ if (!result)
1461
+ return;
1462
+ return {
1463
+ type: baEnum.ApplicationTags.COV_SUBSCRIPTION,
1464
+ value: result.value,
1465
+ len: result.len
1466
+ };
1467
+ }
1468
+ else if (objectType === baEnum.ObjectType.GROUP && propertyId === baEnum.PropertyIdentifier.PRESENT_VALUE) {
1469
+ const result = (0, exports.decodeReadAccessResult)(buffer, offset, maxOffset);
1470
+ if (!result)
1471
+ return;
1472
+ return {
1473
+ type: baEnum.ApplicationTags.READ_ACCESS_RESULT,
1474
+ value: result.value,
1475
+ len: result.len
1476
+ };
1477
+ }
1478
+ else if (propertyId === baEnum.PropertyIdentifier.LIST_OF_OBJECT_PROPERTY_REFERENCES || propertyId === baEnum.PropertyIdentifier.LOG_DEVICE_OBJECT_PROPERTY || propertyId === baEnum.PropertyIdentifier.OBJECT_PROPERTY_REFERENCE) {
1479
+ const result = decodeDeviceObjPropertyRef(buffer, offset);
1480
+ if (!result)
1481
+ return;
1482
+ return {
1483
+ type: baEnum.ApplicationTags.OBJECT_PROPERTY_REFERENCE,
1484
+ value: result.value,
1485
+ len: result.len
1486
+ };
1487
+ }
1488
+ else if (propertyId === baEnum.PropertyIdentifier.DATE_LIST) {
1489
+ const result = decodeCalendar(buffer, offset, maxOffset);
1490
+ if (!result)
1491
+ return;
1492
+ return {
1493
+ type: baEnum.ApplicationTags.CONTEXT_SPECIFIC_DECODED,
1494
+ value: result.value,
1495
+ len: result.len
1496
+ };
1497
+ }
1498
+ else if (propertyId === baEnum.PropertyIdentifier.EVENT_TIME_STAMPS) {
1499
+ let subEvtResult;
1500
+ const evtResult = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1501
+ len += 1;
1502
+ if (evtResult.tagNumber === 0) {
1503
+ subEvtResult = (0, exports.decodeBacnetTime)(buffer, offset + 1);
1504
+ return {
1505
+ type: baEnum.ApplicationTags.TIMESTAMP,
1506
+ value: subEvtResult.value,
1507
+ len: subEvtResult.len + 1
1508
+ };
1509
+ }
1510
+ else if (evtResult.tagNumber === 1) {
1511
+ subEvtResult = (0, exports.decodeUnsigned)(buffer, offset + len, evtResult.value);
1512
+ return {
1513
+ type: baEnum.ApplicationTags.UNSIGNED_INTEGER,
1514
+ value: subEvtResult.value,
1515
+ len: subEvtResult.len + 1
1516
+ };
1517
+ }
1518
+ else if (evtResult.tagNumber === 2) {
1519
+ subEvtResult = decodeBacnetDatetime(buffer, offset + len);
1520
+ return {
1521
+ type: baEnum.ApplicationTags.TIMESTAMP,
1522
+ value: subEvtResult.value,
1523
+ len: subEvtResult.len + 2
1524
+ };
1525
+ }
1526
+ else {
1527
+ return;
1528
+ }
1529
+ }
1530
+ const list = [];
1531
+ const tagResult = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1532
+ const multipleValues = isOpeningTag(buffer[offset + len]);
1533
+ while (((len + offset) <= maxOffset) && !isClosingTag(buffer[offset + len])) {
1534
+ const subResult = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1535
+ if (!subResult)
1536
+ return;
1537
+ if (subResult.value === 0) {
1538
+ len += subResult.len;
1539
+ const result = (0, exports.bacappDecodeApplicationData)(buffer, offset + len, maxOffset, baEnum.ASN1_MAX_OBJECT_TYPE, baEnum.ASN1_MAX_PROPERTY_ID);
1540
+ if (!result)
1541
+ return;
1542
+ list.push(result);
1543
+ len += result.len;
1544
+ }
1545
+ else {
1546
+ const overrideTagNumber = bacappContextTagType(propertyId, subResult.tagNumber);
1547
+ if (overrideTagNumber !== baEnum.ASN1_MAX_APPLICATION_TAG) {
1548
+ subResult.tagNumber = overrideTagNumber;
1549
+ }
1550
+ const bacappResult = bacappDecodeData(buffer, offset + len + subResult.len, maxOffset, subResult.tagNumber, subResult.value);
1551
+ if (!bacappResult)
1552
+ return;
1553
+ if (bacappResult.len === subResult.value) {
1554
+ const resObj = {
1555
+ value: bacappResult.value,
1556
+ type: bacappResult.type
1557
+ };
1558
+ // HACK: Drop string specific handling ASAP
1559
+ if (bacappResult.encoding !== undefined)
1560
+ resObj.encoding = bacappResult.encoding;
1561
+ list.push(resObj);
1562
+ len += subResult.len + subResult.value;
1563
+ }
1564
+ else {
1565
+ list.push({
1566
+ value: buffer.slice(offset + len + subResult.len, offset + len + subResult.len + subResult.value),
1567
+ type: baEnum.ApplicationTags.CONTEXT_SPECIFIC_ENCODED
1568
+ });
1569
+ len += subResult.len + subResult.value;
1570
+ }
1571
+ }
1572
+ if (multipleValues === false) {
1573
+ return {
1574
+ len: len,
1575
+ value: list[0],
1576
+ type: baEnum.ApplicationTags.CONTEXT_SPECIFIC_DECODED
1577
+ };
1578
+ }
1579
+ }
1580
+ if ((len + offset) > maxOffset)
1581
+ return;
1582
+ if ((0, exports.decodeIsClosingTagNumber)(buffer, offset + len, tagResult.tagNumber)) {
1583
+ len++;
1584
+ }
1585
+ return {
1586
+ len: len,
1587
+ value: list,
1588
+ type: baEnum.ApplicationTags.CONTEXT_SPECIFIC_DECODED
1589
+ };
1590
+ }
1591
+ else {
1592
+ return;
1593
+ }
1594
+ };
1595
+ const bacappEncodeTimestamp = (buffer, value) => {
1596
+ switch (value.type) {
1597
+ case baEnum.TimeStamp.TIME:
1598
+ encodeContextTime(buffer, 0, value.value);
1599
+ break;
1600
+ case baEnum.TimeStamp.SEQUENCE_NUMBER:
1601
+ (0, exports.encodeContextUnsigned)(buffer, 1, value.value);
1602
+ break;
1603
+ case baEnum.TimeStamp.DATETIME:
1604
+ bacappEncodeContextDatetime(buffer, 2, value.value);
1605
+ break;
1606
+ default:
1607
+ throw new Error('NOT_IMPLEMENTED');
1608
+ }
1609
+ };
1610
+ exports.bacappEncodeTimestamp = bacappEncodeTimestamp;
1611
+ const bacappEncodeContextTimestamp = (buffer, tagNumber, value) => {
1612
+ (0, exports.encodeOpeningTag)(buffer, tagNumber);
1613
+ (0, exports.bacappEncodeTimestamp)(buffer, value);
1614
+ (0, exports.encodeClosingTag)(buffer, tagNumber);
1615
+ };
1616
+ exports.bacappEncodeContextTimestamp = bacappEncodeContextTimestamp;
1617
+ const decodeContextCharacterString = (buffer, offset, maxLength, tagNumber) => {
1618
+ let len = 0;
1619
+ if (!(0, exports.decodeIsContextTag)(buffer, offset + len, tagNumber))
1620
+ return;
1621
+ const result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1622
+ len += result.len;
1623
+ const decodedValue = multiCharsetCharacterstringDecode(buffer, offset + 1 + len, maxLength, buffer[offset + len], result.value - 1);
1624
+ if (!decodedValue)
1625
+ return;
1626
+ len += result.value;
1627
+ return {
1628
+ len: len,
1629
+ value: decodedValue.value,
1630
+ encoding: decodedValue.encoding
1631
+ };
1632
+ };
1633
+ exports.decodeContextCharacterString = decodeContextCharacterString;
1634
+ const decodeIsContextTagWithLength = (buffer, offset, tagNumber) => {
1635
+ const result = (0, exports.decodeTagNumber)(buffer, offset);
1636
+ return {
1637
+ len: result.len,
1638
+ value: isContextSpecific(buffer[offset]) && (result.tagNumber === tagNumber)
1639
+ };
1640
+ };
1641
+ const decodeContextObjectId = (buffer, offset, tagNumber) => {
1642
+ const result = decodeIsContextTagWithLength(buffer, offset, tagNumber);
1643
+ if (!result.value)
1644
+ return;
1645
+ const decodedValue = (0, exports.decodeObjectId)(buffer, offset + result.len);
1646
+ decodedValue.len = decodedValue.len + result.len;
1647
+ return decodedValue;
1648
+ };
1649
+ exports.decodeContextObjectId = decodeContextObjectId;
1650
+ const encodeBacnetCharacterString = (buffer, value, encoding) => {
1651
+ encoding = encoding || baEnum.CharacterStringEncoding.UTF_8;
1652
+ buffer.buffer[buffer.offset++] = encoding;
1653
+ const bufEncoded = iconv.encode(value, getEncodingType(encoding));
1654
+ buffer.offset += bufEncoded.copy(buffer.buffer, buffer.offset);
1655
+ };
1656
+ const encodeApplicationCharacterString = (buffer, value, encoding) => {
1657
+ const tmp = getBuffer();
1658
+ encodeBacnetCharacterString(tmp, value, encoding);
1659
+ (0, exports.encodeTag)(buffer, baEnum.ApplicationTags.CHARACTER_STRING, false, tmp.offset);
1660
+ tmp.buffer.copy(buffer.buffer, buffer.offset, 0, tmp.offset);
1661
+ buffer.offset += tmp.offset;
1662
+ };
1663
+ exports.encodeApplicationCharacterString = encodeApplicationCharacterString;
1664
+ const encodeContextCharacterString = (buffer, tagNumber, value, encoding) => {
1665
+ const tmp = getBuffer();
1666
+ encodeBacnetCharacterString(tmp, value, encoding);
1667
+ (0, exports.encodeTag)(buffer, tagNumber, true, tmp.offset);
1668
+ tmp.buffer.copy(buffer.buffer, buffer.offset, 0, tmp.offset);
1669
+ buffer.offset += tmp.offset;
1670
+ };
1671
+ exports.encodeContextCharacterString = encodeContextCharacterString;