njs-modbus 1.0.1 → 1.2.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/README.md +2 -2
- package/dist/index.cjs +53 -26
- package/dist/index.d.ts +9 -9
- package/dist/index.mjs +53 -26
- package/dist/src/layers/application/rtu-application-layer.d.ts +1 -4
- package/dist/src/layers/physical/abstract-physical-layer.d.ts +1 -0
- package/dist/src/layers/physical/serial-physical-layer.d.ts +2 -0
- package/dist/src/slave/slave.d.ts +5 -5
- package/dist/src/utils/checkRange.d.ts +1 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -69,7 +69,7 @@ npm install njs-modbus
|
|
|
69
69
|
import { SerialPhysicalLayer, RtuApplicationLayer, ModbusMaster } from 'njs-modbus';
|
|
70
70
|
|
|
71
71
|
const physicalLayer = new SerialPhysicalLayer({ path: 'COM1', baudRate: 9600, dataBits: 8, parity: 'none', stopBits: 1 });
|
|
72
|
-
const applicationLayer = new RtuApplicationLayer(physicalLayer
|
|
72
|
+
const applicationLayer = new RtuApplicationLayer(physicalLayer);
|
|
73
73
|
|
|
74
74
|
const modbusMaster = new ModbusMaster(applicationLayer, physicalLayer);
|
|
75
75
|
|
|
@@ -99,7 +99,7 @@ const MB_SERVER = {
|
|
|
99
99
|
};
|
|
100
100
|
|
|
101
101
|
const physicalLayer = new SerialPhysicalLayer({ path: 'COM1', baudRate: 9600, dataBits: 8, parity: 'none', stopBits: 1 });
|
|
102
|
-
const applicationLayer = new RtuApplicationLayer(physicalLayer
|
|
102
|
+
const applicationLayer = new RtuApplicationLayer(physicalLayer);
|
|
103
103
|
|
|
104
104
|
const modbusSlave = new ModbusSlave(
|
|
105
105
|
{
|
package/dist/index.cjs
CHANGED
|
@@ -38,6 +38,9 @@ class SerialPhysicalLayer extends AbstractPhysicalLayer {
|
|
|
38
38
|
get destroyed() {
|
|
39
39
|
return this._destroyed;
|
|
40
40
|
}
|
|
41
|
+
get baudRate() {
|
|
42
|
+
return this._baudRate;
|
|
43
|
+
}
|
|
41
44
|
constructor(options) {
|
|
42
45
|
super();
|
|
43
46
|
Object.defineProperty(this, "TYPE", {
|
|
@@ -58,7 +61,14 @@ class SerialPhysicalLayer extends AbstractPhysicalLayer {
|
|
|
58
61
|
writable: true,
|
|
59
62
|
value: false
|
|
60
63
|
});
|
|
64
|
+
Object.defineProperty(this, "_baudRate", {
|
|
65
|
+
enumerable: true,
|
|
66
|
+
configurable: true,
|
|
67
|
+
writable: true,
|
|
68
|
+
value: void 0
|
|
69
|
+
});
|
|
61
70
|
this._serialport = new serialport.SerialPort(Object.assign(Object.assign({}, options), { autoOpen: false }));
|
|
71
|
+
this._baudRate = options.baudRate;
|
|
62
72
|
}
|
|
63
73
|
open() {
|
|
64
74
|
if (this.destroyed) {
|
|
@@ -93,6 +103,7 @@ class SerialPhysicalLayer extends AbstractPhysicalLayer {
|
|
|
93
103
|
reject(error);
|
|
94
104
|
}
|
|
95
105
|
else {
|
|
106
|
+
this.emit('write', data);
|
|
96
107
|
resolve();
|
|
97
108
|
}
|
|
98
109
|
});
|
|
@@ -189,6 +200,7 @@ class TcpClientPhysicalLayer extends AbstractPhysicalLayer {
|
|
|
189
200
|
reject(error);
|
|
190
201
|
}
|
|
191
202
|
else {
|
|
203
|
+
this.emit('write', data);
|
|
192
204
|
resolve();
|
|
193
205
|
}
|
|
194
206
|
});
|
|
@@ -443,6 +455,7 @@ class UdpPhysicalLayer extends AbstractPhysicalLayer {
|
|
|
443
455
|
reject(error);
|
|
444
456
|
}
|
|
445
457
|
else {
|
|
458
|
+
this.emit('write', data);
|
|
446
459
|
resolve();
|
|
447
460
|
}
|
|
448
461
|
});
|
|
@@ -472,8 +485,22 @@ class AbstractApplicationLayer extends EventEmitter {
|
|
|
472
485
|
}
|
|
473
486
|
|
|
474
487
|
function checkRange(value, range) {
|
|
475
|
-
if (range
|
|
476
|
-
|
|
488
|
+
if (range) {
|
|
489
|
+
if (typeof range[0] === 'number' && typeof range[1] === 'number') {
|
|
490
|
+
if (range[0] < range[1]) {
|
|
491
|
+
return (Array.isArray(value) ? value : [value]).every((n) => n >= range[0] && n <= range[1]);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
else if (range.length > 0) {
|
|
495
|
+
for (const r of range) {
|
|
496
|
+
if (r[0] < r[1]) {
|
|
497
|
+
if ((Array.isArray(value) ? value : [value]).every((n) => n >= r[0] && n <= r[1])) {
|
|
498
|
+
return true;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
return false;
|
|
503
|
+
}
|
|
477
504
|
}
|
|
478
505
|
return true;
|
|
479
506
|
}
|
|
@@ -519,7 +546,7 @@ function lrc(data) {
|
|
|
519
546
|
}
|
|
520
547
|
|
|
521
548
|
class RtuApplicationLayer extends AbstractApplicationLayer {
|
|
522
|
-
constructor(physicalLayer,
|
|
549
|
+
constructor(physicalLayer, bitsBetweenFrames) {
|
|
523
550
|
super();
|
|
524
551
|
Object.defineProperty(this, "_timerThreePointFive", {
|
|
525
552
|
enumerable: true,
|
|
@@ -540,10 +567,10 @@ class RtuApplicationLayer extends AbstractApplicationLayer {
|
|
|
540
567
|
value: []
|
|
541
568
|
});
|
|
542
569
|
let threePointFiveT = 0;
|
|
543
|
-
if (physicalLayer.TYPE === 'SERIAL'
|
|
544
|
-
threePointFiveT = Math.ceil(
|
|
570
|
+
if (physicalLayer.TYPE === 'SERIAL') {
|
|
571
|
+
threePointFiveT = Math.ceil(physicalLayer.baudRate > 19200
|
|
545
572
|
? 1.8
|
|
546
|
-
: getThreePointFiveT(
|
|
573
|
+
: getThreePointFiveT(physicalLayer.baudRate, bitsBetweenFrames));
|
|
547
574
|
}
|
|
548
575
|
const handleData = (data, response) => {
|
|
549
576
|
this._bufferRx = Buffer.concat([this._bufferRx, data]);
|
|
@@ -1368,14 +1395,14 @@ class ModbusSlave extends EventEmitter {
|
|
|
1368
1395
|
});
|
|
1369
1396
|
}
|
|
1370
1397
|
handleFC1(frame, response) {
|
|
1371
|
-
var _a;
|
|
1398
|
+
var _a, _b;
|
|
1372
1399
|
if (frame.data.length === 4) {
|
|
1373
1400
|
if (this.model.readCoils) {
|
|
1374
1401
|
const bufferRx = Buffer.from(frame.data);
|
|
1375
1402
|
const address = bufferRx.readUInt16BE(0);
|
|
1376
1403
|
const length = bufferRx.readUInt16BE(2);
|
|
1377
1404
|
if (length >= 0x0001 && length <= 0x07d0) {
|
|
1378
|
-
if (checkRange([address, address + length], (_a = this.model.
|
|
1405
|
+
if (checkRange([address, address + length], (_b = (_a = this.model).getAddressRange) === null || _b === void 0 ? void 0 : _b.call(_a).coils)) {
|
|
1379
1406
|
Promise.resolve(this.model.readCoils(address, length))
|
|
1380
1407
|
.then((coils) => {
|
|
1381
1408
|
const bufferTx = Buffer.alloc(Math.ceil(length / 8));
|
|
@@ -1404,14 +1431,14 @@ class ModbusSlave extends EventEmitter {
|
|
|
1404
1431
|
}
|
|
1405
1432
|
}
|
|
1406
1433
|
handleFC2(frame, response) {
|
|
1407
|
-
var _a;
|
|
1434
|
+
var _a, _b;
|
|
1408
1435
|
if (frame.data.length === 4) {
|
|
1409
1436
|
if (this.model.readDiscreteInputs) {
|
|
1410
1437
|
const bufferRx = Buffer.from(frame.data);
|
|
1411
1438
|
const address = bufferRx.readUInt16BE(0);
|
|
1412
1439
|
const length = bufferRx.readUInt16BE(2);
|
|
1413
1440
|
if (length >= 0x0001 && length <= 0x07d0) {
|
|
1414
|
-
if (checkRange([address, address + length], (_a = this.model.
|
|
1441
|
+
if (checkRange([address, address + length], (_b = (_a = this.model).getAddressRange) === null || _b === void 0 ? void 0 : _b.call(_a).discreteInputs)) {
|
|
1415
1442
|
Promise.resolve(this.model.readDiscreteInputs(address, length))
|
|
1416
1443
|
.then((discreteInputs) => {
|
|
1417
1444
|
const bufferTx = Buffer.alloc(Math.ceil(length / 8));
|
|
@@ -1440,14 +1467,14 @@ class ModbusSlave extends EventEmitter {
|
|
|
1440
1467
|
}
|
|
1441
1468
|
}
|
|
1442
1469
|
handleFC3(frame, response) {
|
|
1443
|
-
var _a;
|
|
1470
|
+
var _a, _b;
|
|
1444
1471
|
if (frame.data.length === 4) {
|
|
1445
1472
|
if (this.model.readHoldingRegisters) {
|
|
1446
1473
|
const bufferRx = Buffer.from(frame.data);
|
|
1447
1474
|
const address = bufferRx.readUInt16BE(0);
|
|
1448
1475
|
const length = bufferRx.readUInt16BE(2);
|
|
1449
1476
|
if (length >= 0x0001 && length <= 0x007d) {
|
|
1450
|
-
if (checkRange([address, address + length], (_a = this.model.
|
|
1477
|
+
if (checkRange([address, address + length], (_b = (_a = this.model).getAddressRange) === null || _b === void 0 ? void 0 : _b.call(_a).holdingRegisters)) {
|
|
1451
1478
|
Promise.resolve(this.model.readHoldingRegisters(address, length))
|
|
1452
1479
|
.then((registers) => {
|
|
1453
1480
|
const bufferTx = Buffer.alloc(length * 2);
|
|
@@ -1474,14 +1501,14 @@ class ModbusSlave extends EventEmitter {
|
|
|
1474
1501
|
}
|
|
1475
1502
|
}
|
|
1476
1503
|
handleFC4(frame, response) {
|
|
1477
|
-
var _a;
|
|
1504
|
+
var _a, _b;
|
|
1478
1505
|
if (frame.data.length === 4) {
|
|
1479
1506
|
if (this.model.readInputRegisters) {
|
|
1480
1507
|
const bufferRx = Buffer.from(frame.data);
|
|
1481
1508
|
const address = bufferRx.readUInt16BE(0);
|
|
1482
1509
|
const length = bufferRx.readUInt16BE(2);
|
|
1483
1510
|
if (length >= 0x0001 && length <= 0x007d) {
|
|
1484
|
-
if (checkRange([address, address + length], (_a = this.model.
|
|
1511
|
+
if (checkRange([address, address + length], (_b = (_a = this.model).getAddressRange) === null || _b === void 0 ? void 0 : _b.call(_a).inputRegisters)) {
|
|
1485
1512
|
Promise.resolve(this.model.readInputRegisters(address, length))
|
|
1486
1513
|
.then((registers) => {
|
|
1487
1514
|
const bufferTx = Buffer.alloc(length * 2);
|
|
@@ -1508,14 +1535,14 @@ class ModbusSlave extends EventEmitter {
|
|
|
1508
1535
|
}
|
|
1509
1536
|
}
|
|
1510
1537
|
handleFC5(frame, response) {
|
|
1511
|
-
var _a;
|
|
1538
|
+
var _a, _b;
|
|
1512
1539
|
if (frame.data.length === 4) {
|
|
1513
1540
|
if (this.model.writeSingleCoil) {
|
|
1514
1541
|
const bufferRx = Buffer.from(frame.data);
|
|
1515
1542
|
const address = bufferRx.readUInt16BE(0);
|
|
1516
1543
|
const value = bufferRx.readUInt16BE(2);
|
|
1517
1544
|
if (value === 0x0000 || value === 0xff00) {
|
|
1518
|
-
if (checkRange(address, (_a = this.model.
|
|
1545
|
+
if (checkRange(address, (_b = (_a = this.model).getAddressRange) === null || _b === void 0 ? void 0 : _b.call(_a).coils)) {
|
|
1519
1546
|
Promise.resolve(this.model.writeSingleCoil(address, value === 0xff00))
|
|
1520
1547
|
.then(() => {
|
|
1521
1548
|
response(this.applicationLayer.encode(frame));
|
|
@@ -1538,14 +1565,14 @@ class ModbusSlave extends EventEmitter {
|
|
|
1538
1565
|
}
|
|
1539
1566
|
}
|
|
1540
1567
|
handleFC6(frame, response) {
|
|
1541
|
-
var _a;
|
|
1568
|
+
var _a, _b;
|
|
1542
1569
|
if (frame.data.length === 4) {
|
|
1543
1570
|
if (this.model.writeSingleRegister) {
|
|
1544
1571
|
const bufferRx = Buffer.from(frame.data);
|
|
1545
1572
|
const address = bufferRx.readUInt16BE(0);
|
|
1546
1573
|
const value = bufferRx.readUInt16BE(2);
|
|
1547
1574
|
if (value >= 0x0000 && value <= 0xffff) {
|
|
1548
|
-
if (checkRange(address, (_a = this.model.
|
|
1575
|
+
if (checkRange(address, (_b = (_a = this.model).getAddressRange) === null || _b === void 0 ? void 0 : _b.call(_a).holdingRegisters)) {
|
|
1549
1576
|
Promise.resolve(this.model.writeSingleRegister(address, value))
|
|
1550
1577
|
.then(() => {
|
|
1551
1578
|
response(this.applicationLayer.encode(frame));
|
|
@@ -1568,7 +1595,7 @@ class ModbusSlave extends EventEmitter {
|
|
|
1568
1595
|
}
|
|
1569
1596
|
}
|
|
1570
1597
|
handleFC15(frame, response) {
|
|
1571
|
-
var _a;
|
|
1598
|
+
var _a, _b;
|
|
1572
1599
|
if (frame.data.length > 5 && frame.data.length === 5 + frame.data[4]) {
|
|
1573
1600
|
if (this.model.writeMultipleCoils || this.model.writeSingleCoil) {
|
|
1574
1601
|
const bufferRx = Buffer.from(frame.data);
|
|
@@ -1576,7 +1603,7 @@ class ModbusSlave extends EventEmitter {
|
|
|
1576
1603
|
const length = bufferRx.readUInt16BE(2);
|
|
1577
1604
|
const byteCount = bufferRx[4];
|
|
1578
1605
|
if (length >= 0x0001 && length <= 0x07b0 && byteCount === Math.ceil(length / 8)) {
|
|
1579
|
-
if (checkRange([address, address + length], (_a = this.model.
|
|
1606
|
+
if (checkRange([address, address + length], (_b = (_a = this.model).getAddressRange) === null || _b === void 0 ? void 0 : _b.call(_a).coils)) {
|
|
1580
1607
|
const value = Array.from({ length }).map((_, index) => (bufferRx[5 + ~~(index / 8)] & (1 << index % 8)) > 0);
|
|
1581
1608
|
Promise.resolve(this.model.writeMultipleCoils
|
|
1582
1609
|
? this.model.writeMultipleCoils(address, value)
|
|
@@ -1602,7 +1629,7 @@ class ModbusSlave extends EventEmitter {
|
|
|
1602
1629
|
}
|
|
1603
1630
|
}
|
|
1604
1631
|
handleFC16(frame, response) {
|
|
1605
|
-
var _a;
|
|
1632
|
+
var _a, _b;
|
|
1606
1633
|
if (frame.data.length > 5 && frame.data.length === 5 + frame.data[4]) {
|
|
1607
1634
|
if (this.model.writeMultipleRegisters || this.model.writeSingleRegister) {
|
|
1608
1635
|
const bufferRx = Buffer.from(frame.data);
|
|
@@ -1610,7 +1637,7 @@ class ModbusSlave extends EventEmitter {
|
|
|
1610
1637
|
const length = bufferRx.readUInt16BE(2);
|
|
1611
1638
|
const byteCount = bufferRx[4];
|
|
1612
1639
|
if (length >= 0x0001 && length <= 0x007b && byteCount === length * 2) {
|
|
1613
|
-
if (checkRange([address, address + length], (_a = this.model.
|
|
1640
|
+
if (checkRange([address, address + length], (_b = (_a = this.model).getAddressRange) === null || _b === void 0 ? void 0 : _b.call(_a).holdingRegisters)) {
|
|
1614
1641
|
const value = Array.from({ length }).map((_, index) => bufferRx.readUInt16BE(5 + index * 2));
|
|
1615
1642
|
Promise.resolve(this.model.writeMultipleRegisters
|
|
1616
1643
|
? this.model.writeMultipleRegisters(address, value)
|
|
@@ -1652,14 +1679,14 @@ class ModbusSlave extends EventEmitter {
|
|
|
1652
1679
|
}
|
|
1653
1680
|
}
|
|
1654
1681
|
handleFC22(frame, response) {
|
|
1655
|
-
var _a;
|
|
1682
|
+
var _a, _b;
|
|
1656
1683
|
if (frame.data.length === 6) {
|
|
1657
1684
|
if (this.model.maskWriteRegister || (this.model.readHoldingRegisters && this.model.writeSingleRegister)) {
|
|
1658
1685
|
const bufferRx = Buffer.from(frame.data);
|
|
1659
1686
|
const address = bufferRx.readUInt16BE(0);
|
|
1660
1687
|
const andMask = bufferRx.readUInt16BE(2);
|
|
1661
1688
|
const orMask = bufferRx.readUInt16BE(4);
|
|
1662
|
-
if (checkRange(address, (_a = this.model.
|
|
1689
|
+
if (checkRange(address, (_b = (_a = this.model).getAddressRange) === null || _b === void 0 ? void 0 : _b.call(_a).holdingRegisters)) {
|
|
1663
1690
|
Promise.resolve(this.model.maskWriteRegister
|
|
1664
1691
|
? this.model.maskWriteRegister(address, andMask, orMask)
|
|
1665
1692
|
: Promise.resolve(this.model.readHoldingRegisters(address, 1)).then(([value]) => {
|
|
@@ -1682,7 +1709,7 @@ class ModbusSlave extends EventEmitter {
|
|
|
1682
1709
|
}
|
|
1683
1710
|
}
|
|
1684
1711
|
handleFC23(frame, response) {
|
|
1685
|
-
var _a;
|
|
1712
|
+
var _a, _b;
|
|
1686
1713
|
if (frame.data.length > 9 && frame.data.length === 9 + frame.data[8]) {
|
|
1687
1714
|
if (this.model.readHoldingRegisters && (this.model.writeMultipleRegisters || this.model.writeSingleRegister)) {
|
|
1688
1715
|
const bufferRx = Buffer.from(frame.data);
|
|
@@ -1700,7 +1727,7 @@ class ModbusSlave extends EventEmitter {
|
|
|
1700
1727
|
length.write >= 0x0001 &&
|
|
1701
1728
|
length.write <= 0x0079 &&
|
|
1702
1729
|
byteCount === length.write * 2) {
|
|
1703
|
-
if (checkRange([address.read, address.read + length.read, address.write, address.write + length.write], (_a = this.model.
|
|
1730
|
+
if (checkRange([address.read, address.read + length.read, address.write, address.write + length.write], (_b = (_a = this.model).getAddressRange) === null || _b === void 0 ? void 0 : _b.call(_a).holdingRegisters)) {
|
|
1704
1731
|
const value = Array.from({ length: length.write }).map((_, index) => bufferRx.readUInt16BE(9 + index * 2));
|
|
1705
1732
|
Promise.resolve(this.model.writeMultipleRegisters
|
|
1706
1733
|
? this.model.writeMultipleRegisters(address.write, value)
|
package/dist/index.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ declare function getCodeByError(err: Error): ErrorCode;
|
|
|
18
18
|
|
|
19
19
|
interface AbstractPhysicalLayerEvents {
|
|
20
20
|
data: [data: Buffer, response: (data: Buffer) => Promise<void>];
|
|
21
|
+
write: [data: Buffer];
|
|
21
22
|
error: [error: Error];
|
|
22
23
|
close: [];
|
|
23
24
|
}
|
|
@@ -60,8 +61,10 @@ declare class SerialPhysicalLayer extends AbstractPhysicalLayer {
|
|
|
60
61
|
TYPE: 'SERIAL' | 'NET';
|
|
61
62
|
private _serialport;
|
|
62
63
|
private _destroyed;
|
|
64
|
+
private _baudRate;
|
|
63
65
|
get isOpen(): boolean;
|
|
64
66
|
get destroyed(): boolean;
|
|
67
|
+
get baudRate(): number;
|
|
65
68
|
constructor(options: SerialPhysicalLayerOptions);
|
|
66
69
|
open(): Promise<void>;
|
|
67
70
|
write(data: Buffer): Promise<void>;
|
|
@@ -161,10 +164,7 @@ declare class RtuApplicationLayer extends AbstractApplicationLayer {
|
|
|
161
164
|
private _timerThreePointFive?;
|
|
162
165
|
private _bufferRx;
|
|
163
166
|
private _removeAllListeners;
|
|
164
|
-
constructor(physicalLayer: SerialPhysicalLayer | TcpServerPhysicalLayer | TcpClientPhysicalLayer | UdpPhysicalLayer,
|
|
165
|
-
baudRate: number;
|
|
166
|
-
bitsBetweenFrames?: number;
|
|
167
|
-
});
|
|
167
|
+
constructor(physicalLayer: SerialPhysicalLayer | TcpServerPhysicalLayer | TcpClientPhysicalLayer | UdpPhysicalLayer, bitsBetweenFrames?: number);
|
|
168
168
|
private framing;
|
|
169
169
|
encode(data: ApplicationDataUnit): Buffer;
|
|
170
170
|
destroy(): void;
|
|
@@ -298,11 +298,11 @@ interface ModbusSlaveModel {
|
|
|
298
298
|
readDeviceIdentification?: FConvertPromise<() => {
|
|
299
299
|
[index: number]: string;
|
|
300
300
|
}>;
|
|
301
|
-
|
|
302
|
-
discreteInputs?: [number, number];
|
|
303
|
-
coils?: [number, number];
|
|
304
|
-
inputRegisters?: [number, number];
|
|
305
|
-
holdingRegisters?: [number, number];
|
|
301
|
+
getAddressRange?: () => {
|
|
302
|
+
discreteInputs?: [number, number] | [number, number][];
|
|
303
|
+
coils?: [number, number] | [number, number][];
|
|
304
|
+
inputRegisters?: [number, number] | [number, number][];
|
|
305
|
+
holdingRegisters?: [number, number] | [number, number][];
|
|
306
306
|
};
|
|
307
307
|
}
|
|
308
308
|
interface ModbusSlaveEvents {
|
package/dist/index.mjs
CHANGED
|
@@ -36,6 +36,9 @@ class SerialPhysicalLayer extends AbstractPhysicalLayer {
|
|
|
36
36
|
get destroyed() {
|
|
37
37
|
return this._destroyed;
|
|
38
38
|
}
|
|
39
|
+
get baudRate() {
|
|
40
|
+
return this._baudRate;
|
|
41
|
+
}
|
|
39
42
|
constructor(options) {
|
|
40
43
|
super();
|
|
41
44
|
Object.defineProperty(this, "TYPE", {
|
|
@@ -56,7 +59,14 @@ class SerialPhysicalLayer extends AbstractPhysicalLayer {
|
|
|
56
59
|
writable: true,
|
|
57
60
|
value: false
|
|
58
61
|
});
|
|
62
|
+
Object.defineProperty(this, "_baudRate", {
|
|
63
|
+
enumerable: true,
|
|
64
|
+
configurable: true,
|
|
65
|
+
writable: true,
|
|
66
|
+
value: void 0
|
|
67
|
+
});
|
|
59
68
|
this._serialport = new SerialPort(Object.assign(Object.assign({}, options), { autoOpen: false }));
|
|
69
|
+
this._baudRate = options.baudRate;
|
|
60
70
|
}
|
|
61
71
|
open() {
|
|
62
72
|
if (this.destroyed) {
|
|
@@ -91,6 +101,7 @@ class SerialPhysicalLayer extends AbstractPhysicalLayer {
|
|
|
91
101
|
reject(error);
|
|
92
102
|
}
|
|
93
103
|
else {
|
|
104
|
+
this.emit('write', data);
|
|
94
105
|
resolve();
|
|
95
106
|
}
|
|
96
107
|
});
|
|
@@ -187,6 +198,7 @@ class TcpClientPhysicalLayer extends AbstractPhysicalLayer {
|
|
|
187
198
|
reject(error);
|
|
188
199
|
}
|
|
189
200
|
else {
|
|
201
|
+
this.emit('write', data);
|
|
190
202
|
resolve();
|
|
191
203
|
}
|
|
192
204
|
});
|
|
@@ -441,6 +453,7 @@ class UdpPhysicalLayer extends AbstractPhysicalLayer {
|
|
|
441
453
|
reject(error);
|
|
442
454
|
}
|
|
443
455
|
else {
|
|
456
|
+
this.emit('write', data);
|
|
444
457
|
resolve();
|
|
445
458
|
}
|
|
446
459
|
});
|
|
@@ -470,8 +483,22 @@ class AbstractApplicationLayer extends EventEmitter {
|
|
|
470
483
|
}
|
|
471
484
|
|
|
472
485
|
function checkRange(value, range) {
|
|
473
|
-
if (range
|
|
474
|
-
|
|
486
|
+
if (range) {
|
|
487
|
+
if (typeof range[0] === 'number' && typeof range[1] === 'number') {
|
|
488
|
+
if (range[0] < range[1]) {
|
|
489
|
+
return (Array.isArray(value) ? value : [value]).every((n) => n >= range[0] && n <= range[1]);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
else if (range.length > 0) {
|
|
493
|
+
for (const r of range) {
|
|
494
|
+
if (r[0] < r[1]) {
|
|
495
|
+
if ((Array.isArray(value) ? value : [value]).every((n) => n >= r[0] && n <= r[1])) {
|
|
496
|
+
return true;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
return false;
|
|
501
|
+
}
|
|
475
502
|
}
|
|
476
503
|
return true;
|
|
477
504
|
}
|
|
@@ -517,7 +544,7 @@ function lrc(data) {
|
|
|
517
544
|
}
|
|
518
545
|
|
|
519
546
|
class RtuApplicationLayer extends AbstractApplicationLayer {
|
|
520
|
-
constructor(physicalLayer,
|
|
547
|
+
constructor(physicalLayer, bitsBetweenFrames) {
|
|
521
548
|
super();
|
|
522
549
|
Object.defineProperty(this, "_timerThreePointFive", {
|
|
523
550
|
enumerable: true,
|
|
@@ -538,10 +565,10 @@ class RtuApplicationLayer extends AbstractApplicationLayer {
|
|
|
538
565
|
value: []
|
|
539
566
|
});
|
|
540
567
|
let threePointFiveT = 0;
|
|
541
|
-
if (physicalLayer.TYPE === 'SERIAL'
|
|
542
|
-
threePointFiveT = Math.ceil(
|
|
568
|
+
if (physicalLayer.TYPE === 'SERIAL') {
|
|
569
|
+
threePointFiveT = Math.ceil(physicalLayer.baudRate > 19200
|
|
543
570
|
? 1.8
|
|
544
|
-
: getThreePointFiveT(
|
|
571
|
+
: getThreePointFiveT(physicalLayer.baudRate, bitsBetweenFrames));
|
|
545
572
|
}
|
|
546
573
|
const handleData = (data, response) => {
|
|
547
574
|
this._bufferRx = Buffer.concat([this._bufferRx, data]);
|
|
@@ -1366,14 +1393,14 @@ class ModbusSlave extends EventEmitter {
|
|
|
1366
1393
|
});
|
|
1367
1394
|
}
|
|
1368
1395
|
handleFC1(frame, response) {
|
|
1369
|
-
var _a;
|
|
1396
|
+
var _a, _b;
|
|
1370
1397
|
if (frame.data.length === 4) {
|
|
1371
1398
|
if (this.model.readCoils) {
|
|
1372
1399
|
const bufferRx = Buffer.from(frame.data);
|
|
1373
1400
|
const address = bufferRx.readUInt16BE(0);
|
|
1374
1401
|
const length = bufferRx.readUInt16BE(2);
|
|
1375
1402
|
if (length >= 0x0001 && length <= 0x07d0) {
|
|
1376
|
-
if (checkRange([address, address + length], (_a = this.model.
|
|
1403
|
+
if (checkRange([address, address + length], (_b = (_a = this.model).getAddressRange) === null || _b === void 0 ? void 0 : _b.call(_a).coils)) {
|
|
1377
1404
|
Promise.resolve(this.model.readCoils(address, length))
|
|
1378
1405
|
.then((coils) => {
|
|
1379
1406
|
const bufferTx = Buffer.alloc(Math.ceil(length / 8));
|
|
@@ -1402,14 +1429,14 @@ class ModbusSlave extends EventEmitter {
|
|
|
1402
1429
|
}
|
|
1403
1430
|
}
|
|
1404
1431
|
handleFC2(frame, response) {
|
|
1405
|
-
var _a;
|
|
1432
|
+
var _a, _b;
|
|
1406
1433
|
if (frame.data.length === 4) {
|
|
1407
1434
|
if (this.model.readDiscreteInputs) {
|
|
1408
1435
|
const bufferRx = Buffer.from(frame.data);
|
|
1409
1436
|
const address = bufferRx.readUInt16BE(0);
|
|
1410
1437
|
const length = bufferRx.readUInt16BE(2);
|
|
1411
1438
|
if (length >= 0x0001 && length <= 0x07d0) {
|
|
1412
|
-
if (checkRange([address, address + length], (_a = this.model.
|
|
1439
|
+
if (checkRange([address, address + length], (_b = (_a = this.model).getAddressRange) === null || _b === void 0 ? void 0 : _b.call(_a).discreteInputs)) {
|
|
1413
1440
|
Promise.resolve(this.model.readDiscreteInputs(address, length))
|
|
1414
1441
|
.then((discreteInputs) => {
|
|
1415
1442
|
const bufferTx = Buffer.alloc(Math.ceil(length / 8));
|
|
@@ -1438,14 +1465,14 @@ class ModbusSlave extends EventEmitter {
|
|
|
1438
1465
|
}
|
|
1439
1466
|
}
|
|
1440
1467
|
handleFC3(frame, response) {
|
|
1441
|
-
var _a;
|
|
1468
|
+
var _a, _b;
|
|
1442
1469
|
if (frame.data.length === 4) {
|
|
1443
1470
|
if (this.model.readHoldingRegisters) {
|
|
1444
1471
|
const bufferRx = Buffer.from(frame.data);
|
|
1445
1472
|
const address = bufferRx.readUInt16BE(0);
|
|
1446
1473
|
const length = bufferRx.readUInt16BE(2);
|
|
1447
1474
|
if (length >= 0x0001 && length <= 0x007d) {
|
|
1448
|
-
if (checkRange([address, address + length], (_a = this.model.
|
|
1475
|
+
if (checkRange([address, address + length], (_b = (_a = this.model).getAddressRange) === null || _b === void 0 ? void 0 : _b.call(_a).holdingRegisters)) {
|
|
1449
1476
|
Promise.resolve(this.model.readHoldingRegisters(address, length))
|
|
1450
1477
|
.then((registers) => {
|
|
1451
1478
|
const bufferTx = Buffer.alloc(length * 2);
|
|
@@ -1472,14 +1499,14 @@ class ModbusSlave extends EventEmitter {
|
|
|
1472
1499
|
}
|
|
1473
1500
|
}
|
|
1474
1501
|
handleFC4(frame, response) {
|
|
1475
|
-
var _a;
|
|
1502
|
+
var _a, _b;
|
|
1476
1503
|
if (frame.data.length === 4) {
|
|
1477
1504
|
if (this.model.readInputRegisters) {
|
|
1478
1505
|
const bufferRx = Buffer.from(frame.data);
|
|
1479
1506
|
const address = bufferRx.readUInt16BE(0);
|
|
1480
1507
|
const length = bufferRx.readUInt16BE(2);
|
|
1481
1508
|
if (length >= 0x0001 && length <= 0x007d) {
|
|
1482
|
-
if (checkRange([address, address + length], (_a = this.model.
|
|
1509
|
+
if (checkRange([address, address + length], (_b = (_a = this.model).getAddressRange) === null || _b === void 0 ? void 0 : _b.call(_a).inputRegisters)) {
|
|
1483
1510
|
Promise.resolve(this.model.readInputRegisters(address, length))
|
|
1484
1511
|
.then((registers) => {
|
|
1485
1512
|
const bufferTx = Buffer.alloc(length * 2);
|
|
@@ -1506,14 +1533,14 @@ class ModbusSlave extends EventEmitter {
|
|
|
1506
1533
|
}
|
|
1507
1534
|
}
|
|
1508
1535
|
handleFC5(frame, response) {
|
|
1509
|
-
var _a;
|
|
1536
|
+
var _a, _b;
|
|
1510
1537
|
if (frame.data.length === 4) {
|
|
1511
1538
|
if (this.model.writeSingleCoil) {
|
|
1512
1539
|
const bufferRx = Buffer.from(frame.data);
|
|
1513
1540
|
const address = bufferRx.readUInt16BE(0);
|
|
1514
1541
|
const value = bufferRx.readUInt16BE(2);
|
|
1515
1542
|
if (value === 0x0000 || value === 0xff00) {
|
|
1516
|
-
if (checkRange(address, (_a = this.model.
|
|
1543
|
+
if (checkRange(address, (_b = (_a = this.model).getAddressRange) === null || _b === void 0 ? void 0 : _b.call(_a).coils)) {
|
|
1517
1544
|
Promise.resolve(this.model.writeSingleCoil(address, value === 0xff00))
|
|
1518
1545
|
.then(() => {
|
|
1519
1546
|
response(this.applicationLayer.encode(frame));
|
|
@@ -1536,14 +1563,14 @@ class ModbusSlave extends EventEmitter {
|
|
|
1536
1563
|
}
|
|
1537
1564
|
}
|
|
1538
1565
|
handleFC6(frame, response) {
|
|
1539
|
-
var _a;
|
|
1566
|
+
var _a, _b;
|
|
1540
1567
|
if (frame.data.length === 4) {
|
|
1541
1568
|
if (this.model.writeSingleRegister) {
|
|
1542
1569
|
const bufferRx = Buffer.from(frame.data);
|
|
1543
1570
|
const address = bufferRx.readUInt16BE(0);
|
|
1544
1571
|
const value = bufferRx.readUInt16BE(2);
|
|
1545
1572
|
if (value >= 0x0000 && value <= 0xffff) {
|
|
1546
|
-
if (checkRange(address, (_a = this.model.
|
|
1573
|
+
if (checkRange(address, (_b = (_a = this.model).getAddressRange) === null || _b === void 0 ? void 0 : _b.call(_a).holdingRegisters)) {
|
|
1547
1574
|
Promise.resolve(this.model.writeSingleRegister(address, value))
|
|
1548
1575
|
.then(() => {
|
|
1549
1576
|
response(this.applicationLayer.encode(frame));
|
|
@@ -1566,7 +1593,7 @@ class ModbusSlave extends EventEmitter {
|
|
|
1566
1593
|
}
|
|
1567
1594
|
}
|
|
1568
1595
|
handleFC15(frame, response) {
|
|
1569
|
-
var _a;
|
|
1596
|
+
var _a, _b;
|
|
1570
1597
|
if (frame.data.length > 5 && frame.data.length === 5 + frame.data[4]) {
|
|
1571
1598
|
if (this.model.writeMultipleCoils || this.model.writeSingleCoil) {
|
|
1572
1599
|
const bufferRx = Buffer.from(frame.data);
|
|
@@ -1574,7 +1601,7 @@ class ModbusSlave extends EventEmitter {
|
|
|
1574
1601
|
const length = bufferRx.readUInt16BE(2);
|
|
1575
1602
|
const byteCount = bufferRx[4];
|
|
1576
1603
|
if (length >= 0x0001 && length <= 0x07b0 && byteCount === Math.ceil(length / 8)) {
|
|
1577
|
-
if (checkRange([address, address + length], (_a = this.model.
|
|
1604
|
+
if (checkRange([address, address + length], (_b = (_a = this.model).getAddressRange) === null || _b === void 0 ? void 0 : _b.call(_a).coils)) {
|
|
1578
1605
|
const value = Array.from({ length }).map((_, index) => (bufferRx[5 + ~~(index / 8)] & (1 << index % 8)) > 0);
|
|
1579
1606
|
Promise.resolve(this.model.writeMultipleCoils
|
|
1580
1607
|
? this.model.writeMultipleCoils(address, value)
|
|
@@ -1600,7 +1627,7 @@ class ModbusSlave extends EventEmitter {
|
|
|
1600
1627
|
}
|
|
1601
1628
|
}
|
|
1602
1629
|
handleFC16(frame, response) {
|
|
1603
|
-
var _a;
|
|
1630
|
+
var _a, _b;
|
|
1604
1631
|
if (frame.data.length > 5 && frame.data.length === 5 + frame.data[4]) {
|
|
1605
1632
|
if (this.model.writeMultipleRegisters || this.model.writeSingleRegister) {
|
|
1606
1633
|
const bufferRx = Buffer.from(frame.data);
|
|
@@ -1608,7 +1635,7 @@ class ModbusSlave extends EventEmitter {
|
|
|
1608
1635
|
const length = bufferRx.readUInt16BE(2);
|
|
1609
1636
|
const byteCount = bufferRx[4];
|
|
1610
1637
|
if (length >= 0x0001 && length <= 0x007b && byteCount === length * 2) {
|
|
1611
|
-
if (checkRange([address, address + length], (_a = this.model.
|
|
1638
|
+
if (checkRange([address, address + length], (_b = (_a = this.model).getAddressRange) === null || _b === void 0 ? void 0 : _b.call(_a).holdingRegisters)) {
|
|
1612
1639
|
const value = Array.from({ length }).map((_, index) => bufferRx.readUInt16BE(5 + index * 2));
|
|
1613
1640
|
Promise.resolve(this.model.writeMultipleRegisters
|
|
1614
1641
|
? this.model.writeMultipleRegisters(address, value)
|
|
@@ -1650,14 +1677,14 @@ class ModbusSlave extends EventEmitter {
|
|
|
1650
1677
|
}
|
|
1651
1678
|
}
|
|
1652
1679
|
handleFC22(frame, response) {
|
|
1653
|
-
var _a;
|
|
1680
|
+
var _a, _b;
|
|
1654
1681
|
if (frame.data.length === 6) {
|
|
1655
1682
|
if (this.model.maskWriteRegister || (this.model.readHoldingRegisters && this.model.writeSingleRegister)) {
|
|
1656
1683
|
const bufferRx = Buffer.from(frame.data);
|
|
1657
1684
|
const address = bufferRx.readUInt16BE(0);
|
|
1658
1685
|
const andMask = bufferRx.readUInt16BE(2);
|
|
1659
1686
|
const orMask = bufferRx.readUInt16BE(4);
|
|
1660
|
-
if (checkRange(address, (_a = this.model.
|
|
1687
|
+
if (checkRange(address, (_b = (_a = this.model).getAddressRange) === null || _b === void 0 ? void 0 : _b.call(_a).holdingRegisters)) {
|
|
1661
1688
|
Promise.resolve(this.model.maskWriteRegister
|
|
1662
1689
|
? this.model.maskWriteRegister(address, andMask, orMask)
|
|
1663
1690
|
: Promise.resolve(this.model.readHoldingRegisters(address, 1)).then(([value]) => {
|
|
@@ -1680,7 +1707,7 @@ class ModbusSlave extends EventEmitter {
|
|
|
1680
1707
|
}
|
|
1681
1708
|
}
|
|
1682
1709
|
handleFC23(frame, response) {
|
|
1683
|
-
var _a;
|
|
1710
|
+
var _a, _b;
|
|
1684
1711
|
if (frame.data.length > 9 && frame.data.length === 9 + frame.data[8]) {
|
|
1685
1712
|
if (this.model.readHoldingRegisters && (this.model.writeMultipleRegisters || this.model.writeSingleRegister)) {
|
|
1686
1713
|
const bufferRx = Buffer.from(frame.data);
|
|
@@ -1698,7 +1725,7 @@ class ModbusSlave extends EventEmitter {
|
|
|
1698
1725
|
length.write >= 0x0001 &&
|
|
1699
1726
|
length.write <= 0x0079 &&
|
|
1700
1727
|
byteCount === length.write * 2) {
|
|
1701
|
-
if (checkRange([address.read, address.read + length.read, address.write, address.write + length.write], (_a = this.model.
|
|
1728
|
+
if (checkRange([address.read, address.read + length.read, address.write, address.write + length.write], (_b = (_a = this.model).getAddressRange) === null || _b === void 0 ? void 0 : _b.call(_a).holdingRegisters)) {
|
|
1702
1729
|
const value = Array.from({ length: length.write }).map((_, index) => bufferRx.readUInt16BE(9 + index * 2));
|
|
1703
1730
|
Promise.resolve(this.model.writeMultipleRegisters
|
|
1704
1731
|
? this.model.writeMultipleRegisters(address.write, value)
|
|
@@ -6,10 +6,7 @@ export declare class RtuApplicationLayer extends AbstractApplicationLayer {
|
|
|
6
6
|
private _timerThreePointFive?;
|
|
7
7
|
private _bufferRx;
|
|
8
8
|
private _removeAllListeners;
|
|
9
|
-
constructor(physicalLayer: SerialPhysicalLayer | TcpServerPhysicalLayer | TcpClientPhysicalLayer | UdpPhysicalLayer,
|
|
10
|
-
baudRate: number;
|
|
11
|
-
bitsBetweenFrames?: number;
|
|
12
|
-
});
|
|
9
|
+
constructor(physicalLayer: SerialPhysicalLayer | TcpServerPhysicalLayer | TcpClientPhysicalLayer | UdpPhysicalLayer, bitsBetweenFrames?: number);
|
|
13
10
|
private framing;
|
|
14
11
|
encode(data: ApplicationDataUnit): Buffer;
|
|
15
12
|
destroy(): void;
|
|
@@ -28,8 +28,10 @@ export declare class SerialPhysicalLayer extends AbstractPhysicalLayer {
|
|
|
28
28
|
TYPE: 'SERIAL' | 'NET';
|
|
29
29
|
private _serialport;
|
|
30
30
|
private _destroyed;
|
|
31
|
+
private _baudRate;
|
|
31
32
|
get isOpen(): boolean;
|
|
32
33
|
get destroyed(): boolean;
|
|
34
|
+
get baudRate(): number;
|
|
33
35
|
constructor(options: SerialPhysicalLayerOptions);
|
|
34
36
|
open(): Promise<void>;
|
|
35
37
|
write(data: Buffer): Promise<void>;
|
|
@@ -33,11 +33,11 @@ export interface ModbusSlaveModel {
|
|
|
33
33
|
readDeviceIdentification?: FConvertPromise<() => {
|
|
34
34
|
[index: number]: string;
|
|
35
35
|
}>;
|
|
36
|
-
|
|
37
|
-
discreteInputs?: [number, number];
|
|
38
|
-
coils?: [number, number];
|
|
39
|
-
inputRegisters?: [number, number];
|
|
40
|
-
holdingRegisters?: [number, number];
|
|
36
|
+
getAddressRange?: () => {
|
|
37
|
+
discreteInputs?: [number, number] | [number, number][];
|
|
38
|
+
coils?: [number, number] | [number, number][];
|
|
39
|
+
inputRegisters?: [number, number] | [number, number][];
|
|
40
|
+
holdingRegisters?: [number, number] | [number, number][];
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
43
|
interface ModbusSlaveEvents {
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
export declare function checkRange(value: number, range?: [number, number]): boolean;
|
|
2
|
-
export declare function checkRange(values: number[], range?: [number, number]): boolean;
|
|
1
|
+
export declare function checkRange(value: number | number[], range?: [number, number] | [number, number][]): boolean;
|