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,204 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MelsecMcAsciiUdp = void 0;
|
|
4
|
+
const DeviceUdpNet_1 = require("../core/DeviceUdpNet");
|
|
5
|
+
const Core_1 = require("../core/Core");
|
|
6
|
+
const MelsecMcNet_1 = require("./MelsecMcNet");
|
|
7
|
+
/**
|
|
8
|
+
* 三菱 MC 协议 ASCII 格式 UDP 客户端
|
|
9
|
+
* Mitsubishi MC protocol ASCII format over UDP
|
|
10
|
+
*/
|
|
11
|
+
class MelsecMcAsciiUdp extends DeviceUdpNet_1.DeviceUdpNet {
|
|
12
|
+
NetworkNumber = 0;
|
|
13
|
+
PLCNumber = 0xff;
|
|
14
|
+
NetworkStationNumber = 0;
|
|
15
|
+
TargetIOStation = 1023;
|
|
16
|
+
EnableWriteBitToWordRegister = true;
|
|
17
|
+
constructor(ipAddress, port = 6001) {
|
|
18
|
+
super(ipAddress, port);
|
|
19
|
+
this.ByteTransform.DataFormat = Core_1.DataFormat.DCBA;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 将二进制转换为 ASCII
|
|
23
|
+
*/
|
|
24
|
+
toAscii(data) {
|
|
25
|
+
return Buffer.from(data.toString('hex').toUpperCase(), 'ascii');
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 将 ASCII 转换为二进制
|
|
29
|
+
*/
|
|
30
|
+
fromAscii(ascii) {
|
|
31
|
+
return Buffer.from(ascii.toString('ascii'), 'hex');
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 打包 ASCII 格式命令
|
|
35
|
+
*/
|
|
36
|
+
packAscii(core) {
|
|
37
|
+
const header = Buffer.alloc(9);
|
|
38
|
+
header.writeUInt16BE(0x3530, 0); // "50"
|
|
39
|
+
header.writeUInt16BE(0x3030, 2); // "00"
|
|
40
|
+
// 网络号
|
|
41
|
+
const netHex = this.NetworkNumber.toString(16).padStart(2, '0').toUpperCase();
|
|
42
|
+
header[4] = netHex.charCodeAt(0);
|
|
43
|
+
header[5] = netHex.charCodeAt(1);
|
|
44
|
+
// PLC 号
|
|
45
|
+
const plcHex = this.PLCNumber.toString(16).padStart(2, '0').toUpperCase();
|
|
46
|
+
header[6] = plcHex.charCodeAt(0);
|
|
47
|
+
header[7] = plcHex.charCodeAt(1);
|
|
48
|
+
// 目标 IO 站号
|
|
49
|
+
const ioHex = this.TargetIOStation.toString(16).padStart(4, '0').toUpperCase();
|
|
50
|
+
const ioBuffer = Buffer.from(ioHex, 'ascii');
|
|
51
|
+
// 网络站号
|
|
52
|
+
const stationHex = this.NetworkStationNumber.toString(16).padStart(2, '0').toUpperCase();
|
|
53
|
+
const stationBuffer = Buffer.from(stationHex, 'ascii');
|
|
54
|
+
// 数据长度(ASCII 字符数)
|
|
55
|
+
const dataLength = (core.length * 2).toString(16).padStart(4, '0').toUpperCase();
|
|
56
|
+
const lengthBuffer = Buffer.from(dataLength, 'ascii');
|
|
57
|
+
// 监视定时器
|
|
58
|
+
const timer = Buffer.from('0010', 'ascii');
|
|
59
|
+
// 转换核心数据为 ASCII
|
|
60
|
+
const coreAscii = this.toAscii(core);
|
|
61
|
+
return Buffer.concat([
|
|
62
|
+
header,
|
|
63
|
+
ioBuffer,
|
|
64
|
+
stationBuffer,
|
|
65
|
+
lengthBuffer,
|
|
66
|
+
timer,
|
|
67
|
+
coreAscii
|
|
68
|
+
]);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* 发送请求
|
|
72
|
+
*/
|
|
73
|
+
async transact(core) {
|
|
74
|
+
const frame = this.packAscii(core);
|
|
75
|
+
const result = await this.request(frame);
|
|
76
|
+
if (!result.IsSuccess)
|
|
77
|
+
return result;
|
|
78
|
+
const response = result.Content;
|
|
79
|
+
// ASCII 格式:响应至少包含 22 个字符的头部
|
|
80
|
+
if (response.length < 22) {
|
|
81
|
+
return new Core_1.OperateResult('Invalid response length', -1);
|
|
82
|
+
}
|
|
83
|
+
// 提取结束码
|
|
84
|
+
const endCodeHex = response.toString('ascii', 18, 22);
|
|
85
|
+
const endCode = parseInt(endCodeHex, 16);
|
|
86
|
+
if (endCode !== 0) {
|
|
87
|
+
return new Core_1.OperateResult(`Melsec error: 0x${endCode.toString(16)}`, endCode);
|
|
88
|
+
}
|
|
89
|
+
// 提取数据部分并转换为二进制
|
|
90
|
+
const dataAscii = response.subarray(22);
|
|
91
|
+
return Core_1.OperateResult.CreateSuccessResult(this.fromAscii(dataAscii));
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* 读取字数据
|
|
95
|
+
*/
|
|
96
|
+
async Read(address, length) {
|
|
97
|
+
const a = (0, MelsecMcNet_1.parseMelsecAddress)(address, length, false);
|
|
98
|
+
if (!a.IsSuccess)
|
|
99
|
+
return Core_1.OperateResult.CreateFailedResult(a);
|
|
100
|
+
const d = a.Content;
|
|
101
|
+
const core = Buffer.alloc(10);
|
|
102
|
+
core[0] = 0x01; // 批量读取
|
|
103
|
+
core[1] = 0x04; // 子命令
|
|
104
|
+
core[2] = 0x00; // 字单位
|
|
105
|
+
// 起始地址(3字节小端)
|
|
106
|
+
core.writeUIntLE(d.AddressStart, 3, 3);
|
|
107
|
+
// 设备代码
|
|
108
|
+
core[6] = d.DataCode;
|
|
109
|
+
// 读取长度
|
|
110
|
+
core.writeUInt16LE(length, 7);
|
|
111
|
+
return this.transact(core);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* 读取位数据
|
|
115
|
+
*/
|
|
116
|
+
async ReadBool(address, length = 1) {
|
|
117
|
+
const a = (0, MelsecMcNet_1.parseMelsecAddress)(address, length, true);
|
|
118
|
+
if (!a.IsSuccess)
|
|
119
|
+
return Core_1.OperateResult.CreateFailedResult(a);
|
|
120
|
+
const d = a.Content;
|
|
121
|
+
const core = Buffer.alloc(10);
|
|
122
|
+
core[0] = 0x01; // 批量读取
|
|
123
|
+
core[1] = 0x04; // 子命令
|
|
124
|
+
core[2] = 0x01; // 位单位
|
|
125
|
+
// 起始地址(3字节小端)
|
|
126
|
+
core.writeUIntLE(d.AddressStart, 3, 3);
|
|
127
|
+
// 设备代码
|
|
128
|
+
core[6] = d.DataCode;
|
|
129
|
+
// 读取长度
|
|
130
|
+
core.writeUInt16LE(length, 7);
|
|
131
|
+
const result = await this.transact(core);
|
|
132
|
+
if (!result.IsSuccess)
|
|
133
|
+
return Core_1.OperateResult.CreateFailedResult(result);
|
|
134
|
+
const values = [];
|
|
135
|
+
for (let i = 0; i < length; i++) {
|
|
136
|
+
values.push(result.Content[i] !== 0);
|
|
137
|
+
}
|
|
138
|
+
return Core_1.OperateResult.CreateSuccessResult(length === 1 ? values[0] : values);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* 写入字数据
|
|
142
|
+
*/
|
|
143
|
+
async Write(address, data) {
|
|
144
|
+
const length = Math.ceil(data.length / 2);
|
|
145
|
+
const a = (0, MelsecMcNet_1.parseMelsecAddress)(address, length, false);
|
|
146
|
+
if (!a.IsSuccess)
|
|
147
|
+
return Core_1.OperateResult.CreateFailedResult(a);
|
|
148
|
+
const d = a.Content;
|
|
149
|
+
const core = Buffer.alloc(10 + data.length);
|
|
150
|
+
core[0] = 0x01; // 批量写入
|
|
151
|
+
core[1] = 0x14; // 子命令
|
|
152
|
+
core[2] = 0x00; // 字单位
|
|
153
|
+
// 起始地址(3字节小端)
|
|
154
|
+
core.writeUIntLE(d.AddressStart, 3, 3);
|
|
155
|
+
// 设备代码
|
|
156
|
+
core[6] = d.DataCode;
|
|
157
|
+
// 写入长度
|
|
158
|
+
core.writeUInt16LE(length, 7);
|
|
159
|
+
// 数据
|
|
160
|
+
data.copy(core, 10);
|
|
161
|
+
const result = await this.transact(core);
|
|
162
|
+
return result.IsSuccess ? Core_1.OperateResult.CreateSuccessResult() : Core_1.OperateResult.CreateFailedResult(result);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* 读取 Int16
|
|
166
|
+
*/
|
|
167
|
+
async ReadInt16(address, length = 1) {
|
|
168
|
+
const result = await this.Read(address, length);
|
|
169
|
+
if (!result.IsSuccess)
|
|
170
|
+
return Core_1.OperateResult.CreateFailedResult(result);
|
|
171
|
+
const values = [];
|
|
172
|
+
for (let i = 0; i < length; i++) {
|
|
173
|
+
values.push(this.ByteTransform.TransInt16(result.Content, i * 2));
|
|
174
|
+
}
|
|
175
|
+
return Core_1.OperateResult.CreateSuccessResult(length === 1 ? values[0] : values);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* 读取 UInt16
|
|
179
|
+
*/
|
|
180
|
+
async ReadUInt16(address, length = 1) {
|
|
181
|
+
const result = await this.Read(address, length);
|
|
182
|
+
if (!result.IsSuccess)
|
|
183
|
+
return Core_1.OperateResult.CreateFailedResult(result);
|
|
184
|
+
const values = [];
|
|
185
|
+
for (let i = 0; i < length; i++) {
|
|
186
|
+
values.push(this.ByteTransform.TransUInt16(result.Content, i * 2));
|
|
187
|
+
}
|
|
188
|
+
return Core_1.OperateResult.CreateSuccessResult(length === 1 ? values[0] : values);
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* 读取 Float
|
|
192
|
+
*/
|
|
193
|
+
async ReadFloat(address, length = 1) {
|
|
194
|
+
const result = await this.Read(address, length * 2);
|
|
195
|
+
if (!result.IsSuccess)
|
|
196
|
+
return Core_1.OperateResult.CreateFailedResult(result);
|
|
197
|
+
const values = [];
|
|
198
|
+
for (let i = 0; i < length; i++) {
|
|
199
|
+
values.push(this.ByteTransform.TransSingle(result.Content, i * 4));
|
|
200
|
+
}
|
|
201
|
+
return Core_1.OperateResult.CreateSuccessResult(length === 1 ? values[0] : values);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
exports.MelsecMcAsciiUdp = MelsecMcAsciiUdp;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DeviceClient, OperateResult } from '../core/Core';
|
|
2
2
|
export interface McAddressData {
|
|
3
3
|
AddressStart: number;
|
|
4
4
|
Length: number;
|
|
@@ -13,7 +13,6 @@ export declare class MelsecMcNet extends DeviceClient {
|
|
|
13
13
|
NetworkStationNumber: number;
|
|
14
14
|
TargetIOStation: number;
|
|
15
15
|
EnableWriteBitToWordRegister: boolean;
|
|
16
|
-
DataFormat: DataFormat;
|
|
17
16
|
constructor(ipAddress?: string, port?: number);
|
|
18
17
|
protected pack(core: Buffer): Buffer<ArrayBuffer>;
|
|
19
18
|
private transact;
|
|
@@ -47,9 +46,3 @@ export declare class MelsecMcNet extends DeviceClient {
|
|
|
47
46
|
RemoteRun(): Promise<OperateResult<string>>;
|
|
48
47
|
RemoteStop(): Promise<OperateResult<string>>;
|
|
49
48
|
}
|
|
50
|
-
export declare class MelsecMcAsciiNet extends MelsecMcNet {
|
|
51
|
-
}
|
|
52
|
-
export declare class MelsecMcUdp extends MelsecMcNet {
|
|
53
|
-
}
|
|
54
|
-
export declare class MelsecMcAsciiUdp extends MelsecMcNet {
|
|
55
|
-
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.MelsecMcNet = void 0;
|
|
4
4
|
exports.parseMelsecAddress = parseMelsecAddress;
|
|
5
5
|
const Core_1 = require("../core/Core");
|
|
6
6
|
const MC = {
|
|
@@ -61,11 +61,10 @@ class MelsecMcNet extends Core_1.DeviceClient {
|
|
|
61
61
|
NetworkStationNumber = 0;
|
|
62
62
|
TargetIOStation = 1023;
|
|
63
63
|
EnableWriteBitToWordRegister = true;
|
|
64
|
-
DataFormat = Core_1.DataFormat.DCBA;
|
|
65
64
|
constructor(ipAddress, port = 6000) {
|
|
66
65
|
super(ipAddress, ipAddress === undefined ? undefined : port);
|
|
67
66
|
this.Port = ipAddress === undefined ? 5000 : port;
|
|
68
|
-
this.ByteTransform = new Core_1.ByteTransform(
|
|
67
|
+
this.ByteTransform = new Core_1.ByteTransform(Core_1.DataFormat.DCBA);
|
|
69
68
|
}
|
|
70
69
|
pack(core) {
|
|
71
70
|
const h = Buffer.alloc(11 + core.length);
|
|
@@ -163,7 +162,7 @@ class MelsecMcNet extends Core_1.DeviceClient {
|
|
|
163
162
|
async ReadUInt64(a, l) {
|
|
164
163
|
return this.typedRead(a, l ?? 1, 8, (b, o) => this.ByteTransform.TransUInt64(b, o));
|
|
165
164
|
}
|
|
166
|
-
async ReadString(address, length, encoding = '
|
|
165
|
+
async ReadString(address, length, encoding = 'ascii') {
|
|
167
166
|
const r = await this.Read(address, length);
|
|
168
167
|
return r.IsSuccess ? Core_1.OperateResult.CreateSuccessResult(this.ByteTransform.TransString(r.Content, encoding)) : Core_1.OperateResult.CreateFailedResult(r);
|
|
169
168
|
}
|
|
@@ -177,7 +176,7 @@ class MelsecMcNet extends Core_1.DeviceClient {
|
|
|
177
176
|
if (typeof value === 'boolean')
|
|
178
177
|
data = Buffer.from([value ? 1 : 0]);
|
|
179
178
|
else if (typeof value === 'string')
|
|
180
|
-
data = Buffer.from(value);
|
|
179
|
+
data = Buffer.from(value, 'ascii');
|
|
181
180
|
else if (Buffer.isBuffer(value))
|
|
182
181
|
data = value;
|
|
183
182
|
else if (Array.isArray(value) && typeof value[0] === 'boolean')
|
|
@@ -260,12 +259,3 @@ class MelsecMcNet extends Core_1.DeviceClient {
|
|
|
260
259
|
}
|
|
261
260
|
}
|
|
262
261
|
exports.MelsecMcNet = MelsecMcNet;
|
|
263
|
-
class MelsecMcAsciiNet extends MelsecMcNet {
|
|
264
|
-
}
|
|
265
|
-
exports.MelsecMcAsciiNet = MelsecMcAsciiNet;
|
|
266
|
-
class MelsecMcUdp extends MelsecMcNet {
|
|
267
|
-
}
|
|
268
|
-
exports.MelsecMcUdp = MelsecMcUdp;
|
|
269
|
-
class MelsecMcAsciiUdp extends MelsecMcNet {
|
|
270
|
-
}
|
|
271
|
-
exports.MelsecMcAsciiUdp = MelsecMcAsciiUdp;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { DeviceUdpNet } from '../core/DeviceUdpNet';
|
|
2
|
+
import { OperateResult } from '../core/Core';
|
|
3
|
+
import { INetMessage } from '../core/INetMessage';
|
|
4
|
+
/**
|
|
5
|
+
* 三菱 MC 协议二进制格式 UDP 客户端
|
|
6
|
+
* Mitsubishi MC protocol binary format over UDP
|
|
7
|
+
*/
|
|
8
|
+
export declare class MelsecMcUdp extends DeviceUdpNet {
|
|
9
|
+
NetworkNumber: number;
|
|
10
|
+
PLCNumber: number;
|
|
11
|
+
NetworkStationNumber: number;
|
|
12
|
+
TargetIOStation: number;
|
|
13
|
+
EnableWriteBitToWordRegister: boolean;
|
|
14
|
+
constructor(ipAddress?: string, port?: number);
|
|
15
|
+
protected GetNewNetMessage(): INetMessage;
|
|
16
|
+
/**
|
|
17
|
+
* 打包二进制格式命令
|
|
18
|
+
*/
|
|
19
|
+
protected pack(core: Buffer): Buffer;
|
|
20
|
+
/**
|
|
21
|
+
* 发送请求
|
|
22
|
+
*/
|
|
23
|
+
private transact;
|
|
24
|
+
/**
|
|
25
|
+
* 读取字数据
|
|
26
|
+
*/
|
|
27
|
+
Read(address: string, length: number): Promise<OperateResult<Buffer>>;
|
|
28
|
+
/**
|
|
29
|
+
* 读取位数据
|
|
30
|
+
*/
|
|
31
|
+
ReadBool(address: string, length?: number): Promise<OperateResult<boolean | boolean[]>>;
|
|
32
|
+
/**
|
|
33
|
+
* 写入字数据
|
|
34
|
+
*/
|
|
35
|
+
Write(address: string, data: Buffer): Promise<OperateResult<void>>;
|
|
36
|
+
/**
|
|
37
|
+
* 读取 Int16
|
|
38
|
+
*/
|
|
39
|
+
ReadInt16(address: string, length?: number): Promise<OperateResult<number | number[]>>;
|
|
40
|
+
/**
|
|
41
|
+
* 读取 UInt16
|
|
42
|
+
*/
|
|
43
|
+
ReadUInt16(address: string, length?: number): Promise<OperateResult<number | number[]>>;
|
|
44
|
+
/**
|
|
45
|
+
* 读取 Int32
|
|
46
|
+
*/
|
|
47
|
+
ReadInt32(address: string, length?: number): Promise<OperateResult<number | number[]>>;
|
|
48
|
+
/**
|
|
49
|
+
* 读取 Float
|
|
50
|
+
*/
|
|
51
|
+
ReadFloat(address: string, length?: number): Promise<OperateResult<number | number[]>>;
|
|
52
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MelsecMcUdp = void 0;
|
|
4
|
+
const DeviceUdpNet_1 = require("../core/DeviceUdpNet");
|
|
5
|
+
const Core_1 = require("../core/Core");
|
|
6
|
+
const INetMessage_1 = require("../core/INetMessage");
|
|
7
|
+
const MelsecMcNet_1 = require("./MelsecMcNet");
|
|
8
|
+
/**
|
|
9
|
+
* 三菱 MC 协议二进制格式 UDP 客户端
|
|
10
|
+
* Mitsubishi MC protocol binary format over UDP
|
|
11
|
+
*/
|
|
12
|
+
class MelsecMcUdp extends DeviceUdpNet_1.DeviceUdpNet {
|
|
13
|
+
NetworkNumber = 0;
|
|
14
|
+
PLCNumber = 0xff;
|
|
15
|
+
NetworkStationNumber = 0;
|
|
16
|
+
TargetIOStation = 1023;
|
|
17
|
+
EnableWriteBitToWordRegister = true;
|
|
18
|
+
constructor(ipAddress, port = 6001) {
|
|
19
|
+
super(ipAddress, port);
|
|
20
|
+
this.ByteTransform.DataFormat = Core_1.DataFormat.DCBA;
|
|
21
|
+
}
|
|
22
|
+
GetNewNetMessage() {
|
|
23
|
+
return new INetMessage_1.MelsecMcMessage();
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 打包二进制格式命令
|
|
27
|
+
*/
|
|
28
|
+
pack(core) {
|
|
29
|
+
const header = Buffer.alloc(11);
|
|
30
|
+
// 副头部(二进制:0x5000)
|
|
31
|
+
header.writeUInt16LE(0x5000, 0);
|
|
32
|
+
// 网络号
|
|
33
|
+
header[2] = this.NetworkNumber;
|
|
34
|
+
// PLC 号
|
|
35
|
+
header[3] = this.PLCNumber;
|
|
36
|
+
// 目标 IO 站号(2 字节)
|
|
37
|
+
header.writeUInt16LE(this.TargetIOStation, 4);
|
|
38
|
+
// 网络站号
|
|
39
|
+
header[6] = this.NetworkStationNumber;
|
|
40
|
+
// 请求数据长度(2 字节) = core.length + 监视定时器(2)
|
|
41
|
+
header.writeUInt16LE(core.length + 2, 7);
|
|
42
|
+
// 监视定时器(2 字节)
|
|
43
|
+
header.writeUInt16LE(0x0010, 9);
|
|
44
|
+
return Buffer.concat([header, core]);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 发送请求
|
|
48
|
+
*/
|
|
49
|
+
async transact(core) {
|
|
50
|
+
const frame = this.pack(core);
|
|
51
|
+
const result = await this.request(frame);
|
|
52
|
+
if (!result.IsSuccess)
|
|
53
|
+
return result;
|
|
54
|
+
const response = result.Content;
|
|
55
|
+
// 检查响应长度
|
|
56
|
+
if (response.length < 11) {
|
|
57
|
+
return new Core_1.OperateResult('Invalid response length', -1);
|
|
58
|
+
}
|
|
59
|
+
// 提取结束码(偏移 9,2 字节)
|
|
60
|
+
const endCode = response.readUInt16LE(9);
|
|
61
|
+
if (endCode !== 0) {
|
|
62
|
+
return new Core_1.OperateResult(`Melsec error: 0x${endCode.toString(16)}`, endCode);
|
|
63
|
+
}
|
|
64
|
+
// 提取数据部分(从偏移 11 开始)
|
|
65
|
+
return Core_1.OperateResult.CreateSuccessResult(response.subarray(11));
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* 读取字数据
|
|
69
|
+
*/
|
|
70
|
+
async Read(address, length) {
|
|
71
|
+
const a = (0, MelsecMcNet_1.parseMelsecAddress)(address, length, false);
|
|
72
|
+
if (!a.IsSuccess)
|
|
73
|
+
return Core_1.OperateResult.CreateFailedResult(a);
|
|
74
|
+
const d = a.Content;
|
|
75
|
+
const core = Buffer.alloc(10);
|
|
76
|
+
core[0] = 0x01; // 批量读取
|
|
77
|
+
core[1] = 0x04; // 子命令
|
|
78
|
+
core[2] = 0x00; // 字单位
|
|
79
|
+
// 起始地址(3字节小端)
|
|
80
|
+
core.writeUIntLE(d.AddressStart, 3, 3);
|
|
81
|
+
// 设备代码
|
|
82
|
+
core[6] = d.DataCode;
|
|
83
|
+
// 读取长度
|
|
84
|
+
core.writeUInt16LE(length, 7);
|
|
85
|
+
return this.transact(core);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* 读取位数据
|
|
89
|
+
*/
|
|
90
|
+
async ReadBool(address, length = 1) {
|
|
91
|
+
const a = (0, MelsecMcNet_1.parseMelsecAddress)(address, length, true);
|
|
92
|
+
if (!a.IsSuccess)
|
|
93
|
+
return Core_1.OperateResult.CreateFailedResult(a);
|
|
94
|
+
const d = a.Content;
|
|
95
|
+
const core = Buffer.alloc(10);
|
|
96
|
+
core[0] = 0x01; // 批量读取
|
|
97
|
+
core[1] = 0x04; // 子命令
|
|
98
|
+
core[2] = 0x01; // 位单位
|
|
99
|
+
// 起始地址(3字节小端)
|
|
100
|
+
core.writeUIntLE(d.AddressStart, 3, 3);
|
|
101
|
+
// 设备代码
|
|
102
|
+
core[6] = d.DataCode;
|
|
103
|
+
// 读取长度
|
|
104
|
+
core.writeUInt16LE(length, 7);
|
|
105
|
+
const result = await this.transact(core);
|
|
106
|
+
if (!result.IsSuccess)
|
|
107
|
+
return Core_1.OperateResult.CreateFailedResult(result);
|
|
108
|
+
const values = [];
|
|
109
|
+
for (let i = 0; i < length; i++) {
|
|
110
|
+
values.push(result.Content[i] !== 0);
|
|
111
|
+
}
|
|
112
|
+
return Core_1.OperateResult.CreateSuccessResult(length === 1 ? values[0] : values);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* 写入字数据
|
|
116
|
+
*/
|
|
117
|
+
async Write(address, data) {
|
|
118
|
+
const length = Math.ceil(data.length / 2);
|
|
119
|
+
const a = (0, MelsecMcNet_1.parseMelsecAddress)(address, length, false);
|
|
120
|
+
if (!a.IsSuccess)
|
|
121
|
+
return Core_1.OperateResult.CreateFailedResult(a);
|
|
122
|
+
const d = a.Content;
|
|
123
|
+
const core = Buffer.alloc(10 + data.length);
|
|
124
|
+
core[0] = 0x01; // 批量写入
|
|
125
|
+
core[1] = 0x14; // 子命令
|
|
126
|
+
core[2] = 0x00; // 字单位
|
|
127
|
+
// 起始地址(3字节小端)
|
|
128
|
+
core.writeUIntLE(d.AddressStart, 3, 3);
|
|
129
|
+
// 设备代码
|
|
130
|
+
core[6] = d.DataCode;
|
|
131
|
+
// 写入长度
|
|
132
|
+
core.writeUInt16LE(length, 7);
|
|
133
|
+
// 数据
|
|
134
|
+
data.copy(core, 10);
|
|
135
|
+
const result = await this.transact(core);
|
|
136
|
+
return result.IsSuccess ? Core_1.OperateResult.CreateSuccessResult() : Core_1.OperateResult.CreateFailedResult(result);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* 读取 Int16
|
|
140
|
+
*/
|
|
141
|
+
async ReadInt16(address, length = 1) {
|
|
142
|
+
const result = await this.Read(address, length);
|
|
143
|
+
if (!result.IsSuccess)
|
|
144
|
+
return Core_1.OperateResult.CreateFailedResult(result);
|
|
145
|
+
const values = [];
|
|
146
|
+
for (let i = 0; i < length; i++) {
|
|
147
|
+
values.push(this.ByteTransform.TransInt16(result.Content, i * 2));
|
|
148
|
+
}
|
|
149
|
+
return Core_1.OperateResult.CreateSuccessResult(length === 1 ? values[0] : values);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* 读取 UInt16
|
|
153
|
+
*/
|
|
154
|
+
async ReadUInt16(address, length = 1) {
|
|
155
|
+
const result = await this.Read(address, length);
|
|
156
|
+
if (!result.IsSuccess)
|
|
157
|
+
return Core_1.OperateResult.CreateFailedResult(result);
|
|
158
|
+
const values = [];
|
|
159
|
+
for (let i = 0; i < length; i++) {
|
|
160
|
+
values.push(this.ByteTransform.TransUInt16(result.Content, i * 2));
|
|
161
|
+
}
|
|
162
|
+
return Core_1.OperateResult.CreateSuccessResult(length === 1 ? values[0] : values);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* 读取 Int32
|
|
166
|
+
*/
|
|
167
|
+
async ReadInt32(address, length = 1) {
|
|
168
|
+
const result = await this.Read(address, length * 2);
|
|
169
|
+
if (!result.IsSuccess)
|
|
170
|
+
return Core_1.OperateResult.CreateFailedResult(result);
|
|
171
|
+
const values = [];
|
|
172
|
+
for (let i = 0; i < length; i++) {
|
|
173
|
+
values.push(this.ByteTransform.TransInt32(result.Content, i * 4));
|
|
174
|
+
}
|
|
175
|
+
return Core_1.OperateResult.CreateSuccessResult(length === 1 ? values[0] : values);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* 读取 Float
|
|
179
|
+
*/
|
|
180
|
+
async ReadFloat(address, length = 1) {
|
|
181
|
+
const result = await this.Read(address, length * 2);
|
|
182
|
+
if (!result.IsSuccess)
|
|
183
|
+
return Core_1.OperateResult.CreateFailedResult(result);
|
|
184
|
+
const values = [];
|
|
185
|
+
for (let i = 0; i < length; i++) {
|
|
186
|
+
values.push(this.ByteTransform.TransSingle(result.Content, i * 4));
|
|
187
|
+
}
|
|
188
|
+
return Core_1.OperateResult.CreateSuccessResult(length === 1 ? values[0] : values);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
exports.MelsecMcUdp = MelsecMcUdp;
|
|
@@ -1,4 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { DeviceSerialPort } from '../core/DeviceSerialPort';
|
|
2
|
+
import { OperateResult, DataFormat } from '../core/Core';
|
|
3
|
+
import { INetMessage } from '../core/INetMessage';
|
|
4
|
+
/**
|
|
5
|
+
* Modbus ASCII 串口客户端
|
|
6
|
+
* Modbus-ASCII serial client with LRC check
|
|
7
|
+
*/
|
|
8
|
+
export declare class ModbusAscii extends DeviceSerialPort {
|
|
9
|
+
Station: number;
|
|
10
|
+
AddressStartWithZero: boolean;
|
|
11
|
+
BroadcastStation: number;
|
|
12
|
+
get DataFormat(): DataFormat;
|
|
13
|
+
set DataFormat(value: DataFormat);
|
|
14
|
+
constructor(station?: number);
|
|
15
|
+
protected GetNewNetMessage(): INetMessage;
|
|
16
|
+
protected PackCommandWithHeader(command: Buffer): Buffer;
|
|
17
|
+
protected UnpackResponseContent(send: Buffer, response: Buffer): OperateResult<Buffer>;
|
|
18
|
+
static calculateLrc(data: Buffer): number;
|
|
19
|
+
static asciiToBinary(ascii: Buffer): OperateResult<Buffer>;
|
|
20
|
+
static ExtraAsciiResponseContent(send: Buffer, response: Buffer, broadcastStation?: number): OperateResult<Buffer>;
|
|
21
|
+
private addr;
|
|
22
|
+
Read(address: string, length: number): Promise<OperateResult<Buffer>>;
|
|
23
|
+
ReadInt16(address: string, length?: number): Promise<OperateResult<number | number[]>>;
|
|
24
|
+
ReadFloat(address: string, length?: number): Promise<OperateResult<number | number[]>>;
|
|
4
25
|
}
|
|
@@ -1,8 +1,114 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ModbusAscii = void 0;
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
const DeviceSerialPort_1 = require("../core/DeviceSerialPort");
|
|
5
|
+
const Core_1 = require("../core/Core");
|
|
6
|
+
const INetMessage_1 = require("../core/INetMessage");
|
|
7
|
+
const ModbusTcpNet_1 = require("./ModbusTcpNet");
|
|
8
|
+
/**
|
|
9
|
+
* Modbus ASCII 串口客户端
|
|
10
|
+
* Modbus-ASCII serial client with LRC check
|
|
11
|
+
*/
|
|
12
|
+
class ModbusAscii extends DeviceSerialPort_1.DeviceSerialPort {
|
|
13
|
+
Station = 1;
|
|
14
|
+
AddressStartWithZero = true;
|
|
15
|
+
BroadcastStation = -1;
|
|
16
|
+
get DataFormat() {
|
|
17
|
+
return this.ByteTransform.DataFormat;
|
|
18
|
+
}
|
|
19
|
+
set DataFormat(value) {
|
|
20
|
+
this.ByteTransform.DataFormat = value;
|
|
21
|
+
}
|
|
22
|
+
constructor(station = 1) {
|
|
23
|
+
super();
|
|
24
|
+
this.Station = station;
|
|
25
|
+
this.ByteTransform.DataFormat = Core_1.DataFormat.CDAB;
|
|
26
|
+
}
|
|
27
|
+
GetNewNetMessage() {
|
|
28
|
+
return new INetMessage_1.ModbusAsciiMessage();
|
|
29
|
+
}
|
|
30
|
+
PackCommandWithHeader(command) {
|
|
31
|
+
const core = Buffer.concat([Buffer.from([this.Station]), command]);
|
|
32
|
+
const lrc = ModbusAscii.calculateLrc(core);
|
|
33
|
+
const hex = Buffer.concat([core, Buffer.from([lrc])]).toString('hex').toUpperCase();
|
|
34
|
+
return Buffer.from(':' + hex + '\r\n', 'ascii');
|
|
35
|
+
}
|
|
36
|
+
UnpackResponseContent(send, response) {
|
|
37
|
+
return ModbusAscii.ExtraAsciiResponseContent(send, response, this.BroadcastStation);
|
|
38
|
+
}
|
|
39
|
+
static calculateLrc(data) {
|
|
40
|
+
let sum = 0;
|
|
41
|
+
for (const byte of data)
|
|
42
|
+
sum += byte;
|
|
43
|
+
return ((~sum) + 1) & 0xFF;
|
|
44
|
+
}
|
|
45
|
+
static asciiToBinary(ascii) {
|
|
46
|
+
try {
|
|
47
|
+
let str = ascii.toString('ascii').trim();
|
|
48
|
+
if (!str.startsWith(':'))
|
|
49
|
+
return new Core_1.OperateResult('ASCII frame must start with ":"', -1);
|
|
50
|
+
str = str.substring(1);
|
|
51
|
+
if (str.endsWith('\r\n'))
|
|
52
|
+
str = str.substring(0, str.length - 2);
|
|
53
|
+
else if (str.endsWith('\n') || str.endsWith('\r'))
|
|
54
|
+
str = str.substring(0, str.length - 1);
|
|
55
|
+
if (str.length % 2 !== 0)
|
|
56
|
+
return new Core_1.OperateResult('Invalid ASCII length', -2);
|
|
57
|
+
return Core_1.OperateResult.CreateSuccessResult(Buffer.from(str, 'hex'));
|
|
58
|
+
}
|
|
59
|
+
catch (e) {
|
|
60
|
+
return new Core_1.OperateResult(`ASCII decode error: ${e.message}`, -3);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
static ExtraAsciiResponseContent(send, response, broadcastStation = -1) {
|
|
64
|
+
const binaryResult = ModbusAscii.asciiToBinary(response);
|
|
65
|
+
if (!binaryResult.IsSuccess)
|
|
66
|
+
return binaryResult;
|
|
67
|
+
const binary = binaryResult.Content;
|
|
68
|
+
const calculated = ModbusAscii.calculateLrc(binary.subarray(0, binary.length - 1));
|
|
69
|
+
if (calculated !== binary[binary.length - 1])
|
|
70
|
+
return new Core_1.OperateResult(`LRC check failed`, -4);
|
|
71
|
+
const data = binary.subarray(0, binary.length - 1);
|
|
72
|
+
const functionCode = data[1];
|
|
73
|
+
if (functionCode === 0x01 || functionCode === 0x02 || functionCode === 0x03 || functionCode === 0x04) {
|
|
74
|
+
const length = data[2];
|
|
75
|
+
return Core_1.OperateResult.CreateSuccessResult(data.subarray(3, 3 + length));
|
|
76
|
+
}
|
|
77
|
+
return Core_1.OperateResult.CreateSuccessResult(data.subarray(2));
|
|
78
|
+
}
|
|
79
|
+
addr(input, code) {
|
|
80
|
+
const p = (0, ModbusTcpNet_1.parseModbusAddress)(input, this.Station, code);
|
|
81
|
+
if (p.IsSuccess && !this.AddressStartWithZero)
|
|
82
|
+
p.Content.address--;
|
|
83
|
+
return p;
|
|
84
|
+
}
|
|
85
|
+
async Read(address, length) {
|
|
86
|
+
const a = this.addr(address, 3);
|
|
87
|
+
if (!a.IsSuccess)
|
|
88
|
+
return Core_1.OperateResult.CreateFailedResult(a);
|
|
89
|
+
const cmd = Buffer.alloc(5);
|
|
90
|
+
cmd[0] = a.Content.code;
|
|
91
|
+
cmd.writeUInt16BE(a.Content.address, 1);
|
|
92
|
+
cmd.writeUInt16BE(length, 3);
|
|
93
|
+
return this.ReadFromCoreServer(cmd);
|
|
94
|
+
}
|
|
95
|
+
async ReadInt16(address, length = 1) {
|
|
96
|
+
const result = await this.Read(address, length);
|
|
97
|
+
if (!result.IsSuccess)
|
|
98
|
+
return Core_1.OperateResult.CreateFailedResult(result);
|
|
99
|
+
const values = [];
|
|
100
|
+
for (let i = 0; i < length; i++)
|
|
101
|
+
values.push(this.ByteTransform.TransInt16(result.Content, i * 2));
|
|
102
|
+
return Core_1.OperateResult.CreateSuccessResult(length === 1 ? values[0] : values);
|
|
103
|
+
}
|
|
104
|
+
async ReadFloat(address, length = 1) {
|
|
105
|
+
const result = await this.Read(address, length * 2);
|
|
106
|
+
if (!result.IsSuccess)
|
|
107
|
+
return Core_1.OperateResult.CreateFailedResult(result);
|
|
108
|
+
const values = [];
|
|
109
|
+
for (let i = 0; i < length; i++)
|
|
110
|
+
values.push(this.ByteTransform.TransSingle(result.Content, i * 4));
|
|
111
|
+
return Core_1.OperateResult.CreateSuccessResult(length === 1 ? values[0] : values);
|
|
112
|
+
}
|
|
7
113
|
}
|
|
8
114
|
exports.ModbusAscii = ModbusAscii;
|