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