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