njs-modbus 1.3.4 → 1.4.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 +63 -64
- package/dist/index.cjs +165 -148
- package/dist/index.d.ts +4 -3
- package/dist/index.mjs +165 -148
- package/dist/src/slave/slave.d.ts +4 -3
- package/dist/test/master.d.ts +1 -0
- package/dist/test/slave.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -66,6 +66,7 @@ npm install njs-modbus
|
|
|
66
66
|
### Modbus RTU Master
|
|
67
67
|
|
|
68
68
|
```typescript
|
|
69
|
+
import type { ModbusSlaveModel } from 'njs-modbus';
|
|
69
70
|
import { SerialPhysicalLayer, RtuApplicationLayer, ModbusMaster } from 'njs-modbus';
|
|
70
71
|
|
|
71
72
|
const physicalLayer = new SerialPhysicalLayer({ path: 'COM1', baudRate: 9600, dataBits: 8, parity: 'none', stopBits: 1 });
|
|
@@ -100,72 +101,70 @@ const MB_SERVER = {
|
|
|
100
101
|
|
|
101
102
|
const physicalLayer = new SerialPhysicalLayer({ path: 'COM1', baudRate: 9600, dataBits: 8, parity: 'none', stopBits: 1 });
|
|
102
103
|
const applicationLayer = new RtuApplicationLayer(physicalLayer);
|
|
104
|
+
const slave1: ModbusSlaveModel = {
|
|
105
|
+
readDiscreteInputs: (address, length) => {
|
|
106
|
+
return Array.from({ length }).map((_, i) => {
|
|
107
|
+
const discreteInput = MB_SERVER.discreteInputs.get(address + i);
|
|
108
|
+
if (typeof discreteInput === 'undefined') {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
return discreteInput;
|
|
112
|
+
});
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
readCoils: (address, length) => {
|
|
116
|
+
return Array.from({ length }).map((_, i) => {
|
|
117
|
+
const coil = MB_SERVER.coils.get(address + i);
|
|
118
|
+
if (typeof coil === 'undefined') {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
return coil;
|
|
122
|
+
});
|
|
123
|
+
},
|
|
124
|
+
writeSingleCoil: (address, value) => {
|
|
125
|
+
MB_SERVER.coils.set(address, value);
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
readInputRegisters: (address, length) => {
|
|
129
|
+
return Array.from({ length }).map((_, i) => {
|
|
130
|
+
const inputRegister = MB_SERVER.inputRegisters.get(address + i);
|
|
131
|
+
if (typeof inputRegister === 'undefined') {
|
|
132
|
+
return 0;
|
|
133
|
+
}
|
|
134
|
+
return inputRegister;
|
|
135
|
+
});
|
|
136
|
+
},
|
|
103
137
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
readCoils: (address, length) => {
|
|
117
|
-
return Array.from({ length }).map((_, i) => {
|
|
118
|
-
const coil = MB_SERVER.coils.get(address + i);
|
|
119
|
-
if (typeof coil === 'undefined') {
|
|
120
|
-
return false;
|
|
121
|
-
}
|
|
122
|
-
return coil;
|
|
123
|
-
});
|
|
124
|
-
},
|
|
125
|
-
writeSingleCoil: (address, value) => {
|
|
126
|
-
MB_SERVER.coils.set(address, value);
|
|
127
|
-
},
|
|
128
|
-
|
|
129
|
-
readInputRegisters: (address, length) => {
|
|
130
|
-
return Array.from({ length }).map((_, i) => {
|
|
131
|
-
const inputRegister = MB_SERVER.inputRegisters.get(address + i);
|
|
132
|
-
if (typeof inputRegister === 'undefined') {
|
|
133
|
-
return 0;
|
|
134
|
-
}
|
|
135
|
-
return inputRegister;
|
|
136
|
-
});
|
|
137
|
-
},
|
|
138
|
-
|
|
139
|
-
readHoldingRegisters: (address, length) => {
|
|
140
|
-
return Array.from({ length }).map((_, i) => {
|
|
141
|
-
const holdingRegister = MB_SERVER.holdingRegisters.get(address + i);
|
|
142
|
-
if (typeof holdingRegister === 'undefined') {
|
|
143
|
-
return 0;
|
|
144
|
-
}
|
|
145
|
-
return holdingRegister;
|
|
146
|
-
});
|
|
147
|
-
},
|
|
148
|
-
writeSingleRegister: (address, value) => {
|
|
149
|
-
MB_SERVER.holdingRegisters.set(address, value);
|
|
150
|
-
},
|
|
151
|
-
|
|
152
|
-
reportServerId: () => ({ additionalData: [1, 2, 3] }),
|
|
153
|
-
|
|
154
|
-
readDeviceIdentification: () => ({
|
|
155
|
-
0x00: 'Basic:VendorName',
|
|
156
|
-
0x01: 'Basic:ProductCode',
|
|
157
|
-
0x02: 'Basic:MajorMinorRevision',
|
|
158
|
-
0x03: 'Regular:VendorUrl',
|
|
159
|
-
0x04: 'Regular:ProductName',
|
|
160
|
-
0x05: 'Regular:ModelName',
|
|
161
|
-
0x06: 'Regular:UserApplicationName',
|
|
162
|
-
0x80: 'Extended:Extended',
|
|
163
|
-
0xff: 'Extended:Extended',
|
|
164
|
-
}),
|
|
138
|
+
readHoldingRegisters: (address, length) => {
|
|
139
|
+
return Array.from({ length }).map((_, i) => {
|
|
140
|
+
const holdingRegister = MB_SERVER.holdingRegisters.get(address + i);
|
|
141
|
+
if (typeof holdingRegister === 'undefined') {
|
|
142
|
+
return 0;
|
|
143
|
+
}
|
|
144
|
+
return holdingRegister;
|
|
145
|
+
});
|
|
146
|
+
},
|
|
147
|
+
writeSingleRegister: (address, value) => {
|
|
148
|
+
MB_SERVER.holdingRegisters.set(address, value);
|
|
165
149
|
},
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
150
|
+
|
|
151
|
+
reportServerId: () => ({ additionalData: [1, 2, 3] }),
|
|
152
|
+
|
|
153
|
+
readDeviceIdentification: () => ({
|
|
154
|
+
0x00: 'Basic:VendorName',
|
|
155
|
+
0x01: 'Basic:ProductCode',
|
|
156
|
+
0x02: 'Basic:MajorMinorRevision',
|
|
157
|
+
0x03: 'Regular:VendorUrl',
|
|
158
|
+
0x04: 'Regular:ProductName',
|
|
159
|
+
0x05: 'Regular:ModelName',
|
|
160
|
+
0x06: 'Regular:UserApplicationName',
|
|
161
|
+
0x80: 'Extended:Extended',
|
|
162
|
+
0xff: 'Extended:Extended',
|
|
163
|
+
}),
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const modbusSlave = new ModbusSlave(applicationLayer, physicalLayer);
|
|
167
|
+
modbusSlave.add(slave1);
|
|
169
168
|
|
|
170
169
|
modbusSlave
|
|
171
170
|
.open()
|
package/dist/index.cjs
CHANGED
|
@@ -545,6 +545,7 @@ function lrc(data) {
|
|
|
545
545
|
return (~data.reduce((sum, n) => sum + n, 0) + 1) & 0xff;
|
|
546
546
|
}
|
|
547
547
|
|
|
548
|
+
const MAX_FRAME_LENGTH = 256;
|
|
548
549
|
class RtuApplicationLayer extends AbstractApplicationLayer {
|
|
549
550
|
constructor(physicalLayer,
|
|
550
551
|
/**
|
|
@@ -609,11 +610,16 @@ class RtuApplicationLayer extends AbstractApplicationLayer {
|
|
|
609
610
|
}
|
|
610
611
|
});
|
|
611
612
|
};
|
|
612
|
-
if (
|
|
613
|
-
|
|
613
|
+
if (this._bufferRx.length >= MAX_FRAME_LENGTH) {
|
|
614
|
+
handleData();
|
|
614
615
|
}
|
|
615
616
|
else {
|
|
616
|
-
|
|
617
|
+
if (threePointFiveT) {
|
|
618
|
+
this._timerThreePointFive = setTimeout(handleData, threePointFiveT);
|
|
619
|
+
}
|
|
620
|
+
else {
|
|
621
|
+
handleData();
|
|
622
|
+
}
|
|
617
623
|
}
|
|
618
624
|
};
|
|
619
625
|
physicalLayer.on('data', handleData);
|
|
@@ -1498,14 +1504,8 @@ class ModbusSlave extends EventEmitter {
|
|
|
1498
1504
|
get destroyed() {
|
|
1499
1505
|
return this.physicalLayer.destroyed;
|
|
1500
1506
|
}
|
|
1501
|
-
constructor(
|
|
1507
|
+
constructor(applicationLayer, physicalLayer) {
|
|
1502
1508
|
super();
|
|
1503
|
-
Object.defineProperty(this, "model", {
|
|
1504
|
-
enumerable: true,
|
|
1505
|
-
configurable: true,
|
|
1506
|
-
writable: true,
|
|
1507
|
-
value: model
|
|
1508
|
-
});
|
|
1509
1509
|
Object.defineProperty(this, "applicationLayer", {
|
|
1510
1510
|
enumerable: true,
|
|
1511
1511
|
configurable: true,
|
|
@@ -1518,17 +1518,14 @@ class ModbusSlave extends EventEmitter {
|
|
|
1518
1518
|
writable: true,
|
|
1519
1519
|
value: physicalLayer
|
|
1520
1520
|
});
|
|
1521
|
-
Object.defineProperty(this, "
|
|
1521
|
+
Object.defineProperty(this, "models", {
|
|
1522
1522
|
enumerable: true,
|
|
1523
1523
|
configurable: true,
|
|
1524
1524
|
writable: true,
|
|
1525
|
-
value:
|
|
1525
|
+
value: new Map()
|
|
1526
1526
|
});
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
}
|
|
1530
|
-
applicationLayer.on('framing', (frame, _response) => __awaiter(this, void 0, void 0, function* () {
|
|
1531
|
-
if (!(frame.unit === 0x00 || frame.unit === this.unit)) {
|
|
1527
|
+
applicationLayer.on('framing', (frame, _response) => {
|
|
1528
|
+
if (!(frame.unit === 0x00 || this.models.has(frame.unit))) {
|
|
1532
1529
|
return;
|
|
1533
1530
|
}
|
|
1534
1531
|
const response = (data) => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1540,74 +1537,85 @@ class ModbusSlave extends EventEmitter {
|
|
|
1540
1537
|
}
|
|
1541
1538
|
catch (error) { }
|
|
1542
1539
|
});
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1540
|
+
const intercept = (model) => __awaiter(this, void 0, void 0, function* () {
|
|
1541
|
+
if (model.interceptor) {
|
|
1542
|
+
try {
|
|
1543
|
+
const data = yield model.interceptor(frame.fc, frame.data);
|
|
1544
|
+
if (data) {
|
|
1545
|
+
response(this.applicationLayer.encode(Object.assign(Object.assign({}, frame), { data })));
|
|
1546
|
+
return 'break';
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
catch (error) {
|
|
1550
|
+
this.responseError(frame, response, error);
|
|
1551
|
+
return 'break';
|
|
1549
1552
|
}
|
|
1550
1553
|
}
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_FUNCTION));
|
|
1607
|
-
break;
|
|
1554
|
+
});
|
|
1555
|
+
const handleFC = (model) => {
|
|
1556
|
+
switch (frame.fc) {
|
|
1557
|
+
case 0x01: {
|
|
1558
|
+
this.handleFC1(model, frame, response);
|
|
1559
|
+
break;
|
|
1560
|
+
}
|
|
1561
|
+
case 0x02: {
|
|
1562
|
+
this.handleFC2(model, frame, response);
|
|
1563
|
+
break;
|
|
1564
|
+
}
|
|
1565
|
+
case 0x03: {
|
|
1566
|
+
this.handleFC3(model, frame, response);
|
|
1567
|
+
break;
|
|
1568
|
+
}
|
|
1569
|
+
case 0x04: {
|
|
1570
|
+
this.handleFC4(model, frame, response);
|
|
1571
|
+
break;
|
|
1572
|
+
}
|
|
1573
|
+
case 0x05: {
|
|
1574
|
+
this.handleFC5(model, frame, response);
|
|
1575
|
+
break;
|
|
1576
|
+
}
|
|
1577
|
+
case 0x06: {
|
|
1578
|
+
this.handleFC6(model, frame, response);
|
|
1579
|
+
break;
|
|
1580
|
+
}
|
|
1581
|
+
case 0x0f: {
|
|
1582
|
+
this.handleFC15(model, frame, response);
|
|
1583
|
+
break;
|
|
1584
|
+
}
|
|
1585
|
+
case 0x10: {
|
|
1586
|
+
this.handleFC16(model, frame, response);
|
|
1587
|
+
break;
|
|
1588
|
+
}
|
|
1589
|
+
case 0x11: {
|
|
1590
|
+
this.handleFC17(model, frame, response);
|
|
1591
|
+
break;
|
|
1592
|
+
}
|
|
1593
|
+
case 0x16: {
|
|
1594
|
+
this.handleFC22(model, frame, response);
|
|
1595
|
+
break;
|
|
1596
|
+
}
|
|
1597
|
+
case 0x17: {
|
|
1598
|
+
this.handleFC23(model, frame, response);
|
|
1599
|
+
break;
|
|
1600
|
+
}
|
|
1601
|
+
case 0x2b: {
|
|
1602
|
+
this.handleFC43_14(model, frame, response);
|
|
1603
|
+
break;
|
|
1604
|
+
}
|
|
1605
|
+
default: {
|
|
1606
|
+
this.responseError(frame, response, getErrorByCode(exports.ErrorCode.ILLEGAL_FUNCTION));
|
|
1607
|
+
break;
|
|
1608
|
+
}
|
|
1608
1609
|
}
|
|
1610
|
+
};
|
|
1611
|
+
for (const model of frame.unit === 0x00 ? this.models.values() : [this.models.get(frame.unit)]) {
|
|
1612
|
+
intercept(model).then((res) => {
|
|
1613
|
+
if (res !== 'break') {
|
|
1614
|
+
handleFC(model);
|
|
1615
|
+
}
|
|
1616
|
+
});
|
|
1609
1617
|
}
|
|
1610
|
-
})
|
|
1618
|
+
});
|
|
1611
1619
|
physicalLayer.on('error', (error) => {
|
|
1612
1620
|
this.emit('error', error);
|
|
1613
1621
|
});
|
|
@@ -1615,16 +1623,16 @@ class ModbusSlave extends EventEmitter {
|
|
|
1615
1623
|
this.emit('close');
|
|
1616
1624
|
});
|
|
1617
1625
|
}
|
|
1618
|
-
handleFC1(frame, response) {
|
|
1619
|
-
var _a
|
|
1626
|
+
handleFC1(model, frame, response) {
|
|
1627
|
+
var _a;
|
|
1620
1628
|
if (frame.data.length === 4) {
|
|
1621
|
-
if (
|
|
1629
|
+
if (model.readCoils) {
|
|
1622
1630
|
const bufferRx = Buffer.from(frame.data);
|
|
1623
1631
|
const address = bufferRx.readUInt16BE(0);
|
|
1624
1632
|
const length = bufferRx.readUInt16BE(2);
|
|
1625
1633
|
if (length >= 0x0001 && length <= 0x07d0) {
|
|
1626
|
-
if (checkRange([address, address + length], (
|
|
1627
|
-
Promise.resolve(
|
|
1634
|
+
if (checkRange([address, address + length], (_a = model.getAddressRange) === null || _a === void 0 ? void 0 : _a.call(model).coils)) {
|
|
1635
|
+
Promise.resolve(model.readCoils(address, length))
|
|
1628
1636
|
.then((coils) => {
|
|
1629
1637
|
const bufferTx = Buffer.alloc(Math.ceil(length / 8));
|
|
1630
1638
|
coils.forEach((coil, index) => {
|
|
@@ -1651,16 +1659,16 @@ class ModbusSlave extends EventEmitter {
|
|
|
1651
1659
|
}
|
|
1652
1660
|
}
|
|
1653
1661
|
}
|
|
1654
|
-
handleFC2(frame, response) {
|
|
1655
|
-
var _a
|
|
1662
|
+
handleFC2(model, frame, response) {
|
|
1663
|
+
var _a;
|
|
1656
1664
|
if (frame.data.length === 4) {
|
|
1657
|
-
if (
|
|
1665
|
+
if (model.readDiscreteInputs) {
|
|
1658
1666
|
const bufferRx = Buffer.from(frame.data);
|
|
1659
1667
|
const address = bufferRx.readUInt16BE(0);
|
|
1660
1668
|
const length = bufferRx.readUInt16BE(2);
|
|
1661
1669
|
if (length >= 0x0001 && length <= 0x07d0) {
|
|
1662
|
-
if (checkRange([address, address + length], (
|
|
1663
|
-
Promise.resolve(
|
|
1670
|
+
if (checkRange([address, address + length], (_a = model.getAddressRange) === null || _a === void 0 ? void 0 : _a.call(model).discreteInputs)) {
|
|
1671
|
+
Promise.resolve(model.readDiscreteInputs(address, length))
|
|
1664
1672
|
.then((discreteInputs) => {
|
|
1665
1673
|
const bufferTx = Buffer.alloc(Math.ceil(length / 8));
|
|
1666
1674
|
discreteInputs.forEach((discreteInput, index) => {
|
|
@@ -1687,16 +1695,16 @@ class ModbusSlave extends EventEmitter {
|
|
|
1687
1695
|
}
|
|
1688
1696
|
}
|
|
1689
1697
|
}
|
|
1690
|
-
handleFC3(frame, response) {
|
|
1691
|
-
var _a
|
|
1698
|
+
handleFC3(model, frame, response) {
|
|
1699
|
+
var _a;
|
|
1692
1700
|
if (frame.data.length === 4) {
|
|
1693
|
-
if (
|
|
1701
|
+
if (model.readHoldingRegisters) {
|
|
1694
1702
|
const bufferRx = Buffer.from(frame.data);
|
|
1695
1703
|
const address = bufferRx.readUInt16BE(0);
|
|
1696
1704
|
const length = bufferRx.readUInt16BE(2);
|
|
1697
1705
|
if (length >= 0x0001 && length <= 0x007d) {
|
|
1698
|
-
if (checkRange([address, address + length], (
|
|
1699
|
-
Promise.resolve(
|
|
1706
|
+
if (checkRange([address, address + length], (_a = model.getAddressRange) === null || _a === void 0 ? void 0 : _a.call(model).holdingRegisters)) {
|
|
1707
|
+
Promise.resolve(model.readHoldingRegisters(address, length))
|
|
1700
1708
|
.then((registers) => {
|
|
1701
1709
|
const bufferTx = Buffer.alloc(length * 2);
|
|
1702
1710
|
registers.forEach((register, index) => {
|
|
@@ -1721,16 +1729,16 @@ class ModbusSlave extends EventEmitter {
|
|
|
1721
1729
|
}
|
|
1722
1730
|
}
|
|
1723
1731
|
}
|
|
1724
|
-
handleFC4(frame, response) {
|
|
1725
|
-
var _a
|
|
1732
|
+
handleFC4(model, frame, response) {
|
|
1733
|
+
var _a;
|
|
1726
1734
|
if (frame.data.length === 4) {
|
|
1727
|
-
if (
|
|
1735
|
+
if (model.readInputRegisters) {
|
|
1728
1736
|
const bufferRx = Buffer.from(frame.data);
|
|
1729
1737
|
const address = bufferRx.readUInt16BE(0);
|
|
1730
1738
|
const length = bufferRx.readUInt16BE(2);
|
|
1731
1739
|
if (length >= 0x0001 && length <= 0x007d) {
|
|
1732
|
-
if (checkRange([address, address + length], (
|
|
1733
|
-
Promise.resolve(
|
|
1740
|
+
if (checkRange([address, address + length], (_a = model.getAddressRange) === null || _a === void 0 ? void 0 : _a.call(model).inputRegisters)) {
|
|
1741
|
+
Promise.resolve(model.readInputRegisters(address, length))
|
|
1734
1742
|
.then((registers) => {
|
|
1735
1743
|
const bufferTx = Buffer.alloc(length * 2);
|
|
1736
1744
|
registers.forEach((register, index) => {
|
|
@@ -1755,16 +1763,16 @@ class ModbusSlave extends EventEmitter {
|
|
|
1755
1763
|
}
|
|
1756
1764
|
}
|
|
1757
1765
|
}
|
|
1758
|
-
handleFC5(frame, response) {
|
|
1759
|
-
var _a
|
|
1766
|
+
handleFC5(model, frame, response) {
|
|
1767
|
+
var _a;
|
|
1760
1768
|
if (frame.data.length === 4) {
|
|
1761
|
-
if (
|
|
1769
|
+
if (model.writeSingleCoil) {
|
|
1762
1770
|
const bufferRx = Buffer.from(frame.data);
|
|
1763
1771
|
const address = bufferRx.readUInt16BE(0);
|
|
1764
1772
|
const value = bufferRx.readUInt16BE(2);
|
|
1765
1773
|
if (value === 0x0000 || value === 0xff00) {
|
|
1766
|
-
if (checkRange(address, (
|
|
1767
|
-
Promise.resolve(
|
|
1774
|
+
if (checkRange(address, (_a = model.getAddressRange) === null || _a === void 0 ? void 0 : _a.call(model).coils)) {
|
|
1775
|
+
Promise.resolve(model.writeSingleCoil(address, value === 0xff00))
|
|
1768
1776
|
.then(() => {
|
|
1769
1777
|
response(this.applicationLayer.encode(frame));
|
|
1770
1778
|
})
|
|
@@ -1785,16 +1793,16 @@ class ModbusSlave extends EventEmitter {
|
|
|
1785
1793
|
}
|
|
1786
1794
|
}
|
|
1787
1795
|
}
|
|
1788
|
-
handleFC6(frame, response) {
|
|
1789
|
-
var _a
|
|
1796
|
+
handleFC6(model, frame, response) {
|
|
1797
|
+
var _a;
|
|
1790
1798
|
if (frame.data.length === 4) {
|
|
1791
|
-
if (
|
|
1799
|
+
if (model.writeSingleRegister) {
|
|
1792
1800
|
const bufferRx = Buffer.from(frame.data);
|
|
1793
1801
|
const address = bufferRx.readUInt16BE(0);
|
|
1794
1802
|
const value = bufferRx.readUInt16BE(2);
|
|
1795
1803
|
if (value >= 0x0000 && value <= 0xffff) {
|
|
1796
|
-
if (checkRange(address, (
|
|
1797
|
-
Promise.resolve(
|
|
1804
|
+
if (checkRange(address, (_a = model.getAddressRange) === null || _a === void 0 ? void 0 : _a.call(model).holdingRegisters)) {
|
|
1805
|
+
Promise.resolve(model.writeSingleRegister(address, value))
|
|
1798
1806
|
.then(() => {
|
|
1799
1807
|
response(this.applicationLayer.encode(frame));
|
|
1800
1808
|
})
|
|
@@ -1815,20 +1823,20 @@ class ModbusSlave extends EventEmitter {
|
|
|
1815
1823
|
}
|
|
1816
1824
|
}
|
|
1817
1825
|
}
|
|
1818
|
-
handleFC15(frame, response) {
|
|
1819
|
-
var _a
|
|
1826
|
+
handleFC15(model, frame, response) {
|
|
1827
|
+
var _a;
|
|
1820
1828
|
if (frame.data.length > 5 && frame.data.length === 5 + frame.data[4]) {
|
|
1821
|
-
if (
|
|
1829
|
+
if (model.writeMultipleCoils || model.writeSingleCoil) {
|
|
1822
1830
|
const bufferRx = Buffer.from(frame.data);
|
|
1823
1831
|
const address = bufferRx.readUInt16BE(0);
|
|
1824
1832
|
const length = bufferRx.readUInt16BE(2);
|
|
1825
1833
|
const byteCount = bufferRx[4];
|
|
1826
1834
|
if (length >= 0x0001 && length <= 0x07b0 && byteCount === Math.ceil(length / 8)) {
|
|
1827
|
-
if (checkRange([address, address + length], (
|
|
1835
|
+
if (checkRange([address, address + length], (_a = model.getAddressRange) === null || _a === void 0 ? void 0 : _a.call(model).coils)) {
|
|
1828
1836
|
const value = Array.from({ length }).map((_, index) => (bufferRx[5 + ~~(index / 8)] & (1 << index % 8)) > 0);
|
|
1829
|
-
Promise.resolve(
|
|
1830
|
-
?
|
|
1831
|
-
: Promise.all(value.map((v, i) =>
|
|
1837
|
+
Promise.resolve(model.writeMultipleCoils
|
|
1838
|
+
? model.writeMultipleCoils(address, value)
|
|
1839
|
+
: Promise.all(value.map((v, i) => model.writeSingleCoil(address + i, v))))
|
|
1832
1840
|
.then(() => {
|
|
1833
1841
|
response(this.applicationLayer.encode(Object.assign(Object.assign({}, frame), { data: Array.from(bufferRx).slice(0, 4) })));
|
|
1834
1842
|
})
|
|
@@ -1849,20 +1857,20 @@ class ModbusSlave extends EventEmitter {
|
|
|
1849
1857
|
}
|
|
1850
1858
|
}
|
|
1851
1859
|
}
|
|
1852
|
-
handleFC16(frame, response) {
|
|
1853
|
-
var _a
|
|
1860
|
+
handleFC16(model, frame, response) {
|
|
1861
|
+
var _a;
|
|
1854
1862
|
if (frame.data.length > 5 && frame.data.length === 5 + frame.data[4]) {
|
|
1855
|
-
if (
|
|
1863
|
+
if (model.writeMultipleRegisters || model.writeSingleRegister) {
|
|
1856
1864
|
const bufferRx = Buffer.from(frame.data);
|
|
1857
1865
|
const address = bufferRx.readUInt16BE(0);
|
|
1858
1866
|
const length = bufferRx.readUInt16BE(2);
|
|
1859
1867
|
const byteCount = bufferRx[4];
|
|
1860
1868
|
if (length >= 0x0001 && length <= 0x007b && byteCount === length * 2) {
|
|
1861
|
-
if (checkRange([address, address + length], (
|
|
1869
|
+
if (checkRange([address, address + length], (_a = model.getAddressRange) === null || _a === void 0 ? void 0 : _a.call(model).holdingRegisters)) {
|
|
1862
1870
|
const value = Array.from({ length }).map((_, index) => bufferRx.readUInt16BE(5 + index * 2));
|
|
1863
|
-
Promise.resolve(
|
|
1864
|
-
?
|
|
1865
|
-
: Promise.all(value.map((v, i) =>
|
|
1871
|
+
Promise.resolve(model.writeMultipleRegisters
|
|
1872
|
+
? model.writeMultipleRegisters(address, value)
|
|
1873
|
+
: Promise.all(value.map((v, i) => model.writeSingleRegister(address + i, v))))
|
|
1866
1874
|
.then(() => {
|
|
1867
1875
|
response(this.applicationLayer.encode(Object.assign(Object.assign({}, frame), { data: Array.from(bufferRx).slice(0, 4) })));
|
|
1868
1876
|
})
|
|
@@ -1883,11 +1891,13 @@ class ModbusSlave extends EventEmitter {
|
|
|
1883
1891
|
}
|
|
1884
1892
|
}
|
|
1885
1893
|
}
|
|
1886
|
-
handleFC17(frame, response) {
|
|
1894
|
+
handleFC17(model, frame, response) {
|
|
1887
1895
|
if (frame.data.length === 0) {
|
|
1888
|
-
if (
|
|
1889
|
-
Promise.resolve(
|
|
1890
|
-
.then((
|
|
1896
|
+
if (model.reportServerId) {
|
|
1897
|
+
Promise.resolve(model.reportServerId())
|
|
1898
|
+
.then((_a) => {
|
|
1899
|
+
var _b;
|
|
1900
|
+
var { serverId = (_b = model.unit) !== null && _b !== void 0 ? _b : 1, runIndicatorStatus = true, additionalData = [] } = _a;
|
|
1891
1901
|
response(this.applicationLayer.encode(Object.assign(Object.assign({}, frame), { data: [2 + additionalData.length, serverId, runIndicatorStatus ? 0xff : 0x00].concat(additionalData) })));
|
|
1892
1902
|
})
|
|
1893
1903
|
.catch((error) => {
|
|
@@ -1899,19 +1909,19 @@ class ModbusSlave extends EventEmitter {
|
|
|
1899
1909
|
}
|
|
1900
1910
|
}
|
|
1901
1911
|
}
|
|
1902
|
-
handleFC22(frame, response) {
|
|
1903
|
-
var _a
|
|
1912
|
+
handleFC22(model, frame, response) {
|
|
1913
|
+
var _a;
|
|
1904
1914
|
if (frame.data.length === 6) {
|
|
1905
|
-
if (
|
|
1915
|
+
if (model.maskWriteRegister || (model.readHoldingRegisters && model.writeSingleRegister)) {
|
|
1906
1916
|
const bufferRx = Buffer.from(frame.data);
|
|
1907
1917
|
const address = bufferRx.readUInt16BE(0);
|
|
1908
1918
|
const andMask = bufferRx.readUInt16BE(2);
|
|
1909
1919
|
const orMask = bufferRx.readUInt16BE(4);
|
|
1910
|
-
if (checkRange(address, (
|
|
1911
|
-
Promise.resolve(
|
|
1912
|
-
?
|
|
1913
|
-
: Promise.resolve(
|
|
1914
|
-
return Promise.resolve(
|
|
1920
|
+
if (checkRange(address, (_a = model.getAddressRange) === null || _a === void 0 ? void 0 : _a.call(model).holdingRegisters)) {
|
|
1921
|
+
Promise.resolve(model.maskWriteRegister
|
|
1922
|
+
? model.maskWriteRegister(address, andMask, orMask)
|
|
1923
|
+
: Promise.resolve(model.readHoldingRegisters(address, 1)).then(([value]) => {
|
|
1924
|
+
return Promise.resolve(model.writeSingleRegister(address, (value & andMask) | (orMask & (~andMask & 0xff))));
|
|
1915
1925
|
}))
|
|
1916
1926
|
.then(() => {
|
|
1917
1927
|
response(this.applicationLayer.encode(frame));
|
|
@@ -1929,10 +1939,10 @@ class ModbusSlave extends EventEmitter {
|
|
|
1929
1939
|
}
|
|
1930
1940
|
}
|
|
1931
1941
|
}
|
|
1932
|
-
handleFC23(frame, response) {
|
|
1933
|
-
var _a
|
|
1942
|
+
handleFC23(model, frame, response) {
|
|
1943
|
+
var _a;
|
|
1934
1944
|
if (frame.data.length > 9 && frame.data.length === 9 + frame.data[8]) {
|
|
1935
|
-
if (
|
|
1945
|
+
if (model.readHoldingRegisters && (model.writeMultipleRegisters || model.writeSingleRegister)) {
|
|
1936
1946
|
const bufferRx = Buffer.from(frame.data);
|
|
1937
1947
|
const address = {
|
|
1938
1948
|
read: bufferRx.readUInt16BE(0),
|
|
@@ -1948,12 +1958,12 @@ class ModbusSlave extends EventEmitter {
|
|
|
1948
1958
|
length.write >= 0x0001 &&
|
|
1949
1959
|
length.write <= 0x0079 &&
|
|
1950
1960
|
byteCount === length.write * 2) {
|
|
1951
|
-
if (checkRange([address.read, address.read + length.read, address.write, address.write + length.write], (
|
|
1961
|
+
if (checkRange([address.read, address.read + length.read, address.write, address.write + length.write], (_a = model.getAddressRange) === null || _a === void 0 ? void 0 : _a.call(model).holdingRegisters)) {
|
|
1952
1962
|
const value = Array.from({ length: length.write }).map((_, index) => bufferRx.readUInt16BE(9 + index * 2));
|
|
1953
|
-
Promise.resolve(
|
|
1954
|
-
?
|
|
1955
|
-
: Promise.all(value.map((v, i) =>
|
|
1956
|
-
.then(() => Promise.resolve(
|
|
1963
|
+
Promise.resolve(model.writeMultipleRegisters
|
|
1964
|
+
? model.writeMultipleRegisters(address.write, value)
|
|
1965
|
+
: Promise.all(value.map((v, i) => model.writeSingleRegister(address.write + i, v))))
|
|
1966
|
+
.then(() => Promise.resolve(model.readHoldingRegisters(address.read, length.read)))
|
|
1957
1967
|
.then((registers) => {
|
|
1958
1968
|
const bufferTx = Buffer.alloc(length.read * 2);
|
|
1959
1969
|
registers.forEach((register, index) => {
|
|
@@ -1978,9 +1988,9 @@ class ModbusSlave extends EventEmitter {
|
|
|
1978
1988
|
}
|
|
1979
1989
|
}
|
|
1980
1990
|
}
|
|
1981
|
-
handleFC43_14(frame, response) {
|
|
1991
|
+
handleFC43_14(model, frame, response) {
|
|
1982
1992
|
if (frame.data.length === 3) {
|
|
1983
|
-
if (frame.data[0] === 0x0e &&
|
|
1993
|
+
if (frame.data[0] === 0x0e && model.readDeviceIdentification) {
|
|
1984
1994
|
const readDeviceIDCode = frame.data[1];
|
|
1985
1995
|
let objectID = frame.data[2];
|
|
1986
1996
|
switch (readDeviceIDCode) {
|
|
@@ -2014,7 +2024,7 @@ class ModbusSlave extends EventEmitter {
|
|
|
2014
2024
|
return;
|
|
2015
2025
|
}
|
|
2016
2026
|
}
|
|
2017
|
-
Promise.resolve(
|
|
2027
|
+
Promise.resolve(model.readDeviceIdentification())
|
|
2018
2028
|
.then((identification) => {
|
|
2019
2029
|
const objects = new Map([
|
|
2020
2030
|
[0x00, 'null'],
|
|
@@ -2092,6 +2102,13 @@ class ModbusSlave extends EventEmitter {
|
|
|
2092
2102
|
responseError(frame, response, error) {
|
|
2093
2103
|
response(this.applicationLayer.encode(Object.assign(Object.assign({}, frame), { fc: frame.fc | 0x80, data: [getCodeByError(error)] })));
|
|
2094
2104
|
}
|
|
2105
|
+
add(model) {
|
|
2106
|
+
var _a;
|
|
2107
|
+
this.models.set((_a = model.unit) !== null && _a !== void 0 ? _a : 1, model);
|
|
2108
|
+
}
|
|
2109
|
+
remove(unit) {
|
|
2110
|
+
this.models.delete(unit);
|
|
2111
|
+
}
|
|
2095
2112
|
open(...args) {
|
|
2096
2113
|
return this.physicalLayer.open(...args);
|
|
2097
2114
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -342,13 +342,12 @@ interface ModbusSlaveEvents {
|
|
|
342
342
|
close: [];
|
|
343
343
|
}
|
|
344
344
|
declare class ModbusSlave<A extends AbstractApplicationLayer, P extends AbstractPhysicalLayer> extends EventEmitter<ModbusSlaveEvents> {
|
|
345
|
-
private model;
|
|
346
345
|
private applicationLayer;
|
|
347
346
|
private physicalLayer;
|
|
348
|
-
|
|
347
|
+
models: Map<number, ModbusSlaveModel>;
|
|
349
348
|
get isOpen(): boolean;
|
|
350
349
|
get destroyed(): boolean;
|
|
351
|
-
constructor(
|
|
350
|
+
constructor(applicationLayer: A, physicalLayer: P);
|
|
352
351
|
private handleFC1;
|
|
353
352
|
private handleFC2;
|
|
354
353
|
private handleFC3;
|
|
@@ -362,6 +361,8 @@ declare class ModbusSlave<A extends AbstractApplicationLayer, P extends Abstract
|
|
|
362
361
|
private handleFC23;
|
|
363
362
|
private handleFC43_14;
|
|
364
363
|
private responseError;
|
|
364
|
+
add(model: ModbusSlaveModel): void;
|
|
365
|
+
remove(unit: number): void;
|
|
365
366
|
open(...args: Parameters<P['open']>): Promise<void>;
|
|
366
367
|
close(): Promise<void>;
|
|
367
368
|
destroy(): Promise<void>;
|
package/dist/index.mjs
CHANGED
|
@@ -543,6 +543,7 @@ function lrc(data) {
|
|
|
543
543
|
return (~data.reduce((sum, n) => sum + n, 0) + 1) & 0xff;
|
|
544
544
|
}
|
|
545
545
|
|
|
546
|
+
const MAX_FRAME_LENGTH = 256;
|
|
546
547
|
class RtuApplicationLayer extends AbstractApplicationLayer {
|
|
547
548
|
constructor(physicalLayer,
|
|
548
549
|
/**
|
|
@@ -607,11 +608,16 @@ class RtuApplicationLayer extends AbstractApplicationLayer {
|
|
|
607
608
|
}
|
|
608
609
|
});
|
|
609
610
|
};
|
|
610
|
-
if (
|
|
611
|
-
|
|
611
|
+
if (this._bufferRx.length >= MAX_FRAME_LENGTH) {
|
|
612
|
+
handleData();
|
|
612
613
|
}
|
|
613
614
|
else {
|
|
614
|
-
|
|
615
|
+
if (threePointFiveT) {
|
|
616
|
+
this._timerThreePointFive = setTimeout(handleData, threePointFiveT);
|
|
617
|
+
}
|
|
618
|
+
else {
|
|
619
|
+
handleData();
|
|
620
|
+
}
|
|
615
621
|
}
|
|
616
622
|
};
|
|
617
623
|
physicalLayer.on('data', handleData);
|
|
@@ -1496,14 +1502,8 @@ class ModbusSlave extends EventEmitter {
|
|
|
1496
1502
|
get destroyed() {
|
|
1497
1503
|
return this.physicalLayer.destroyed;
|
|
1498
1504
|
}
|
|
1499
|
-
constructor(
|
|
1505
|
+
constructor(applicationLayer, physicalLayer) {
|
|
1500
1506
|
super();
|
|
1501
|
-
Object.defineProperty(this, "model", {
|
|
1502
|
-
enumerable: true,
|
|
1503
|
-
configurable: true,
|
|
1504
|
-
writable: true,
|
|
1505
|
-
value: model
|
|
1506
|
-
});
|
|
1507
1507
|
Object.defineProperty(this, "applicationLayer", {
|
|
1508
1508
|
enumerable: true,
|
|
1509
1509
|
configurable: true,
|
|
@@ -1516,17 +1516,14 @@ class ModbusSlave extends EventEmitter {
|
|
|
1516
1516
|
writable: true,
|
|
1517
1517
|
value: physicalLayer
|
|
1518
1518
|
});
|
|
1519
|
-
Object.defineProperty(this, "
|
|
1519
|
+
Object.defineProperty(this, "models", {
|
|
1520
1520
|
enumerable: true,
|
|
1521
1521
|
configurable: true,
|
|
1522
1522
|
writable: true,
|
|
1523
|
-
value:
|
|
1523
|
+
value: new Map()
|
|
1524
1524
|
});
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
}
|
|
1528
|
-
applicationLayer.on('framing', (frame, _response) => __awaiter(this, void 0, void 0, function* () {
|
|
1529
|
-
if (!(frame.unit === 0x00 || frame.unit === this.unit)) {
|
|
1525
|
+
applicationLayer.on('framing', (frame, _response) => {
|
|
1526
|
+
if (!(frame.unit === 0x00 || this.models.has(frame.unit))) {
|
|
1530
1527
|
return;
|
|
1531
1528
|
}
|
|
1532
1529
|
const response = (data) => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1538,74 +1535,85 @@ class ModbusSlave extends EventEmitter {
|
|
|
1538
1535
|
}
|
|
1539
1536
|
catch (error) { }
|
|
1540
1537
|
});
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1538
|
+
const intercept = (model) => __awaiter(this, void 0, void 0, function* () {
|
|
1539
|
+
if (model.interceptor) {
|
|
1540
|
+
try {
|
|
1541
|
+
const data = yield model.interceptor(frame.fc, frame.data);
|
|
1542
|
+
if (data) {
|
|
1543
|
+
response(this.applicationLayer.encode(Object.assign(Object.assign({}, frame), { data })));
|
|
1544
|
+
return 'break';
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
catch (error) {
|
|
1548
|
+
this.responseError(frame, response, error);
|
|
1549
|
+
return 'break';
|
|
1547
1550
|
}
|
|
1548
1551
|
}
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
this.responseError(frame, response, getErrorByCode(ErrorCode.ILLEGAL_FUNCTION));
|
|
1605
|
-
break;
|
|
1552
|
+
});
|
|
1553
|
+
const handleFC = (model) => {
|
|
1554
|
+
switch (frame.fc) {
|
|
1555
|
+
case 0x01: {
|
|
1556
|
+
this.handleFC1(model, frame, response);
|
|
1557
|
+
break;
|
|
1558
|
+
}
|
|
1559
|
+
case 0x02: {
|
|
1560
|
+
this.handleFC2(model, frame, response);
|
|
1561
|
+
break;
|
|
1562
|
+
}
|
|
1563
|
+
case 0x03: {
|
|
1564
|
+
this.handleFC3(model, frame, response);
|
|
1565
|
+
break;
|
|
1566
|
+
}
|
|
1567
|
+
case 0x04: {
|
|
1568
|
+
this.handleFC4(model, frame, response);
|
|
1569
|
+
break;
|
|
1570
|
+
}
|
|
1571
|
+
case 0x05: {
|
|
1572
|
+
this.handleFC5(model, frame, response);
|
|
1573
|
+
break;
|
|
1574
|
+
}
|
|
1575
|
+
case 0x06: {
|
|
1576
|
+
this.handleFC6(model, frame, response);
|
|
1577
|
+
break;
|
|
1578
|
+
}
|
|
1579
|
+
case 0x0f: {
|
|
1580
|
+
this.handleFC15(model, frame, response);
|
|
1581
|
+
break;
|
|
1582
|
+
}
|
|
1583
|
+
case 0x10: {
|
|
1584
|
+
this.handleFC16(model, frame, response);
|
|
1585
|
+
break;
|
|
1586
|
+
}
|
|
1587
|
+
case 0x11: {
|
|
1588
|
+
this.handleFC17(model, frame, response);
|
|
1589
|
+
break;
|
|
1590
|
+
}
|
|
1591
|
+
case 0x16: {
|
|
1592
|
+
this.handleFC22(model, frame, response);
|
|
1593
|
+
break;
|
|
1594
|
+
}
|
|
1595
|
+
case 0x17: {
|
|
1596
|
+
this.handleFC23(model, frame, response);
|
|
1597
|
+
break;
|
|
1598
|
+
}
|
|
1599
|
+
case 0x2b: {
|
|
1600
|
+
this.handleFC43_14(model, frame, response);
|
|
1601
|
+
break;
|
|
1602
|
+
}
|
|
1603
|
+
default: {
|
|
1604
|
+
this.responseError(frame, response, getErrorByCode(ErrorCode.ILLEGAL_FUNCTION));
|
|
1605
|
+
break;
|
|
1606
|
+
}
|
|
1606
1607
|
}
|
|
1608
|
+
};
|
|
1609
|
+
for (const model of frame.unit === 0x00 ? this.models.values() : [this.models.get(frame.unit)]) {
|
|
1610
|
+
intercept(model).then((res) => {
|
|
1611
|
+
if (res !== 'break') {
|
|
1612
|
+
handleFC(model);
|
|
1613
|
+
}
|
|
1614
|
+
});
|
|
1607
1615
|
}
|
|
1608
|
-
})
|
|
1616
|
+
});
|
|
1609
1617
|
physicalLayer.on('error', (error) => {
|
|
1610
1618
|
this.emit('error', error);
|
|
1611
1619
|
});
|
|
@@ -1613,16 +1621,16 @@ class ModbusSlave extends EventEmitter {
|
|
|
1613
1621
|
this.emit('close');
|
|
1614
1622
|
});
|
|
1615
1623
|
}
|
|
1616
|
-
handleFC1(frame, response) {
|
|
1617
|
-
var _a
|
|
1624
|
+
handleFC1(model, frame, response) {
|
|
1625
|
+
var _a;
|
|
1618
1626
|
if (frame.data.length === 4) {
|
|
1619
|
-
if (
|
|
1627
|
+
if (model.readCoils) {
|
|
1620
1628
|
const bufferRx = Buffer.from(frame.data);
|
|
1621
1629
|
const address = bufferRx.readUInt16BE(0);
|
|
1622
1630
|
const length = bufferRx.readUInt16BE(2);
|
|
1623
1631
|
if (length >= 0x0001 && length <= 0x07d0) {
|
|
1624
|
-
if (checkRange([address, address + length], (
|
|
1625
|
-
Promise.resolve(
|
|
1632
|
+
if (checkRange([address, address + length], (_a = model.getAddressRange) === null || _a === void 0 ? void 0 : _a.call(model).coils)) {
|
|
1633
|
+
Promise.resolve(model.readCoils(address, length))
|
|
1626
1634
|
.then((coils) => {
|
|
1627
1635
|
const bufferTx = Buffer.alloc(Math.ceil(length / 8));
|
|
1628
1636
|
coils.forEach((coil, index) => {
|
|
@@ -1649,16 +1657,16 @@ class ModbusSlave extends EventEmitter {
|
|
|
1649
1657
|
}
|
|
1650
1658
|
}
|
|
1651
1659
|
}
|
|
1652
|
-
handleFC2(frame, response) {
|
|
1653
|
-
var _a
|
|
1660
|
+
handleFC2(model, frame, response) {
|
|
1661
|
+
var _a;
|
|
1654
1662
|
if (frame.data.length === 4) {
|
|
1655
|
-
if (
|
|
1663
|
+
if (model.readDiscreteInputs) {
|
|
1656
1664
|
const bufferRx = Buffer.from(frame.data);
|
|
1657
1665
|
const address = bufferRx.readUInt16BE(0);
|
|
1658
1666
|
const length = bufferRx.readUInt16BE(2);
|
|
1659
1667
|
if (length >= 0x0001 && length <= 0x07d0) {
|
|
1660
|
-
if (checkRange([address, address + length], (
|
|
1661
|
-
Promise.resolve(
|
|
1668
|
+
if (checkRange([address, address + length], (_a = model.getAddressRange) === null || _a === void 0 ? void 0 : _a.call(model).discreteInputs)) {
|
|
1669
|
+
Promise.resolve(model.readDiscreteInputs(address, length))
|
|
1662
1670
|
.then((discreteInputs) => {
|
|
1663
1671
|
const bufferTx = Buffer.alloc(Math.ceil(length / 8));
|
|
1664
1672
|
discreteInputs.forEach((discreteInput, index) => {
|
|
@@ -1685,16 +1693,16 @@ class ModbusSlave extends EventEmitter {
|
|
|
1685
1693
|
}
|
|
1686
1694
|
}
|
|
1687
1695
|
}
|
|
1688
|
-
handleFC3(frame, response) {
|
|
1689
|
-
var _a
|
|
1696
|
+
handleFC3(model, frame, response) {
|
|
1697
|
+
var _a;
|
|
1690
1698
|
if (frame.data.length === 4) {
|
|
1691
|
-
if (
|
|
1699
|
+
if (model.readHoldingRegisters) {
|
|
1692
1700
|
const bufferRx = Buffer.from(frame.data);
|
|
1693
1701
|
const address = bufferRx.readUInt16BE(0);
|
|
1694
1702
|
const length = bufferRx.readUInt16BE(2);
|
|
1695
1703
|
if (length >= 0x0001 && length <= 0x007d) {
|
|
1696
|
-
if (checkRange([address, address + length], (
|
|
1697
|
-
Promise.resolve(
|
|
1704
|
+
if (checkRange([address, address + length], (_a = model.getAddressRange) === null || _a === void 0 ? void 0 : _a.call(model).holdingRegisters)) {
|
|
1705
|
+
Promise.resolve(model.readHoldingRegisters(address, length))
|
|
1698
1706
|
.then((registers) => {
|
|
1699
1707
|
const bufferTx = Buffer.alloc(length * 2);
|
|
1700
1708
|
registers.forEach((register, index) => {
|
|
@@ -1719,16 +1727,16 @@ class ModbusSlave extends EventEmitter {
|
|
|
1719
1727
|
}
|
|
1720
1728
|
}
|
|
1721
1729
|
}
|
|
1722
|
-
handleFC4(frame, response) {
|
|
1723
|
-
var _a
|
|
1730
|
+
handleFC4(model, frame, response) {
|
|
1731
|
+
var _a;
|
|
1724
1732
|
if (frame.data.length === 4) {
|
|
1725
|
-
if (
|
|
1733
|
+
if (model.readInputRegisters) {
|
|
1726
1734
|
const bufferRx = Buffer.from(frame.data);
|
|
1727
1735
|
const address = bufferRx.readUInt16BE(0);
|
|
1728
1736
|
const length = bufferRx.readUInt16BE(2);
|
|
1729
1737
|
if (length >= 0x0001 && length <= 0x007d) {
|
|
1730
|
-
if (checkRange([address, address + length], (
|
|
1731
|
-
Promise.resolve(
|
|
1738
|
+
if (checkRange([address, address + length], (_a = model.getAddressRange) === null || _a === void 0 ? void 0 : _a.call(model).inputRegisters)) {
|
|
1739
|
+
Promise.resolve(model.readInputRegisters(address, length))
|
|
1732
1740
|
.then((registers) => {
|
|
1733
1741
|
const bufferTx = Buffer.alloc(length * 2);
|
|
1734
1742
|
registers.forEach((register, index) => {
|
|
@@ -1753,16 +1761,16 @@ class ModbusSlave extends EventEmitter {
|
|
|
1753
1761
|
}
|
|
1754
1762
|
}
|
|
1755
1763
|
}
|
|
1756
|
-
handleFC5(frame, response) {
|
|
1757
|
-
var _a
|
|
1764
|
+
handleFC5(model, frame, response) {
|
|
1765
|
+
var _a;
|
|
1758
1766
|
if (frame.data.length === 4) {
|
|
1759
|
-
if (
|
|
1767
|
+
if (model.writeSingleCoil) {
|
|
1760
1768
|
const bufferRx = Buffer.from(frame.data);
|
|
1761
1769
|
const address = bufferRx.readUInt16BE(0);
|
|
1762
1770
|
const value = bufferRx.readUInt16BE(2);
|
|
1763
1771
|
if (value === 0x0000 || value === 0xff00) {
|
|
1764
|
-
if (checkRange(address, (
|
|
1765
|
-
Promise.resolve(
|
|
1772
|
+
if (checkRange(address, (_a = model.getAddressRange) === null || _a === void 0 ? void 0 : _a.call(model).coils)) {
|
|
1773
|
+
Promise.resolve(model.writeSingleCoil(address, value === 0xff00))
|
|
1766
1774
|
.then(() => {
|
|
1767
1775
|
response(this.applicationLayer.encode(frame));
|
|
1768
1776
|
})
|
|
@@ -1783,16 +1791,16 @@ class ModbusSlave extends EventEmitter {
|
|
|
1783
1791
|
}
|
|
1784
1792
|
}
|
|
1785
1793
|
}
|
|
1786
|
-
handleFC6(frame, response) {
|
|
1787
|
-
var _a
|
|
1794
|
+
handleFC6(model, frame, response) {
|
|
1795
|
+
var _a;
|
|
1788
1796
|
if (frame.data.length === 4) {
|
|
1789
|
-
if (
|
|
1797
|
+
if (model.writeSingleRegister) {
|
|
1790
1798
|
const bufferRx = Buffer.from(frame.data);
|
|
1791
1799
|
const address = bufferRx.readUInt16BE(0);
|
|
1792
1800
|
const value = bufferRx.readUInt16BE(2);
|
|
1793
1801
|
if (value >= 0x0000 && value <= 0xffff) {
|
|
1794
|
-
if (checkRange(address, (
|
|
1795
|
-
Promise.resolve(
|
|
1802
|
+
if (checkRange(address, (_a = model.getAddressRange) === null || _a === void 0 ? void 0 : _a.call(model).holdingRegisters)) {
|
|
1803
|
+
Promise.resolve(model.writeSingleRegister(address, value))
|
|
1796
1804
|
.then(() => {
|
|
1797
1805
|
response(this.applicationLayer.encode(frame));
|
|
1798
1806
|
})
|
|
@@ -1813,20 +1821,20 @@ class ModbusSlave extends EventEmitter {
|
|
|
1813
1821
|
}
|
|
1814
1822
|
}
|
|
1815
1823
|
}
|
|
1816
|
-
handleFC15(frame, response) {
|
|
1817
|
-
var _a
|
|
1824
|
+
handleFC15(model, frame, response) {
|
|
1825
|
+
var _a;
|
|
1818
1826
|
if (frame.data.length > 5 && frame.data.length === 5 + frame.data[4]) {
|
|
1819
|
-
if (
|
|
1827
|
+
if (model.writeMultipleCoils || model.writeSingleCoil) {
|
|
1820
1828
|
const bufferRx = Buffer.from(frame.data);
|
|
1821
1829
|
const address = bufferRx.readUInt16BE(0);
|
|
1822
1830
|
const length = bufferRx.readUInt16BE(2);
|
|
1823
1831
|
const byteCount = bufferRx[4];
|
|
1824
1832
|
if (length >= 0x0001 && length <= 0x07b0 && byteCount === Math.ceil(length / 8)) {
|
|
1825
|
-
if (checkRange([address, address + length], (
|
|
1833
|
+
if (checkRange([address, address + length], (_a = model.getAddressRange) === null || _a === void 0 ? void 0 : _a.call(model).coils)) {
|
|
1826
1834
|
const value = Array.from({ length }).map((_, index) => (bufferRx[5 + ~~(index / 8)] & (1 << index % 8)) > 0);
|
|
1827
|
-
Promise.resolve(
|
|
1828
|
-
?
|
|
1829
|
-
: Promise.all(value.map((v, i) =>
|
|
1835
|
+
Promise.resolve(model.writeMultipleCoils
|
|
1836
|
+
? model.writeMultipleCoils(address, value)
|
|
1837
|
+
: Promise.all(value.map((v, i) => model.writeSingleCoil(address + i, v))))
|
|
1830
1838
|
.then(() => {
|
|
1831
1839
|
response(this.applicationLayer.encode(Object.assign(Object.assign({}, frame), { data: Array.from(bufferRx).slice(0, 4) })));
|
|
1832
1840
|
})
|
|
@@ -1847,20 +1855,20 @@ class ModbusSlave extends EventEmitter {
|
|
|
1847
1855
|
}
|
|
1848
1856
|
}
|
|
1849
1857
|
}
|
|
1850
|
-
handleFC16(frame, response) {
|
|
1851
|
-
var _a
|
|
1858
|
+
handleFC16(model, frame, response) {
|
|
1859
|
+
var _a;
|
|
1852
1860
|
if (frame.data.length > 5 && frame.data.length === 5 + frame.data[4]) {
|
|
1853
|
-
if (
|
|
1861
|
+
if (model.writeMultipleRegisters || model.writeSingleRegister) {
|
|
1854
1862
|
const bufferRx = Buffer.from(frame.data);
|
|
1855
1863
|
const address = bufferRx.readUInt16BE(0);
|
|
1856
1864
|
const length = bufferRx.readUInt16BE(2);
|
|
1857
1865
|
const byteCount = bufferRx[4];
|
|
1858
1866
|
if (length >= 0x0001 && length <= 0x007b && byteCount === length * 2) {
|
|
1859
|
-
if (checkRange([address, address + length], (
|
|
1867
|
+
if (checkRange([address, address + length], (_a = model.getAddressRange) === null || _a === void 0 ? void 0 : _a.call(model).holdingRegisters)) {
|
|
1860
1868
|
const value = Array.from({ length }).map((_, index) => bufferRx.readUInt16BE(5 + index * 2));
|
|
1861
|
-
Promise.resolve(
|
|
1862
|
-
?
|
|
1863
|
-
: Promise.all(value.map((v, i) =>
|
|
1869
|
+
Promise.resolve(model.writeMultipleRegisters
|
|
1870
|
+
? model.writeMultipleRegisters(address, value)
|
|
1871
|
+
: Promise.all(value.map((v, i) => model.writeSingleRegister(address + i, v))))
|
|
1864
1872
|
.then(() => {
|
|
1865
1873
|
response(this.applicationLayer.encode(Object.assign(Object.assign({}, frame), { data: Array.from(bufferRx).slice(0, 4) })));
|
|
1866
1874
|
})
|
|
@@ -1881,11 +1889,13 @@ class ModbusSlave extends EventEmitter {
|
|
|
1881
1889
|
}
|
|
1882
1890
|
}
|
|
1883
1891
|
}
|
|
1884
|
-
handleFC17(frame, response) {
|
|
1892
|
+
handleFC17(model, frame, response) {
|
|
1885
1893
|
if (frame.data.length === 0) {
|
|
1886
|
-
if (
|
|
1887
|
-
Promise.resolve(
|
|
1888
|
-
.then((
|
|
1894
|
+
if (model.reportServerId) {
|
|
1895
|
+
Promise.resolve(model.reportServerId())
|
|
1896
|
+
.then((_a) => {
|
|
1897
|
+
var _b;
|
|
1898
|
+
var { serverId = (_b = model.unit) !== null && _b !== void 0 ? _b : 1, runIndicatorStatus = true, additionalData = [] } = _a;
|
|
1889
1899
|
response(this.applicationLayer.encode(Object.assign(Object.assign({}, frame), { data: [2 + additionalData.length, serverId, runIndicatorStatus ? 0xff : 0x00].concat(additionalData) })));
|
|
1890
1900
|
})
|
|
1891
1901
|
.catch((error) => {
|
|
@@ -1897,19 +1907,19 @@ class ModbusSlave extends EventEmitter {
|
|
|
1897
1907
|
}
|
|
1898
1908
|
}
|
|
1899
1909
|
}
|
|
1900
|
-
handleFC22(frame, response) {
|
|
1901
|
-
var _a
|
|
1910
|
+
handleFC22(model, frame, response) {
|
|
1911
|
+
var _a;
|
|
1902
1912
|
if (frame.data.length === 6) {
|
|
1903
|
-
if (
|
|
1913
|
+
if (model.maskWriteRegister || (model.readHoldingRegisters && model.writeSingleRegister)) {
|
|
1904
1914
|
const bufferRx = Buffer.from(frame.data);
|
|
1905
1915
|
const address = bufferRx.readUInt16BE(0);
|
|
1906
1916
|
const andMask = bufferRx.readUInt16BE(2);
|
|
1907
1917
|
const orMask = bufferRx.readUInt16BE(4);
|
|
1908
|
-
if (checkRange(address, (
|
|
1909
|
-
Promise.resolve(
|
|
1910
|
-
?
|
|
1911
|
-
: Promise.resolve(
|
|
1912
|
-
return Promise.resolve(
|
|
1918
|
+
if (checkRange(address, (_a = model.getAddressRange) === null || _a === void 0 ? void 0 : _a.call(model).holdingRegisters)) {
|
|
1919
|
+
Promise.resolve(model.maskWriteRegister
|
|
1920
|
+
? model.maskWriteRegister(address, andMask, orMask)
|
|
1921
|
+
: Promise.resolve(model.readHoldingRegisters(address, 1)).then(([value]) => {
|
|
1922
|
+
return Promise.resolve(model.writeSingleRegister(address, (value & andMask) | (orMask & (~andMask & 0xff))));
|
|
1913
1923
|
}))
|
|
1914
1924
|
.then(() => {
|
|
1915
1925
|
response(this.applicationLayer.encode(frame));
|
|
@@ -1927,10 +1937,10 @@ class ModbusSlave extends EventEmitter {
|
|
|
1927
1937
|
}
|
|
1928
1938
|
}
|
|
1929
1939
|
}
|
|
1930
|
-
handleFC23(frame, response) {
|
|
1931
|
-
var _a
|
|
1940
|
+
handleFC23(model, frame, response) {
|
|
1941
|
+
var _a;
|
|
1932
1942
|
if (frame.data.length > 9 && frame.data.length === 9 + frame.data[8]) {
|
|
1933
|
-
if (
|
|
1943
|
+
if (model.readHoldingRegisters && (model.writeMultipleRegisters || model.writeSingleRegister)) {
|
|
1934
1944
|
const bufferRx = Buffer.from(frame.data);
|
|
1935
1945
|
const address = {
|
|
1936
1946
|
read: bufferRx.readUInt16BE(0),
|
|
@@ -1946,12 +1956,12 @@ class ModbusSlave extends EventEmitter {
|
|
|
1946
1956
|
length.write >= 0x0001 &&
|
|
1947
1957
|
length.write <= 0x0079 &&
|
|
1948
1958
|
byteCount === length.write * 2) {
|
|
1949
|
-
if (checkRange([address.read, address.read + length.read, address.write, address.write + length.write], (
|
|
1959
|
+
if (checkRange([address.read, address.read + length.read, address.write, address.write + length.write], (_a = model.getAddressRange) === null || _a === void 0 ? void 0 : _a.call(model).holdingRegisters)) {
|
|
1950
1960
|
const value = Array.from({ length: length.write }).map((_, index) => bufferRx.readUInt16BE(9 + index * 2));
|
|
1951
|
-
Promise.resolve(
|
|
1952
|
-
?
|
|
1953
|
-
: Promise.all(value.map((v, i) =>
|
|
1954
|
-
.then(() => Promise.resolve(
|
|
1961
|
+
Promise.resolve(model.writeMultipleRegisters
|
|
1962
|
+
? model.writeMultipleRegisters(address.write, value)
|
|
1963
|
+
: Promise.all(value.map((v, i) => model.writeSingleRegister(address.write + i, v))))
|
|
1964
|
+
.then(() => Promise.resolve(model.readHoldingRegisters(address.read, length.read)))
|
|
1955
1965
|
.then((registers) => {
|
|
1956
1966
|
const bufferTx = Buffer.alloc(length.read * 2);
|
|
1957
1967
|
registers.forEach((register, index) => {
|
|
@@ -1976,9 +1986,9 @@ class ModbusSlave extends EventEmitter {
|
|
|
1976
1986
|
}
|
|
1977
1987
|
}
|
|
1978
1988
|
}
|
|
1979
|
-
handleFC43_14(frame, response) {
|
|
1989
|
+
handleFC43_14(model, frame, response) {
|
|
1980
1990
|
if (frame.data.length === 3) {
|
|
1981
|
-
if (frame.data[0] === 0x0e &&
|
|
1991
|
+
if (frame.data[0] === 0x0e && model.readDeviceIdentification) {
|
|
1982
1992
|
const readDeviceIDCode = frame.data[1];
|
|
1983
1993
|
let objectID = frame.data[2];
|
|
1984
1994
|
switch (readDeviceIDCode) {
|
|
@@ -2012,7 +2022,7 @@ class ModbusSlave extends EventEmitter {
|
|
|
2012
2022
|
return;
|
|
2013
2023
|
}
|
|
2014
2024
|
}
|
|
2015
|
-
Promise.resolve(
|
|
2025
|
+
Promise.resolve(model.readDeviceIdentification())
|
|
2016
2026
|
.then((identification) => {
|
|
2017
2027
|
const objects = new Map([
|
|
2018
2028
|
[0x00, 'null'],
|
|
@@ -2090,6 +2100,13 @@ class ModbusSlave extends EventEmitter {
|
|
|
2090
2100
|
responseError(frame, response, error) {
|
|
2091
2101
|
response(this.applicationLayer.encode(Object.assign(Object.assign({}, frame), { fc: frame.fc | 0x80, data: [getCodeByError(error)] })));
|
|
2092
2102
|
}
|
|
2103
|
+
add(model) {
|
|
2104
|
+
var _a;
|
|
2105
|
+
this.models.set((_a = model.unit) !== null && _a !== void 0 ? _a : 1, model);
|
|
2106
|
+
}
|
|
2107
|
+
remove(unit) {
|
|
2108
|
+
this.models.delete(unit);
|
|
2109
|
+
}
|
|
2093
2110
|
open(...args) {
|
|
2094
2111
|
return this.physicalLayer.open(...args);
|
|
2095
2112
|
}
|
|
@@ -45,13 +45,12 @@ interface ModbusSlaveEvents {
|
|
|
45
45
|
close: [];
|
|
46
46
|
}
|
|
47
47
|
export declare class ModbusSlave<A extends AbstractApplicationLayer, P extends AbstractPhysicalLayer> extends EventEmitter<ModbusSlaveEvents> {
|
|
48
|
-
private model;
|
|
49
48
|
private applicationLayer;
|
|
50
49
|
private physicalLayer;
|
|
51
|
-
|
|
50
|
+
models: Map<number, ModbusSlaveModel>;
|
|
52
51
|
get isOpen(): boolean;
|
|
53
52
|
get destroyed(): boolean;
|
|
54
|
-
constructor(
|
|
53
|
+
constructor(applicationLayer: A, physicalLayer: P);
|
|
55
54
|
private handleFC1;
|
|
56
55
|
private handleFC2;
|
|
57
56
|
private handleFC3;
|
|
@@ -65,6 +64,8 @@ export declare class ModbusSlave<A extends AbstractApplicationLayer, P extends A
|
|
|
65
64
|
private handleFC23;
|
|
66
65
|
private handleFC43_14;
|
|
67
66
|
private responseError;
|
|
67
|
+
add(model: ModbusSlaveModel): void;
|
|
68
|
+
remove(unit: number): void;
|
|
68
69
|
open(...args: Parameters<P['open']>): Promise<void>;
|
|
69
70
|
close(): Promise<void>;
|
|
70
71
|
destroy(): Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|