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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.OmronFinsNet = exports.OmronPlcType = void 0;
|
|
4
4
|
exports.parseOmronAddress = parseOmronAddress;
|
|
5
5
|
const Core_1 = require("../core/Core");
|
|
6
6
|
var OmronPlcType;
|
|
@@ -8,23 +8,40 @@ var OmronPlcType;
|
|
|
8
8
|
OmronPlcType[OmronPlcType["CSCJ"] = 1] = "CSCJ";
|
|
9
9
|
OmronPlcType[OmronPlcType["CV"] = 2] = "CV";
|
|
10
10
|
})(OmronPlcType || (exports.OmronPlcType = OmronPlcType = {}));
|
|
11
|
-
const area = {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
11
|
+
const area = {
|
|
12
|
+
D: [0x02, 0x82],
|
|
13
|
+
DM: [0x02, 0x82],
|
|
14
|
+
C: [0x30, 0xB0],
|
|
15
|
+
CIO: [0x30, 0xB0],
|
|
16
|
+
W: [0x31, 0xB1],
|
|
17
|
+
WR: [0x31, 0xB1],
|
|
18
|
+
H: [0x32, 0xB2],
|
|
19
|
+
HR: [0x32, 0xB2],
|
|
20
|
+
A: [0x33, 0xB3],
|
|
21
|
+
AR: [0x33, 0xB3],
|
|
22
|
+
E: [0x20, 0xA0],
|
|
23
|
+
EM: [0x20, 0xA0],
|
|
24
|
+
TIM: [0x09, 0x89],
|
|
25
|
+
CNT: [0x09, 0x89]
|
|
26
|
+
};
|
|
27
|
+
function parseOmronAddress(input) {
|
|
28
|
+
try {
|
|
29
|
+
const m = input.trim().match(/^([A-Za-z]+)([0-9A-Fa-f]+)(?:\.([0-9]+))?$/);
|
|
30
|
+
if (!m)
|
|
31
|
+
throw new Error(`Invalid Omron address: ${input}`);
|
|
32
|
+
const key = m[1].toUpperCase(), a = area[key];
|
|
33
|
+
if (!a)
|
|
34
|
+
throw new Error(`Unsupported Omron address: ${input}`);
|
|
35
|
+
const word = Number.parseInt(m[2], key === 'E' || key === 'EM' ? 16 : 10);
|
|
36
|
+
const bit = Number(m[3] ?? 0);
|
|
37
|
+
if (bit < 0 || bit > 15)
|
|
38
|
+
throw new Error('Invalid bit index');
|
|
39
|
+
return Core_1.OperateResult.CreateSuccessResult({ BitCode: a[0], WordCode: a[1], AddressStart: word * 16 + bit });
|
|
40
|
+
}
|
|
41
|
+
catch (e) {
|
|
42
|
+
return new Core_1.OperateResult(e.message);
|
|
43
|
+
}
|
|
24
44
|
}
|
|
25
|
-
catch (e) {
|
|
26
|
-
return new Core_1.OperateResult(e.message);
|
|
27
|
-
} }
|
|
28
45
|
class OmronFinsNet extends Core_1.DeviceClient {
|
|
29
46
|
ICF = 0x80;
|
|
30
47
|
RSV = 0;
|
|
@@ -39,57 +56,181 @@ class OmronFinsNet extends Core_1.DeviceClient {
|
|
|
39
56
|
ReadSplits = 500;
|
|
40
57
|
PlcType = OmronPlcType.CSCJ;
|
|
41
58
|
ReceiveUntilEmpty = false;
|
|
42
|
-
constructor(ipAddress, port = 9600) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
async
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
59
|
+
constructor(ipAddress, port = 9600) {
|
|
60
|
+
super(ipAddress, ipAddress === undefined ? undefined : port);
|
|
61
|
+
this.Port = ipAddress === undefined ? 5000 : port;
|
|
62
|
+
this.ByteTransform = new Core_1.ByteTransform(Core_1.DataFormat.CDAB);
|
|
63
|
+
this.ByteTransform.IsStringReverseByteWord = true;
|
|
64
|
+
}
|
|
65
|
+
pack(core) {
|
|
66
|
+
const h = Buffer.alloc(26 + core.length);
|
|
67
|
+
Buffer.from('FINS').copy(h);
|
|
68
|
+
h.writeUInt32BE(18 + core.length, 4);
|
|
69
|
+
h[11] = 2;
|
|
70
|
+
h[16] = this.ICF;
|
|
71
|
+
h[17] = this.RSV;
|
|
72
|
+
h[18] = this.GCT;
|
|
73
|
+
h[19] = this.DNA;
|
|
74
|
+
h[20] = this.DA1;
|
|
75
|
+
h[21] = this.DA2;
|
|
76
|
+
h[22] = this.SNA;
|
|
77
|
+
h[23] = this.SA1;
|
|
78
|
+
h[24] = this.SA2;
|
|
79
|
+
this.SID = (this.SID + 1) & 255;
|
|
80
|
+
h[25] = this.SID;
|
|
81
|
+
core.copy(h, 26);
|
|
82
|
+
return h;
|
|
83
|
+
}
|
|
84
|
+
async transact(core) {
|
|
85
|
+
const frame = this.pack(core);
|
|
86
|
+
const r = await this.request(frame, data => {
|
|
87
|
+
if (data.length < 30)
|
|
88
|
+
throw new Error('incomplete FINS response');
|
|
89
|
+
const n = data.readUInt32BE(4);
|
|
90
|
+
if (data.length < 8 + n)
|
|
91
|
+
throw new Error('incomplete FINS response');
|
|
92
|
+
return data.subarray(0, 8 + n);
|
|
93
|
+
});
|
|
94
|
+
if (!r.IsSuccess)
|
|
95
|
+
return r;
|
|
96
|
+
const b = r.Content;
|
|
97
|
+
const status = b.readUInt32BE(12);
|
|
98
|
+
if (status !== 0)
|
|
99
|
+
return new Core_1.OperateResult(`FINS TCP error ${status}`, status);
|
|
100
|
+
const end = b.length;
|
|
101
|
+
return Core_1.OperateResult.CreateSuccessResult(b.subarray(30, end));
|
|
102
|
+
}
|
|
103
|
+
command(address, length, isBit = false, write) {
|
|
104
|
+
const a = parseOmronAddress(address);
|
|
105
|
+
if (!a.IsSuccess)
|
|
106
|
+
return Core_1.OperateResult.CreateFailedResult(a);
|
|
107
|
+
const d = a.Content;
|
|
108
|
+
const c = Buffer.alloc(8 + (write?.length ?? 0));
|
|
109
|
+
c[0] = 1;
|
|
110
|
+
c[1] = write ? 2 : 1;
|
|
111
|
+
c[2] = isBit ? d.BitCode : d.WordCode;
|
|
112
|
+
c[3] = (d.AddressStart >> 16) & 255;
|
|
113
|
+
c[4] = (d.AddressStart >> 8) & 255;
|
|
114
|
+
c[5] = d.AddressStart & 255;
|
|
115
|
+
c[6] = (length >> 8) & 255;
|
|
116
|
+
c[7] = length & 255;
|
|
117
|
+
if (write)
|
|
118
|
+
write.copy(c, 8);
|
|
119
|
+
return Core_1.OperateResult.CreateSuccessResult(c);
|
|
120
|
+
}
|
|
121
|
+
async Read(address, length) {
|
|
122
|
+
const c = this.command(address, length, false);
|
|
123
|
+
if (!c.IsSuccess)
|
|
124
|
+
return c;
|
|
125
|
+
return this.transact(c.Content);
|
|
126
|
+
}
|
|
127
|
+
// FINS 字符串默认使用 UTF-8 编码。
|
|
128
|
+
async ReadString(address, length, encoding = 'utf8') {
|
|
129
|
+
const result = await this.Read(address, length);
|
|
130
|
+
return result.IsSuccess
|
|
131
|
+
? Core_1.OperateResult.CreateSuccessResult(this.ByteTransform.TransString(result.Content, encoding))
|
|
132
|
+
: Core_1.OperateResult.CreateFailedResult(result);
|
|
133
|
+
}
|
|
134
|
+
async ReadBool(address, length) {
|
|
135
|
+
const n = length ?? 1, c = this.command(address, n, true);
|
|
136
|
+
if (!c.IsSuccess)
|
|
137
|
+
return Core_1.OperateResult.CreateFailedResult(c);
|
|
138
|
+
const r = await this.transact(c.Content);
|
|
139
|
+
if (!r.IsSuccess)
|
|
140
|
+
return Core_1.OperateResult.CreateFailedResult(r);
|
|
141
|
+
const vals = Array.from(r.Content, x => x !== 0).slice(0, n);
|
|
142
|
+
return Core_1.OperateResult.CreateSuccessResult(length === undefined ? vals[0] : vals);
|
|
143
|
+
}
|
|
144
|
+
async typedRead(address, length, width, fn) {
|
|
145
|
+
const r = await this.Read(address, length * width / 2);
|
|
146
|
+
if (!r.IsSuccess)
|
|
147
|
+
return Core_1.OperateResult.CreateFailedResult(r);
|
|
148
|
+
const vals = Array.from({ length }, (_, i) => fn(r.Content, i * width));
|
|
149
|
+
return Core_1.OperateResult.CreateSuccessResult(length === 1 ? vals[0] : vals);
|
|
150
|
+
}
|
|
151
|
+
async ReadInt16(a, l) {
|
|
152
|
+
return this.typedRead(a, l ?? 1, 2, (b, o) => this.ByteTransform.TransInt16(b, o));
|
|
153
|
+
}
|
|
154
|
+
async ReadUInt16(a, l) {
|
|
155
|
+
return this.typedRead(a, l ?? 1, 2, (b, o) => this.ByteTransform.TransUInt16(b, o));
|
|
156
|
+
}
|
|
157
|
+
async ReadInt32(a, l) {
|
|
158
|
+
return this.typedRead(a, l ?? 1, 4, (b, o) => this.ByteTransform.TransInt32(b, o));
|
|
159
|
+
}
|
|
160
|
+
async ReadUInt32(a, l) {
|
|
161
|
+
return this.typedRead(a, l ?? 1, 4, (b, o) => this.ByteTransform.TransUInt32(b, o));
|
|
162
|
+
}
|
|
163
|
+
async ReadFloat(a, l) {
|
|
164
|
+
return this.typedRead(a, l ?? 1, 4, (b, o) => this.ByteTransform.TransSingle(b, o));
|
|
165
|
+
}
|
|
166
|
+
async ReadDouble(a, l) {
|
|
167
|
+
return this.typedRead(a, l ?? 1, 8, (b, o) => this.ByteTransform.TransDouble(b, o));
|
|
168
|
+
}
|
|
169
|
+
async ReadInt64(a, l) {
|
|
170
|
+
return this.typedRead(a, l ?? 1, 8, (b, o) => this.ByteTransform.TransInt64(b, o));
|
|
171
|
+
}
|
|
172
|
+
async ReadUInt64(a, l) {
|
|
173
|
+
return this.typedRead(a, l ?? 1, 8, (b, o) => this.ByteTransform.TransUInt64(b, o));
|
|
174
|
+
}
|
|
175
|
+
async Write(address, value) {
|
|
176
|
+
const isBit = typeof value === 'boolean' || (Array.isArray(value) && typeof value[0] === 'boolean');
|
|
177
|
+
let data;
|
|
178
|
+
if (typeof value === 'boolean')
|
|
179
|
+
data = Buffer.from([value ? 1 : 0]);
|
|
180
|
+
else if (typeof value === 'string')
|
|
181
|
+
data = Buffer.from(value);
|
|
182
|
+
else if (Buffer.isBuffer(value))
|
|
183
|
+
data = value;
|
|
184
|
+
else if (Array.isArray(value) && typeof value[0] === 'boolean')
|
|
185
|
+
data = Buffer.from(value.map(x => x ? 1 : 0));
|
|
186
|
+
else
|
|
187
|
+
data = this.ByteTransform.TransByte(value, 2);
|
|
188
|
+
const c = this.command(address, isBit ? data.length : data.length / 2, isBit, data);
|
|
189
|
+
if (!c.IsSuccess)
|
|
190
|
+
return c;
|
|
191
|
+
const r = await this.transact(c.Content);
|
|
192
|
+
return r.IsSuccess ? Core_1.OperateResult.CreateSuccessResult() : r;
|
|
193
|
+
}
|
|
194
|
+
WriteByte(a, v) {
|
|
195
|
+
return this.Write(a, this.ByteTransform.TransByte(new Core_1.Byte(v)));
|
|
196
|
+
}
|
|
197
|
+
WriteInt16(a, v) {
|
|
198
|
+
return this.Write(a, this.ByteTransform.TransByte(new Core_1.Int16(v)));
|
|
199
|
+
}
|
|
200
|
+
WriteUInt16(a, v) {
|
|
201
|
+
return this.Write(a, this.ByteTransform.TransByte(new Core_1.UInt16(v)));
|
|
202
|
+
}
|
|
203
|
+
WriteInt32(a, v) {
|
|
204
|
+
return this.Write(a, this.ByteTransform.TransByte(new Core_1.Int32(v)));
|
|
205
|
+
}
|
|
206
|
+
WriteUInt32(a, v) {
|
|
207
|
+
return this.Write(a, this.ByteTransform.TransByte(new Core_1.UInt32(v)));
|
|
208
|
+
}
|
|
209
|
+
WriteFloat(a, v) {
|
|
210
|
+
return this.Write(a, this.ByteTransform.TransByte(new Core_1.Float(v)));
|
|
211
|
+
}
|
|
212
|
+
WriteDouble(a, v) {
|
|
213
|
+
return this.Write(a, this.ByteTransform.TransByte(new Core_1.Double(v)));
|
|
214
|
+
}
|
|
215
|
+
WriteInt64(a, v) {
|
|
216
|
+
return this.Write(a, this.ByteTransform.TransByte(new Core_1.Int64(v)));
|
|
217
|
+
}
|
|
218
|
+
WriteUInt64(a, v) {
|
|
219
|
+
return this.Write(a, this.ByteTransform.TransByte(new Core_1.UInt64(v)));
|
|
220
|
+
}
|
|
221
|
+
async Run() {
|
|
222
|
+
const r = await this.transact(Buffer.from([4, 1, 255, 255, 4]));
|
|
223
|
+
return r.IsSuccess ? Core_1.OperateResult.CreateSuccessResult() : r;
|
|
224
|
+
}
|
|
225
|
+
async Stop() {
|
|
226
|
+
const r = await this.transact(Buffer.from([4, 2, 255, 255]));
|
|
227
|
+
return r.IsSuccess ? Core_1.OperateResult.CreateSuccessResult() : r;
|
|
228
|
+
}
|
|
229
|
+
async ConnectServerAsync() {
|
|
230
|
+
return this.ConnectServer();
|
|
231
|
+
}
|
|
232
|
+
async ConnectCloseAsync() {
|
|
233
|
+
return this.ConnectClose();
|
|
234
|
+
}
|
|
91
235
|
}
|
|
92
236
|
exports.OmronFinsNet = OmronFinsNet;
|
|
93
|
-
class OmronFinsUdp extends OmronFinsNet {
|
|
94
|
-
}
|
|
95
|
-
exports.OmronFinsUdp = OmronFinsUdp;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { DeviceUdpNet } from '../core/DeviceUdpNet';
|
|
2
|
+
import { OperateResult } from '../core/Core';
|
|
3
|
+
import { INetMessage } from '../core/INetMessage';
|
|
4
|
+
/**
|
|
5
|
+
* Omron FINS UDP 客户端
|
|
6
|
+
* 用于通过 FINS/UDP 与设备通信。
|
|
7
|
+
*/
|
|
8
|
+
export declare class OmronFinsUdp extends DeviceUdpNet {
|
|
9
|
+
DA1: number;
|
|
10
|
+
DA2: number;
|
|
11
|
+
SA1: number;
|
|
12
|
+
SA2: number;
|
|
13
|
+
SID: number;
|
|
14
|
+
constructor(ipAddress?: string, port?: number);
|
|
15
|
+
protected GetNewNetMessage(): INetMessage;
|
|
16
|
+
/**
|
|
17
|
+
* 构建 FINS 命令帧
|
|
18
|
+
*/
|
|
19
|
+
private buildFinsCommand;
|
|
20
|
+
/**
|
|
21
|
+
* 读取数据区
|
|
22
|
+
*/
|
|
23
|
+
Read(address: string, length: number): Promise<OperateResult<Buffer>>;
|
|
24
|
+
ReadString(address: string, length: number, encoding?: BufferEncoding): Promise<OperateResult<string>>;
|
|
25
|
+
/**
|
|
26
|
+
* 读取 UInt16
|
|
27
|
+
*/
|
|
28
|
+
ReadUInt16(address: string, length?: number): Promise<OperateResult<number | number[]>>;
|
|
29
|
+
/**
|
|
30
|
+
* 读取 Int16
|
|
31
|
+
*/
|
|
32
|
+
ReadInt16(address: string, length?: number): Promise<OperateResult<number | number[]>>;
|
|
33
|
+
/**
|
|
34
|
+
* 读取 Float
|
|
35
|
+
*/
|
|
36
|
+
ReadFloat(address: string, length?: number): Promise<OperateResult<number | number[]>>;
|
|
37
|
+
/**
|
|
38
|
+
* 写入数据区
|
|
39
|
+
*/
|
|
40
|
+
Write(address: string, data: Buffer): Promise<OperateResult<void>>;
|
|
41
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OmronFinsUdp = void 0;
|
|
4
|
+
const DeviceUdpNet_1 = require("../core/DeviceUdpNet");
|
|
5
|
+
const Core_1 = require("../core/Core");
|
|
6
|
+
const INetMessage_1 = require("../core/INetMessage");
|
|
7
|
+
/**
|
|
8
|
+
* Omron FINS UDP 客户端
|
|
9
|
+
* 用于通过 FINS/UDP 与设备通信。
|
|
10
|
+
*/
|
|
11
|
+
class OmronFinsUdp extends DeviceUdpNet_1.DeviceUdpNet {
|
|
12
|
+
DA1 = 0; // 目标网络地址
|
|
13
|
+
DA2 = 0; // 目标节点地址
|
|
14
|
+
SA1 = 0; // 源网络地址
|
|
15
|
+
SA2 = 0; // 源节点地址
|
|
16
|
+
SID = 0; // 服务 ID
|
|
17
|
+
constructor(ipAddress, port = 9600) {
|
|
18
|
+
super(ipAddress, port);
|
|
19
|
+
this.ByteTransform.DataFormat = Core_1.DataFormat.CDAB;
|
|
20
|
+
}
|
|
21
|
+
GetNewNetMessage() {
|
|
22
|
+
return new INetMessage_1.FinsUdpMessage();
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 构建 FINS 命令帧
|
|
26
|
+
*/
|
|
27
|
+
buildFinsCommand(command) {
|
|
28
|
+
const header = Buffer.alloc(10);
|
|
29
|
+
// FINS 头部
|
|
30
|
+
header[0] = 0x80; // ICF
|
|
31
|
+
header[1] = 0x00; // RSV
|
|
32
|
+
header[2] = 0x02; // GCT
|
|
33
|
+
header[3] = this.DA1; // DNA
|
|
34
|
+
header[4] = this.DA2; // DA1
|
|
35
|
+
header[5] = 0x00; // DA2
|
|
36
|
+
header[6] = this.SA1; // SNA
|
|
37
|
+
header[7] = this.SA2; // SA1
|
|
38
|
+
header[8] = 0x00; // SA2
|
|
39
|
+
header[9] = this.SID++; // SID
|
|
40
|
+
return Buffer.concat([header, command]);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 读取数据区
|
|
44
|
+
*/
|
|
45
|
+
async Read(address, length) {
|
|
46
|
+
// 解析地址(简化实现,实际应该更复杂)
|
|
47
|
+
const addr = parseInt(address);
|
|
48
|
+
const cmd = Buffer.alloc(8);
|
|
49
|
+
cmd[0] = 0x01; // MRC: 读取命令
|
|
50
|
+
cmd[1] = 0x01; // SRC: 读取子命令
|
|
51
|
+
cmd[2] = 0x82; // 存储区代码(DM区)
|
|
52
|
+
cmd.writeUInt16BE(addr, 3); // 起始地址
|
|
53
|
+
cmd[5] = 0x00; // bit
|
|
54
|
+
cmd.writeUInt16BE(length, 6); // 长度
|
|
55
|
+
const frame = this.buildFinsCommand(cmd);
|
|
56
|
+
const result = await this.request(frame);
|
|
57
|
+
if (!result.IsSuccess)
|
|
58
|
+
return result;
|
|
59
|
+
const response = result.Content;
|
|
60
|
+
if (response.length < 12) {
|
|
61
|
+
return new Core_1.OperateResult('Invalid FINS response length', -1);
|
|
62
|
+
}
|
|
63
|
+
// 检查响应码
|
|
64
|
+
const endCode = response.readUInt16BE(10);
|
|
65
|
+
if (endCode !== 0) {
|
|
66
|
+
return new Core_1.OperateResult(`FINS error code: ${endCode}`, endCode);
|
|
67
|
+
}
|
|
68
|
+
// 提取数据
|
|
69
|
+
return Core_1.OperateResult.CreateSuccessResult(response.subarray(12));
|
|
70
|
+
}
|
|
71
|
+
// FINS 字符串默认使用 UTF-8 编码。
|
|
72
|
+
async ReadString(address, length, encoding = 'utf8') {
|
|
73
|
+
const result = await this.Read(address, length);
|
|
74
|
+
return result.IsSuccess
|
|
75
|
+
? Core_1.OperateResult.CreateSuccessResult(this.ByteTransform.TransString(result.Content, encoding))
|
|
76
|
+
: Core_1.OperateResult.CreateFailedResult(result);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 读取 UInt16
|
|
80
|
+
*/
|
|
81
|
+
async ReadUInt16(address, length = 1) {
|
|
82
|
+
const result = await this.Read(address, length);
|
|
83
|
+
if (!result.IsSuccess)
|
|
84
|
+
return Core_1.OperateResult.CreateFailedResult(result);
|
|
85
|
+
const values = [];
|
|
86
|
+
for (let i = 0; i < length; i++) {
|
|
87
|
+
values.push(this.ByteTransform.TransUInt16(result.Content, i * 2));
|
|
88
|
+
}
|
|
89
|
+
return Core_1.OperateResult.CreateSuccessResult(length === 1 ? values[0] : values);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 读取 Int16
|
|
93
|
+
*/
|
|
94
|
+
async ReadInt16(address, length = 1) {
|
|
95
|
+
const result = await this.Read(address, length);
|
|
96
|
+
if (!result.IsSuccess)
|
|
97
|
+
return Core_1.OperateResult.CreateFailedResult(result);
|
|
98
|
+
const values = [];
|
|
99
|
+
for (let i = 0; i < length; i++) {
|
|
100
|
+
values.push(this.ByteTransform.TransInt16(result.Content, i * 2));
|
|
101
|
+
}
|
|
102
|
+
return Core_1.OperateResult.CreateSuccessResult(length === 1 ? values[0] : values);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* 读取 Float
|
|
106
|
+
*/
|
|
107
|
+
async ReadFloat(address, length = 1) {
|
|
108
|
+
const result = await this.Read(address, length * 2);
|
|
109
|
+
if (!result.IsSuccess)
|
|
110
|
+
return Core_1.OperateResult.CreateFailedResult(result);
|
|
111
|
+
const values = [];
|
|
112
|
+
for (let i = 0; i < length; i++) {
|
|
113
|
+
values.push(this.ByteTransform.TransSingle(result.Content, i * 4));
|
|
114
|
+
}
|
|
115
|
+
return Core_1.OperateResult.CreateSuccessResult(length === 1 ? values[0] : values);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* 写入数据区
|
|
119
|
+
*/
|
|
120
|
+
async Write(address, data) {
|
|
121
|
+
const addr = parseInt(address);
|
|
122
|
+
const length = Math.ceil(data.length / 2);
|
|
123
|
+
const cmd = Buffer.alloc(8 + data.length);
|
|
124
|
+
cmd[0] = 0x01; // MRC: 写入命令
|
|
125
|
+
cmd[1] = 0x02; // SRC: 写入子命令
|
|
126
|
+
cmd[2] = 0x82; // 存储区代码(DM区)
|
|
127
|
+
cmd.writeUInt16BE(addr, 3);
|
|
128
|
+
cmd[5] = 0x00;
|
|
129
|
+
cmd.writeUInt16BE(length, 6);
|
|
130
|
+
data.copy(cmd, 8);
|
|
131
|
+
const frame = this.buildFinsCommand(cmd);
|
|
132
|
+
const result = await this.request(frame);
|
|
133
|
+
if (!result.IsSuccess)
|
|
134
|
+
return Core_1.OperateResult.CreateFailedResult(result);
|
|
135
|
+
const response = result.Content;
|
|
136
|
+
if (response.length < 12) {
|
|
137
|
+
return new Core_1.OperateResult('Invalid FINS response length', -1);
|
|
138
|
+
}
|
|
139
|
+
const endCode = response.readUInt16BE(10);
|
|
140
|
+
if (endCode !== 0) {
|
|
141
|
+
return new Core_1.OperateResult(`FINS error code: ${endCode}`, endCode);
|
|
142
|
+
}
|
|
143
|
+
return Core_1.OperateResult.CreateSuccessResult();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
exports.OmronFinsUdp = OmronFinsUdp;
|
|
@@ -48,6 +48,12 @@ export declare class SiemensS7Net extends DeviceClient {
|
|
|
48
48
|
ReadInt64(a: string, l?: number): Promise<OperateResult<any>>;
|
|
49
49
|
ReadUInt64(a: string, l?: number): Promise<OperateResult<any>>;
|
|
50
50
|
ReadString(address: string, length?: number, encoding?: BufferEncoding): Promise<OperateResult<string>>;
|
|
51
|
+
/**
|
|
52
|
+
* 读取西门子专用 S7 字符串。前几个字节保存字符串元数据,
|
|
53
|
+
* 因此需要先读取长度,再读取实际字符串内容。S200 Smart 只有当前长度字节,
|
|
54
|
+
* 其他 S7 CPU 保存最大长度和当前长度两个字节。
|
|
55
|
+
*/
|
|
56
|
+
ReadS7String(address: string, encoding?: BufferEncoding): Promise<OperateResult<string>>;
|
|
51
57
|
Write(address: string, value: Buffer | number | boolean | string | number[] | boolean[]): Promise<OperateResult<any>>;
|
|
52
58
|
WriteByte(a: string, v: number): Promise<OperateResult<any>>;
|
|
53
59
|
WriteInt16(a: string, v: number): Promise<OperateResult<any>>;
|
|
@@ -64,7 +64,7 @@ class SiemensS7Net extends Core_1.DeviceClient {
|
|
|
64
64
|
super(ipAddress, ipAddress === undefined ? undefined : 102);
|
|
65
65
|
this.Port = port ?? 102;
|
|
66
66
|
this.PlcType = siemens;
|
|
67
|
-
// S7
|
|
67
|
+
// S7 数据按高字节在前的顺序传输。
|
|
68
68
|
this.ByteTransform = new Core_1.ByteTransform(Core_1.DataFormat.ABCD);
|
|
69
69
|
}
|
|
70
70
|
static parseTpkt(data) {
|
|
@@ -111,7 +111,11 @@ class SiemensS7Net extends Core_1.DeviceClient {
|
|
|
111
111
|
return tpkt;
|
|
112
112
|
}
|
|
113
113
|
messageId = 1;
|
|
114
|
-
nextMessageId() {
|
|
114
|
+
nextMessageId() {
|
|
115
|
+
const id = this.messageId;
|
|
116
|
+
this.messageId = (this.messageId + 1) & 0xffff;
|
|
117
|
+
return id;
|
|
118
|
+
}
|
|
115
119
|
async ConnectServer() {
|
|
116
120
|
const connected = await super.ConnectServer();
|
|
117
121
|
if (!connected.IsSuccess || this.initialized)
|
|
@@ -127,10 +131,16 @@ class SiemensS7Net extends Core_1.DeviceClient {
|
|
|
127
131
|
return second;
|
|
128
132
|
this.initialized = true;
|
|
129
133
|
return Core_1.OperateResult.CreateSuccessResult();
|
|
130
|
-
})().finally(() => {
|
|
134
|
+
})().finally(() => {
|
|
135
|
+
this.initializing = undefined;
|
|
136
|
+
});
|
|
131
137
|
return this.initializing;
|
|
132
138
|
}
|
|
133
|
-
async ConnectClose() {
|
|
139
|
+
async ConnectClose() {
|
|
140
|
+
this.initialized = false;
|
|
141
|
+
this.initializing = undefined;
|
|
142
|
+
return super.ConnectClose();
|
|
143
|
+
}
|
|
134
144
|
connectionSetupPacket() {
|
|
135
145
|
const packet = Buffer.from([3, 0, 0, 22, 0x11, 0xe0, 0, 0, 0, 1, 0, 0xc0, 1, 10, 0xc1, 2, 1, 2, 0xc2, 2, 1, 0]);
|
|
136
146
|
packet[20] = this.ConnectionType;
|
|
@@ -199,10 +209,39 @@ class SiemensS7Net extends Core_1.DeviceClient {
|
|
|
199
209
|
async ReadUInt64(a, l) {
|
|
200
210
|
return this.typedRead(a, l ?? 1, 8, (b, o) => this.ByteTransform.TransUInt64(b, o));
|
|
201
211
|
}
|
|
202
|
-
async ReadString(address, length, encoding = '
|
|
212
|
+
async ReadString(address, length, encoding = 'ascii') {
|
|
203
213
|
const r = await this.Read(address, length ?? 254);
|
|
204
214
|
return r.IsSuccess ? Core_1.OperateResult.CreateSuccessResult(this.ByteTransform.TransString(r.Content, encoding)) : Core_1.OperateResult.CreateFailedResult(r);
|
|
205
215
|
}
|
|
216
|
+
/**
|
|
217
|
+
* 读取西门子专用 S7 字符串。前几个字节保存字符串元数据,
|
|
218
|
+
* 因此需要先读取长度,再读取实际字符串内容。S200 Smart 只有当前长度字节,
|
|
219
|
+
* 其他 S7 CPU 保存最大长度和当前长度两个字节。
|
|
220
|
+
*/
|
|
221
|
+
async ReadS7String(address, encoding = 'ascii') {
|
|
222
|
+
if (this.PlcType === SiemensPLCS.S200Smart) {
|
|
223
|
+
const header = await this.Read(address, 1);
|
|
224
|
+
if (!header.IsSuccess)
|
|
225
|
+
return Core_1.OperateResult.CreateFailedResult(header);
|
|
226
|
+
const length = header.Content[0];
|
|
227
|
+
const data = await this.Read(address, length + 1);
|
|
228
|
+
if (!data.IsSuccess)
|
|
229
|
+
return Core_1.OperateResult.CreateFailedResult(data);
|
|
230
|
+
return Core_1.OperateResult.CreateSuccessResult(Buffer.from(data.Content.subarray(1, 1 + length)).toString(encoding));
|
|
231
|
+
}
|
|
232
|
+
const header = await this.Read(address, 2);
|
|
233
|
+
if (!header.IsSuccess)
|
|
234
|
+
return Core_1.OperateResult.CreateFailedResult(header);
|
|
235
|
+
const maxLength = header.Content[0];
|
|
236
|
+
const length = header.Content[1];
|
|
237
|
+
if (maxLength === 0 || maxLength === 0xff || length > maxLength) {
|
|
238
|
+
return new Core_1.OperateResult('Value in plc is not string type');
|
|
239
|
+
}
|
|
240
|
+
const data = await this.Read(address, length + 2);
|
|
241
|
+
if (!data.IsSuccess)
|
|
242
|
+
return Core_1.OperateResult.CreateFailedResult(data);
|
|
243
|
+
return Core_1.OperateResult.CreateSuccessResult(Buffer.from(data.Content.subarray(2, 2 + length)).toString(encoding));
|
|
244
|
+
}
|
|
206
245
|
async Write(address, value) {
|
|
207
246
|
const a = parseS7Address(address);
|
|
208
247
|
if (!a.IsSuccess)
|
|
@@ -211,7 +250,7 @@ class SiemensS7Net extends Core_1.DeviceClient {
|
|
|
211
250
|
if (typeof value === 'boolean')
|
|
212
251
|
data = Buffer.from([value ? 1 : 0]);
|
|
213
252
|
else if (typeof value === 'string')
|
|
214
|
-
data = Buffer.from(value);
|
|
253
|
+
data = Buffer.from(value, 'ascii');
|
|
215
254
|
else if (Buffer.isBuffer(value))
|
|
216
255
|
data = value;
|
|
217
256
|
else if (Array.isArray(value) && typeof value[0] === 'boolean')
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ModbusTcpNet } from '../modbus/ModbusTcpNet';
|
|
2
|
+
import { OperateResult } from '../core/Core';
|
|
3
|
+
export declare enum XinJESeries {
|
|
4
|
+
XC = "XC",
|
|
5
|
+
XD = "XD",
|
|
6
|
+
XL = "XL"
|
|
7
|
+
}
|
|
8
|
+
export declare class XinJETcpNet extends ModbusTcpNet {
|
|
9
|
+
Series: XinJESeries;
|
|
10
|
+
constructor(ipAddress?: string, port?: number, series?: XinJESeries);
|
|
11
|
+
private CalculateXinJEStartAddress;
|
|
12
|
+
private TranslateToModbusAddress;
|
|
13
|
+
private ParseXCAddress;
|
|
14
|
+
private ParseXDXLAddress;
|
|
15
|
+
Read(address: string, length: number): Promise<OperateResult<Buffer>>;
|
|
16
|
+
ReadBool(address: string, length?: number): Promise<OperateResult<boolean | boolean[]>>;
|
|
17
|
+
ReadInt16(address: string, length?: number): Promise<OperateResult<number | number[]>>;
|
|
18
|
+
}
|