@bitpoolos/edge-bacnet 1.1.8 → 1.2.1

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 (122) hide show
  1. package/bacnet_client.js +331 -168
  2. package/bacnet_device.js +50 -16
  3. package/bacnet_gateway.html +119 -15
  4. package/bacnet_gateway.js +388 -395
  5. package/bacnet_read.html +32 -11
  6. package/bacnet_read.js +1 -1
  7. package/bacnet_server.js +16 -12
  8. package/common.js +26 -19
  9. package/examples/1-Discover-Read.json +1 -1
  10. package/examples/2-Discover-Write.json +1 -1
  11. package/examples/3-Discover-Read-Write.json +1 -1
  12. package/package.json +3 -3
  13. package/resources/{node-bacnet/LICENSE.md → node-bacstack-ts/LICENSE} +3 -4
  14. package/resources/node-bacstack-ts/README.md +75 -0
  15. package/resources/{node-bacnet → node-bacstack-ts/dist}/index.js +0 -2
  16. package/resources/node-bacstack-ts/dist/lib/apdu.js +193 -0
  17. package/resources/node-bacstack-ts/dist/lib/asn1.js +1660 -0
  18. package/resources/node-bacstack-ts/dist/lib/bvlc.js +47 -0
  19. package/resources/node-bacstack-ts/dist/lib/client.js +1454 -0
  20. package/resources/node-bacstack-ts/dist/lib/enum.js +2114 -0
  21. package/resources/node-bacstack-ts/dist/lib/npdu.js +112 -0
  22. package/resources/node-bacstack-ts/dist/lib/services/add-list-element.js +58 -0
  23. package/resources/node-bacstack-ts/dist/lib/services/alarm-acknowledge.js +93 -0
  24. package/resources/node-bacstack-ts/dist/lib/services/alarm-summary.js +42 -0
  25. package/resources/node-bacstack-ts/dist/lib/services/atomic-read-file.js +157 -0
  26. package/resources/node-bacstack-ts/dist/lib/services/atomic-write-file.js +136 -0
  27. package/resources/node-bacstack-ts/dist/lib/services/cov-notify.js +119 -0
  28. package/resources/node-bacstack-ts/dist/lib/services/create-object.js +104 -0
  29. package/resources/node-bacstack-ts/dist/lib/services/delete-object.js +21 -0
  30. package/resources/node-bacstack-ts/dist/lib/services/device-communication-control.js +46 -0
  31. package/resources/node-bacstack-ts/dist/lib/services/error.js +27 -0
  32. package/resources/node-bacstack-ts/dist/lib/services/event-information.js +100 -0
  33. package/resources/node-bacstack-ts/dist/lib/services/event-notify-data.js +219 -0
  34. package/resources/node-bacstack-ts/dist/lib/services/get-enrollment-summary.js +172 -0
  35. package/resources/node-bacstack-ts/dist/lib/services/get-event-information.js +135 -0
  36. package/resources/node-bacstack-ts/dist/lib/services/i-am-broadcast.js +59 -0
  37. package/resources/node-bacstack-ts/dist/lib/services/i-have-broadcast.js +34 -0
  38. package/resources/node-bacstack-ts/dist/lib/services/index.js +32 -0
  39. package/resources/node-bacstack-ts/dist/lib/services/life-safety-operation.js +40 -0
  40. package/resources/node-bacstack-ts/dist/lib/services/private-transfer.js +43 -0
  41. package/resources/node-bacstack-ts/dist/lib/services/read-property-multiple.js +44 -0
  42. package/resources/node-bacstack-ts/dist/lib/services/read-property.js +122 -0
  43. package/resources/node-bacstack-ts/dist/lib/services/read-range.js +201 -0
  44. package/resources/node-bacstack-ts/dist/lib/services/reinitialize-device.js +35 -0
  45. package/resources/node-bacstack-ts/dist/lib/services/subscribe-cov.js +55 -0
  46. package/resources/node-bacstack-ts/dist/lib/services/subscribe-property.js +93 -0
  47. package/resources/node-bacstack-ts/dist/lib/services/time-sync.js +31 -0
  48. package/resources/node-bacstack-ts/dist/lib/services/who-has.js +56 -0
  49. package/resources/node-bacstack-ts/dist/lib/services/who-is.js +45 -0
  50. package/resources/node-bacstack-ts/dist/lib/services/write-property-multiple.js +105 -0
  51. package/resources/node-bacstack-ts/dist/lib/services/write-property.js +90 -0
  52. package/resources/node-bacstack-ts/dist/lib/transport.js +49 -0
  53. package/resources/node-bacstack-ts/dist/lib/types.js +2 -0
  54. package/resources/node-bacstack-ts/package.json +94 -0
  55. package/resources/node-bacnet/CHANGELOG.md +0 -481
  56. package/resources/node-bacnet/README.md +0 -91
  57. package/resources/node-bacnet/docs/Client.html +0 -4422
  58. package/resources/node-bacnet/docs/bacnet-icon-quad.png +0 -0
  59. package/resources/node-bacnet/docs/bacnet-icon-quad128.png +0 -0
  60. package/resources/node-bacnet/docs/bacnet-icon-quad64.png +0 -0
  61. package/resources/node-bacnet/docs/bacnet-icon-small.xcf +0 -0
  62. package/resources/node-bacnet/docs/bacnet-icon.xcf +0 -0
  63. package/resources/node-bacnet/docs/bacnet.html +0 -7032
  64. package/resources/node-bacnet/docs/client.js.html +0 -1759
  65. package/resources/node-bacnet/docs/enum.js.html +0 -2530
  66. package/resources/node-bacnet/docs/global.html +0 -2068
  67. package/resources/node-bacnet/docs/images/mocha-logo.svg +0 -65
  68. package/resources/node-bacnet/docs/index.html +0 -283
  69. package/resources/node-bacnet/docs/scripts/collapse.js +0 -11
  70. package/resources/node-bacnet/docs/scripts/jquery-3.1.1.min.js +0 -4
  71. package/resources/node-bacnet/docs/scripts/linenumber.js +0 -26
  72. package/resources/node-bacnet/docs/scripts/prettify/Apache-License-2.0.txt +0 -202
  73. package/resources/node-bacnet/docs/scripts/prettify/lang-css.js +0 -2
  74. package/resources/node-bacnet/docs/scripts/prettify/prettify.js +0 -28
  75. package/resources/node-bacnet/docs/scripts/search.js +0 -47
  76. package/resources/node-bacnet/docs/services_i-am.js.html +0 -157
  77. package/resources/node-bacnet/docs/services_time-sync.js.html +0 -118
  78. package/resources/node-bacnet/docs/services_who-is.js.html +0 -138
  79. package/resources/node-bacnet/docs/styles/jsdoc.css +0 -683
  80. package/resources/node-bacnet/docs/styles/prettify.css +0 -82
  81. package/resources/node-bacnet/examples/discover-devices.js +0 -66
  82. package/resources/node-bacnet/examples/read-device.js +0 -510
  83. package/resources/node-bacnet/examples/subscribe-cov.js +0 -75
  84. package/resources/node-bacnet/lib/apdu.js +0 -209
  85. package/resources/node-bacnet/lib/asn1.js +0 -1733
  86. package/resources/node-bacnet/lib/bvlc.js +0 -90
  87. package/resources/node-bacnet/lib/client.js +0 -1695
  88. package/resources/node-bacnet/lib/enum.js +0 -2463
  89. package/resources/node-bacnet/lib/npdu.js +0 -123
  90. package/resources/node-bacnet/lib/services/add-list-element.js +0 -64
  91. package/resources/node-bacnet/lib/services/alarm-acknowledge.js +0 -90
  92. package/resources/node-bacnet/lib/services/alarm-summary.js +0 -42
  93. package/resources/node-bacnet/lib/services/atomic-read-file.js +0 -162
  94. package/resources/node-bacnet/lib/services/atomic-write-file.js +0 -138
  95. package/resources/node-bacnet/lib/services/cov-notify.js +0 -126
  96. package/resources/node-bacnet/lib/services/create-object.js +0 -106
  97. package/resources/node-bacnet/lib/services/delete-object.js +0 -23
  98. package/resources/node-bacnet/lib/services/device-communication-control.js +0 -48
  99. package/resources/node-bacnet/lib/services/error.js +0 -33
  100. package/resources/node-bacnet/lib/services/event-information.js +0 -99
  101. package/resources/node-bacnet/lib/services/event-notify-data.js +0 -229
  102. package/resources/node-bacnet/lib/services/get-enrollment-summary.js +0 -178
  103. package/resources/node-bacnet/lib/services/get-event-information.js +0 -144
  104. package/resources/node-bacnet/lib/services/i-am.js +0 -90
  105. package/resources/node-bacnet/lib/services/i-have.js +0 -34
  106. package/resources/node-bacnet/lib/services/index.js +0 -34
  107. package/resources/node-bacnet/lib/services/life-safety-operation.js +0 -40
  108. package/resources/node-bacnet/lib/services/private-transfer.js +0 -43
  109. package/resources/node-bacnet/lib/services/read-property-multiple.js +0 -50
  110. package/resources/node-bacnet/lib/services/read-property.js +0 -130
  111. package/resources/node-bacnet/lib/services/read-range.js +0 -201
  112. package/resources/node-bacnet/lib/services/register-foreign-device.js +0 -18
  113. package/resources/node-bacnet/lib/services/reinitialize-device.js +0 -37
  114. package/resources/node-bacnet/lib/services/subscribe-cov.js +0 -57
  115. package/resources/node-bacnet/lib/services/subscribe-property.js +0 -97
  116. package/resources/node-bacnet/lib/services/time-sync.js +0 -51
  117. package/resources/node-bacnet/lib/services/who-has.js +0 -54
  118. package/resources/node-bacnet/lib/services/who-is.js +0 -71
  119. package/resources/node-bacnet/lib/services/write-property-multiple.js +0 -117
  120. package/resources/node-bacnet/lib/services/write-property.js +0 -94
  121. package/resources/node-bacnet/lib/transport.js +0 -82
  122. package/resources/node-bacnet/package.json +0 -92
