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,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InovanceSerialOverTcp = void 0;
|
|
4
|
+
const ModbusRtuOverTcp_1 = require("../modbus/ModbusRtuOverTcp");
|
|
5
|
+
const Core_1 = require("../core/Core");
|
|
6
|
+
const InovanceTcpNet_1 = require("./InovanceTcpNet");
|
|
7
|
+
/**
|
|
8
|
+
* 汇川 PLC 串口协议 over TCP 客户端(基于 Modbus RTU over TCP)
|
|
9
|
+
* Inovance PLC serial protocol over TCP client (based on Modbus RTU over TCP)
|
|
10
|
+
*/
|
|
11
|
+
class InovanceSerialOverTcp extends ModbusRtuOverTcp_1.ModbusRtuOverTcp {
|
|
12
|
+
Series = InovanceTcpNet_1.InovanceSeries.AM;
|
|
13
|
+
constructor(ipAddress, port = 502, station = 1) {
|
|
14
|
+
super(ipAddress, port, station);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 地址转换:将汇川地址转换为 Modbus 地址
|
|
18
|
+
*/
|
|
19
|
+
TranslateToModbusAddress(address, modbusCode) {
|
|
20
|
+
return (0, InovanceTcpNet_1.parseInovanceAddress)(this.Series, address, modbusCode);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 读取数据
|
|
24
|
+
*/
|
|
25
|
+
async Read(address, length) {
|
|
26
|
+
const a = this.TranslateToModbusAddress(address, 3);
|
|
27
|
+
return a.IsSuccess ? super.Read(a.Content, length) : Core_1.OperateResult.CreateFailedResult(a);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 读取布尔值
|
|
31
|
+
*/
|
|
32
|
+
async ReadBool(address, length = 1) {
|
|
33
|
+
const a = this.TranslateToModbusAddress(address, 1);
|
|
34
|
+
if (!a.IsSuccess)
|
|
35
|
+
return Core_1.OperateResult.CreateFailedResult(a);
|
|
36
|
+
// 构建读取线圈命令
|
|
37
|
+
const cmd = Buffer.alloc(5);
|
|
38
|
+
cmd[0] = 1; // 功能码 01
|
|
39
|
+
cmd.writeUInt16BE(parseInt(a.Content), 1);
|
|
40
|
+
cmd.writeUInt16BE(length, 3);
|
|
41
|
+
const result = await this.sendRequest(cmd);
|
|
42
|
+
if (!result.IsSuccess)
|
|
43
|
+
return Core_1.OperateResult.CreateFailedResult(result);
|
|
44
|
+
const values = [];
|
|
45
|
+
for (let i = 0; i < length; i++) {
|
|
46
|
+
const byteIndex = Math.floor(i / 8);
|
|
47
|
+
const bitIndex = i % 8;
|
|
48
|
+
values.push((result.Content[byteIndex] & (1 << bitIndex)) !== 0);
|
|
49
|
+
}
|
|
50
|
+
return Core_1.OperateResult.CreateSuccessResult(length === 1 ? values[0] : values);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* 写入数据
|
|
54
|
+
*/
|
|
55
|
+
async Write(address, value) {
|
|
56
|
+
// 判断是位写入还是字写入
|
|
57
|
+
const isBitWrite = typeof value === 'boolean' || (Array.isArray(value) && typeof value[0] === 'boolean');
|
|
58
|
+
const code = isBitWrite ? 5 : 6;
|
|
59
|
+
const a = this.TranslateToModbusAddress(address, code);
|
|
60
|
+
if (!a.IsSuccess)
|
|
61
|
+
return Core_1.OperateResult.CreateFailedResult(a);
|
|
62
|
+
const addr = parseInt(a.Content);
|
|
63
|
+
// 布尔值写入
|
|
64
|
+
if (typeof value === 'boolean') {
|
|
65
|
+
const cmd = Buffer.alloc(5);
|
|
66
|
+
cmd[0] = 5;
|
|
67
|
+
cmd.writeUInt16BE(addr, 1);
|
|
68
|
+
cmd.writeUInt16BE(value ? 0xFF00 : 0x0000, 3);
|
|
69
|
+
const result = await this.sendRequest(cmd);
|
|
70
|
+
return result.IsSuccess ? Core_1.OperateResult.CreateSuccessResult() : Core_1.OperateResult.CreateFailedResult(result);
|
|
71
|
+
}
|
|
72
|
+
// 布尔数组写入
|
|
73
|
+
if (Array.isArray(value) && typeof value[0] === 'boolean') {
|
|
74
|
+
const bools = value;
|
|
75
|
+
const byteCount = Math.ceil(bools.length / 8);
|
|
76
|
+
const data = Buffer.alloc(byteCount);
|
|
77
|
+
for (let i = 0; i < bools.length; i++) {
|
|
78
|
+
if (bools[i]) {
|
|
79
|
+
const byteIndex = Math.floor(i / 8);
|
|
80
|
+
const bitIndex = i % 8;
|
|
81
|
+
data[byteIndex] |= (1 << bitIndex);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const cmd = Buffer.alloc(6 + byteCount);
|
|
85
|
+
cmd[0] = 15;
|
|
86
|
+
cmd.writeUInt16BE(addr, 1);
|
|
87
|
+
cmd.writeUInt16BE(bools.length, 3);
|
|
88
|
+
cmd[5] = byteCount;
|
|
89
|
+
data.copy(cmd, 6);
|
|
90
|
+
const result = await this.sendRequest(cmd);
|
|
91
|
+
return result.IsSuccess ? Core_1.OperateResult.CreateSuccessResult() : Core_1.OperateResult.CreateFailedResult(result);
|
|
92
|
+
}
|
|
93
|
+
// Buffer 写入
|
|
94
|
+
if (Buffer.isBuffer(value)) {
|
|
95
|
+
const length = Math.ceil(value.length / 2);
|
|
96
|
+
const a16 = this.TranslateToModbusAddress(address, 16);
|
|
97
|
+
if (!a16.IsSuccess)
|
|
98
|
+
return Core_1.OperateResult.CreateFailedResult(a16);
|
|
99
|
+
const addr16 = parseInt(a16.Content);
|
|
100
|
+
if (length === 1) {
|
|
101
|
+
const cmd = Buffer.alloc(5);
|
|
102
|
+
cmd[0] = 6;
|
|
103
|
+
cmd.writeUInt16BE(addr16, 1);
|
|
104
|
+
cmd.writeUInt16BE(value.readUInt16BE(0), 3);
|
|
105
|
+
const result = await this.sendRequest(cmd);
|
|
106
|
+
return result.IsSuccess ? Core_1.OperateResult.CreateSuccessResult() : Core_1.OperateResult.CreateFailedResult(result);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
const cmd = Buffer.alloc(6 + value.length);
|
|
110
|
+
cmd[0] = 16;
|
|
111
|
+
cmd.writeUInt16BE(addr16, 1);
|
|
112
|
+
cmd.writeUInt16BE(length, 3);
|
|
113
|
+
cmd[5] = value.length;
|
|
114
|
+
value.copy(cmd, 6);
|
|
115
|
+
const result = await this.sendRequest(cmd);
|
|
116
|
+
return result.IsSuccess ? Core_1.OperateResult.CreateSuccessResult() : Core_1.OperateResult.CreateFailedResult(result);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// 数字写入
|
|
120
|
+
if (typeof value === 'number') {
|
|
121
|
+
const cmd = Buffer.alloc(5);
|
|
122
|
+
cmd[0] = 6;
|
|
123
|
+
cmd.writeUInt16BE(addr, 1);
|
|
124
|
+
cmd.writeUInt16BE(value & 0xFFFF, 3);
|
|
125
|
+
const result = await this.sendRequest(cmd);
|
|
126
|
+
return result.IsSuccess ? Core_1.OperateResult.CreateSuccessResult() : Core_1.OperateResult.CreateFailedResult(result);
|
|
127
|
+
}
|
|
128
|
+
// 数字数组写入
|
|
129
|
+
if (Array.isArray(value) && typeof value[0] === 'number') {
|
|
130
|
+
const nums = value;
|
|
131
|
+
const data = Buffer.alloc(nums.length * 2);
|
|
132
|
+
for (let i = 0; i < nums.length; i++) {
|
|
133
|
+
data.writeUInt16BE(nums[i] & 0xFFFF, i * 2);
|
|
134
|
+
}
|
|
135
|
+
const cmd = Buffer.alloc(6 + data.length);
|
|
136
|
+
cmd[0] = 16;
|
|
137
|
+
cmd.writeUInt16BE(addr, 1);
|
|
138
|
+
cmd.writeUInt16BE(nums.length, 3);
|
|
139
|
+
cmd[5] = data.length;
|
|
140
|
+
data.copy(cmd, 6);
|
|
141
|
+
const result = await this.sendRequest(cmd);
|
|
142
|
+
return result.IsSuccess ? Core_1.OperateResult.CreateSuccessResult() : Core_1.OperateResult.CreateFailedResult(result);
|
|
143
|
+
}
|
|
144
|
+
return new Core_1.OperateResult('Unsupported value type', -1);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* 读取 Int16
|
|
148
|
+
*/
|
|
149
|
+
async ReadInt16(address, length = 1) {
|
|
150
|
+
const a = this.TranslateToModbusAddress(address, 3);
|
|
151
|
+
return a.IsSuccess ? super.ReadInt16(a.Content, length) : Core_1.OperateResult.CreateFailedResult(a);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* 读取 Float
|
|
155
|
+
*/
|
|
156
|
+
async ReadFloat(address, length = 1) {
|
|
157
|
+
const a = this.TranslateToModbusAddress(address, 3);
|
|
158
|
+
return a.IsSuccess ? super.ReadFloat(a.Content, length) : Core_1.OperateResult.CreateFailedResult(a);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* 读取字节(MB 地址)
|
|
162
|
+
*/
|
|
163
|
+
async ReadByte(address) {
|
|
164
|
+
const n = Number(address.replace(/^MB?/i, ''));
|
|
165
|
+
const r = await this.Read(`MW${Math.floor(n / 2)}`, 1);
|
|
166
|
+
if (!r.IsSuccess)
|
|
167
|
+
return Core_1.OperateResult.CreateFailedResult(r);
|
|
168
|
+
// 偶数字节在高位,奇数字节在低位
|
|
169
|
+
return Core_1.OperateResult.CreateSuccessResult(n % 2 === 0 ? r.Content[1] : r.Content[0]);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
exports.InovanceSerialOverTcp = InovanceSerialOverTcp;
|
|
@@ -17,7 +17,5 @@ export declare class InovanceTcpNet extends ModbusTcpNet {
|
|
|
17
17
|
Write(address: string, value: any): Promise<any>;
|
|
18
18
|
ReadByte(address: string): Promise<OperateResult<any>>;
|
|
19
19
|
}
|
|
20
|
-
export
|
|
21
|
-
}
|
|
22
|
-
export declare class InovanceSerialOverTcp extends InovanceTcpNet {
|
|
23
|
-
}
|
|
20
|
+
export { InovanceSerial } from './InovanceSerial';
|
|
21
|
+
export { InovanceSerialOverTcp } from './InovanceSerialOverTcp';
|
|
@@ -57,7 +57,17 @@ function parseInovanceAddress(series, address, modbusCode) {
|
|
|
57
57
|
return Core_1.OperateResult.CreateSuccessResult(station + `x=${modbusCode + 48};` + address.replace(/^SDW?/i, ''));
|
|
58
58
|
}
|
|
59
59
|
if (series === InovanceSeries.H3U) {
|
|
60
|
-
const map = {
|
|
60
|
+
const map = {
|
|
61
|
+
X: 63488,
|
|
62
|
+
Y: 64512,
|
|
63
|
+
SM: 9216,
|
|
64
|
+
S: 57344,
|
|
65
|
+
T: 61440,
|
|
66
|
+
C: 62464,
|
|
67
|
+
D: 0,
|
|
68
|
+
SD: 9216,
|
|
69
|
+
R: 12288
|
|
70
|
+
};
|
|
61
71
|
const m = upper.match(/^(SM|SD|[A-Z]+)(.+)$/);
|
|
62
72
|
if (m && map[m[1]] !== undefined)
|
|
63
73
|
return Core_1.OperateResult.CreateSuccessResult(station + String(map[m[1]] + (m[1] === 'X' || m[1] === 'Y' ? parseInt(m[2], 8) : parseInt(m[2], 10))));
|
|
@@ -76,18 +86,35 @@ function parseInovanceAddress(series, address, modbusCode) {
|
|
|
76
86
|
}
|
|
77
87
|
class InovanceTcpNet extends ModbusTcpNet_1.ModbusTcpNet {
|
|
78
88
|
Series = InovanceSeries.AM;
|
|
79
|
-
constructor(ipAddress, port = 502, station = 1) {
|
|
80
|
-
|
|
89
|
+
constructor(ipAddress, port = 502, station = 1) {
|
|
90
|
+
super(ipAddress, port, station);
|
|
91
|
+
}
|
|
92
|
+
TranslateToModbusAddress(address, modbusCode) {
|
|
93
|
+
return parseInovanceAddress(this.Series, address, modbusCode);
|
|
94
|
+
}
|
|
81
95
|
// Address translation changes only the wire address; data API remains Modbus-compatible.
|
|
82
|
-
async Read(address, length) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
96
|
+
async Read(address, length) {
|
|
97
|
+
const a = this.TranslateToModbusAddress(address, 3);
|
|
98
|
+
return a.IsSuccess ? super.Read(a.Content, length) : Core_1.OperateResult.CreateFailedResult(a);
|
|
99
|
+
}
|
|
100
|
+
async ReadBool(address, length) {
|
|
101
|
+
const a = this.TranslateToModbusAddress(address, 1);
|
|
102
|
+
return a.IsSuccess ? super.ReadBool(a.Content, length) : Core_1.OperateResult.CreateFailedResult(a);
|
|
103
|
+
}
|
|
104
|
+
async Write(address, value) {
|
|
105
|
+
const code = typeof value === 'boolean' || (Array.isArray(value) && typeof value[0] === 'boolean') ? 1 : 16;
|
|
106
|
+
const a = this.TranslateToModbusAddress(address, code);
|
|
107
|
+
return a.IsSuccess ? super.Write(a.Content, value) : Core_1.OperateResult.CreateFailedResult(a);
|
|
108
|
+
}
|
|
109
|
+
async ReadByte(address) {
|
|
110
|
+
const n = Number(address.replace(/^MB?/i, ''));
|
|
111
|
+
const r = await this.Read(`MW${Math.floor(n / 2)}`, 1);
|
|
112
|
+
return r.IsSuccess ? Core_1.OperateResult.CreateSuccessResult(n % 2 === 0 ? r.Content[1] : r.Content[0]) : Core_1.OperateResult.CreateFailedResult(r);
|
|
113
|
+
}
|
|
86
114
|
}
|
|
87
115
|
exports.InovanceTcpNet = InovanceTcpNet;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
exports
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
exports.InovanceSerialOverTcp = InovanceSerialOverTcp;
|
|
116
|
+
// 导出串口和串口 over TCP 实现
|
|
117
|
+
var InovanceSerial_1 = require("./InovanceSerial");
|
|
118
|
+
Object.defineProperty(exports, "InovanceSerial", { enumerable: true, get: function () { return InovanceSerial_1.InovanceSerial; } });
|
|
119
|
+
var InovanceSerialOverTcp_1 = require("./InovanceSerialOverTcp");
|
|
120
|
+
Object.defineProperty(exports, "InovanceSerialOverTcp", { enumerable: true, get: function () { return InovanceSerialOverTcp_1.InovanceSerialOverTcp; } });
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { DeviceClient, OperateResult } from '../core/Core';
|
|
2
|
+
/**
|
|
3
|
+
* 三菱 MC 协议 ASCII 格式客户端
|
|
4
|
+
* Mitsubishi MC protocol ASCII format over TCP
|
|
5
|
+
*/
|
|
6
|
+
export declare class MelsecMcAsciiNet extends DeviceClient {
|
|
7
|
+
NetworkNumber: number;
|
|
8
|
+
PLCNumber: number;
|
|
9
|
+
NetworkStationNumber: number;
|
|
10
|
+
TargetIOStation: number;
|
|
11
|
+
EnableWriteBitToWordRegister: boolean;
|
|
12
|
+
constructor(ipAddress?: string, port?: number);
|
|
13
|
+
/**
|
|
14
|
+
* 将二进制转换为 ASCII
|
|
15
|
+
*/
|
|
16
|
+
private toAscii;
|
|
17
|
+
/**
|
|
18
|
+
* 将 ASCII 转换为二进制
|
|
19
|
+
*/
|
|
20
|
+
private fromAscii;
|
|
21
|
+
/**
|
|
22
|
+
* 打包 ASCII 格式命令
|
|
23
|
+
*/
|
|
24
|
+
protected packAscii(core: Buffer): Buffer;
|
|
25
|
+
/**
|
|
26
|
+
* 发送请求
|
|
27
|
+
*/
|
|
28
|
+
private transact;
|
|
29
|
+
/**
|
|
30
|
+
* 读取字数据
|
|
31
|
+
*/
|
|
32
|
+
Read(address: string, length: number): Promise<OperateResult<Buffer>>;
|
|
33
|
+
/**
|
|
34
|
+
* 读取位数据
|
|
35
|
+
*/
|
|
36
|
+
ReadBool(address: string, length?: number): Promise<OperateResult<boolean | boolean[]>>;
|
|
37
|
+
/**
|
|
38
|
+
* 写入字数据
|
|
39
|
+
*/
|
|
40
|
+
Write(address: string, data: Buffer): Promise<OperateResult<void>>;
|
|
41
|
+
/**
|
|
42
|
+
* 读取 Int16
|
|
43
|
+
*/
|
|
44
|
+
ReadInt16(address: string, length?: number): Promise<OperateResult<number | number[]>>;
|
|
45
|
+
/**
|
|
46
|
+
* 读取 Float
|
|
47
|
+
*/
|
|
48
|
+
ReadFloat(address: string, length?: number): Promise<OperateResult<number | number[]>>;
|
|
49
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MelsecMcAsciiNet = void 0;
|
|
4
|
+
const Core_1 = require("../core/Core");
|
|
5
|
+
const MelsecMcNet_1 = require("./MelsecMcNet");
|
|
6
|
+
/**
|
|
7
|
+
* 三菱 MC 协议 ASCII 格式客户端
|
|
8
|
+
* Mitsubishi MC protocol ASCII format over TCP
|
|
9
|
+
*/
|
|
10
|
+
class MelsecMcAsciiNet extends Core_1.DeviceClient {
|
|
11
|
+
NetworkNumber = 0;
|
|
12
|
+
PLCNumber = 0xff;
|
|
13
|
+
NetworkStationNumber = 0;
|
|
14
|
+
TargetIOStation = 1023;
|
|
15
|
+
EnableWriteBitToWordRegister = true;
|
|
16
|
+
constructor(ipAddress, port = 6001) {
|
|
17
|
+
super(ipAddress, port);
|
|
18
|
+
this.ByteTransform.DataFormat = Core_1.DataFormat.DCBA;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 将二进制转换为 ASCII
|
|
22
|
+
*/
|
|
23
|
+
toAscii(data) {
|
|
24
|
+
return Buffer.from(data.toString('hex').toUpperCase(), 'ascii');
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 将 ASCII 转换为二进制
|
|
28
|
+
*/
|
|
29
|
+
fromAscii(ascii) {
|
|
30
|
+
return Buffer.from(ascii.toString('ascii'), 'hex');
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 打包 ASCII 格式命令
|
|
34
|
+
*/
|
|
35
|
+
packAscii(core) {
|
|
36
|
+
const header = Buffer.alloc(9);
|
|
37
|
+
header.writeUInt16BE(0x3530, 0); // "50"
|
|
38
|
+
header.writeUInt16BE(0x3030, 2); // "00"
|
|
39
|
+
// 网络号
|
|
40
|
+
header[4] = this.NetworkNumber.toString(16).toUpperCase().charCodeAt(0);
|
|
41
|
+
header[5] = this.NetworkNumber.toString(16).toUpperCase().charCodeAt(0);
|
|
42
|
+
// PLC 号
|
|
43
|
+
const plcHex = this.PLCNumber.toString(16).padStart(2, '0').toUpperCase();
|
|
44
|
+
header[6] = plcHex.charCodeAt(0);
|
|
45
|
+
header[7] = plcHex.charCodeAt(1);
|
|
46
|
+
// 目标 IO 站号
|
|
47
|
+
const ioHex = this.TargetIOStation.toString(16).padStart(4, '0').toUpperCase();
|
|
48
|
+
const ioBuffer = Buffer.from(ioHex, 'ascii');
|
|
49
|
+
// 网络站号
|
|
50
|
+
const stationHex = this.NetworkStationNumber.toString(16).padStart(2, '0').toUpperCase();
|
|
51
|
+
const stationBuffer = Buffer.from(stationHex, 'ascii');
|
|
52
|
+
// 数据长度(ASCII 字符数)
|
|
53
|
+
const dataLength = (core.length * 2).toString(16).padStart(4, '0').toUpperCase();
|
|
54
|
+
const lengthBuffer = Buffer.from(dataLength, 'ascii');
|
|
55
|
+
// 监视定时器
|
|
56
|
+
const timer = Buffer.from('0010', 'ascii');
|
|
57
|
+
// 转换核心数据为 ASCII
|
|
58
|
+
const coreAscii = this.toAscii(core);
|
|
59
|
+
return Buffer.concat([
|
|
60
|
+
header,
|
|
61
|
+
ioBuffer,
|
|
62
|
+
stationBuffer,
|
|
63
|
+
lengthBuffer,
|
|
64
|
+
timer,
|
|
65
|
+
coreAscii
|
|
66
|
+
]);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* 发送请求
|
|
70
|
+
*/
|
|
71
|
+
async transact(core) {
|
|
72
|
+
const frame = this.packAscii(core);
|
|
73
|
+
const result = await this.request(frame, (data) => {
|
|
74
|
+
// ASCII 格式:响应至少包含 22 个字符的头部
|
|
75
|
+
if (data.length < 22)
|
|
76
|
+
throw new Error('incomplete');
|
|
77
|
+
// 提取数据长度
|
|
78
|
+
const lengthHex = data.toString('ascii', 14, 18);
|
|
79
|
+
const dataLength = parseInt(lengthHex, 16);
|
|
80
|
+
// 总长度 = 头部(22) + 数据长度
|
|
81
|
+
if (data.length < 22 + dataLength)
|
|
82
|
+
throw new Error('incomplete');
|
|
83
|
+
return data.subarray(0, 22 + dataLength);
|
|
84
|
+
});
|
|
85
|
+
if (!result.IsSuccess)
|
|
86
|
+
return result;
|
|
87
|
+
const response = result.Content;
|
|
88
|
+
// 提取结束码
|
|
89
|
+
const endCodeHex = response.toString('ascii', 18, 22);
|
|
90
|
+
const endCode = parseInt(endCodeHex, 16);
|
|
91
|
+
if (endCode !== 0) {
|
|
92
|
+
return new Core_1.OperateResult(`Melsec error: 0x${endCode.toString(16)}`, endCode);
|
|
93
|
+
}
|
|
94
|
+
// 提取数据部分并转换为二进制
|
|
95
|
+
const dataAscii = response.subarray(22);
|
|
96
|
+
return Core_1.OperateResult.CreateSuccessResult(this.fromAscii(dataAscii));
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* 读取字数据
|
|
100
|
+
*/
|
|
101
|
+
async Read(address, length) {
|
|
102
|
+
const a = (0, MelsecMcNet_1.parseMelsecAddress)(address, length, false);
|
|
103
|
+
if (!a.IsSuccess)
|
|
104
|
+
return Core_1.OperateResult.CreateFailedResult(a);
|
|
105
|
+
const d = a.Content;
|
|
106
|
+
const core = Buffer.alloc(10);
|
|
107
|
+
core[0] = 0x01; // 批量读取
|
|
108
|
+
core[1] = 0x04; // 子命令
|
|
109
|
+
core[2] = 0x00; // 字单位
|
|
110
|
+
// 起始地址(3字节小端)
|
|
111
|
+
core.writeUIntLE(d.AddressStart, 3, 3);
|
|
112
|
+
// 设备代码
|
|
113
|
+
core[6] = d.DataCode;
|
|
114
|
+
// 读取长度
|
|
115
|
+
core.writeUInt16LE(length, 7);
|
|
116
|
+
return this.transact(core);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* 读取位数据
|
|
120
|
+
*/
|
|
121
|
+
async ReadBool(address, length = 1) {
|
|
122
|
+
const a = (0, MelsecMcNet_1.parseMelsecAddress)(address, length, true);
|
|
123
|
+
if (!a.IsSuccess)
|
|
124
|
+
return Core_1.OperateResult.CreateFailedResult(a);
|
|
125
|
+
const d = a.Content;
|
|
126
|
+
const core = Buffer.alloc(10);
|
|
127
|
+
core[0] = 0x01; // 批量读取
|
|
128
|
+
core[1] = 0x04; // 子命令
|
|
129
|
+
core[2] = 0x01; // 位单位
|
|
130
|
+
// 起始地址(3字节小端)
|
|
131
|
+
core.writeUIntLE(d.AddressStart, 3, 3);
|
|
132
|
+
// 设备代码
|
|
133
|
+
core[6] = d.DataCode;
|
|
134
|
+
// 读取长度
|
|
135
|
+
core.writeUInt16LE(length, 7);
|
|
136
|
+
const result = await this.transact(core);
|
|
137
|
+
if (!result.IsSuccess)
|
|
138
|
+
return Core_1.OperateResult.CreateFailedResult(result);
|
|
139
|
+
const values = [];
|
|
140
|
+
for (let i = 0; i < length; i++) {
|
|
141
|
+
values.push(result.Content[i] !== 0);
|
|
142
|
+
}
|
|
143
|
+
return Core_1.OperateResult.CreateSuccessResult(length === 1 ? values[0] : values);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* 写入字数据
|
|
147
|
+
*/
|
|
148
|
+
async Write(address, data) {
|
|
149
|
+
const length = Math.ceil(data.length / 2);
|
|
150
|
+
const a = (0, MelsecMcNet_1.parseMelsecAddress)(address, length, false);
|
|
151
|
+
if (!a.IsSuccess)
|
|
152
|
+
return Core_1.OperateResult.CreateFailedResult(a);
|
|
153
|
+
const d = a.Content;
|
|
154
|
+
const core = Buffer.alloc(10 + data.length);
|
|
155
|
+
core[0] = 0x01; // 批量写入
|
|
156
|
+
core[1] = 0x14; // 子命令
|
|
157
|
+
core[2] = 0x00; // 字单位
|
|
158
|
+
// 起始地址(3字节小端)
|
|
159
|
+
core.writeUIntLE(d.AddressStart, 3, 3);
|
|
160
|
+
// 设备代码
|
|
161
|
+
core[6] = d.DataCode;
|
|
162
|
+
// 写入长度
|
|
163
|
+
core.writeUInt16LE(length, 7);
|
|
164
|
+
// 数据
|
|
165
|
+
data.copy(core, 10);
|
|
166
|
+
const result = await this.transact(core);
|
|
167
|
+
return result.IsSuccess ? Core_1.OperateResult.CreateSuccessResult() : Core_1.OperateResult.CreateFailedResult(result);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* 读取 Int16
|
|
171
|
+
*/
|
|
172
|
+
async ReadInt16(address, length = 1) {
|
|
173
|
+
const result = await this.Read(address, length);
|
|
174
|
+
if (!result.IsSuccess)
|
|
175
|
+
return Core_1.OperateResult.CreateFailedResult(result);
|
|
176
|
+
const values = [];
|
|
177
|
+
for (let i = 0; i < length; i++) {
|
|
178
|
+
values.push(this.ByteTransform.TransInt16(result.Content, i * 2));
|
|
179
|
+
}
|
|
180
|
+
return Core_1.OperateResult.CreateSuccessResult(length === 1 ? values[0] : values);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* 读取 Float
|
|
184
|
+
*/
|
|
185
|
+
async ReadFloat(address, length = 1) {
|
|
186
|
+
const result = await this.Read(address, length * 2);
|
|
187
|
+
if (!result.IsSuccess)
|
|
188
|
+
return Core_1.OperateResult.CreateFailedResult(result);
|
|
189
|
+
const values = [];
|
|
190
|
+
for (let i = 0; i < length; i++) {
|
|
191
|
+
values.push(this.ByteTransform.TransSingle(result.Content, i * 4));
|
|
192
|
+
}
|
|
193
|
+
return Core_1.OperateResult.CreateSuccessResult(length === 1 ? values[0] : values);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
exports.MelsecMcAsciiNet = MelsecMcAsciiNet;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { DeviceUdpNet } from '../core/DeviceUdpNet';
|
|
2
|
+
import { OperateResult } from '../core/Core';
|
|
3
|
+
/**
|
|
4
|
+
* 三菱 MC 协议 ASCII 格式 UDP 客户端
|
|
5
|
+
* Mitsubishi MC protocol ASCII format over UDP
|
|
6
|
+
*/
|
|
7
|
+
export declare class MelsecMcAsciiUdp extends DeviceUdpNet {
|
|
8
|
+
NetworkNumber: number;
|
|
9
|
+
PLCNumber: number;
|
|
10
|
+
NetworkStationNumber: number;
|
|
11
|
+
TargetIOStation: number;
|
|
12
|
+
EnableWriteBitToWordRegister: boolean;
|
|
13
|
+
constructor(ipAddress?: string, port?: number);
|
|
14
|
+
/**
|
|
15
|
+
* 将二进制转换为 ASCII
|
|
16
|
+
*/
|
|
17
|
+
private toAscii;
|
|
18
|
+
/**
|
|
19
|
+
* 将 ASCII 转换为二进制
|
|
20
|
+
*/
|
|
21
|
+
private fromAscii;
|
|
22
|
+
/**
|
|
23
|
+
* 打包 ASCII 格式命令
|
|
24
|
+
*/
|
|
25
|
+
protected packAscii(core: Buffer): Buffer;
|
|
26
|
+
/**
|
|
27
|
+
* 发送请求
|
|
28
|
+
*/
|
|
29
|
+
private transact;
|
|
30
|
+
/**
|
|
31
|
+
* 读取字数据
|
|
32
|
+
*/
|
|
33
|
+
Read(address: string, length: number): Promise<OperateResult<Buffer>>;
|
|
34
|
+
/**
|
|
35
|
+
* 读取位数据
|
|
36
|
+
*/
|
|
37
|
+
ReadBool(address: string, length?: number): Promise<OperateResult<boolean | boolean[]>>;
|
|
38
|
+
/**
|
|
39
|
+
* 写入字数据
|
|
40
|
+
*/
|
|
41
|
+
Write(address: string, data: Buffer): Promise<OperateResult<void>>;
|
|
42
|
+
/**
|
|
43
|
+
* 读取 Int16
|
|
44
|
+
*/
|
|
45
|
+
ReadInt16(address: string, length?: number): Promise<OperateResult<number | number[]>>;
|
|
46
|
+
/**
|
|
47
|
+
* 读取 UInt16
|
|
48
|
+
*/
|
|
49
|
+
ReadUInt16(address: string, length?: number): Promise<OperateResult<number | number[]>>;
|
|
50
|
+
/**
|
|
51
|
+
* 读取 Float
|
|
52
|
+
*/
|
|
53
|
+
ReadFloat(address: string, length?: number): Promise<OperateResult<number | number[]>>;
|
|
54
|
+
}
|