njs-modbus 1.0.0

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.
package/dist/index.cjs ADDED
@@ -0,0 +1,1872 @@
1
+ 'use strict';
2
+
3
+ var EventEmitter = require('node:events');
4
+ var serialport = require('serialport');
5
+ var node_net = require('node:net');
6
+ var node_dgram = require('node:dgram');
7
+
8
+ exports.ErrorCode = void 0;
9
+ (function (ErrorCode) {
10
+ ErrorCode[ErrorCode["ILLEGAL_FUNCTION"] = 1] = "ILLEGAL_FUNCTION";
11
+ ErrorCode[ErrorCode["ILLEGAL_DATA_ADDRESS"] = 2] = "ILLEGAL_DATA_ADDRESS";
12
+ ErrorCode[ErrorCode["ILLEGAL_DATA_VALUE"] = 3] = "ILLEGAL_DATA_VALUE";
13
+ ErrorCode[ErrorCode["SERVER_DEVICE_FAILURE"] = 4] = "SERVER_DEVICE_FAILURE";
14
+ ErrorCode[ErrorCode["ACKNOWLEDGE"] = 5] = "ACKNOWLEDGE";
15
+ ErrorCode[ErrorCode["SERVER_DEVICE_BUSY"] = 6] = "SERVER_DEVICE_BUSY";
16
+ ErrorCode[ErrorCode["MEMORY_PARITY_ERROR"] = 8] = "MEMORY_PARITY_ERROR";
17
+ ErrorCode[ErrorCode["GATEWAY_PATH_UNAVAILABLE"] = 10] = "GATEWAY_PATH_UNAVAILABLE";
18
+ ErrorCode[ErrorCode["GATEWAY_TARGET_DEVICE_FAILED_TO_RESPOND"] = 11] = "GATEWAY_TARGET_DEVICE_FAILED_TO_RESPOND";
19
+ })(exports.ErrorCode || (exports.ErrorCode = {}));
20
+ const PREFIX = 'MODBUS_ERROR_CODE_';
21
+ function getErrorByCode(code) {
22
+ return new Error(PREFIX + code);
23
+ }
24
+ function getCodeByError(err) {
25
+ if (err.message.startsWith(PREFIX)) {
26
+ return Number(err.message.slice(PREFIX.length));
27
+ }
28
+ return exports.ErrorCode.SERVER_DEVICE_FAILURE;
29
+ }
30
+
31
+ class AbstractPhysicalLayer extends EventEmitter {
32
+ }
33
+
34
+ class SerialPhysicalLayer extends AbstractPhysicalLayer {
35
+ get isOpen() {
36
+ return this._serialport.isOpen;
37
+ }
38
+ get destroyed() {
39
+ return this._destroyed;
40
+ }
41
+ constructor(options) {
42
+ super();
43
+ Object.defineProperty(this, "TYPE", {
44
+ enumerable: true,
45
+ configurable: true,
46
+ writable: true,
47
+ value: 'SERIAL'
48
+ });
49
+ Object.defineProperty(this, "_serialport", {
50
+ enumerable: true,
51
+ configurable: true,
52
+ writable: true,
53
+ value: void 0
54
+ });
55
+ Object.defineProperty(this, "_destroyed", {
56
+ enumerable: true,
57
+ configurable: true,
58
+ writable: true,
59
+ value: false
60
+ });
61
+ this._serialport = new serialport.SerialPort(Object.assign(Object.assign({}, options), { autoOpen: false }));
62
+ }
63
+ open() {
64
+ if (this.destroyed) {
65
+ return Promise.reject(new Error('Port is destroyed'));
66
+ }
67
+ return new Promise((resolve, reject) => {
68
+ this._serialport.open((error) => {
69
+ if (error) {
70
+ reject(error);
71
+ }
72
+ else {
73
+ this._serialport.on('data', (data) => {
74
+ this.emit('data', data, (data) => this.write(data));
75
+ });
76
+ this._serialport.on('error', (error) => {
77
+ this.emit('error', error);
78
+ });
79
+ this._serialport.on('close', () => {
80
+ this._serialport.removeAllListeners();
81
+ this.emit('close');
82
+ });
83
+ resolve();
84
+ }
85
+ });
86
+ });
87
+ }
88
+ write(data) {
89
+ return new Promise((resolve, reject) => {
90
+ if (this.isOpen) {
91
+ this._serialport.write(data, (error) => {
92
+ if (error) {
93
+ reject(error);
94
+ }
95
+ else {
96
+ resolve();
97
+ }
98
+ });
99
+ }
100
+ else {
101
+ reject(new Error('Port is not open'));
102
+ }
103
+ });
104
+ }
105
+ close() {
106
+ return new Promise((resolve) => {
107
+ this._serialport.removeAllListeners();
108
+ this._serialport.close(() => {
109
+ resolve();
110
+ });
111
+ });
112
+ }
113
+ destroy() {
114
+ this._destroyed = true;
115
+ this.removeAllListeners();
116
+ return this.close();
117
+ }
118
+ }
119
+
120
+ class TcpClientPhysicalLayer extends AbstractPhysicalLayer {
121
+ get isOpen() {
122
+ return this._isOpen;
123
+ }
124
+ get destroyed() {
125
+ return this._destroyed;
126
+ }
127
+ constructor(options) {
128
+ super();
129
+ Object.defineProperty(this, "TYPE", {
130
+ enumerable: true,
131
+ configurable: true,
132
+ writable: true,
133
+ value: 'NET'
134
+ });
135
+ Object.defineProperty(this, "_socket", {
136
+ enumerable: true,
137
+ configurable: true,
138
+ writable: true,
139
+ value: void 0
140
+ });
141
+ Object.defineProperty(this, "_isOpen", {
142
+ enumerable: true,
143
+ configurable: true,
144
+ writable: true,
145
+ value: false
146
+ });
147
+ Object.defineProperty(this, "_destroyed", {
148
+ enumerable: true,
149
+ configurable: true,
150
+ writable: true,
151
+ value: false
152
+ });
153
+ this._socket = new node_net.Socket(options);
154
+ }
155
+ open(options) {
156
+ if (this.destroyed) {
157
+ return Promise.reject(new Error('Port is destroyed'));
158
+ }
159
+ return new Promise((resolve, reject) => {
160
+ let called = false;
161
+ this._socket.connect(Object.assign(Object.assign({}, options), { port: 502 }), () => {
162
+ called = true;
163
+ this._isOpen = true;
164
+ this._socket.on('data', (data) => {
165
+ this.emit('data', data, (data) => this.write(data));
166
+ });
167
+ this._socket.on('close', () => {
168
+ this._isOpen = false;
169
+ this._socket.removeAllListeners();
170
+ this.emit('close');
171
+ });
172
+ resolve();
173
+ });
174
+ this._socket.on('error', (error) => {
175
+ if (called) {
176
+ this.emit('error', error);
177
+ }
178
+ else {
179
+ reject(error);
180
+ }
181
+ });
182
+ });
183
+ }
184
+ write(data) {
185
+ return new Promise((resolve, reject) => {
186
+ if (this.isOpen) {
187
+ this._socket.write(data, (error) => {
188
+ if (error) {
189
+ reject(error);
190
+ }
191
+ else {
192
+ resolve();
193
+ }
194
+ });
195
+ }
196
+ else {
197
+ reject(new Error('Port is not open'));
198
+ }
199
+ });
200
+ }
201
+ close() {
202
+ return new Promise((resolve) => {
203
+ this._isOpen = false;
204
+ this._socket.removeAllListeners();
205
+ this._socket.destroy();
206
+ resolve();
207
+ });
208
+ }
209
+ destroy() {
210
+ this._destroyed = true;
211
+ this.removeAllListeners();
212
+ return this.close();
213
+ }
214
+ }
215
+
216
+ class TcpServerPhysicalLayer extends AbstractPhysicalLayer {
217
+ get isOpen() {
218
+ return this._isOpen;
219
+ }
220
+ get destroyed() {
221
+ return this._destroyed;
222
+ }
223
+ constructor(options) {
224
+ super();
225
+ Object.defineProperty(this, "TYPE", {
226
+ enumerable: true,
227
+ configurable: true,
228
+ writable: true,
229
+ value: 'NET'
230
+ });
231
+ Object.defineProperty(this, "_server", {
232
+ enumerable: true,
233
+ configurable: true,
234
+ writable: true,
235
+ value: void 0
236
+ });
237
+ Object.defineProperty(this, "_isOpen", {
238
+ enumerable: true,
239
+ configurable: true,
240
+ writable: true,
241
+ value: false
242
+ });
243
+ Object.defineProperty(this, "_destroyed", {
244
+ enumerable: true,
245
+ configurable: true,
246
+ writable: true,
247
+ value: false
248
+ });
249
+ Object.defineProperty(this, "_sockets", {
250
+ enumerable: true,
251
+ configurable: true,
252
+ writable: true,
253
+ value: new Set()
254
+ });
255
+ this._server = node_net.createServer(options, (socket) => {
256
+ this._sockets.add(socket);
257
+ socket.on('data', (data) => {
258
+ this.emit('data', data, (data) => new Promise((resolve, reject) => {
259
+ socket.write(data, (error) => {
260
+ if (error) {
261
+ reject(error);
262
+ }
263
+ else {
264
+ resolve();
265
+ }
266
+ });
267
+ }));
268
+ });
269
+ socket.once('close', () => {
270
+ socket.removeAllListeners();
271
+ this._sockets.delete(socket);
272
+ });
273
+ });
274
+ }
275
+ open(options) {
276
+ if (this.destroyed) {
277
+ return Promise.reject(new Error('Port is destroyed'));
278
+ }
279
+ return new Promise((resolve, reject) => {
280
+ var _a;
281
+ let called = false;
282
+ this._server.listen(Object.assign(Object.assign({}, options), { port: (_a = options.port) !== null && _a !== void 0 ? _a : 502 }), () => {
283
+ called = true;
284
+ this._isOpen = true;
285
+ this._sockets.clear();
286
+ this._server.on('close', () => {
287
+ this._isOpen = false;
288
+ this._server.removeAllListeners();
289
+ for (const socket of this._sockets) {
290
+ socket.removeAllListeners();
291
+ }
292
+ this.emit('close');
293
+ });
294
+ resolve();
295
+ });
296
+ this._server.on('error', (error) => {
297
+ if (called) {
298
+ this.emit('error', error);
299
+ }
300
+ else {
301
+ reject(error);
302
+ }
303
+ });
304
+ });
305
+ }
306
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
307
+ write(data) {
308
+ return new Promise((resolve, reject) => {
309
+ reject(new Error('Not supported'));
310
+ });
311
+ }
312
+ close() {
313
+ return new Promise((resolve) => {
314
+ this._isOpen = false;
315
+ this._server.removeAllListeners();
316
+ for (const socket of this._sockets) {
317
+ socket.removeAllListeners();
318
+ }
319
+ this._server.close(() => {
320
+ resolve();
321
+ });
322
+ });
323
+ }
324
+ destroy() {
325
+ this._destroyed = true;
326
+ this.removeAllListeners();
327
+ return this.close();
328
+ }
329
+ }
330
+
331
+ class UdpPhysicalLayer extends AbstractPhysicalLayer {
332
+ get isOpen() {
333
+ return this._isOpen;
334
+ }
335
+ get destroyed() {
336
+ return this._destroyed;
337
+ }
338
+ /**
339
+ *
340
+ * @param options
341
+ * @param remote If omitted, as server.
342
+ * Otherwise as client.
343
+ */
344
+ constructor(options, remote) {
345
+ var _a, _b;
346
+ super();
347
+ Object.defineProperty(this, "TYPE", {
348
+ enumerable: true,
349
+ configurable: true,
350
+ writable: true,
351
+ value: 'NET'
352
+ });
353
+ Object.defineProperty(this, "_socket", {
354
+ enumerable: true,
355
+ configurable: true,
356
+ writable: true,
357
+ value: void 0
358
+ });
359
+ Object.defineProperty(this, "_isOpen", {
360
+ enumerable: true,
361
+ configurable: true,
362
+ writable: true,
363
+ value: false
364
+ });
365
+ Object.defineProperty(this, "_destroyed", {
366
+ enumerable: true,
367
+ configurable: true,
368
+ writable: true,
369
+ value: false
370
+ });
371
+ Object.defineProperty(this, "_port", {
372
+ enumerable: true,
373
+ configurable: true,
374
+ writable: true,
375
+ value: void 0
376
+ });
377
+ Object.defineProperty(this, "_address", {
378
+ enumerable: true,
379
+ configurable: true,
380
+ writable: true,
381
+ value: void 0
382
+ });
383
+ Object.defineProperty(this, "isServer", {
384
+ enumerable: true,
385
+ configurable: true,
386
+ writable: true,
387
+ value: void 0
388
+ });
389
+ this._socket = node_dgram.createSocket(Object.assign(Object.assign({}, options), { type: (_a = options === null || options === void 0 ? void 0 : options.type) !== null && _a !== void 0 ? _a : 'udp4' }), (msg, rinfo) => {
390
+ this.emit('data', msg, (data) => new Promise((resolve, reject) => {
391
+ this._socket.send(data, rinfo.port, rinfo.address, (error) => {
392
+ if (error) {
393
+ reject(error);
394
+ }
395
+ else {
396
+ resolve();
397
+ }
398
+ });
399
+ }));
400
+ });
401
+ this.isServer = !remote;
402
+ this._port = (_b = remote === null || remote === void 0 ? void 0 : remote.port) !== null && _b !== void 0 ? _b : 502;
403
+ this._address = remote === null || remote === void 0 ? void 0 : remote.address;
404
+ }
405
+ open(options) {
406
+ if (this.destroyed) {
407
+ return Promise.reject(new Error('Port is destroyed'));
408
+ }
409
+ return new Promise((resolve, reject) => {
410
+ var _a;
411
+ if (this.isServer) {
412
+ let called = false;
413
+ this._socket.bind(Object.assign(Object.assign({}, options), { port: (_a = options.port) !== null && _a !== void 0 ? _a : 502 }), () => {
414
+ called = true;
415
+ this._isOpen = true;
416
+ this._socket.on('close', () => {
417
+ this._isOpen = false;
418
+ this._socket.removeAllListeners();
419
+ this.emit('close');
420
+ });
421
+ resolve();
422
+ });
423
+ this._socket.on('error', (error) => {
424
+ if (called) {
425
+ this.emit('error', error);
426
+ }
427
+ else {
428
+ reject(error);
429
+ }
430
+ });
431
+ }
432
+ else {
433
+ this._isOpen = true;
434
+ resolve();
435
+ }
436
+ });
437
+ }
438
+ write(data) {
439
+ return new Promise((resolve, reject) => {
440
+ if (this.isOpen) {
441
+ this._socket.send(data, this._port, this._address, (error) => {
442
+ if (error) {
443
+ reject(error);
444
+ }
445
+ else {
446
+ resolve();
447
+ }
448
+ });
449
+ }
450
+ else {
451
+ reject(new Error('Port is not open'));
452
+ }
453
+ });
454
+ }
455
+ close() {
456
+ return new Promise((resolve) => {
457
+ this._isOpen = false;
458
+ this._socket.removeAllListeners();
459
+ this._socket.close(() => {
460
+ resolve();
461
+ });
462
+ });
463
+ }
464
+ destroy() {
465
+ this._destroyed = true;
466
+ this.removeAllListeners();
467
+ return this.close();
468
+ }
469
+ }
470
+
471
+ class AbstractApplicationLayer extends EventEmitter {
472
+ }
473
+
474
+ function checkRange(value, range) {
475
+ if (range && range[0] < range[1]) {
476
+ return (Array.isArray(value) ? value : [value]).every((n) => n >= range[0] && n <= range[1]);
477
+ }
478
+ return true;
479
+ }
480
+
481
+ const TABLE = [
482
+ 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, 0xcc01,
483
+ 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, 0xd801, 0x18c0,
484
+ 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, 0x1400, 0xd4c1, 0xd581,
485
+ 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, 0xf001, 0x30c0, 0x3180, 0xf141,
486
+ 0x3300, 0xf3c1, 0xf281, 0x3240, 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01,
487
+ 0x3fc0, 0x3e80, 0xfe41, 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0,
488
+ 0x2a80, 0xea41, 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40, 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681,
489
+ 0x2640, 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
490
+ 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, 0xaa01,
491
+ 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, 0xbe01, 0x7ec0,
492
+ 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, 0x7200, 0xb2c1, 0xb381,
493
+ 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, 0x9601, 0x56c0, 0x5780, 0x9741,
494
+ 0x5500, 0x95c1, 0x9481, 0x5440, 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901,
495
+ 0x59c0, 0x5880, 0x9841, 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0,
496
+ 0x4c80, 0x8c41, 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081,
497
+ 0x4040,
498
+ ];
499
+ function crc(data) {
500
+ let crc = 0xffff;
501
+ for (let index = 0; index < data.length; index++) {
502
+ crc = (TABLE[(crc ^ data[index]) & 0xff] ^ (crc >> 8)) & 0xffff;
503
+ }
504
+ return crc;
505
+ }
506
+
507
+ /**
508
+ * Get time interval between message frames witch well-known as 3.5T.
509
+ * @param baudRate Serial port baud rate.
510
+ * @param {number} [approximation=48] Approximate number of bits corresponding to 3.5T.
511
+ * @returns `ms`.
512
+ */
513
+ function getThreePointFiveT(baudRate, approximation = 48) {
514
+ return (approximation * 1000) / baudRate;
515
+ }
516
+
517
+ function lrc(data) {
518
+ return (~data.reduce((sum, n) => sum + n, 0) + 1) & 0xff;
519
+ }
520
+
521
+ class RtuApplicationLayer extends AbstractApplicationLayer {
522
+ constructor(physicalLayer, serialFrameInterval) {
523
+ super();
524
+ Object.defineProperty(this, "_timerThreePointFive", {
525
+ enumerable: true,
526
+ configurable: true,
527
+ writable: true,
528
+ value: void 0
529
+ });
530
+ Object.defineProperty(this, "_bufferRx", {
531
+ enumerable: true,
532
+ configurable: true,
533
+ writable: true,
534
+ value: Buffer.alloc(0)
535
+ });
536
+ Object.defineProperty(this, "_removeAllListeners", {
537
+ enumerable: true,
538
+ configurable: true,
539
+ writable: true,
540
+ value: []
541
+ });
542
+ let threePointFiveT = 0;
543
+ if (physicalLayer.TYPE === 'SERIAL' && serialFrameInterval) {
544
+ threePointFiveT = Math.ceil(serialFrameInterval.baudRate > 19200
545
+ ? 1.8
546
+ : getThreePointFiveT(serialFrameInterval.baudRate, serialFrameInterval.bitsBetweenFrames));
547
+ }
548
+ const handleData = (data, response) => {
549
+ this._bufferRx = Buffer.concat([this._bufferRx, data]);
550
+ clearTimeout(this._timerThreePointFive);
551
+ const handleData = () => {
552
+ const frame = this.framing(this._bufferRx);
553
+ if (frame) {
554
+ this.emit('framing', frame, response);
555
+ }
556
+ this._bufferRx = Buffer.alloc(0);
557
+ };
558
+ if (threePointFiveT) {
559
+ this._timerThreePointFive = setTimeout(handleData, threePointFiveT);
560
+ }
561
+ else {
562
+ handleData();
563
+ }
564
+ };
565
+ physicalLayer.on('data', handleData);
566
+ this._removeAllListeners.push(() => {
567
+ physicalLayer.removeListener('data', handleData);
568
+ });
569
+ const handleClose = () => {
570
+ clearTimeout(this._timerThreePointFive);
571
+ this._bufferRx = Buffer.alloc(0);
572
+ };
573
+ physicalLayer.on('close', handleClose);
574
+ this._removeAllListeners.push(() => {
575
+ physicalLayer.removeListener('close', handleClose);
576
+ });
577
+ }
578
+ framing(buffer) {
579
+ if (buffer.length >= 4) {
580
+ const crcPassed = buffer.readUInt16LE(buffer.length - 2) === crc(buffer.subarray(0, buffer.length - 2));
581
+ if (crcPassed) {
582
+ return {
583
+ unit: buffer[0],
584
+ fc: buffer[1],
585
+ data: Array.from(buffer.subarray(2, buffer.length - 2)),
586
+ buffer,
587
+ };
588
+ }
589
+ }
590
+ }
591
+ encode(data) {
592
+ const buffer = Buffer.alloc(data.data.length + 4);
593
+ buffer.writeUInt8(data.unit, 0);
594
+ buffer.writeUInt8(data.fc, 1);
595
+ data.data.forEach((num, index) => {
596
+ buffer.writeUInt8(num, 2 + index);
597
+ });
598
+ buffer.writeUInt16LE(crc(buffer.subarray(0, -2)), buffer.length - 2);
599
+ return buffer;
600
+ }
601
+ destroy() {
602
+ this.removeAllListeners();
603
+ for (const removeAllListener of this._removeAllListeners) {
604
+ removeAllListener();
605
+ }
606
+ clearTimeout(this._timerThreePointFive);
607
+ }
608
+ }
609
+
610
+ const CHAR_CODE = {
611
+ COLON: ':'.charCodeAt(0),
612
+ CR: '\r'.charCodeAt(0),
613
+ LF: '\n'.charCodeAt(0),
614
+ };
615
+ class AsciiApplicationLayer extends AbstractApplicationLayer {
616
+ constructor(physicalLayer) {
617
+ super();
618
+ Object.defineProperty(this, "_status", {
619
+ enumerable: true,
620
+ configurable: true,
621
+ writable: true,
622
+ value: 'idle'
623
+ });
624
+ Object.defineProperty(this, "_frame", {
625
+ enumerable: true,
626
+ configurable: true,
627
+ writable: true,
628
+ value: []
629
+ });
630
+ Object.defineProperty(this, "_removeAllListeners", {
631
+ enumerable: true,
632
+ configurable: true,
633
+ writable: true,
634
+ value: []
635
+ });
636
+ const handleData = (data, response) => {
637
+ data.forEach((value) => {
638
+ switch (this._status) {
639
+ case 'idle': {
640
+ if (value === CHAR_CODE.COLON) {
641
+ this._status = 'reception';
642
+ this._frame = [];
643
+ }
644
+ break;
645
+ }
646
+ case 'reception': {
647
+ if (value === CHAR_CODE.COLON) {
648
+ this._frame = [];
649
+ }
650
+ else if (value === CHAR_CODE.CR) {
651
+ this._status = 'waiting end';
652
+ }
653
+ else {
654
+ this._frame.push(value);
655
+ }
656
+ break;
657
+ }
658
+ case 'waiting end': {
659
+ if (value === CHAR_CODE.COLON) {
660
+ this._status = 'reception';
661
+ this._frame = [];
662
+ }
663
+ else {
664
+ this._status = 'idle';
665
+ if (value === CHAR_CODE.LF) {
666
+ const frame = this.framing(Buffer.from(this._frame));
667
+ if (frame) {
668
+ this.emit('framing', frame, response);
669
+ }
670
+ }
671
+ }
672
+ break;
673
+ }
674
+ }
675
+ });
676
+ };
677
+ physicalLayer.on('data', handleData);
678
+ this._removeAllListeners.push(() => {
679
+ physicalLayer.removeListener('data', handleData);
680
+ });
681
+ const handleClose = () => {
682
+ this._status = 'reception';
683
+ this._frame = [];
684
+ };
685
+ physicalLayer.on('close', handleClose);
686
+ this._removeAllListeners.push(() => {
687
+ physicalLayer.removeListener('close', handleClose);
688
+ });
689
+ }
690
+ framing(_buffer) {
691
+ if (_buffer.length >= 6 && _buffer.length % 2 === 0) {
692
+ const frame = [];
693
+ let num = '';
694
+ for (const value of _buffer) {
695
+ num += String.fromCharCode(value);
696
+ if (num.length === 2) {
697
+ frame.push(Number('0x' + num));
698
+ num = '';
699
+ }
700
+ }
701
+ const buffer = Buffer.from(frame);
702
+ const lrcPassed = buffer[buffer.length - 1] === lrc(buffer.subarray(0, buffer.length - 1));
703
+ if (lrcPassed) {
704
+ return {
705
+ unit: buffer[0],
706
+ fc: buffer[1],
707
+ data: Array.from(buffer.subarray(2, buffer.length - 1)),
708
+ buffer: _buffer,
709
+ };
710
+ }
711
+ }
712
+ }
713
+ encode(data) {
714
+ const buffer = Buffer.alloc(data.data.length + 3);
715
+ buffer.writeUInt8(data.unit, 0);
716
+ buffer.writeUInt8(data.fc, 1);
717
+ data.data.forEach((num, index) => {
718
+ buffer.writeUInt8(num, 2 + index);
719
+ });
720
+ buffer.writeUInt8(lrc(buffer.subarray(0, -1)), buffer.length - 1);
721
+ let frame = ':';
722
+ for (const value of buffer) {
723
+ frame += value.toString(16).toUpperCase().padStart(2, '0');
724
+ }
725
+ frame += '\r\n';
726
+ return Buffer.from(frame);
727
+ }
728
+ destroy() {
729
+ this.removeAllListeners();
730
+ for (const removeAllListener of this._removeAllListeners) {
731
+ removeAllListener();
732
+ }
733
+ }
734
+ }
735
+
736
+ class TcpApplicationLayer extends AbstractApplicationLayer {
737
+ constructor(physicalLayer) {
738
+ super();
739
+ Object.defineProperty(this, "_transactionId", {
740
+ enumerable: true,
741
+ configurable: true,
742
+ writable: true,
743
+ value: 1
744
+ });
745
+ Object.defineProperty(this, "_removeAllListeners", {
746
+ enumerable: true,
747
+ configurable: true,
748
+ writable: true,
749
+ value: []
750
+ });
751
+ const handleData = (data, response) => {
752
+ const frame = this.framing(data);
753
+ if (frame) {
754
+ this.emit('framing', frame, response);
755
+ }
756
+ };
757
+ physicalLayer.on('data', handleData);
758
+ this._removeAllListeners.push(() => {
759
+ physicalLayer.removeListener('data', handleData);
760
+ });
761
+ }
762
+ framing(buffer) {
763
+ if (buffer.length >= 8) {
764
+ if (buffer[2] === 0 && buffer[3] === 0 && buffer.readUInt16BE(4) === buffer.length - 6) {
765
+ return {
766
+ transaction: buffer.readUInt16BE(0),
767
+ unit: buffer[6],
768
+ fc: buffer[7],
769
+ data: Array.from(buffer.subarray(8)),
770
+ buffer,
771
+ };
772
+ }
773
+ }
774
+ }
775
+ encode(data) {
776
+ var _a;
777
+ const buffer = Buffer.alloc(data.data.length + 8);
778
+ buffer.writeUInt16BE((_a = data.transaction) !== null && _a !== void 0 ? _a : this._transactionId, 0);
779
+ buffer.writeUInt16BE(0, 2);
780
+ buffer.writeUInt16BE(data.data.length + 2, 4);
781
+ buffer.writeUInt8(data.unit, 6);
782
+ buffer.writeUInt8(data.fc, 7);
783
+ data.data.forEach((num, index) => {
784
+ buffer.writeUInt8(num, 8 + index);
785
+ });
786
+ this._transactionId = (this._transactionId + 1) % 256 || 1;
787
+ return buffer;
788
+ }
789
+ destroy() {
790
+ this.removeAllListeners();
791
+ for (const removeAllListener of this._removeAllListeners) {
792
+ removeAllListener();
793
+ }
794
+ }
795
+ }
796
+
797
+ /******************************************************************************
798
+ Copyright (c) Microsoft Corporation.
799
+
800
+ Permission to use, copy, modify, and/or distribute this software for any
801
+ purpose with or without fee is hereby granted.
802
+
803
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
804
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
805
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
806
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
807
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
808
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
809
+ PERFORMANCE OF THIS SOFTWARE.
810
+ ***************************************************************************** */
811
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
812
+
813
+
814
+ function __awaiter(thisArg, _arguments, P, generator) {
815
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
816
+ return new (P || (P = Promise))(function (resolve, reject) {
817
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
818
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
819
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
820
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
821
+ });
822
+ }
823
+
824
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
825
+ var e = new Error(message);
826
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
827
+ };
828
+
829
+ class ModbusMaster extends EventEmitter {
830
+ get isOpen() {
831
+ return this.physicalLayer.isOpen;
832
+ }
833
+ get destroyed() {
834
+ return this.physicalLayer.destroyed;
835
+ }
836
+ constructor(applicationLayer, physicalLayer, timeout = 1000) {
837
+ super();
838
+ Object.defineProperty(this, "applicationLayer", {
839
+ enumerable: true,
840
+ configurable: true,
841
+ writable: true,
842
+ value: applicationLayer
843
+ });
844
+ Object.defineProperty(this, "physicalLayer", {
845
+ enumerable: true,
846
+ configurable: true,
847
+ writable: true,
848
+ value: physicalLayer
849
+ });
850
+ Object.defineProperty(this, "timeout", {
851
+ enumerable: true,
852
+ configurable: true,
853
+ writable: true,
854
+ value: timeout
855
+ });
856
+ Object.defineProperty(this, "_responses", {
857
+ enumerable: true,
858
+ configurable: true,
859
+ writable: true,
860
+ value: new Set()
861
+ });
862
+ Object.defineProperty(this, "writeFC1", {
863
+ enumerable: true,
864
+ configurable: true,
865
+ writable: true,
866
+ value: void 0
867
+ });
868
+ Object.defineProperty(this, "writeFC2", {
869
+ enumerable: true,
870
+ configurable: true,
871
+ writable: true,
872
+ value: void 0
873
+ });
874
+ Object.defineProperty(this, "writeFC3", {
875
+ enumerable: true,
876
+ configurable: true,
877
+ writable: true,
878
+ value: void 0
879
+ });
880
+ Object.defineProperty(this, "writeFC4", {
881
+ enumerable: true,
882
+ configurable: true,
883
+ writable: true,
884
+ value: void 0
885
+ });
886
+ Object.defineProperty(this, "writeFC5", {
887
+ enumerable: true,
888
+ configurable: true,
889
+ writable: true,
890
+ value: void 0
891
+ });
892
+ Object.defineProperty(this, "writeFC6", {
893
+ enumerable: true,
894
+ configurable: true,
895
+ writable: true,
896
+ value: void 0
897
+ });
898
+ Object.defineProperty(this, "writeFC15", {
899
+ enumerable: true,
900
+ configurable: true,
901
+ writable: true,
902
+ value: void 0
903
+ });
904
+ Object.defineProperty(this, "writeFC16", {
905
+ enumerable: true,
906
+ configurable: true,
907
+ writable: true,
908
+ value: void 0
909
+ });
910
+ Object.defineProperty(this, "handleFC17", {
911
+ enumerable: true,
912
+ configurable: true,
913
+ writable: true,
914
+ value: void 0
915
+ });
916
+ Object.defineProperty(this, "handleFC22", {
917
+ enumerable: true,
918
+ configurable: true,
919
+ writable: true,
920
+ value: void 0
921
+ });
922
+ Object.defineProperty(this, "handleFC23", {
923
+ enumerable: true,
924
+ configurable: true,
925
+ writable: true,
926
+ value: void 0
927
+ });
928
+ Object.defineProperty(this, "handleFC43_14", {
929
+ enumerable: true,
930
+ configurable: true,
931
+ writable: true,
932
+ value: void 0
933
+ });
934
+ this.writeFC1 = this.readCoils;
935
+ this.writeFC2 = this.readDiscreteInputs;
936
+ this.writeFC3 = this.readHoldingRegisters;
937
+ this.writeFC4 = this.readInputRegisters;
938
+ this.writeFC5 = this.writeSingleCoil;
939
+ this.writeFC6 = this.writeSingleRegister;
940
+ this.writeFC15 = this.writeMultipleCoils;
941
+ this.writeFC16 = this.writeMultipleRegisters;
942
+ this.handleFC17 = this.reportServerId;
943
+ this.handleFC22 = this.maskWriteRegister;
944
+ this.handleFC23 = this.readAndWriteMultipleRegisters;
945
+ this.handleFC43_14 = this.readDeviceIdentification;
946
+ applicationLayer.on('framing', (frame) => __awaiter(this, void 0, void 0, function* () {
947
+ for (const response of this._responses) {
948
+ response(frame);
949
+ }
950
+ }));
951
+ physicalLayer.on('error', (error) => {
952
+ this.emit('error', error);
953
+ });
954
+ physicalLayer.on('close', () => {
955
+ this.emit('close');
956
+ });
957
+ }
958
+ waitResponse(timeout, cb) {
959
+ return new Promise((resolve, reject) => {
960
+ const tid = setTimeout(() => {
961
+ this._responses.delete(response);
962
+ reject('Timeout');
963
+ }, timeout);
964
+ const response = (frame) => {
965
+ const data = cb(frame);
966
+ if (typeof data !== 'undefined') {
967
+ clearTimeout(tid);
968
+ this._responses.delete(response);
969
+ resolve({
970
+ transaction: frame.transaction,
971
+ unit: frame.unit,
972
+ fc: frame.fc,
973
+ data,
974
+ buffer: frame.buffer,
975
+ });
976
+ }
977
+ };
978
+ this._responses.add(response);
979
+ });
980
+ }
981
+ writeFC1Or2(unit, fc, address, length, timeout) {
982
+ const bufferTx = Buffer.alloc(4);
983
+ bufferTx.writeUInt16BE(address, 0);
984
+ bufferTx.writeUInt16BE(length, 2);
985
+ this.physicalLayer.write(this.applicationLayer.encode({
986
+ unit,
987
+ fc,
988
+ data: Array.from(bufferTx),
989
+ }));
990
+ if (unit !== 0) {
991
+ return this.waitResponse(timeout, (frame) => {
992
+ const byteCount = Math.ceil(length / 8);
993
+ if (frame.unit === unit && frame.fc === fc && frame.data.length === 1 + byteCount && frame.data[0] === byteCount) {
994
+ return Array.from({ length }).map((_, index) => (frame.data[1 + ~~(index / 8)] & (1 << index % 8)) > 0);
995
+ }
996
+ });
997
+ }
998
+ }
999
+ readCoils(unit, address, length, timeout = this.timeout) {
1000
+ return this.writeFC1Or2(unit, 0x01, address, length, timeout);
1001
+ }
1002
+ readDiscreteInputs(unit, address, length, timeout = this.timeout) {
1003
+ return this.writeFC1Or2(unit, 0x02, address, length, timeout);
1004
+ }
1005
+ writeFC3Or4(unit, fc, address, length, timeout) {
1006
+ const bufferTx = Buffer.alloc(4);
1007
+ bufferTx.writeUInt16BE(address, 0);
1008
+ bufferTx.writeUInt16BE(length, 2);
1009
+ this.physicalLayer.write(this.applicationLayer.encode({
1010
+ unit,
1011
+ fc,
1012
+ data: Array.from(bufferTx),
1013
+ }));
1014
+ if (unit !== 0) {
1015
+ return this.waitResponse(timeout, (frame) => {
1016
+ const byteCount = length * 2;
1017
+ if (frame.unit === unit && frame.fc === fc && frame.data.length === 1 + byteCount && frame.data[0] === byteCount) {
1018
+ const bufferRx = Buffer.from(frame.data.slice(1));
1019
+ return Array.from({ length }).map((_, index) => bufferRx.readUInt16BE(index * 2));
1020
+ }
1021
+ });
1022
+ }
1023
+ }
1024
+ readHoldingRegisters(unit, address, length, timeout = this.timeout) {
1025
+ return this.writeFC3Or4(unit, 0x03, address, length, timeout);
1026
+ }
1027
+ readInputRegisters(unit, address, length, timeout = this.timeout) {
1028
+ return this.writeFC3Or4(unit, 0x04, address, length, timeout);
1029
+ }
1030
+ writeSingleCoil(unit, address, value, timeout = this.timeout) {
1031
+ const fc = 0x05;
1032
+ const bufferTx = Buffer.alloc(4);
1033
+ bufferTx.writeUInt16BE(address, 0);
1034
+ bufferTx.writeUInt16BE(value ? 0xff00 : 0x0000, 2);
1035
+ this.physicalLayer.write(this.applicationLayer.encode({
1036
+ unit,
1037
+ fc,
1038
+ data: Array.from(bufferTx),
1039
+ }));
1040
+ if (unit !== 0) {
1041
+ return this.waitResponse(timeout, (frame) => {
1042
+ if (frame.unit === unit &&
1043
+ frame.fc === fc &&
1044
+ frame.data.length === bufferTx.length &&
1045
+ frame.data.every((v, i) => v === bufferTx[i])) {
1046
+ return value;
1047
+ }
1048
+ });
1049
+ }
1050
+ }
1051
+ writeSingleRegister(unit, address, value, timeout = this.timeout) {
1052
+ const fc = 0x06;
1053
+ const bufferTx = Buffer.alloc(4);
1054
+ bufferTx.writeUInt16BE(address, 0);
1055
+ bufferTx.writeUInt16BE(value, 2);
1056
+ this.physicalLayer.write(this.applicationLayer.encode({
1057
+ unit,
1058
+ fc,
1059
+ data: Array.from(bufferTx),
1060
+ }));
1061
+ if (unit !== 0) {
1062
+ return this.waitResponse(timeout, (frame) => {
1063
+ if (frame.unit === unit &&
1064
+ frame.fc === fc &&
1065
+ frame.data.length === bufferTx.length &&
1066
+ frame.data.every((v, i) => v === bufferTx[i])) {
1067
+ return value;
1068
+ }
1069
+ });
1070
+ }
1071
+ }
1072
+ writeMultipleCoils(unit, address, value, timeout = this.timeout) {
1073
+ const fc = 0x0f;
1074
+ const byteCount = Math.ceil(value.length / 8);
1075
+ const bufferTx = Buffer.alloc(5 + byteCount);
1076
+ bufferTx.writeUInt16BE(address, 0);
1077
+ bufferTx.writeUInt16BE(value.length, 2);
1078
+ bufferTx.writeUInt8(byteCount, 4);
1079
+ value.forEach((v, i) => {
1080
+ if (v) {
1081
+ bufferTx[5 + ~~(i / 8)] |= 1 << i % 8;
1082
+ }
1083
+ });
1084
+ this.physicalLayer.write(this.applicationLayer.encode({
1085
+ unit,
1086
+ fc,
1087
+ data: Array.from(bufferTx),
1088
+ }));
1089
+ if (unit !== 0) {
1090
+ return this.waitResponse(timeout, (frame) => {
1091
+ if (frame.unit === unit && frame.fc === fc && frame.data.length === 4 && frame.data.every((v, i) => v === bufferTx[i])) {
1092
+ return value;
1093
+ }
1094
+ });
1095
+ }
1096
+ }
1097
+ writeMultipleRegisters(unit, address, value, timeout = this.timeout) {
1098
+ const fc = 0x10;
1099
+ const byteCount = value.length * 2;
1100
+ const bufferTx = Buffer.alloc(5 + byteCount);
1101
+ bufferTx.writeUInt16BE(address, 0);
1102
+ bufferTx.writeUInt16BE(value.length, 2);
1103
+ bufferTx.writeUInt8(byteCount, 4);
1104
+ value.forEach((v, i) => {
1105
+ bufferTx.writeUInt16BE(v, 5 + i * 2);
1106
+ });
1107
+ this.physicalLayer.write(this.applicationLayer.encode({
1108
+ unit,
1109
+ fc,
1110
+ data: Array.from(bufferTx),
1111
+ }));
1112
+ if (unit !== 0) {
1113
+ return this.waitResponse(timeout, (frame) => {
1114
+ if (frame.unit === unit && frame.fc === fc && frame.data.length === 4 && frame.data.every((v, i) => v === bufferTx[i])) {
1115
+ return value;
1116
+ }
1117
+ });
1118
+ }
1119
+ }
1120
+ reportServerId(unit, timeout = this.timeout) {
1121
+ const fc = 0x11;
1122
+ this.physicalLayer.write(this.applicationLayer.encode({
1123
+ unit,
1124
+ fc,
1125
+ data: [],
1126
+ }));
1127
+ if (unit !== 0) {
1128
+ return this.waitResponse(timeout, (frame) => {
1129
+ if (frame.unit === unit && frame.fc === fc && frame.data.length >= 3) {
1130
+ const byteCount = frame.data[0];
1131
+ if (frame.data.length - 1 === byteCount) {
1132
+ return {
1133
+ serverId: frame.data[1],
1134
+ runIndicatorStatus: frame.data[2] === 0xff,
1135
+ additionalData: frame.data.slice(3),
1136
+ };
1137
+ }
1138
+ }
1139
+ });
1140
+ }
1141
+ }
1142
+ maskWriteRegister(unit, address, andMask, orMask, timeout = this.timeout) {
1143
+ const fc = 0x16;
1144
+ const bufferTx = Buffer.alloc(6);
1145
+ bufferTx.writeUInt16BE(address, 0);
1146
+ bufferTx.writeUInt16BE(andMask, 2);
1147
+ bufferTx.writeUInt16BE(orMask, 4);
1148
+ this.physicalLayer.write(this.applicationLayer.encode({
1149
+ unit,
1150
+ fc,
1151
+ data: Array.from(bufferTx),
1152
+ }));
1153
+ if (unit !== 0) {
1154
+ return this.waitResponse(timeout, (frame) => {
1155
+ if (frame.unit === unit && frame.fc === fc && frame.data.length === 6 && frame.data.every((v, i) => v === bufferTx[i])) {
1156
+ return { andMask, orMask };
1157
+ }
1158
+ });
1159
+ }
1160
+ }
1161
+ readAndWriteMultipleRegisters(unit, read, write, timeout = this.timeout) {
1162
+ const fc = 0x17;
1163
+ const byteCount = write.value.length * 2;
1164
+ const bufferTx = Buffer.alloc(9 + byteCount);
1165
+ bufferTx.writeUInt16BE(read.address, 0);
1166
+ bufferTx.writeUInt16BE(read.length, 2);
1167
+ bufferTx.writeUInt16BE(write.address, 4);
1168
+ bufferTx.writeUInt16BE(write.value.length, 6);
1169
+ bufferTx.writeUInt8(byteCount, 8);
1170
+ write.value.forEach((v, i) => {
1171
+ bufferTx.writeUInt16BE(v, 9 + i * 2);
1172
+ });
1173
+ this.physicalLayer.write(this.applicationLayer.encode({
1174
+ unit,
1175
+ fc,
1176
+ data: Array.from(bufferTx),
1177
+ }));
1178
+ if (unit !== 0) {
1179
+ return this.waitResponse(timeout, (frame) => {
1180
+ if (frame.unit === unit && frame.fc === fc && frame.data.length === 1 + byteCount && frame.data[0] === byteCount) {
1181
+ const bufferRx = Buffer.from(frame.data.slice(1));
1182
+ return Array.from({ length: read.length }).map((_, index) => bufferRx.readUInt16BE(index * 2));
1183
+ }
1184
+ });
1185
+ }
1186
+ }
1187
+ readDeviceIdentification(unit, readDeviceIDCode, objectId, timeout = this.timeout) {
1188
+ const fc = 0x2b;
1189
+ this.physicalLayer.write(this.applicationLayer.encode({
1190
+ unit,
1191
+ fc,
1192
+ data: [0x0e, readDeviceIDCode, objectId],
1193
+ }));
1194
+ if (unit !== 0) {
1195
+ return this.waitResponse(timeout, (frame) => {
1196
+ if (frame.unit === unit &&
1197
+ frame.fc === fc &&
1198
+ frame.data.length >= 6 &&
1199
+ frame.data[0] === 0x0e &&
1200
+ frame.data[1] === readDeviceIDCode) {
1201
+ const conformityLevel = frame.data[2];
1202
+ const moreFollows = frame.data[3] === 0xff;
1203
+ const nextObjectId = frame.data[4];
1204
+ const objectLength = frame.data[5];
1205
+ const objects = [];
1206
+ let object = [];
1207
+ for (const v of frame.data.slice(6)) {
1208
+ switch (object.length) {
1209
+ case 0:
1210
+ case 1: {
1211
+ object.push(v);
1212
+ break;
1213
+ }
1214
+ case 2: {
1215
+ object.push([v]);
1216
+ break;
1217
+ }
1218
+ case 3: {
1219
+ object[2].push(v);
1220
+ break;
1221
+ }
1222
+ }
1223
+ if (object.length === 3 && object[1] === object[2].length) {
1224
+ objects.push({ id: object[0], value: Buffer.from(object[2]).toString() });
1225
+ object = [];
1226
+ }
1227
+ }
1228
+ if (objects.length === objectLength) {
1229
+ return {
1230
+ readDeviceIDCode,
1231
+ conformityLevel,
1232
+ moreFollows,
1233
+ nextObjectId,
1234
+ objects,
1235
+ };
1236
+ }
1237
+ }
1238
+ });
1239
+ }
1240
+ }
1241
+ open(...args) {
1242
+ return this.physicalLayer.open(...args);
1243
+ }
1244
+ close() {
1245
+ return this.physicalLayer.close();
1246
+ }
1247
+ destroy() {
1248
+ this.removeAllListeners();
1249
+ this.applicationLayer.destroy();
1250
+ return this.physicalLayer.destroy();
1251
+ }
1252
+ }
1253
+
1254
+ class ModbusSlave extends EventEmitter {
1255
+ get isOpen() {
1256
+ return this.physicalLayer.isOpen;
1257
+ }
1258
+ get destroyed() {
1259
+ return this.physicalLayer.destroyed;
1260
+ }
1261
+ constructor(model, applicationLayer, physicalLayer) {
1262
+ super();
1263
+ Object.defineProperty(this, "model", {
1264
+ enumerable: true,
1265
+ configurable: true,
1266
+ writable: true,
1267
+ value: model
1268
+ });
1269
+ Object.defineProperty(this, "applicationLayer", {
1270
+ enumerable: true,
1271
+ configurable: true,
1272
+ writable: true,
1273
+ value: applicationLayer
1274
+ });
1275
+ Object.defineProperty(this, "physicalLayer", {
1276
+ enumerable: true,
1277
+ configurable: true,
1278
+ writable: true,
1279
+ value: physicalLayer
1280
+ });
1281
+ Object.defineProperty(this, "unit", {
1282
+ enumerable: true,
1283
+ configurable: true,
1284
+ writable: true,
1285
+ value: 1
1286
+ });
1287
+ if (typeof model.unit !== 'undefined') {
1288
+ this.unit = model.unit;
1289
+ }
1290
+ applicationLayer.on('framing', (frame, _response) => __awaiter(this, void 0, void 0, function* () {
1291
+ if (!(frame.unit === 0x00 || frame.unit === this.unit)) {
1292
+ return;
1293
+ }
1294
+ const response = frame.unit === 0x00 ? () => Promise.resolve() : _response;
1295
+ if (model.interceptor) {
1296
+ try {
1297
+ const data = yield model.interceptor(frame.fc, frame.data);
1298
+ if (data) {
1299
+ response(this.applicationLayer.encode(Object.assign(Object.assign({}, frame), { data })));
1300
+ return;
1301
+ }
1302
+ }
1303
+ catch (error) {
1304
+ this.responseError(frame, response, error);
1305
+ return;
1306
+ }
1307
+ }
1308
+ switch (frame.fc) {
1309
+ case 0x01: {
1310
+ this.handleFC1(frame, response);
1311
+ break;
1312
+ }
1313
+ case 0x02: {
1314
+ this.handleFC2(frame, response);
1315
+ break;
1316
+ }
1317
+ case 0x03: {
1318
+ this.handleFC3(frame, response);
1319
+ break;
1320
+ }
1321
+ case 0x04: {
1322
+ this.handleFC4(frame, response);
1323
+ break;
1324
+ }
1325
+ case 0x05: {
1326
+ this.handleFC5(frame, response);
1327
+ break;
1328
+ }
1329
+ case 0x06: {
1330
+ this.handleFC6(frame, response);
1331
+ break;
1332
+ }
1333
+ case 0x0f: {
1334
+ this.handleFC15(frame, response);
1335
+ break;
1336
+ }
1337
+ case 0x10: {
1338
+ this.handleFC16(frame, response);
1339
+ break;
1340
+ }
1341
+ case 0x11: {
1342
+ this.handleFC17(frame, response);
1343
+ break;
1344
+ }
1345
+ case 0x16: {
1346
+ this.handleFC22(frame, response);
1347
+ break;
1348
+ }
1349
+ case 0x17: {
1350
+ this.handleFC23(frame, response);
1351
+ break;
1352
+ }
1353
+ case 0x2b: {
1354
+ this.handleFC43_14(frame, response);
1355
+ break;
1356
+ }
1357
+ default: {
1358
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_FUNCTION));
1359
+ break;
1360
+ }
1361
+ }
1362
+ }));
1363
+ physicalLayer.on('error', (error) => {
1364
+ this.emit('error', error);
1365
+ });
1366
+ physicalLayer.on('close', () => {
1367
+ this.emit('close');
1368
+ });
1369
+ }
1370
+ handleFC1(frame, response) {
1371
+ var _a;
1372
+ if (frame.data.length === 4) {
1373
+ if (this.model.readCoils) {
1374
+ const bufferRx = Buffer.from(frame.data);
1375
+ const address = bufferRx.readUInt16BE(0);
1376
+ const length = bufferRx.readUInt16BE(2);
1377
+ if (length >= 0x0001 && length <= 0x07d0) {
1378
+ if (checkRange([address, address + length], (_a = this.model.addressRange) === null || _a === void 0 ? void 0 : _a.coils)) {
1379
+ Promise.resolve(this.model.readCoils(address, length))
1380
+ .then((coils) => {
1381
+ const bufferTx = Buffer.alloc(Math.ceil(length / 8));
1382
+ coils.forEach((coil, index) => {
1383
+ if (coil) {
1384
+ bufferTx[~~(index / 8)] |= 1 << index % 8;
1385
+ }
1386
+ });
1387
+ response(this.applicationLayer.encode(Object.assign(Object.assign({}, frame), { data: [bufferTx.length].concat(Array.from(bufferTx)) })));
1388
+ })
1389
+ .catch((error) => {
1390
+ this.responseError(frame, response, error);
1391
+ });
1392
+ }
1393
+ else {
1394
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_DATA_ADDRESS));
1395
+ }
1396
+ }
1397
+ else {
1398
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_DATA_VALUE));
1399
+ }
1400
+ }
1401
+ else {
1402
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_FUNCTION));
1403
+ }
1404
+ }
1405
+ }
1406
+ handleFC2(frame, response) {
1407
+ var _a;
1408
+ if (frame.data.length === 4) {
1409
+ if (this.model.readDiscreteInputs) {
1410
+ const bufferRx = Buffer.from(frame.data);
1411
+ const address = bufferRx.readUInt16BE(0);
1412
+ const length = bufferRx.readUInt16BE(2);
1413
+ if (length >= 0x0001 && length <= 0x07d0) {
1414
+ if (checkRange([address, address + length], (_a = this.model.addressRange) === null || _a === void 0 ? void 0 : _a.discreteInputs)) {
1415
+ Promise.resolve(this.model.readDiscreteInputs(address, length))
1416
+ .then((discreteInputs) => {
1417
+ const bufferTx = Buffer.alloc(Math.ceil(length / 8));
1418
+ discreteInputs.forEach((discreteInput, index) => {
1419
+ if (discreteInput) {
1420
+ bufferTx[~~(index / 8)] |= 1 << index % 8;
1421
+ }
1422
+ });
1423
+ response(this.applicationLayer.encode(Object.assign(Object.assign({}, frame), { data: [bufferTx.length].concat(Array.from(bufferTx)) })));
1424
+ })
1425
+ .catch((error) => {
1426
+ this.responseError(frame, response, error);
1427
+ });
1428
+ }
1429
+ else {
1430
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_DATA_ADDRESS));
1431
+ }
1432
+ }
1433
+ else {
1434
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_DATA_VALUE));
1435
+ }
1436
+ }
1437
+ else {
1438
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_FUNCTION));
1439
+ }
1440
+ }
1441
+ }
1442
+ handleFC3(frame, response) {
1443
+ var _a;
1444
+ if (frame.data.length === 4) {
1445
+ if (this.model.readHoldingRegisters) {
1446
+ const bufferRx = Buffer.from(frame.data);
1447
+ const address = bufferRx.readUInt16BE(0);
1448
+ const length = bufferRx.readUInt16BE(2);
1449
+ if (length >= 0x0001 && length <= 0x007d) {
1450
+ if (checkRange([address, address + length], (_a = this.model.addressRange) === null || _a === void 0 ? void 0 : _a.holdingRegisters)) {
1451
+ Promise.resolve(this.model.readHoldingRegisters(address, length))
1452
+ .then((registers) => {
1453
+ const bufferTx = Buffer.alloc(length * 2);
1454
+ registers.forEach((register, index) => {
1455
+ bufferTx.writeUInt16BE(register, index * 2);
1456
+ });
1457
+ response(this.applicationLayer.encode(Object.assign(Object.assign({}, frame), { data: [bufferTx.length].concat(Array.from(bufferTx)) })));
1458
+ })
1459
+ .catch((error) => {
1460
+ this.responseError(frame, response, error);
1461
+ });
1462
+ }
1463
+ else {
1464
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_DATA_ADDRESS));
1465
+ }
1466
+ }
1467
+ else {
1468
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_DATA_VALUE));
1469
+ }
1470
+ }
1471
+ else {
1472
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_FUNCTION));
1473
+ }
1474
+ }
1475
+ }
1476
+ handleFC4(frame, response) {
1477
+ var _a;
1478
+ if (frame.data.length === 4) {
1479
+ if (this.model.readInputRegisters) {
1480
+ const bufferRx = Buffer.from(frame.data);
1481
+ const address = bufferRx.readUInt16BE(0);
1482
+ const length = bufferRx.readUInt16BE(2);
1483
+ if (length >= 0x0001 && length <= 0x007d) {
1484
+ if (checkRange([address, address + length], (_a = this.model.addressRange) === null || _a === void 0 ? void 0 : _a.inputRegisters)) {
1485
+ Promise.resolve(this.model.readInputRegisters(address, length))
1486
+ .then((registers) => {
1487
+ const bufferTx = Buffer.alloc(length * 2);
1488
+ registers.forEach((register, index) => {
1489
+ bufferTx.writeUInt16BE(register, index * 2);
1490
+ });
1491
+ response(this.applicationLayer.encode(Object.assign(Object.assign({}, frame), { data: [bufferTx.length].concat(Array.from(bufferTx)) })));
1492
+ })
1493
+ .catch((error) => {
1494
+ this.responseError(frame, response, error);
1495
+ });
1496
+ }
1497
+ else {
1498
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_DATA_ADDRESS));
1499
+ }
1500
+ }
1501
+ else {
1502
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_DATA_VALUE));
1503
+ }
1504
+ }
1505
+ else {
1506
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_FUNCTION));
1507
+ }
1508
+ }
1509
+ }
1510
+ handleFC5(frame, response) {
1511
+ var _a;
1512
+ if (frame.data.length === 4) {
1513
+ if (this.model.writeSingleCoil) {
1514
+ const bufferRx = Buffer.from(frame.data);
1515
+ const address = bufferRx.readUInt16BE(0);
1516
+ const value = bufferRx.readUInt16BE(2);
1517
+ if (value === 0x0000 || value === 0xff00) {
1518
+ if (checkRange(address, (_a = this.model.addressRange) === null || _a === void 0 ? void 0 : _a.coils)) {
1519
+ Promise.resolve(this.model.writeSingleCoil(address, value === 0xff00))
1520
+ .then(() => {
1521
+ response(this.applicationLayer.encode(frame));
1522
+ })
1523
+ .catch((error) => {
1524
+ this.responseError(frame, response, error);
1525
+ });
1526
+ }
1527
+ else {
1528
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_DATA_ADDRESS));
1529
+ }
1530
+ }
1531
+ else {
1532
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_DATA_VALUE));
1533
+ }
1534
+ }
1535
+ else {
1536
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_FUNCTION));
1537
+ }
1538
+ }
1539
+ }
1540
+ handleFC6(frame, response) {
1541
+ var _a;
1542
+ if (frame.data.length === 4) {
1543
+ if (this.model.writeSingleRegister) {
1544
+ const bufferRx = Buffer.from(frame.data);
1545
+ const address = bufferRx.readUInt16BE(0);
1546
+ const value = bufferRx.readUInt16BE(2);
1547
+ if (value >= 0x0000 && value <= 0xffff) {
1548
+ if (checkRange(address, (_a = this.model.addressRange) === null || _a === void 0 ? void 0 : _a.holdingRegisters)) {
1549
+ Promise.resolve(this.model.writeSingleRegister(address, value))
1550
+ .then(() => {
1551
+ response(this.applicationLayer.encode(frame));
1552
+ })
1553
+ .catch((error) => {
1554
+ this.responseError(frame, response, error);
1555
+ });
1556
+ }
1557
+ else {
1558
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_DATA_ADDRESS));
1559
+ }
1560
+ }
1561
+ else {
1562
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_DATA_VALUE));
1563
+ }
1564
+ }
1565
+ else {
1566
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_FUNCTION));
1567
+ }
1568
+ }
1569
+ }
1570
+ handleFC15(frame, response) {
1571
+ var _a;
1572
+ if (frame.data.length > 5 && frame.data.length === 5 + frame.data[4]) {
1573
+ if (this.model.writeMultipleCoils || this.model.writeSingleCoil) {
1574
+ const bufferRx = Buffer.from(frame.data);
1575
+ const address = bufferRx.readUInt16BE(0);
1576
+ const length = bufferRx.readUInt16BE(2);
1577
+ const byteCount = bufferRx[4];
1578
+ if (length >= 0x0001 && length <= 0x07b0 && byteCount === Math.ceil(length / 8)) {
1579
+ if (checkRange([address, address + length], (_a = this.model.addressRange) === null || _a === void 0 ? void 0 : _a.coils)) {
1580
+ const value = Array.from({ length }).map((_, index) => (bufferRx[5 + ~~(index / 8)] & (1 << index % 8)) > 0);
1581
+ Promise.resolve(this.model.writeMultipleCoils
1582
+ ? this.model.writeMultipleCoils(address, value)
1583
+ : Promise.all(value.map((v, i) => this.model.writeSingleCoil(address + i, v))))
1584
+ .then(() => {
1585
+ response(this.applicationLayer.encode(Object.assign(Object.assign({}, frame), { data: Array.from(bufferRx).slice(0, 4) })));
1586
+ })
1587
+ .catch((error) => {
1588
+ this.responseError(frame, response, error);
1589
+ });
1590
+ }
1591
+ else {
1592
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_DATA_ADDRESS));
1593
+ }
1594
+ }
1595
+ else {
1596
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_DATA_VALUE));
1597
+ }
1598
+ }
1599
+ else {
1600
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_FUNCTION));
1601
+ }
1602
+ }
1603
+ }
1604
+ handleFC16(frame, response) {
1605
+ var _a;
1606
+ if (frame.data.length > 5 && frame.data.length === 5 + frame.data[4]) {
1607
+ if (this.model.writeMultipleRegisters || this.model.writeSingleRegister) {
1608
+ const bufferRx = Buffer.from(frame.data);
1609
+ const address = bufferRx.readUInt16BE(0);
1610
+ const length = bufferRx.readUInt16BE(2);
1611
+ const byteCount = bufferRx[4];
1612
+ if (length >= 0x0001 && length <= 0x007b && byteCount === length * 2) {
1613
+ if (checkRange([address, address + length], (_a = this.model.addressRange) === null || _a === void 0 ? void 0 : _a.holdingRegisters)) {
1614
+ const value = Array.from({ length }).map((_, index) => bufferRx.readUInt16BE(5 + index * 2));
1615
+ Promise.resolve(this.model.writeMultipleRegisters
1616
+ ? this.model.writeMultipleRegisters(address, value)
1617
+ : Promise.all(value.map((v, i) => this.model.writeSingleRegister(address + i, v))))
1618
+ .then(() => {
1619
+ response(this.applicationLayer.encode(Object.assign(Object.assign({}, frame), { data: Array.from(bufferRx).slice(0, 4) })));
1620
+ })
1621
+ .catch((error) => {
1622
+ this.responseError(frame, response, error);
1623
+ });
1624
+ }
1625
+ else {
1626
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_DATA_ADDRESS));
1627
+ }
1628
+ }
1629
+ else {
1630
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_DATA_VALUE));
1631
+ }
1632
+ }
1633
+ else {
1634
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_FUNCTION));
1635
+ }
1636
+ }
1637
+ }
1638
+ handleFC17(frame, response) {
1639
+ if (frame.data.length === 0) {
1640
+ if (this.model.reportServerId) {
1641
+ Promise.resolve(this.model.reportServerId())
1642
+ .then(({ serverId = this.unit, runIndicatorStatus = true, additionalData = [] }) => {
1643
+ response(this.applicationLayer.encode(Object.assign(Object.assign({}, frame), { data: [2 + additionalData.length, serverId, runIndicatorStatus ? 0xff : 0x00].concat(additionalData) })));
1644
+ })
1645
+ .catch((error) => {
1646
+ this.responseError(frame, response, error);
1647
+ });
1648
+ }
1649
+ else {
1650
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_FUNCTION));
1651
+ }
1652
+ }
1653
+ }
1654
+ handleFC22(frame, response) {
1655
+ var _a;
1656
+ if (frame.data.length === 6) {
1657
+ if (this.model.maskWriteRegister || (this.model.readHoldingRegisters && this.model.writeSingleRegister)) {
1658
+ const bufferRx = Buffer.from(frame.data);
1659
+ const address = bufferRx.readUInt16BE(0);
1660
+ const andMask = bufferRx.readUInt16BE(2);
1661
+ const orMask = bufferRx.readUInt16BE(4);
1662
+ if (checkRange(address, (_a = this.model.addressRange) === null || _a === void 0 ? void 0 : _a.holdingRegisters)) {
1663
+ Promise.resolve(this.model.maskWriteRegister
1664
+ ? this.model.maskWriteRegister(address, andMask, orMask)
1665
+ : Promise.resolve(this.model.readHoldingRegisters(address, 1)).then(([value]) => {
1666
+ return Promise.resolve(this.model.writeSingleRegister(address, (value & andMask) | (orMask & (~andMask & 0xff))));
1667
+ }))
1668
+ .then(() => {
1669
+ response(this.applicationLayer.encode(frame));
1670
+ })
1671
+ .catch((error) => {
1672
+ this.responseError(frame, response, error);
1673
+ });
1674
+ }
1675
+ else {
1676
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_DATA_ADDRESS));
1677
+ }
1678
+ }
1679
+ else {
1680
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_FUNCTION));
1681
+ }
1682
+ }
1683
+ }
1684
+ handleFC23(frame, response) {
1685
+ var _a;
1686
+ if (frame.data.length > 9 && frame.data.length === 9 + frame.data[8]) {
1687
+ if (this.model.readHoldingRegisters && (this.model.writeMultipleRegisters || this.model.writeSingleRegister)) {
1688
+ const bufferRx = Buffer.from(frame.data);
1689
+ const address = {
1690
+ read: bufferRx.readUInt16BE(0),
1691
+ write: bufferRx.readUInt16BE(4),
1692
+ };
1693
+ const length = {
1694
+ read: bufferRx.readUInt16BE(2),
1695
+ write: bufferRx.readUInt16BE(6),
1696
+ };
1697
+ const byteCount = bufferRx[8];
1698
+ if (length.read >= 0x0001 &&
1699
+ length.read <= 0x007d &&
1700
+ length.write >= 0x0001 &&
1701
+ length.write <= 0x0079 &&
1702
+ byteCount === length.write * 2) {
1703
+ if (checkRange([address.read, address.read + length.read, address.write, address.write + length.write], (_a = this.model.addressRange) === null || _a === void 0 ? void 0 : _a.holdingRegisters)) {
1704
+ const value = Array.from({ length: length.write }).map((_, index) => bufferRx.readUInt16BE(9 + index * 2));
1705
+ Promise.resolve(this.model.writeMultipleRegisters
1706
+ ? this.model.writeMultipleRegisters(address.write, value)
1707
+ : Promise.all(value.map((v, i) => this.model.writeSingleRegister(address.write + i, v))))
1708
+ .then(() => Promise.resolve(this.model.readHoldingRegisters(address.read, length.read)))
1709
+ .then((registers) => {
1710
+ const bufferTx = Buffer.alloc(length.read * 2);
1711
+ registers.forEach((register, index) => {
1712
+ bufferTx.writeUInt16BE(register, index * 2);
1713
+ });
1714
+ response(this.applicationLayer.encode(Object.assign(Object.assign({}, frame), { data: [bufferTx.length].concat(Array.from(bufferTx)) })));
1715
+ })
1716
+ .catch((error) => {
1717
+ this.responseError(frame, response, error);
1718
+ });
1719
+ }
1720
+ else {
1721
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_DATA_ADDRESS));
1722
+ }
1723
+ }
1724
+ else {
1725
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_DATA_VALUE));
1726
+ }
1727
+ }
1728
+ else {
1729
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_FUNCTION));
1730
+ }
1731
+ }
1732
+ }
1733
+ handleFC43_14(frame, response) {
1734
+ if (frame.data.length === 3) {
1735
+ if (frame.data[0] === 0x0e && this.model.readDeviceIdentification) {
1736
+ const readDeviceIDCode = frame.data[1];
1737
+ let objectID = frame.data[2];
1738
+ switch (readDeviceIDCode) {
1739
+ case 0x01: {
1740
+ if (objectID > 0x02 || (objectID > 0x06 && objectID < 0x80)) {
1741
+ objectID = 0x00;
1742
+ }
1743
+ break;
1744
+ }
1745
+ case 0x02: {
1746
+ if (objectID >= 0x80 || (objectID > 0x06 && objectID < 0x80)) {
1747
+ objectID = 0x00;
1748
+ }
1749
+ break;
1750
+ }
1751
+ case 0x03: {
1752
+ if (objectID > 0x06 && objectID < 0x80) {
1753
+ objectID = 0x00;
1754
+ }
1755
+ break;
1756
+ }
1757
+ case 0x04: {
1758
+ if (objectID > 0x06 && objectID < 0x80) {
1759
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_DATA_ADDRESS));
1760
+ return;
1761
+ }
1762
+ break;
1763
+ }
1764
+ default: {
1765
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_DATA_VALUE));
1766
+ return;
1767
+ }
1768
+ }
1769
+ Promise.resolve(this.model.readDeviceIdentification())
1770
+ .then((identification) => {
1771
+ const objects = new Map([
1772
+ [0x00, 'null'],
1773
+ [0x01, 'null'],
1774
+ [0x02, 'null'],
1775
+ ]);
1776
+ for (const [key, value] of Object.entries(identification)) {
1777
+ const id = parseInt(key);
1778
+ if (!isNaN(id) && id >= 0 && id <= 255) {
1779
+ objects.set(id, value);
1780
+ }
1781
+ }
1782
+ if (!objects.has(objectID)) {
1783
+ if (readDeviceIDCode === 0x04) {
1784
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_DATA_ADDRESS));
1785
+ return;
1786
+ }
1787
+ objectID = 0x00;
1788
+ }
1789
+ const ids = [];
1790
+ let totalLength = 10;
1791
+ let lastID = 0;
1792
+ let conformityLevel = 0x81;
1793
+ for (const [id, value] of objects.entries()) {
1794
+ if (id < 0x00 || (id >= 0x07 && id <= 0x7f) || id > 0xff) {
1795
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.SERVER_DEVICE_FAILURE));
1796
+ return;
1797
+ }
1798
+ if (id > 0x02) {
1799
+ conformityLevel = 0x82;
1800
+ }
1801
+ if (id > 0x80) {
1802
+ conformityLevel = 0x83;
1803
+ }
1804
+ if (objectID > id) {
1805
+ continue;
1806
+ }
1807
+ if (value.length > 245) {
1808
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.SERVER_DEVICE_FAILURE));
1809
+ return;
1810
+ }
1811
+ if (lastID !== 0) {
1812
+ continue;
1813
+ }
1814
+ if (value.length + 2 > 253 - totalLength) {
1815
+ if (lastID === 0) {
1816
+ lastID = id;
1817
+ }
1818
+ }
1819
+ else {
1820
+ totalLength += value.length + 2;
1821
+ ids.push(id);
1822
+ if (readDeviceIDCode === 0x04) {
1823
+ break;
1824
+ }
1825
+ }
1826
+ }
1827
+ ids.sort((a, b) => a - b);
1828
+ response(this.applicationLayer.encode(Object.assign(Object.assign({}, frame), { data: [0x0e, readDeviceIDCode, conformityLevel, lastID === 0 ? 0x00 : 0xff, lastID, ids.length].concat(ids
1829
+ .map((id) => {
1830
+ const value = objects.get(id);
1831
+ return [id, value.length].concat(Array.from(Buffer.from(value)));
1832
+ })
1833
+ .flat()) })));
1834
+ })
1835
+ .catch((error) => {
1836
+ this.responseError(frame, response, error);
1837
+ });
1838
+ }
1839
+ else {
1840
+ this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_FUNCTION));
1841
+ }
1842
+ }
1843
+ }
1844
+ responseError(frame, response, error) {
1845
+ response(this.applicationLayer.encode(Object.assign(Object.assign({}, frame), { fc: frame.fc | 0x80, data: [getCodeByError(error)] })));
1846
+ }
1847
+ open(...args) {
1848
+ return this.physicalLayer.open(...args);
1849
+ }
1850
+ close() {
1851
+ return this.physicalLayer.close();
1852
+ }
1853
+ destroy() {
1854
+ this.removeAllListeners();
1855
+ this.applicationLayer.destroy();
1856
+ return this.physicalLayer.destroy();
1857
+ }
1858
+ }
1859
+
1860
+ exports.AbstractApplicationLayer = AbstractApplicationLayer;
1861
+ exports.AbstractPhysicalLayer = AbstractPhysicalLayer;
1862
+ exports.AsciiApplicationLayer = AsciiApplicationLayer;
1863
+ exports.ModbusMaster = ModbusMaster;
1864
+ exports.ModbusSlave = ModbusSlave;
1865
+ exports.RtuApplicationLayer = RtuApplicationLayer;
1866
+ exports.SerialPhysicalLayer = SerialPhysicalLayer;
1867
+ exports.TcpApplicationLayer = TcpApplicationLayer;
1868
+ exports.TcpClientPhysicalLayer = TcpClientPhysicalLayer;
1869
+ exports.TcpServerPhysicalLayer = TcpServerPhysicalLayer;
1870
+ exports.UdpPhysicalLayer = UdpPhysicalLayer;
1871
+ exports.getCodeByError = getCodeByError;
1872
+ exports.getErrorByCode = getErrorByCode;