@@ -0,0 +1,1660 @@
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: 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
+ const resObj = {
675
+ len: len + result.len,
676
+ type: result.type,
677
+ value: result.value
678
+ };
679
+ // HACK: Drop string specific handling ASAP
680
+ if (result.encoding !== undefined)
681
+ resObj.encoding = result.encoding;
682
+ return resObj;
683
+ }
684
+ }
685
+ else {
686
+ return bacappDecodeContextApplicationData(buffer, offset, maxOffset, objectType, propertyId);
687
+ }
688
+ };
689
+ exports.bacappDecodeApplicationData = bacappDecodeApplicationData;
690
+ const encodeReadAccessResult = (buffer, value) => {
691
+ (0, exports.encodeContextObjectId)(buffer, 0, value.objectId.type, value.objectId.instance);
692
+ (0, exports.encodeOpeningTag)(buffer, 1);
693
+ value.values.forEach((item) => {
694
+ (0, exports.encodeContextEnumerated)(buffer, 2, item.property.id);
695
+ if (item.property.index !== baEnum.ASN1_ARRAY_ALL) {
696
+ (0, exports.encodeContextUnsigned)(buffer, 3, item.property.index);
697
+ }
698
+ if (item.value && item.value[0] && item.value[0].value && item.value[0].value.type === 'BacnetError') {
699
+ (0, exports.encodeOpeningTag)(buffer, 5);
700
+ (0, exports.encodeApplicationEnumerated)(buffer, item.value[0].value.errorClass);
701
+ (0, exports.encodeApplicationEnumerated)(buffer, item.value[0].value.errorCode);
702
+ (0, exports.encodeClosingTag)(buffer, 5);
703
+ }
704
+ else {
705
+ (0, exports.encodeOpeningTag)(buffer, 4);
706
+ item.value.forEach((subItem) => (0, exports.bacappEncodeApplicationData)(buffer, subItem));
707
+ (0, exports.encodeClosingTag)(buffer, 4);
708
+ }
709
+ });
710
+ (0, exports.encodeClosingTag)(buffer, 1);
711
+ };
712
+ exports.encodeReadAccessResult = encodeReadAccessResult;
713
+ const decodeReadAccessResult = (buffer, offset, apduLen) => {
714
+ let len = 0;
715
+ const value = {};
716
+ if (!(0, exports.decodeIsContextTag)(buffer, offset + len, 0))
717
+ return;
718
+ len++;
719
+ let result = (0, exports.decodeObjectId)(buffer, offset + len);
720
+ value.objectId = {
721
+ type: result.objectType,
722
+ instance: result.instance
723
+ };
724
+ len += result.len;
725
+ if (!(0, exports.decodeIsOpeningTagNumber)(buffer, offset + len, 1))
726
+ return;
727
+ len++;
728
+ const values = [];
729
+ while ((apduLen - len) > 0) {
730
+ const newEntry = {};
731
+ if ((0, exports.decodeIsClosingTagNumber)(buffer, offset + len, 1)) {
732
+ len++;
733
+ break;
734
+ }
735
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
736
+ len += result.len;
737
+ if (result.tagNumber !== 2)
738
+ return;
739
+ result = (0, exports.decodeEnumerated)(buffer, offset + len, result.value);
740
+ newEntry.id = result.value;
741
+ len += result.len;
742
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
743
+ if (result.tagNumber === 3) {
744
+ len += result.len;
745
+ result = (0, exports.decodeUnsigned)(buffer, offset + len, result.value);
746
+ newEntry.index = result.value;
747
+ len += result.len;
748
+ }
749
+ else {
750
+ newEntry.index = baEnum.ASN1_ARRAY_ALL;
751
+ }
752
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
753
+ len += result.len;
754
+ if (result.tagNumber === 4) {
755
+ const localValues = [];
756
+ while ((len + offset) <= buffer.length && !(0, exports.decodeIsClosingTagNumber)(buffer, offset + len, 4)) {
757
+ const localResult = (0, exports.bacappDecodeApplicationData)(buffer, offset + len, apduLen + offset - 1, value.objectId.type, newEntry.id);
758
+ if (!localResult)
759
+ return;
760
+ len += localResult.len;
761
+ const resObj = {
762
+ value: localResult.value,
763
+ type: localResult.type
764
+ };
765
+ // HACK: Drop string specific handling ASAP
766
+ if (localResult.encoding !== undefined)
767
+ resObj.encoding = localResult.encoding;
768
+ localValues.push(resObj);
769
+ }
770
+ if (!(0, exports.decodeIsClosingTagNumber)(buffer, offset + len, 4))
771
+ return;
772
+ if ((localValues.length === 2) && (localValues[0].type === baEnum.ApplicationTags.DATE) && (localValues[1].type === baEnum.ApplicationTags.TIME)) {
773
+ const date = localValues[0].value;
774
+ const time = localValues[1].value;
775
+ const bdatetime = new Date(date.year, date.month, date.day, time.hour, time.minute, time.second, time.millisecond);
776
+ newEntry.value = [{ type: baEnum.ApplicationTags.DATETIME, value: bdatetime }];
777
+ }
778
+ else {
779
+ newEntry.value = localValues;
780
+ }
781
+ len++;
782
+ }
783
+ else if (result.tagNumber === 5) {
784
+ const err = {};
785
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
786
+ len += result.len;
787
+ result = (0, exports.decodeEnumerated)(buffer, offset + len, result.value);
788
+ len += result.len;
789
+ err.errorClass = result.value;
790
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
791
+ len += result.len;
792
+ result = (0, exports.decodeEnumerated)(buffer, offset + len, result.value);
793
+ len += result.len;
794
+ err.errorCode = result.value;
795
+ if (!(0, exports.decodeIsClosingTagNumber)(buffer, offset + len, 5))
796
+ return;
797
+ len++;
798
+ newEntry.value = [{
799
+ type: baEnum.ApplicationTags.ERROR,
800
+ value: err
801
+ }];
802
+ }
803
+ values.push(newEntry);
804
+ }
805
+ value.values = values;
806
+ return {
807
+ len: len,
808
+ value: value
809
+ };
810
+ };
811
+ exports.decodeReadAccessResult = decodeReadAccessResult;
812
+ const decodeSigned = (buffer, offset, length) => ({
813
+ len: length,
814
+ value: buffer.readIntBE(offset, length)
815
+ });
816
+ exports.decodeSigned = decodeSigned;
817
+ const decodeReal = (buffer, offset) => ({
818
+ len: 4,
819
+ value: buffer.readFloatBE(offset)
820
+ });
821
+ exports.decodeReal = decodeReal;
822
+ const decodeRealSafe = (buffer, offset, lenValue) => {
823
+ if (lenValue !== 4) {
824
+ return {
825
+ len: lenValue,
826
+ value: 0
827
+ };
828
+ }
829
+ else {
830
+ return (0, exports.decodeReal)(buffer, offset);
831
+ }
832
+ };
833
+ const decodeDouble = (buffer, offset) => ({
834
+ len: 8,
835
+ value: buffer.readDoubleBE(offset)
836
+ });
837
+ const decodeDoubleSafe = (buffer, offset, lenValue) => {
838
+ if (lenValue !== 8) {
839
+ return {
840
+ len: lenValue,
841
+ value: 0
842
+ };
843
+ }
844
+ else {
845
+ return decodeDouble(buffer, offset);
846
+ }
847
+ };
848
+ const decodeOctetString = (buffer, offset, maxLength, octetStringOffset, octetStringLength) => {
849
+ const octetString = [];
850
+ for (let i = octetStringOffset; i < (octetStringOffset + octetStringLength); i++) {
851
+ octetString.push(buffer[offset + i]);
852
+ }
853
+ return {
854
+ len: octetStringLength,
855
+ value: octetString
856
+ };
857
+ };
858
+ exports.decodeOctetString = decodeOctetString;
859
+ const multiCharsetCharacterstringDecode = (buffer, offset, maxLength, encoding, length) => {
860
+ const stringBuf = Buffer.alloc(length);
861
+ buffer.copy(stringBuf, 0, offset, offset + length);
862
+ return {
863
+ value: iconv.decode(stringBuf, getEncodingType(encoding, buffer, offset)),
864
+ len: length + 1,
865
+ encoding: encoding
866
+ };
867
+ };
868
+ const decodeCharacterString = (buffer, offset, maxLength, lenValue) => {
869
+ return multiCharsetCharacterstringDecode(buffer, offset + 1, maxLength, buffer[offset], lenValue - 1);
870
+ };
871
+ exports.decodeCharacterString = decodeCharacterString;
872
+ const bitstringSetBitsUsed = (bitString, bytesUsed, unusedBits) => {
873
+ bitString.bitsUsed = bytesUsed * 8;
874
+ bitString.bitsUsed -= unusedBits;
875
+ };
876
+ const decodeBitstring = (buffer, offset, lenValue) => {
877
+ let len = 0;
878
+ const bitString = { value: [], bitsUsed: 0 };
879
+ if (lenValue > 0) {
880
+ const bytesUsed = lenValue - 1;
881
+ if (bytesUsed <= baEnum.ASN1_MAX_BITSTRING_BYTES) {
882
+ len = 1;
883
+ for (let i = 0; i < bytesUsed; i++) {
884
+ bitString.value.push(byteReverseBits(buffer[offset + len++]));
885
+ }
886
+ const unusedBits = buffer[offset] & 0x07;
887
+ bitstringSetBitsUsed(bitString, bytesUsed, unusedBits);
888
+ }
889
+ }
890
+ return {
891
+ len: len,
892
+ value: bitString
893
+ };
894
+ };
895
+ exports.decodeBitstring = decodeBitstring;
896
+ const decodeDate = (buffer, offset) => {
897
+ let date;
898
+ const year = buffer[offset] + 1900;
899
+ const month = buffer[offset + 1];
900
+ const day = buffer[offset + 2];
901
+ const wday = buffer[offset + 3];
902
+ if (month === 0xFF && day === 0xFF && wday === 0xFF && (year - 1900) === 0xFF) {
903
+ date = new Date(1, 1, 1);
904
+ }
905
+ else {
906
+ date = new Date(year, month, day);
907
+ }
908
+ return {
909
+ len: 4,
910
+ value: date
911
+ };
912
+ };
913
+ exports.decodeDate = decodeDate;
914
+ const decodeDateSafe = (buffer, offset, lenValue) => {
915
+ if (lenValue !== 4) {
916
+ return {
917
+ len: lenValue,
918
+ value: new Date(1, 1, 1)
919
+ };
920
+ }
921
+ else {
922
+ return (0, exports.decodeDate)(buffer, offset);
923
+ }
924
+ };
925
+ const decodeApplicationDate = (buffer, offset) => {
926
+ const result = (0, exports.decodeTagNumber)(buffer, offset);
927
+ if (result.tagNumber === baEnum.ApplicationTags.DATE) {
928
+ const value = (0, exports.decodeDate)(buffer, offset + 1);
929
+ return {
930
+ len: value.len + 1,
931
+ value: value.value
932
+ };
933
+ }
934
+ };
935
+ exports.decodeApplicationDate = decodeApplicationDate;
936
+ const decodeBacnetTime = (buffer, offset) => {
937
+ let value;
938
+ const hour = buffer[offset + 0];
939
+ const min = buffer[offset + 1];
940
+ const sec = buffer[offset + 2];
941
+ let hundredths = buffer[offset + 3];
942
+ if (hour === 0xFF && min === 0xFF && sec === 0xFF && hundredths === 0xFF) {
943
+ value = new Date(1, 1, 1);
944
+ }
945
+ else {
946
+ if (hundredths > 100)
947
+ hundredths = 0;
948
+ value = new Date(1, 1, 1, hour, min, sec, hundredths * 10);
949
+ }
950
+ return {
951
+ len: 4,
952
+ value: value
953
+ };
954
+ };
955
+ exports.decodeBacnetTime = decodeBacnetTime;
956
+ const decodeBacnetTimeSafe = (buffer, offset, len) => {
957
+ if (len !== 4) {
958
+ return { len, value: new Date(1, 1, 1) };
959
+ }
960
+ else {
961
+ return (0, exports.decodeBacnetTime)(buffer, offset);
962
+ }
963
+ };
964
+ const decodeApplicationTime = (buffer, offset) => {
965
+ const result = (0, exports.decodeTagNumber)(buffer, offset);
966
+ if (result.tagNumber === baEnum.ApplicationTags.TIME) {
967
+ const value = (0, exports.decodeBacnetTime)(buffer, offset + 1);
968
+ return {
969
+ len: value.len + 1,
970
+ value: value.value
971
+ };
972
+ }
973
+ };
974
+ exports.decodeApplicationTime = decodeApplicationTime;
975
+ const decodeBacnetDatetime = (buffer, offset) => {
976
+ let len = 0;
977
+ const rawDate = (0, exports.decodeApplicationDate)(buffer, offset + len);
978
+ len += rawDate.len;
979
+ const date = rawDate.value;
980
+ const rawTime = (0, exports.decodeApplicationTime)(buffer, offset + len);
981
+ len += rawTime.len;
982
+ const time = rawTime.value;
983
+ return {
984
+ len: len,
985
+ value: new Date(date.getFullYear(), date.getMonth(), date.getDay(), time.getHours(), time.getMinutes(), time.getSeconds(), time.getMilliseconds())
986
+ };
987
+ };
988
+ const bacappDecodeData = (buffer, offset, maxLength, tagDataType, lenValueType) => {
989
+ let result;
990
+ const value = {
991
+ len: 0,
992
+ type: tagDataType
993
+ };
994
+ switch (tagDataType) {
995
+ case baEnum.ApplicationTags.NULL:
996
+ value.value = null;
997
+ break;
998
+ case baEnum.ApplicationTags.BOOLEAN:
999
+ value.value = lenValueType > 0 ? true : false;
1000
+ break;
1001
+ case baEnum.ApplicationTags.UNSIGNED_INTEGER:
1002
+ result = (0, exports.decodeUnsigned)(buffer, offset, lenValueType);
1003
+ value.len += result.len;
1004
+ value.value = result.value;
1005
+ break;
1006
+ case baEnum.ApplicationTags.SIGNED_INTEGER:
1007
+ result = (0, exports.decodeSigned)(buffer, offset, lenValueType);
1008
+ value.len += result.len;
1009
+ value.value = result.value;
1010
+ break;
1011
+ case baEnum.ApplicationTags.REAL:
1012
+ result = decodeRealSafe(buffer, offset, lenValueType);
1013
+ value.len += result.len;
1014
+ value.value = result.value;
1015
+ break;
1016
+ case baEnum.ApplicationTags.DOUBLE:
1017
+ result = decodeDoubleSafe(buffer, offset, lenValueType);
1018
+ value.len += result.len;
1019
+ value.value = result.value;
1020
+ break;
1021
+ case baEnum.ApplicationTags.OCTET_STRING:
1022
+ result = (0, exports.decodeOctetString)(buffer, offset, maxLength, 0, lenValueType);
1023
+ value.len += result.len;
1024
+ value.value = result.value;
1025
+ break;
1026
+ case baEnum.ApplicationTags.CHARACTER_STRING:
1027
+ result = (0, exports.decodeCharacterString)(buffer, offset, maxLength, lenValueType);
1028
+ value.len += result.len;
1029
+ value.value = result.value;
1030
+ value.encoding = result.encoding;
1031
+ break;
1032
+ case baEnum.ApplicationTags.BIT_STRING:
1033
+ result = (0, exports.decodeBitstring)(buffer, offset, lenValueType);
1034
+ value.len += result.len;
1035
+ value.value = result.value;
1036
+ break;
1037
+ case baEnum.ApplicationTags.ENUMERATED:
1038
+ result = (0, exports.decodeEnumerated)(buffer, offset, lenValueType);
1039
+ value.len += result.len;
1040
+ value.value = result.value;
1041
+ break;
1042
+ case baEnum.ApplicationTags.DATE:
1043
+ result = decodeDateSafe(buffer, offset, lenValueType);
1044
+ value.len += result.len;
1045
+ value.value = result.value;
1046
+ break;
1047
+ case baEnum.ApplicationTags.TIME:
1048
+ result = decodeBacnetTimeSafe(buffer, offset, lenValueType);
1049
+ value.len += result.len;
1050
+ value.value = result.value;
1051
+ break;
1052
+ case baEnum.ApplicationTags.OBJECTIDENTIFIER:
1053
+ result = decodeObjectIdSafe(buffer, offset, lenValueType);
1054
+ value.len += result.len;
1055
+ value.value = { type: result.objectType, instance: result.instance };
1056
+ break;
1057
+ default:
1058
+ break;
1059
+ }
1060
+ return value;
1061
+ };
1062
+ const bacappContextTagType = (property, tagNumber) => {
1063
+ let tag = 0;
1064
+ switch (property) {
1065
+ case baEnum.PropertyIdentifier.ACTUAL_SHED_LEVEL:
1066
+ case baEnum.PropertyIdentifier.REQUESTED_SHED_LEVEL:
1067
+ case baEnum.PropertyIdentifier.EXPECTED_SHED_LEVEL:
1068
+ switch (tagNumber) {
1069
+ case 0:
1070
+ case 1:
1071
+ tag = baEnum.ApplicationTags.UNSIGNED_INTEGER;
1072
+ break;
1073
+ case 2:
1074
+ tag = baEnum.ApplicationTags.REAL;
1075
+ break;
1076
+ default:
1077
+ break;
1078
+ }
1079
+ break;
1080
+ case baEnum.PropertyIdentifier.ACTION:
1081
+ switch (tagNumber) {
1082
+ case 0:
1083
+ case 1:
1084
+ tag = baEnum.ApplicationTags.OBJECTIDENTIFIER;
1085
+ break;
1086
+ case 2:
1087
+ tag = baEnum.ApplicationTags.ENUMERATED;
1088
+ break;
1089
+ case 3:
1090
+ case 5:
1091
+ case 6:
1092
+ tag = baEnum.ApplicationTags.UNSIGNED_INTEGER;
1093
+ break;
1094
+ case 7:
1095
+ case 8:
1096
+ tag = baEnum.ApplicationTags.BOOLEAN;
1097
+ break;
1098
+ default:
1099
+ break;
1100
+ }
1101
+ break;
1102
+ case baEnum.PropertyIdentifier.LIST_OF_GROUP_MEMBERS:
1103
+ switch (tagNumber) {
1104
+ case 0:
1105
+ tag = baEnum.ApplicationTags.OBJECTIDENTIFIER;
1106
+ break;
1107
+ default:
1108
+ break;
1109
+ }
1110
+ break;
1111
+ case baEnum.PropertyIdentifier.EXCEPTION_SCHEDULE:
1112
+ switch (tagNumber) {
1113
+ case 1:
1114
+ tag = baEnum.ApplicationTags.OBJECTIDENTIFIER;
1115
+ break;
1116
+ case 3:
1117
+ tag = baEnum.ApplicationTags.UNSIGNED_INTEGER;
1118
+ break;
1119
+ default:
1120
+ break;
1121
+ }
1122
+ break;
1123
+ case baEnum.PropertyIdentifier.LOG_DEVICE_OBJECT_PROPERTY:
1124
+ switch (tagNumber) {
1125
+ case 0:
1126
+ case 3:
1127
+ tag = baEnum.ApplicationTags.OBJECTIDENTIFIER;
1128
+ break;
1129
+ case 1:
1130
+ tag = baEnum.ApplicationTags.ENUMERATED;
1131
+ break;
1132
+ case 2:
1133
+ tag = baEnum.ApplicationTags.UNSIGNED_INTEGER;
1134
+ break;
1135
+ default:
1136
+ break;
1137
+ }
1138
+ break;
1139
+ case baEnum.PropertyIdentifier.SUBORDINATE_LIST:
1140
+ switch (tagNumber) {
1141
+ case 0:
1142
+ case 1:
1143
+ tag = baEnum.ApplicationTags.OBJECTIDENTIFIER;
1144
+ break;
1145
+ default:
1146
+ break;
1147
+ }
1148
+ break;
1149
+ case baEnum.PropertyIdentifier.RECIPIENT_LIST:
1150
+ switch (tagNumber) {
1151
+ case 0:
1152
+ tag = baEnum.ApplicationTags.OBJECTIDENTIFIER;
1153
+ break;
1154
+ default:
1155
+ break;
1156
+ }
1157
+ break;
1158
+ case baEnum.PropertyIdentifier.ACTIVE_COV_SUBSCRIPTIONS:
1159
+ switch (tagNumber) {
1160
+ case 0:
1161
+ case 1:
1162
+ break;
1163
+ case 2:
1164
+ tag = baEnum.ApplicationTags.BOOLEAN;
1165
+ break;
1166
+ case 3:
1167
+ tag = baEnum.ApplicationTags.UNSIGNED_INTEGER;
1168
+ break;
1169
+ case 4:
1170
+ tag = baEnum.ApplicationTags.REAL;
1171
+ break;
1172
+ default:
1173
+ break;
1174
+ }
1175
+ break;
1176
+ default:
1177
+ break;
1178
+ }
1179
+ return tag;
1180
+ };
1181
+ const decodeDeviceObjPropertyRef = (buffer, offset) => {
1182
+ let len = 0;
1183
+ let arrayIndex = baEnum.ASN1_ARRAY_ALL;
1184
+ if (!(0, exports.decodeIsContextTag)(buffer, offset + len, 0))
1185
+ return;
1186
+ len++;
1187
+ let objectId = (0, exports.decodeObjectId)(buffer, offset + len);
1188
+ len += objectId.len;
1189
+ let result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1190
+ len += result.len;
1191
+ if (result.tagNumber !== 1)
1192
+ return;
1193
+ const id = (0, exports.decodeEnumerated)(buffer, offset + len, result.value);
1194
+ len += id.len;
1195
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1196
+ if (result.tagNumber === 2) {
1197
+ len += result.len;
1198
+ // FIXME: This doesn't seem to be used
1199
+ arrayIndex = (0, exports.decodeUnsigned)(buffer, offset + len, result.value);
1200
+ len += arrayIndex.len;
1201
+ }
1202
+ if ((0, exports.decodeIsContextTag)(buffer, offset + len, 3)) {
1203
+ if (!isClosingTag(buffer[offset + len])) {
1204
+ len++;
1205
+ objectId = (0, exports.decodeObjectId)(buffer, offset + len);
1206
+ len += objectId.len;
1207
+ }
1208
+ }
1209
+ return {
1210
+ len: len,
1211
+ value: {
1212
+ objectId: objectId,
1213
+ id: id
1214
+ }
1215
+ };
1216
+ };
1217
+ const decodeReadAccessSpecification = (buffer, offset, apduLen) => {
1218
+ let len = 0;
1219
+ const value = {};
1220
+ if (!(0, exports.decodeIsContextTag)(buffer, offset + len, 0))
1221
+ return;
1222
+ len++;
1223
+ let decodedValue = (0, exports.decodeObjectId)(buffer, offset + len);
1224
+ value.objectId = {
1225
+ type: decodedValue.objectType,
1226
+ instance: decodedValue.instance
1227
+ };
1228
+ len += decodedValue.len;
1229
+ if (!(0, exports.decodeIsOpeningTagNumber)(buffer, offset + len, 1))
1230
+ return;
1231
+ len++;
1232
+ const propertyIdAndArrayIndex = [];
1233
+ while ((apduLen - len) > 1 && !(0, exports.decodeIsClosingTagNumber)(buffer, offset + len, 1)) {
1234
+ const propertyRef = {};
1235
+ if (!isContextSpecific(buffer[offset + len]))
1236
+ return;
1237
+ const result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1238
+ len += result.len;
1239
+ if (result.tagNumber !== 0)
1240
+ return;
1241
+ if ((len + result.value) >= apduLen)
1242
+ return;
1243
+ decodedValue = (0, exports.decodeEnumerated)(buffer, offset + len, result.value);
1244
+ propertyRef.id = decodedValue.value;
1245
+ len += decodedValue.len;
1246
+ propertyRef.index = baEnum.ASN1_ARRAY_ALL;
1247
+ if (isContextSpecific(buffer[offset + len]) && !isClosingTag(buffer[offset + len])) {
1248
+ const tmp = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1249
+ if (tmp.tagNumber === 1) {
1250
+ len += tmp.len;
1251
+ if ((len + tmp.value) >= apduLen)
1252
+ return;
1253
+ decodedValue = (0, exports.decodeUnsigned)(buffer, offset + len, tmp.value);
1254
+ propertyRef.index = decodedValue.value;
1255
+ len += decodedValue.len;
1256
+ }
1257
+ }
1258
+ propertyIdAndArrayIndex.push(propertyRef);
1259
+ }
1260
+ if (!(0, exports.decodeIsClosingTagNumber)(buffer, offset + len, 1))
1261
+ return;
1262
+ len++;
1263
+ value.properties = propertyIdAndArrayIndex;
1264
+ return {
1265
+ len: len,
1266
+ value: value
1267
+ };
1268
+ };
1269
+ exports.decodeReadAccessSpecification = decodeReadAccessSpecification;
1270
+ const decodeCovSubscription = (buffer, offset, apduLen) => {
1271
+ let len = 0;
1272
+ const value = {};
1273
+ let result;
1274
+ let decodedValue;
1275
+ value.recipient = {};
1276
+ if (!(0, exports.decodeIsOpeningTagNumber)(buffer, offset + len, 0))
1277
+ return;
1278
+ len++;
1279
+ if (!(0, exports.decodeIsOpeningTagNumber)(buffer, offset + len, 0))
1280
+ return;
1281
+ len++;
1282
+ if (!(0, exports.decodeIsOpeningTagNumber)(buffer, offset + len, 1))
1283
+ return;
1284
+ len++;
1285
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1286
+ len += result.len;
1287
+ if (result.tagNumber !== baEnum.ApplicationTags.UNSIGNED_INTEGER)
1288
+ return;
1289
+ decodedValue = (0, exports.decodeUnsigned)(buffer, offset + len, result.value);
1290
+ len += decodedValue.len;
1291
+ value.recipient.net = decodedValue.value;
1292
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1293
+ len += result.len;
1294
+ if (result.tagNumber !== baEnum.ApplicationTags.OCTET_STRING)
1295
+ return;
1296
+ decodedValue = (0, exports.decodeOctetString)(buffer, offset + len, apduLen, 0, result.value);
1297
+ len += decodedValue.len;
1298
+ value.recipient.adr = decodedValue.value;
1299
+ if (!(0, exports.decodeIsClosingTagNumber)(buffer, offset + len, 1))
1300
+ return;
1301
+ len++;
1302
+ if (!(0, exports.decodeIsClosingTagNumber)(buffer, offset + len, 0))
1303
+ return;
1304
+ len++;
1305
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1306
+ len += result.len;
1307
+ if (result.tagNumber !== 1)
1308
+ return;
1309
+ decodedValue = (0, exports.decodeUnsigned)(buffer, offset + len, result.value);
1310
+ len += decodedValue.len;
1311
+ value.subscriptionProcessId = decodedValue.value;
1312
+ if (!(0, exports.decodeIsClosingTagNumber)(buffer, offset + len, 0))
1313
+ return;
1314
+ len++;
1315
+ if (!(0, exports.decodeIsOpeningTagNumber)(buffer, offset + len, 1))
1316
+ return;
1317
+ len++;
1318
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1319
+ len += result.len;
1320
+ if (result.tagNumber !== 0)
1321
+ return;
1322
+ decodedValue = (0, exports.decodeObjectId)(buffer, offset + len);
1323
+ len += decodedValue.len;
1324
+ value.monitoredObjectId = {
1325
+ type: decodedValue.objectType,
1326
+ instance: decodedValue.instance
1327
+ };
1328
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1329
+ len += result.len;
1330
+ if (result.tagNumber !== 1)
1331
+ return;
1332
+ decodedValue = (0, exports.decodeEnumerated)(buffer, offset + len, result.value);
1333
+ len += decodedValue.len;
1334
+ value.monitoredProperty = {};
1335
+ value.monitoredProperty.id = decodedValue.value;
1336
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1337
+ if (result.tagNumber === 2) {
1338
+ len += result.len;
1339
+ decodedValue = (0, exports.decodeUnsigned)(buffer, offset + len, result.value);
1340
+ len += decodedValue.len;
1341
+ value.monitoredProperty.index = decodedValue.value;
1342
+ }
1343
+ else {
1344
+ value.monitoredProperty.index = baEnum.ASN1_ARRAY_ALL;
1345
+ }
1346
+ if (!(0, exports.decodeIsClosingTagNumber)(buffer, offset + len, 1))
1347
+ return;
1348
+ len++;
1349
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1350
+ len += result.len;
1351
+ if (result.tagNumber !== 2)
1352
+ return;
1353
+ value.issueConfirmedNotifications = buffer[offset + len] > 0 ? true : false;
1354
+ len++;
1355
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1356
+ len += result.len;
1357
+ if (result.tagNumber !== 3)
1358
+ return;
1359
+ decodedValue = (0, exports.decodeUnsigned)(buffer, offset + len, result.value);
1360
+ len += decodedValue.len;
1361
+ value.timeRemaining = decodedValue.value;
1362
+ if (len < apduLen && !isClosingTag(buffer[offset + len])) {
1363
+ result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1364
+ len += result.len;
1365
+ if (result.tagNumber !== 4)
1366
+ return;
1367
+ decodedValue = (0, exports.decodeReal)(buffer, offset + len);
1368
+ len += decodedValue.len;
1369
+ value.covIncrement = decodedValue.value;
1370
+ }
1371
+ return {
1372
+ len: len,
1373
+ value: value
1374
+ };
1375
+ };
1376
+ const decodeCalendarDate = (buffer, offset) => ({
1377
+ len: 4,
1378
+ year: buffer[offset],
1379
+ month: buffer[offset + 1],
1380
+ day: buffer[offset + 2],
1381
+ wday: buffer[offset + 3]
1382
+ });
1383
+ const decodeCalendarDateRange = (buffer, offset) => {
1384
+ let len = 1;
1385
+ const startDate = (0, exports.decodeDate)(buffer, offset + len);
1386
+ len += startDate.len + 1;
1387
+ const endDate = (0, exports.decodeDate)(buffer, offset + len);
1388
+ len += endDate.len + 1;
1389
+ return {
1390
+ len: len,
1391
+ startDate: startDate,
1392
+ endDate: endDate
1393
+ };
1394
+ };
1395
+ const decodeCalendarWeekDay = (buffer, offset) => ({
1396
+ len: 3,
1397
+ month: buffer[offset],
1398
+ week: buffer[offset + 1],
1399
+ wday: buffer[offset + 2]
1400
+ });
1401
+ const decodeCalendar = (buffer, offset, apduLen) => {
1402
+ let len = 0;
1403
+ const entries = [];
1404
+ while (len < apduLen) {
1405
+ const result = (0, exports.decodeTagNumber)(buffer, offset + len);
1406
+ len += result.len;
1407
+ switch (result.tagNumber) {
1408
+ case 0: {
1409
+ const decodedValue = decodeCalendarDate(buffer, offset + len);
1410
+ len += decodedValue.len;
1411
+ entries.push(decodedValue);
1412
+ break;
1413
+ }
1414
+ case 1: {
1415
+ const decodedValue = decodeCalendarDateRange(buffer, offset + len);
1416
+ len += decodedValue.len;
1417
+ entries.push(decodedValue);
1418
+ break;
1419
+ }
1420
+ case 2: {
1421
+ const decodedValue = decodeCalendarWeekDay(buffer, offset + len);
1422
+ len += decodedValue.len;
1423
+ entries.push(decodedValue);
1424
+ break;
1425
+ }
1426
+ default:
1427
+ return {
1428
+ len: len - 1,
1429
+ value: entries
1430
+ };
1431
+ }
1432
+ }
1433
+ };
1434
+ const bacappDecodeContextApplicationData = (buffer, offset, maxOffset, objectType, propertyId) => {
1435
+ let len = 0;
1436
+ if (isContextSpecific(buffer[offset])) {
1437
+ if (propertyId === baEnum.PropertyIdentifier.LIST_OF_GROUP_MEMBERS) {
1438
+ const result = (0, exports.decodeReadAccessSpecification)(buffer, offset, maxOffset);
1439
+ if (!result)
1440
+ return;
1441
+ return {
1442
+ type: baEnum.ApplicationTags.READ_ACCESS_SPECIFICATION,
1443
+ value: result.value,
1444
+ len: result.len
1445
+ };
1446
+ }
1447
+ else if (propertyId === baEnum.PropertyIdentifier.ACTIVE_COV_SUBSCRIPTIONS) {
1448
+ const result = decodeCovSubscription(buffer, offset, maxOffset);
1449
+ if (!result)
1450
+ return;
1451
+ return {
1452
+ type: baEnum.ApplicationTags.COV_SUBSCRIPTION,
1453
+ value: result.value,
1454
+ len: result.len
1455
+ };
1456
+ }
1457
+ else if (objectType === baEnum.ObjectType.GROUP && propertyId === baEnum.PropertyIdentifier.PRESENT_VALUE) {
1458
+ const result = (0, exports.decodeReadAccessResult)(buffer, offset, maxOffset);
1459
+ if (!result)
1460
+ return;
1461
+ return {
1462
+ type: baEnum.ApplicationTags.READ_ACCESS_RESULT,
1463
+ value: result.value,
1464
+ len: result.len
1465
+ };
1466
+ }
1467
+ else if (propertyId === baEnum.PropertyIdentifier.LIST_OF_OBJECT_PROPERTY_REFERENCES || propertyId === baEnum.PropertyIdentifier.LOG_DEVICE_OBJECT_PROPERTY || propertyId === baEnum.PropertyIdentifier.OBJECT_PROPERTY_REFERENCE) {
1468
+ const result = decodeDeviceObjPropertyRef(buffer, offset);
1469
+ if (!result)
1470
+ return;
1471
+ return {
1472
+ type: baEnum.ApplicationTags.OBJECT_PROPERTY_REFERENCE,
1473
+ value: result.value,
1474
+ len: result.len
1475
+ };
1476
+ }
1477
+ else if (propertyId === baEnum.PropertyIdentifier.DATE_LIST) {
1478
+ const result = decodeCalendar(buffer, offset, maxOffset);
1479
+ if (!result)
1480
+ return;
1481
+ return {
1482
+ type: baEnum.ApplicationTags.CONTEXT_SPECIFIC_DECODED,
1483
+ value: result.value,
1484
+ len: result.len
1485
+ };
1486
+ }
1487
+ else if (propertyId === baEnum.PropertyIdentifier.EVENT_TIME_STAMPS) {
1488
+ let subEvtResult;
1489
+ const evtResult = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1490
+ len += 1;
1491
+ if (evtResult.tagNumber === 0) {
1492
+ subEvtResult = (0, exports.decodeBacnetTime)(buffer, offset + 1);
1493
+ return {
1494
+ type: baEnum.ApplicationTags.TIMESTAMP,
1495
+ value: subEvtResult.value,
1496
+ len: subEvtResult.len + 1
1497
+ };
1498
+ }
1499
+ else if (evtResult.tagNumber === 1) {
1500
+ subEvtResult = (0, exports.decodeUnsigned)(buffer, offset + len, evtResult.value);
1501
+ return {
1502
+ type: baEnum.ApplicationTags.UNSIGNED_INTEGER,
1503
+ value: subEvtResult.value,
1504
+ len: subEvtResult.len + 1
1505
+ };
1506
+ }
1507
+ else if (evtResult.tagNumber === 2) {
1508
+ subEvtResult = decodeBacnetDatetime(buffer, offset + len);
1509
+ return {
1510
+ type: baEnum.ApplicationTags.TIMESTAMP,
1511
+ value: subEvtResult.value,
1512
+ len: subEvtResult.len + 2
1513
+ };
1514
+ }
1515
+ else {
1516
+ return;
1517
+ }
1518
+ }
1519
+ const list = [];
1520
+ const tagResult = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1521
+ const multipleValues = isOpeningTag(buffer[offset + len]);
1522
+ while (((len + offset) <= maxOffset) && !isClosingTag(buffer[offset + len])) {
1523
+ const subResult = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1524
+ if (!subResult)
1525
+ return;
1526
+ if (subResult.value === 0) {
1527
+ len += subResult.len;
1528
+ const result = (0, exports.bacappDecodeApplicationData)(buffer, offset + len, maxOffset, baEnum.ASN1_MAX_OBJECT_TYPE, baEnum.ASN1_MAX_PROPERTY_ID);
1529
+ if (!result)
1530
+ return;
1531
+ list.push(result);
1532
+ len += result.len;
1533
+ }
1534
+ else {
1535
+ const overrideTagNumber = bacappContextTagType(propertyId, subResult.tagNumber);
1536
+ if (overrideTagNumber !== baEnum.ASN1_MAX_APPLICATION_TAG) {
1537
+ subResult.tagNumber = overrideTagNumber;
1538
+ }
1539
+ const bacappResult = bacappDecodeData(buffer, offset + len + subResult.len, maxOffset, subResult.tagNumber, subResult.value);
1540
+ if (!bacappResult)
1541
+ return;
1542
+ if (bacappResult.len === subResult.value) {
1543
+ const resObj = {
1544
+ value: bacappResult.value,
1545
+ type: bacappResult.type
1546
+ };
1547
+ // HACK: Drop string specific handling ASAP
1548
+ if (bacappResult.encoding !== undefined)
1549
+ resObj.encoding = bacappResult.encoding;
1550
+ list.push(resObj);
1551
+ len += subResult.len + subResult.value;
1552
+ }
1553
+ else {
1554
+ list.push({
1555
+ value: buffer.slice(offset + len + subResult.len, offset + len + subResult.len + subResult.value),
1556
+ type: baEnum.ApplicationTags.CONTEXT_SPECIFIC_ENCODED
1557
+ });
1558
+ len += subResult.len + subResult.value;
1559
+ }
1560
+ }
1561
+ if (multipleValues === false) {
1562
+ return {
1563
+ len: len,
1564
+ value: list[0],
1565
+ type: baEnum.ApplicationTags.CONTEXT_SPECIFIC_DECODED
1566
+ };
1567
+ }
1568
+ }
1569
+ if ((len + offset) > maxOffset)
1570
+ return;
1571
+ if ((0, exports.decodeIsClosingTagNumber)(buffer, offset + len, tagResult.tagNumber)) {
1572
+ len++;
1573
+ }
1574
+ return {
1575
+ len: len,
1576
+ value: list,
1577
+ type: baEnum.ApplicationTags.CONTEXT_SPECIFIC_DECODED
1578
+ };
1579
+ }
1580
+ else {
1581
+ return;
1582
+ }
1583
+ };
1584
+ const bacappEncodeTimestamp = (buffer, value) => {
1585
+ switch (value.type) {
1586
+ case baEnum.TimeStamp.TIME:
1587
+ encodeContextTime(buffer, 0, value.value);
1588
+ break;
1589
+ case baEnum.TimeStamp.SEQUENCE_NUMBER:
1590
+ (0, exports.encodeContextUnsigned)(buffer, 1, value.value);
1591
+ break;
1592
+ case baEnum.TimeStamp.DATETIME:
1593
+ bacappEncodeContextDatetime(buffer, 2, value.value);
1594
+ break;
1595
+ default:
1596
+ throw new Error('NOT_IMPLEMENTED');
1597
+ }
1598
+ };
1599
+ exports.bacappEncodeTimestamp = bacappEncodeTimestamp;
1600
+ const bacappEncodeContextTimestamp = (buffer, tagNumber, value) => {
1601
+ (0, exports.encodeOpeningTag)(buffer, tagNumber);
1602
+ (0, exports.bacappEncodeTimestamp)(buffer, value);
1603
+ (0, exports.encodeClosingTag)(buffer, tagNumber);
1604
+ };
1605
+ exports.bacappEncodeContextTimestamp = bacappEncodeContextTimestamp;
1606
+ const decodeContextCharacterString = (buffer, offset, maxLength, tagNumber) => {
1607
+ let len = 0;
1608
+ if (!(0, exports.decodeIsContextTag)(buffer, offset + len, tagNumber))
1609
+ return;
1610
+ const result = (0, exports.decodeTagNumberAndValue)(buffer, offset + len);
1611
+ len += result.len;
1612
+ const decodedValue = multiCharsetCharacterstringDecode(buffer, offset + 1 + len, maxLength, buffer[offset + len], result.value - 1);
1613
+ if (!decodedValue)
1614
+ return;
1615
+ len += result.value;
1616
+ return {
1617
+ len: len,
1618
+ value: decodedValue.value,
1619
+ encoding: decodedValue.encoding
1620
+ };
1621
+ };
1622
+ exports.decodeContextCharacterString = decodeContextCharacterString;
1623
+ const decodeIsContextTagWithLength = (buffer, offset, tagNumber) => {
1624
+ const result = (0, exports.decodeTagNumber)(buffer, offset);
1625
+ return {
1626
+ len: result.len,
1627
+ value: isContextSpecific(buffer[offset]) && (result.tagNumber === tagNumber)
1628
+ };
1629
+ };
1630
+ const decodeContextObjectId = (buffer, offset, tagNumber) => {
1631
+ const result = decodeIsContextTagWithLength(buffer, offset, tagNumber);
1632
+ if (!result.value)
1633
+ return;
1634
+ const decodedValue = (0, exports.decodeObjectId)(buffer, offset + result.len);
1635
+ decodedValue.len = decodedValue.len + result.len;
1636
+ return decodedValue;
1637
+ };
1638
+ exports.decodeContextObjectId = decodeContextObjectId;
1639
+ const encodeBacnetCharacterString = (buffer, value, encoding) => {
1640
+ encoding = encoding || baEnum.CharacterStringEncoding.UTF_8;
1641
+ buffer.buffer[buffer.offset++] = encoding;
1642
+ const bufEncoded = iconv.encode(value, getEncodingType(encoding));
1643
+ buffer.offset += bufEncoded.copy(buffer.buffer, buffer.offset);
1644
+ };
1645
+ const encodeApplicationCharacterString = (buffer, value, encoding) => {
1646
+ const tmp = getBuffer();
1647
+ encodeBacnetCharacterString(tmp, value, encoding);
1648
+ (0, exports.encodeTag)(buffer, baEnum.ApplicationTags.CHARACTER_STRING, false, tmp.offset);
1649
+ tmp.buffer.copy(buffer.buffer, buffer.offset, 0, tmp.offset);
1650
+ buffer.offset += tmp.offset;
1651
+ };
1652
+ exports.encodeApplicationCharacterString = encodeApplicationCharacterString;
1653
+ const encodeContextCharacterString = (buffer, tagNumber, value, encoding) => {
1654
+ const tmp = getBuffer();
1655
+ encodeBacnetCharacterString(tmp, value, encoding);
1656
+ (0, exports.encodeTag)(buffer, tagNumber, true, tmp.offset);
1657
+ tmp.buffer.copy(buffer.buffer, buffer.offset, 0, tmp.offset);
1658
+ buffer.offset += tmp.offset;
1659
+ };
1660
+ exports.encodeContextCharacterString = encodeContextCharacterString;