ts-communication 1.0.0 → 1.1.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/LICENSE +15 -0
- package/README.md +246 -14
- package/dist/Invt/InvtModbusTcp.d.ts +88 -0
- package/dist/Invt/InvtModbusTcp.js +255 -0
- package/dist/XCommunication.d.ts +18 -0
- package/dist/XCommunication.js +29 -0
- package/dist/ab/AbEtherNetIp.d.ts +1 -0
- package/dist/ab/AbEtherNetIp.js +2 -0
- package/dist/core/CommunicationLock.d.ts +88 -0
- package/dist/core/CommunicationLock.js +156 -0
- package/dist/core/Core.d.ts +27 -1
- package/dist/core/Core.js +375 -71
- package/dist/core/DeviceSerialPort.d.ts +64 -0
- package/dist/core/DeviceSerialPort.js +283 -0
- package/dist/core/DeviceUdpNet.d.ts +56 -0
- package/dist/core/DeviceUdpNet.js +307 -0
- package/dist/core/INetMessage.d.ts +145 -0
- package/dist/core/INetMessage.js +240 -0
- package/dist/debug/PingTest.d.ts +11 -0
- package/dist/debug/PingTest.js +59 -0
- package/dist/debug/tcpClient.d.ts +11 -0
- package/dist/debug/tcpClient.js +116 -0
- package/dist/debug/tcpServer.d.ts +12 -0
- package/dist/debug/tcpServer.js +102 -0
- package/dist/delta/DeltaTcpNet.d.ts +65 -0
- package/dist/delta/DeltaTcpNet.js +346 -0
- package/dist/ge/GeSRTPNet.d.ts +49 -0
- package/dist/ge/GeSRTPNet.js +337 -0
- package/dist/inovance/InovanceEasyNet.d.ts +8 -0
- package/dist/inovance/InovanceEasyNet.js +103 -0
- package/dist/inovance/InovanceSerial.d.ts +55 -0
- package/dist/inovance/InovanceSerial.js +145 -0
- package/dist/inovance/InovanceSerialOverTcp.d.ts +39 -0
- package/dist/inovance/InovanceSerialOverTcp.js +172 -0
- package/dist/inovance/InovanceTcpNet.d.ts +2 -4
- package/dist/inovance/InovanceTcpNet.js +40 -13
- package/dist/melsec/MelsecMcAsciiNet.d.ts +49 -0
- package/dist/melsec/MelsecMcAsciiNet.js +196 -0
- package/dist/melsec/MelsecMcAsciiUdp.d.ts +54 -0
- package/dist/melsec/MelsecMcAsciiUdp.js +204 -0
- package/dist/melsec/MelsecMcNet.d.ts +1 -8
- package/dist/melsec/MelsecMcNet.js +4 -14
- package/dist/melsec/MelsecMcUdp.d.ts +52 -0
- package/dist/melsec/MelsecMcUdp.js +191 -0
- package/dist/modbus/ModbusAscii.d.ts +24 -3
- package/dist/modbus/ModbusAscii.js +109 -3
- package/dist/modbus/ModbusAsciiOverTcp.d.ts +21 -3
- package/dist/modbus/ModbusAsciiOverTcp.js +67 -3
- package/dist/modbus/ModbusRtu.d.ts +101 -13
- package/dist/modbus/ModbusRtu.js +355 -21
- package/dist/modbus/ModbusRtuOverTcp.d.ts +23 -3
- package/dist/modbus/ModbusRtuOverTcp.js +68 -3
- package/dist/modbus/ModbusTcpNet.d.ts +16 -3
- package/dist/modbus/ModbusTcpNet.js +192 -60
- package/dist/modbus/ModbusUdpNet.d.ts +26 -3
- package/dist/modbus/ModbusUdpNet.js +125 -2
- package/dist/omron/OmronFinsNet.d.ts +1 -2
- package/dist/omron/OmronFinsNet.js +210 -69
- package/dist/omron/OmronFinsUdp.d.ts +41 -0
- package/dist/omron/OmronFinsUdp.js +146 -0
- package/dist/siemens/SiemensS7Net.d.ts +6 -0
- package/dist/siemens/SiemensS7Net.js +45 -6
- package/dist/xinjie/XinJETcpNet.d.ts +18 -0
- package/dist/xinjie/XinJETcpNet.js +106 -0
- package/package.json +16 -3
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InvtModbusTcp = void 0;
|
|
4
|
+
const ModbusTcpNet_1 = require("../modbus/ModbusTcpNet");
|
|
5
|
+
const Core_1 = require("../core/Core");
|
|
6
|
+
/**
|
|
7
|
+
* 英威腾 TS600 系列 PLC 的 Modbus TCP 通讯类
|
|
8
|
+
* 支持通过 PLC 原生地址格式进行读写操作
|
|
9
|
+
*/
|
|
10
|
+
class InvtModbusTcp extends ModbusTcpNet_1.ModbusTcpNet {
|
|
11
|
+
constructor(ipAddress, port = 502, station = 1) {
|
|
12
|
+
super(ipAddress, port, station);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* 将英威腾 PLC 地址转换为 Modbus 地址
|
|
16
|
+
* @param address 英威腾 PLC 地址,例如:M100、S100、X0、Y0、T100、C100、D100、R100
|
|
17
|
+
* @param modbusCode Modbus功能码
|
|
18
|
+
* @returns 转换后的Modbus地址
|
|
19
|
+
*/
|
|
20
|
+
TranslateToModbusAddress(address, modbusCode) {
|
|
21
|
+
try {
|
|
22
|
+
let station = '';
|
|
23
|
+
// 提取站号参数
|
|
24
|
+
const stationMatch = address.match(/^s=(\d+);(.*)$/i);
|
|
25
|
+
if (stationMatch) {
|
|
26
|
+
station = `s=${stationMatch[1]};`;
|
|
27
|
+
address = stationMatch[2];
|
|
28
|
+
}
|
|
29
|
+
const isBitCode = modbusCode === 1 || modbusCode === 15 || modbusCode === 5;
|
|
30
|
+
if (isBitCode) {
|
|
31
|
+
// 线圈类型地址转换
|
|
32
|
+
// M:内部继电器(偏移量 0)
|
|
33
|
+
if (/^M\d+/i.test(address)) {
|
|
34
|
+
const num = parseInt(address.substring(1), 10);
|
|
35
|
+
return Core_1.OperateResult.CreateSuccessResult(station + num.toString());
|
|
36
|
+
}
|
|
37
|
+
// S:状态继电器(偏移量 32768)
|
|
38
|
+
if (/^S\d+/i.test(address)) {
|
|
39
|
+
const num = parseInt(address.substring(1), 10);
|
|
40
|
+
return Core_1.OperateResult.CreateSuccessResult(station + (num + 32768).toString());
|
|
41
|
+
}
|
|
42
|
+
// X:输入继电器(偏移量 40960,地址为八进制)
|
|
43
|
+
if (/^X[0-7]+/i.test(address)) {
|
|
44
|
+
const num = parseInt(address.substring(1), 8);
|
|
45
|
+
return Core_1.OperateResult.CreateSuccessResult(station + (num + 40960).toString());
|
|
46
|
+
}
|
|
47
|
+
// Y:输出继电器(偏移量 45056,地址为八进制)
|
|
48
|
+
if (/^Y[0-7]+/i.test(address)) {
|
|
49
|
+
const num = parseInt(address.substring(1), 8);
|
|
50
|
+
return Core_1.OperateResult.CreateSuccessResult(station + (num + 45056).toString());
|
|
51
|
+
}
|
|
52
|
+
// T:定时器触点(偏移量 49152)
|
|
53
|
+
if (/^T\d+/i.test(address)) {
|
|
54
|
+
const num = parseInt(address.substring(1), 10);
|
|
55
|
+
return Core_1.OperateResult.CreateSuccessResult(station + (num + 49152).toString());
|
|
56
|
+
}
|
|
57
|
+
// C:计数器触点(偏移量 49664)
|
|
58
|
+
if (/^C\d+/i.test(address)) {
|
|
59
|
+
const num = parseInt(address.substring(1), 10);
|
|
60
|
+
return Core_1.OperateResult.CreateSuccessResult(station + (num + 49664).toString());
|
|
61
|
+
}
|
|
62
|
+
// D:数据寄存器位访问
|
|
63
|
+
if (/^D\d+\.\d+/i.test(address)) {
|
|
64
|
+
return Core_1.OperateResult.CreateSuccessResult(station + address.substring(1));
|
|
65
|
+
}
|
|
66
|
+
// R:扩展寄存器位访问
|
|
67
|
+
if (/^R\d+\.\d+/i.test(address)) {
|
|
68
|
+
const parts = address.substring(1).split('.');
|
|
69
|
+
const wordAddr = parseInt(parts[0], 10);
|
|
70
|
+
return Core_1.OperateResult.CreateSuccessResult(station + `${wordAddr + 32768}.${parts[1]}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
// 寄存器类型地址转换
|
|
75
|
+
// T:定时器当前值(偏移量 57344)
|
|
76
|
+
if (/^T\d+/i.test(address)) {
|
|
77
|
+
const num = parseInt(address.substring(1), 10);
|
|
78
|
+
return Core_1.OperateResult.CreateSuccessResult(station + (num + 57344).toString());
|
|
79
|
+
}
|
|
80
|
+
// C:计数器当前值(偏移量 57856)
|
|
81
|
+
if (/^C\d+/i.test(address)) {
|
|
82
|
+
const num = parseInt(address.substring(1), 10);
|
|
83
|
+
return Core_1.OperateResult.CreateSuccessResult(station + (num + 57856).toString());
|
|
84
|
+
}
|
|
85
|
+
// Z:变址寄存器(偏移量 58368,32 位地址乘 2)
|
|
86
|
+
if (/^Z\d+/i.test(address)) {
|
|
87
|
+
// 数字部分从 Z 前缀之后开始。
|
|
88
|
+
const num = parseInt(address.substring(1), 10);
|
|
89
|
+
return Core_1.OperateResult.CreateSuccessResult(station + (num * 2 + 58368).toString());
|
|
90
|
+
}
|
|
91
|
+
// D:数据寄存器(偏移量 0)
|
|
92
|
+
if (/^D\d+/i.test(address)) {
|
|
93
|
+
const num = parseInt(address.substring(1), 10);
|
|
94
|
+
return Core_1.OperateResult.CreateSuccessResult(station + num.toString());
|
|
95
|
+
}
|
|
96
|
+
// R:扩展寄存器(偏移量 32768)
|
|
97
|
+
if (/^R\d+/i.test(address)) {
|
|
98
|
+
const num = parseInt(address.substring(1), 10);
|
|
99
|
+
return Core_1.OperateResult.CreateSuccessResult(station + (num + 32768).toString());
|
|
100
|
+
}
|
|
101
|
+
// M:内部继电器状态读取(使用功能码 1)
|
|
102
|
+
if (/^M\d+/i.test(address)) {
|
|
103
|
+
const num = parseInt(address.substring(1), 10);
|
|
104
|
+
return Core_1.OperateResult.CreateSuccessResult(station + `x=1;${num}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
throw new Error(`Unsupported Invt address: ${address}`);
|
|
108
|
+
}
|
|
109
|
+
catch (e) {
|
|
110
|
+
return new Core_1.OperateResult(e.message);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* 读取寄存器数据
|
|
115
|
+
*/
|
|
116
|
+
async Read(address, length) {
|
|
117
|
+
const a = this.TranslateToModbusAddress(address, 3);
|
|
118
|
+
return a.IsSuccess ? super.Read(a.Content, length) : Core_1.OperateResult.CreateFailedResult(a);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* 读取布尔类型数据
|
|
122
|
+
*/
|
|
123
|
+
async ReadBool(address, length) {
|
|
124
|
+
const a = this.TranslateToModbusAddress(address, 1);
|
|
125
|
+
return a.IsSuccess ? super.ReadBool(a.Content, length) : Core_1.OperateResult.CreateFailedResult(a);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* 读取线圈
|
|
129
|
+
*/
|
|
130
|
+
async ReadCoil(address, length) {
|
|
131
|
+
return this.ReadBool(address, length);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* 写入数据
|
|
135
|
+
*/
|
|
136
|
+
async Write(address, value) {
|
|
137
|
+
// 单个线圈使用功能码 5,线圈数组使用功能码 15。
|
|
138
|
+
const code = typeof value === 'boolean' ? 5 : Array.isArray(value) && typeof value[0] === 'boolean' ? 15 : 16;
|
|
139
|
+
const a = this.TranslateToModbusAddress(address, code);
|
|
140
|
+
return a.IsSuccess ? super.Write(a.Content, value) : Core_1.OperateResult.CreateFailedResult(a);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* 读取Int16类型数据
|
|
144
|
+
*/
|
|
145
|
+
async ReadInt16(address, length) {
|
|
146
|
+
const a = this.TranslateToModbusAddress(address, 3);
|
|
147
|
+
return a.IsSuccess ? super.ReadInt16(a.Content, length) : Core_1.OperateResult.CreateFailedResult(a);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* 读取UInt16类型数据
|
|
151
|
+
*/
|
|
152
|
+
async ReadUInt16(address, length) {
|
|
153
|
+
const a = this.TranslateToModbusAddress(address, 3);
|
|
154
|
+
return a.IsSuccess ? super.ReadUInt16(a.Content, length) : Core_1.OperateResult.CreateFailedResult(a);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* 读取Int32类型数据
|
|
158
|
+
*/
|
|
159
|
+
async ReadInt32(address, length) {
|
|
160
|
+
const a = this.TranslateToModbusAddress(address, 3);
|
|
161
|
+
return a.IsSuccess ? super.ReadInt32(a.Content, length) : Core_1.OperateResult.CreateFailedResult(a);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* 读取UInt32类型数据
|
|
165
|
+
*/
|
|
166
|
+
async ReadUInt32(address, length) {
|
|
167
|
+
const a = this.TranslateToModbusAddress(address, 3);
|
|
168
|
+
return a.IsSuccess ? super.ReadUInt32(a.Content, length) : Core_1.OperateResult.CreateFailedResult(a);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* 读取Float类型数据
|
|
172
|
+
*/
|
|
173
|
+
async ReadFloat(address, length) {
|
|
174
|
+
const a = this.TranslateToModbusAddress(address, 3);
|
|
175
|
+
return a.IsSuccess ? super.ReadFloat(a.Content, length) : Core_1.OperateResult.CreateFailedResult(a);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* 读取Double类型数据
|
|
179
|
+
*/
|
|
180
|
+
async ReadDouble(address, length) {
|
|
181
|
+
const a = this.TranslateToModbusAddress(address, 3);
|
|
182
|
+
return a.IsSuccess ? super.ReadDouble(a.Content, length) : Core_1.OperateResult.CreateFailedResult(a);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* 读取 64 位整数。父类的类型读取路径使用原始读取,避免已转换地址再次映射。
|
|
186
|
+
*/
|
|
187
|
+
async ReadInt64(address, length) {
|
|
188
|
+
const a = this.TranslateToModbusAddress(address, 3);
|
|
189
|
+
return a.IsSuccess ? super.ReadInt64(a.Content, length) : Core_1.OperateResult.CreateFailedResult(a);
|
|
190
|
+
}
|
|
191
|
+
async ReadUInt64(address, length) {
|
|
192
|
+
const a = this.TranslateToModbusAddress(address, 3);
|
|
193
|
+
return a.IsSuccess ? super.ReadUInt64(a.Content, length) : Core_1.OperateResult.CreateFailedResult(a);
|
|
194
|
+
}
|
|
195
|
+
async ReadString(address, length, encoding = 'ascii') {
|
|
196
|
+
const a = this.TranslateToModbusAddress(address, 3);
|
|
197
|
+
if (!a.IsSuccess)
|
|
198
|
+
return Core_1.OperateResult.CreateFailedResult(a);
|
|
199
|
+
const result = await super.Read(a.Content, length);
|
|
200
|
+
return result.IsSuccess
|
|
201
|
+
? Core_1.OperateResult.CreateSuccessResult(this.ByteTransform.TransString(result.Content, encoding))
|
|
202
|
+
: Core_1.OperateResult.CreateFailedResult(result);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* 写入Int16类型数据
|
|
206
|
+
*/
|
|
207
|
+
async WriteInt16(address, value) {
|
|
208
|
+
const a = this.TranslateToModbusAddress(address, 6);
|
|
209
|
+
return a.IsSuccess ? super.WriteInt16(a.Content, value) : Core_1.OperateResult.CreateFailedResult(a);
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* 写入UInt16类型数据
|
|
213
|
+
*/
|
|
214
|
+
async WriteUInt16(address, value) {
|
|
215
|
+
const a = this.TranslateToModbusAddress(address, 6);
|
|
216
|
+
return a.IsSuccess ? super.WriteUInt16(a.Content, value) : Core_1.OperateResult.CreateFailedResult(a);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* 写入Int32类型数据
|
|
220
|
+
*/
|
|
221
|
+
async WriteInt32(address, value) {
|
|
222
|
+
const a = this.TranslateToModbusAddress(address, 16);
|
|
223
|
+
return a.IsSuccess ? super.WriteInt32(a.Content, value) : Core_1.OperateResult.CreateFailedResult(a);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* 写入UInt32类型数据
|
|
227
|
+
*/
|
|
228
|
+
async WriteUInt32(address, value) {
|
|
229
|
+
const a = this.TranslateToModbusAddress(address, 16);
|
|
230
|
+
return a.IsSuccess ? super.WriteUInt32(a.Content, value) : Core_1.OperateResult.CreateFailedResult(a);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* 写入Float类型数据
|
|
234
|
+
*/
|
|
235
|
+
async WriteFloat(address, value) {
|
|
236
|
+
const a = this.TranslateToModbusAddress(address, 16);
|
|
237
|
+
return a.IsSuccess ? super.WriteFloat(a.Content, value) : Core_1.OperateResult.CreateFailedResult(a);
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* 写入Double类型数据
|
|
241
|
+
*/
|
|
242
|
+
async WriteDouble(address, value) {
|
|
243
|
+
const a = this.TranslateToModbusAddress(address, 16);
|
|
244
|
+
return a.IsSuccess ? super.WriteDouble(a.Content, value) : Core_1.OperateResult.CreateFailedResult(a);
|
|
245
|
+
}
|
|
246
|
+
async WriteInt64(address, value) {
|
|
247
|
+
const a = this.TranslateToModbusAddress(address, 16);
|
|
248
|
+
return a.IsSuccess ? super.WriteInt64(a.Content, value) : Core_1.OperateResult.CreateFailedResult(a);
|
|
249
|
+
}
|
|
250
|
+
async WriteUInt64(address, value) {
|
|
251
|
+
const a = this.TranslateToModbusAddress(address, 16);
|
|
252
|
+
return a.IsSuccess ? super.WriteUInt64(a.Content, value) : Core_1.OperateResult.CreateFailedResult(a);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
exports.InvtModbusTcp = InvtModbusTcp;
|
package/dist/XCommunication.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
export * from './core/Core';
|
|
2
|
+
export * from './core/CommunicationLock';
|
|
3
|
+
export * from './core/INetMessage';
|
|
4
|
+
export * from './core/DeviceSerialPort';
|
|
5
|
+
export * from './core/DeviceUdpNet';
|
|
2
6
|
export * from './modbus/ModbusTcpNet';
|
|
3
7
|
export * from './modbus/ModbusRtu';
|
|
4
8
|
export * from './modbus/ModbusRtuOverTcp';
|
|
@@ -7,5 +11,19 @@ export * from './modbus/ModbusAsciiOverTcp';
|
|
|
7
11
|
export * from './modbus/ModbusUdpNet';
|
|
8
12
|
export * from './siemens/SiemensS7Net';
|
|
9
13
|
export * from './melsec/MelsecMcNet';
|
|
14
|
+
export * from './melsec/MelsecMcUdp';
|
|
15
|
+
export * from './melsec/MelsecMcAsciiNet';
|
|
16
|
+
export * from './melsec/MelsecMcAsciiUdp';
|
|
10
17
|
export * from './omron/OmronFinsNet';
|
|
18
|
+
export * from './omron/OmronFinsUdp';
|
|
11
19
|
export * from './inovance/InovanceTcpNet';
|
|
20
|
+
export * from './inovance/InovanceSerial';
|
|
21
|
+
export * from './inovance/InovanceSerialOverTcp';
|
|
22
|
+
export * from './inovance/InovanceEasyNet';
|
|
23
|
+
export * from './Invt/InvtModbusTcp';
|
|
24
|
+
export * from './ge/GeSRTPNet';
|
|
25
|
+
export * from './delta/DeltaTcpNet';
|
|
26
|
+
export * from './xinjie/XinJETcpNet';
|
|
27
|
+
export * from './debug/PingTest';
|
|
28
|
+
export * from './debug/tcpClient';
|
|
29
|
+
export * from './debug/tcpServer';
|
package/dist/XCommunication.js
CHANGED
|
@@ -14,14 +14,43 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
// Core
|
|
17
18
|
__exportStar(require("./core/Core"), exports);
|
|
19
|
+
__exportStar(require("./core/CommunicationLock"), exports);
|
|
20
|
+
__exportStar(require("./core/INetMessage"), exports);
|
|
21
|
+
__exportStar(require("./core/DeviceSerialPort"), exports);
|
|
22
|
+
__exportStar(require("./core/DeviceUdpNet"), exports);
|
|
23
|
+
// Modbus
|
|
18
24
|
__exportStar(require("./modbus/ModbusTcpNet"), exports);
|
|
19
25
|
__exportStar(require("./modbus/ModbusRtu"), exports);
|
|
20
26
|
__exportStar(require("./modbus/ModbusRtuOverTcp"), exports);
|
|
21
27
|
__exportStar(require("./modbus/ModbusAscii"), exports);
|
|
22
28
|
__exportStar(require("./modbus/ModbusAsciiOverTcp"), exports);
|
|
23
29
|
__exportStar(require("./modbus/ModbusUdpNet"), exports);
|
|
30
|
+
// Siemens
|
|
24
31
|
__exportStar(require("./siemens/SiemensS7Net"), exports);
|
|
32
|
+
// Melsec
|
|
25
33
|
__exportStar(require("./melsec/MelsecMcNet"), exports);
|
|
34
|
+
__exportStar(require("./melsec/MelsecMcUdp"), exports);
|
|
35
|
+
__exportStar(require("./melsec/MelsecMcAsciiNet"), exports);
|
|
36
|
+
__exportStar(require("./melsec/MelsecMcAsciiUdp"), exports);
|
|
37
|
+
// Omron
|
|
26
38
|
__exportStar(require("./omron/OmronFinsNet"), exports);
|
|
39
|
+
__exportStar(require("./omron/OmronFinsUdp"), exports);
|
|
40
|
+
// Inovance
|
|
27
41
|
__exportStar(require("./inovance/InovanceTcpNet"), exports);
|
|
42
|
+
__exportStar(require("./inovance/InovanceSerial"), exports);
|
|
43
|
+
__exportStar(require("./inovance/InovanceSerialOverTcp"), exports);
|
|
44
|
+
__exportStar(require("./inovance/InovanceEasyNet"), exports);
|
|
45
|
+
// Invt
|
|
46
|
+
__exportStar(require("./Invt/InvtModbusTcp"), exports);
|
|
47
|
+
// 通用电气
|
|
48
|
+
__exportStar(require("./ge/GeSRTPNet"), exports);
|
|
49
|
+
// 台达
|
|
50
|
+
__exportStar(require("./delta/DeltaTcpNet"), exports);
|
|
51
|
+
// XinJE
|
|
52
|
+
__exportStar(require("./xinjie/XinJETcpNet"), exports);
|
|
53
|
+
// Debug
|
|
54
|
+
__exportStar(require("./debug/PingTest"), exports);
|
|
55
|
+
__exportStar(require("./debug/tcpClient"), exports);
|
|
56
|
+
__exportStar(require("./debug/tcpServer"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { OperateResult } from './Core';
|
|
2
|
+
/**
|
|
3
|
+
* 用于通信的锁的接口对象,定义了进入锁和离开锁的方法接口信息
|
|
4
|
+
* An interface object for a lock used for communication that defines interface information for the methods used to enter and exit the lock
|
|
5
|
+
*/
|
|
6
|
+
export interface ICommunicationLock {
|
|
7
|
+
/**
|
|
8
|
+
* 进入锁操作,指定超时时间,单位毫秒,并返回是否成功获得锁的标记
|
|
9
|
+
* Enters the lock operation, specifies the timeout period in milliseconds, and returns a flag as to whether the lock was successfully obtained.
|
|
10
|
+
* @param timeout 超时时间(毫秒)
|
|
11
|
+
* @returns 是否成功获得锁
|
|
12
|
+
*/
|
|
13
|
+
EnterLock(timeout: number): Promise<OperateResult<void>>;
|
|
14
|
+
/**
|
|
15
|
+
* 离开锁操作
|
|
16
|
+
* Leave lock operation
|
|
17
|
+
*/
|
|
18
|
+
LeaveLock(): void;
|
|
19
|
+
/**
|
|
20
|
+
* 释放资源
|
|
21
|
+
* Dispose resources
|
|
22
|
+
*/
|
|
23
|
+
dispose(): void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 无锁实现,直接返回成功,用于不需要锁的场景
|
|
27
|
+
* No lock implementation, returns success directly, used for scenarios that do not require locks
|
|
28
|
+
*/
|
|
29
|
+
export declare class CommunicationLockNone implements ICommunicationLock {
|
|
30
|
+
EnterLock(timeout: number): Promise<OperateResult<void>>;
|
|
31
|
+
LeaveLock(): void;
|
|
32
|
+
dispose(): void;
|
|
33
|
+
toString(): string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 用于通信的一个简单的混合锁,基于 Promise 队列实现
|
|
37
|
+
* A simple hybrid lock for communication, implemented based on Promise queue
|
|
38
|
+
*/
|
|
39
|
+
export declare class CommunicationLockSimple implements ICommunicationLock {
|
|
40
|
+
private waiters;
|
|
41
|
+
private queue;
|
|
42
|
+
/**
|
|
43
|
+
* 获取当前锁是否在等待当中
|
|
44
|
+
* Gets whether the current lock is waiting
|
|
45
|
+
*/
|
|
46
|
+
get IsWaiting(): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* 进入锁操作
|
|
49
|
+
* @param timeout 超时时间(毫秒)
|
|
50
|
+
*/
|
|
51
|
+
EnterLock(timeout: number): Promise<OperateResult<void>>;
|
|
52
|
+
/**
|
|
53
|
+
* 离开锁操作
|
|
54
|
+
*/
|
|
55
|
+
LeaveLock(): void;
|
|
56
|
+
/**
|
|
57
|
+
* 释放资源
|
|
58
|
+
*/
|
|
59
|
+
dispose(): void;
|
|
60
|
+
toString(): string;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 请求队列管理器,确保请求按顺序执行
|
|
64
|
+
* Request queue manager to ensure requests are executed in order
|
|
65
|
+
*/
|
|
66
|
+
export declare class RequestQueue {
|
|
67
|
+
private queue;
|
|
68
|
+
private processing;
|
|
69
|
+
/**
|
|
70
|
+
* 将请求加入队列并执行
|
|
71
|
+
* Add request to queue and execute
|
|
72
|
+
* @param fn 要执行的异步函数
|
|
73
|
+
* @returns 执行结果
|
|
74
|
+
*/
|
|
75
|
+
enqueue<T>(fn: () => Promise<T>): Promise<T>;
|
|
76
|
+
/**
|
|
77
|
+
* 处理队列
|
|
78
|
+
*/
|
|
79
|
+
private processQueue;
|
|
80
|
+
/**
|
|
81
|
+
* 获取当前队列长度
|
|
82
|
+
*/
|
|
83
|
+
get length(): number;
|
|
84
|
+
/**
|
|
85
|
+
* 清空队列
|
|
86
|
+
*/
|
|
87
|
+
clear(): void;
|
|
88
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RequestQueue = exports.CommunicationLockSimple = exports.CommunicationLockNone = void 0;
|
|
4
|
+
const Core_1 = require("./Core");
|
|
5
|
+
/**
|
|
6
|
+
* 无锁实现,直接返回成功,用于不需要锁的场景
|
|
7
|
+
* No lock implementation, returns success directly, used for scenarios that do not require locks
|
|
8
|
+
*/
|
|
9
|
+
class CommunicationLockNone {
|
|
10
|
+
async EnterLock(timeout) {
|
|
11
|
+
return Core_1.OperateResult.CreateSuccessResult();
|
|
12
|
+
}
|
|
13
|
+
LeaveLock() {
|
|
14
|
+
// 无操作
|
|
15
|
+
}
|
|
16
|
+
dispose() {
|
|
17
|
+
// 无操作
|
|
18
|
+
}
|
|
19
|
+
toString() {
|
|
20
|
+
return 'CommunicationLockNone[NoLock]';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.CommunicationLockNone = CommunicationLockNone;
|
|
24
|
+
/**
|
|
25
|
+
* 用于通信的一个简单的混合锁,基于 Promise 队列实现
|
|
26
|
+
* A simple hybrid lock for communication, implemented based on Promise queue
|
|
27
|
+
*/
|
|
28
|
+
class CommunicationLockSimple {
|
|
29
|
+
waiters = 0;
|
|
30
|
+
queue = [];
|
|
31
|
+
/**
|
|
32
|
+
* 获取当前锁是否在等待当中
|
|
33
|
+
* Gets whether the current lock is waiting
|
|
34
|
+
*/
|
|
35
|
+
get IsWaiting() {
|
|
36
|
+
return this.waiters > 0;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 进入锁操作
|
|
40
|
+
* @param timeout 超时时间(毫秒)
|
|
41
|
+
*/
|
|
42
|
+
async EnterLock(timeout) {
|
|
43
|
+
try {
|
|
44
|
+
this.waiters++;
|
|
45
|
+
// 如果是第一个进入,直接获得锁
|
|
46
|
+
if (this.waiters === 1) {
|
|
47
|
+
return Core_1.OperateResult.CreateSuccessResult();
|
|
48
|
+
}
|
|
49
|
+
// 否则加入等待队列
|
|
50
|
+
return new Promise((resolve, reject) => {
|
|
51
|
+
const timer = setTimeout(() => {
|
|
52
|
+
// 超时,从队列中移除
|
|
53
|
+
const index = this.queue.findIndex(item => item.timer === timer);
|
|
54
|
+
if (index >= 0) {
|
|
55
|
+
this.queue.splice(index, 1);
|
|
56
|
+
}
|
|
57
|
+
this.waiters--;
|
|
58
|
+
resolve(new Core_1.OperateResult(`Enter lock failed, timeout: ${timeout}`, -1));
|
|
59
|
+
}, timeout);
|
|
60
|
+
this.queue.push({ resolve: () => resolve(Core_1.OperateResult.CreateSuccessResult()), reject, timer });
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
catch (ex) {
|
|
64
|
+
this.waiters--;
|
|
65
|
+
return new Core_1.OperateResult(`Enter lock failed, message: ${ex.message}`, -1);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* 离开锁操作
|
|
70
|
+
*/
|
|
71
|
+
LeaveLock() {
|
|
72
|
+
this.waiters--;
|
|
73
|
+
// 如果还有等待的请求,唤醒下一个
|
|
74
|
+
if (this.waiters > 0 && this.queue.length > 0) {
|
|
75
|
+
const next = this.queue.shift();
|
|
76
|
+
if (next) {
|
|
77
|
+
clearTimeout(next.timer);
|
|
78
|
+
next.resolve();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 释放资源
|
|
84
|
+
*/
|
|
85
|
+
dispose() {
|
|
86
|
+
// 清理所有等待的请求
|
|
87
|
+
for (const item of this.queue) {
|
|
88
|
+
clearTimeout(item.timer);
|
|
89
|
+
item.reject(new Error('Lock disposed'));
|
|
90
|
+
}
|
|
91
|
+
this.queue = [];
|
|
92
|
+
this.waiters = 0;
|
|
93
|
+
}
|
|
94
|
+
toString() {
|
|
95
|
+
return `CommunicationLockSimple[${this.IsWaiting ? 'Locking' : 'Unlock'}]`;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
exports.CommunicationLockSimple = CommunicationLockSimple;
|
|
99
|
+
/**
|
|
100
|
+
* 请求队列管理器,确保请求按顺序执行
|
|
101
|
+
* Request queue manager to ensure requests are executed in order
|
|
102
|
+
*/
|
|
103
|
+
class RequestQueue {
|
|
104
|
+
queue = [];
|
|
105
|
+
processing = false;
|
|
106
|
+
/**
|
|
107
|
+
* 将请求加入队列并执行
|
|
108
|
+
* Add request to queue and execute
|
|
109
|
+
* @param fn 要执行的异步函数
|
|
110
|
+
* @returns 执行结果
|
|
111
|
+
*/
|
|
112
|
+
async enqueue(fn) {
|
|
113
|
+
return new Promise((resolve, reject) => {
|
|
114
|
+
this.queue.push({ fn, resolve, reject });
|
|
115
|
+
this.processQueue();
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* 处理队列
|
|
120
|
+
*/
|
|
121
|
+
async processQueue() {
|
|
122
|
+
if (this.processing || this.queue.length === 0) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
this.processing = true;
|
|
126
|
+
while (this.queue.length > 0) {
|
|
127
|
+
const item = this.queue.shift();
|
|
128
|
+
if (!item)
|
|
129
|
+
break;
|
|
130
|
+
try {
|
|
131
|
+
const result = await item.fn();
|
|
132
|
+
item.resolve(result);
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
item.reject(error);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
this.processing = false;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* 获取当前队列长度
|
|
142
|
+
*/
|
|
143
|
+
get length() {
|
|
144
|
+
return this.queue.length;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* 清空队列
|
|
148
|
+
*/
|
|
149
|
+
clear() {
|
|
150
|
+
for (const item of this.queue) {
|
|
151
|
+
item.reject(new Error('Queue cleared'));
|
|
152
|
+
}
|
|
153
|
+
this.queue = [];
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
exports.RequestQueue = RequestQueue;
|
package/dist/core/Core.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import * as net from 'node:net';
|
|
2
|
+
import { ICommunicationLock, RequestQueue } from './CommunicationLock';
|
|
3
|
+
import { INetMessage } from './INetMessage';
|
|
2
4
|
export declare enum DataFormat {
|
|
3
5
|
ABCD = "ABCD",
|
|
4
6
|
BADC = "BADC",
|
|
@@ -60,6 +62,11 @@ export declare class ByteTransform {
|
|
|
60
62
|
IsStringReverseByteWord: boolean;
|
|
61
63
|
DataFormat: DataFormat;
|
|
62
64
|
constructor(format?: DataFormat);
|
|
65
|
+
/**
|
|
66
|
+
* 按照 DataFormat 重新排序字节
|
|
67
|
+
* 完全匹配 C# RegularByteTransform 的 ByteTransDataFormat* 方法
|
|
68
|
+
* 转换后的字节将用小端序 DataView 读取
|
|
69
|
+
*/
|
|
63
70
|
private order;
|
|
64
71
|
private view;
|
|
65
72
|
private dataView;
|
|
@@ -84,12 +91,31 @@ export declare abstract class DeviceClient {
|
|
|
84
91
|
ConnectionId: string;
|
|
85
92
|
protected socket?: net.Socket;
|
|
86
93
|
private connecting?;
|
|
94
|
+
protected communicationLock: ICommunicationLock;
|
|
95
|
+
protected requestQueue: RequestQueue;
|
|
96
|
+
EnableCommunicationLock: boolean;
|
|
87
97
|
constructor(ipAddress?: string, port?: number);
|
|
98
|
+
/**
|
|
99
|
+
* 获取当前协议的消息解析器
|
|
100
|
+
* 子类应该重写此方法以提供特定协议的消息解析器
|
|
101
|
+
*/
|
|
102
|
+
protected GetNewNetMessage(): INetMessage | undefined;
|
|
88
103
|
ConnectServer(): Promise<OperateResult<any>>;
|
|
89
104
|
ConnectClose(): Promise<OperateResult<any>>;
|
|
90
|
-
|
|
105
|
+
/**
|
|
106
|
+
* 发送请求并接收响应(带通信锁和队列)
|
|
107
|
+
*/
|
|
108
|
+
protected request(frame: Buffer, parser?: (data: Buffer) => Buffer): Promise<OperateResult<Buffer>>;
|
|
109
|
+
/**
|
|
110
|
+
* 使用 INetMessage 解析器发送请求
|
|
111
|
+
*/
|
|
112
|
+
private requestWithMessage;
|
|
91
113
|
/** Send one frame on an already connected socket (used by protocol handshakes). */
|
|
92
114
|
protected requestConnected(frame: Buffer, parser: (data: Buffer) => Buffer): Promise<OperateResult<Buffer>>;
|
|
115
|
+
/**
|
|
116
|
+
* 批量发送请求(自动合并结果)
|
|
117
|
+
*/
|
|
118
|
+
protected ReadFromCoreServer(commands: Buffer[]): Promise<OperateResult<Buffer>>;
|
|
93
119
|
protected fromResult<T>(result: OperateResult<Buffer>, fn: (data: Buffer) => T): OperateResult<T>;
|
|
94
120
|
}
|
|
95
121
|
export declare function wordsFor(type: string, length: number): number;
|