@ya-modbus/emulator 0.7.1 → 0.9.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/CHANGELOG.md +12 -0
- package/README.md +97 -5
- package/dist/cjs/src/emulator.d.ts.map +1 -1
- package/dist/cjs/src/emulator.js +14 -1
- package/dist/cjs/src/emulator.js.map +1 -1
- package/dist/cjs/src/transports/rtu.d.ts +12 -15
- package/dist/cjs/src/transports/rtu.d.ts.map +1 -1
- package/dist/cjs/src/transports/rtu.js +172 -78
- package/dist/cjs/src/transports/rtu.js.map +1 -1
- package/dist/cjs/src/transports/tcp.d.ts +38 -0
- package/dist/cjs/src/transports/tcp.d.ts.map +1 -0
- package/dist/cjs/src/transports/tcp.js +209 -0
- package/dist/cjs/src/transports/tcp.js.map +1 -0
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/emulator.d.ts.map +1 -1
- package/dist/esm/src/emulator.js +14 -1
- package/dist/esm/src/emulator.js.map +1 -1
- package/dist/esm/src/transports/rtu.d.ts +12 -15
- package/dist/esm/src/transports/rtu.d.ts.map +1 -1
- package/dist/esm/src/transports/rtu.js +172 -78
- package/dist/esm/src/transports/rtu.js.map +1 -1
- package/dist/esm/src/transports/tcp.d.ts +38 -0
- package/dist/esm/src/transports/tcp.d.ts.map +1 -0
- package/dist/esm/src/transports/tcp.js +205 -0
- package/dist/esm/src/transports/tcp.js.map +1 -0
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emulator.js","sourceRoot":"","sources":["../../../src/emulator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAE5C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAGlD,MAAM,OAAO,cAAc;IAKzB,YAAY,MAAsB;QAJ1B,YAAO,GAAgC,IAAI,GAAG,EAAE,CAAA;QAEhD,YAAO,GAAG,KAAK,CAAA;QAGrB,mCAAmC;QACnC,IAAI,MAAM,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;YAClC,IAAI,CAAC,SAAS,GAAG,IAAI,eAAe,EAAE,CAAA;QACxC,CAAC;aAAM,IAAI,MAAM,CAAC,SAAS,KAAK,KAAK,EAAE,CAAC;YACtC,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACpD,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAA;YACnE,CAAC;YACD,6EAA6E;YAC7E,MAAM,SAAS,GAMX;gBACF,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,GAAG,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;gBACnE,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;gBAC7D,GAAG,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;gBACnE,GAAG,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;aACpE,CAAA;YACD,IAAI,CAAC,SAAS,GAAG,IAAI,YAAY,CAAC,SAAS,CAAC,CAAA;QAC9C,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,0BAA0B,MAAM,CAAC,SAAS,EAAE,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"emulator.js","sourceRoot":"","sources":["../../../src/emulator.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* RTU (serial) transport for Modbus emulator
|
|
3
3
|
*
|
|
4
|
-
* This implementation uses modbus-serial for protocol handling.
|
|
5
|
-
* Serial port communication will be added in future iterations.
|
|
4
|
+
* This implementation uses modbus-serial ServerSerial for protocol handling.
|
|
6
5
|
*/
|
|
7
6
|
import { BaseTransport } from './base.js';
|
|
8
7
|
export interface RtuTransportConfig {
|
|
@@ -13,32 +12,30 @@ export interface RtuTransportConfig {
|
|
|
13
12
|
stopBits?: 1 | 2;
|
|
14
13
|
}
|
|
15
14
|
export declare class RtuTransport extends BaseTransport {
|
|
15
|
+
private config;
|
|
16
16
|
private requestHandler?;
|
|
17
|
+
private server?;
|
|
17
18
|
private started;
|
|
18
|
-
constructor(
|
|
19
|
+
constructor(config: RtuTransportConfig);
|
|
19
20
|
start(): Promise<void>;
|
|
20
21
|
stop(): Promise<void>;
|
|
21
22
|
send(_slaveId: number, _response: Buffer): Promise<void>;
|
|
22
23
|
onRequest(handler: (slaveId: number, request: Buffer) => Promise<Buffer>): void;
|
|
23
24
|
/**
|
|
24
|
-
* Handle
|
|
25
|
-
* @internal
|
|
25
|
+
* Handle register read operations
|
|
26
26
|
*/
|
|
27
|
-
|
|
27
|
+
private handleRegisterRead;
|
|
28
28
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* Returns CRC as a 16-bit value that can be written with writeUInt16LE
|
|
29
|
+
* Handle register write operations
|
|
32
30
|
*/
|
|
33
|
-
private
|
|
31
|
+
private handleRegisterWrite;
|
|
34
32
|
/**
|
|
35
|
-
*
|
|
33
|
+
* Handle coil read operations
|
|
36
34
|
*/
|
|
37
|
-
private
|
|
35
|
+
private handleCoilRead;
|
|
38
36
|
/**
|
|
39
|
-
*
|
|
40
|
-
* @internal
|
|
37
|
+
* Handle coil write operations
|
|
41
38
|
*/
|
|
42
|
-
|
|
39
|
+
private handleCoilWrite;
|
|
43
40
|
}
|
|
44
41
|
//# sourceMappingURL=rtu.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rtu.d.ts","sourceRoot":"","sources":["../../../../src/transports/rtu.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"rtu.d.ts","sourceRoot":"","sources":["../../../../src/transports/rtu.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAEzC,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAAA;IAChC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;IAChB,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;CACjB;AAED,qBAAa,YAAa,SAAQ,aAAa;IAC7C,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,cAAc,CAAC,CAAuD;IAC9E,OAAO,CAAC,MAAM,CAAC,CAAc;IAC7B,OAAO,CAAC,OAAO,CAAQ;gBAEX,MAAM,EAAE,kBAAkB;IAKhC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAuEtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAuB3B,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASxD,SAAS,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI;IAI/E;;OAEG;YACW,kBAAkB;IAmChC;;OAEG;YACW,mBAAmB;IAqCjC;;OAEG;YACW,cAAc;IAiC5B;;OAEG;YACW,eAAe;CAoB9B"}
|
|
@@ -1,120 +1,214 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* RTU (serial) transport for Modbus emulator
|
|
3
3
|
*
|
|
4
|
-
* This implementation uses modbus-serial for protocol handling.
|
|
5
|
-
* Serial port communication will be added in future iterations.
|
|
4
|
+
* This implementation uses modbus-serial ServerSerial for protocol handling.
|
|
6
5
|
*/
|
|
6
|
+
import { ServerSerial } from 'modbus-serial';
|
|
7
7
|
import { BaseTransport } from './base.js';
|
|
8
8
|
export class RtuTransport extends BaseTransport {
|
|
9
|
-
constructor(
|
|
9
|
+
constructor(config) {
|
|
10
10
|
super();
|
|
11
11
|
this.started = false;
|
|
12
|
-
|
|
12
|
+
this.config = config;
|
|
13
13
|
}
|
|
14
|
-
start() {
|
|
15
|
-
this.started
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
async start() {
|
|
15
|
+
if (this.started) {
|
|
16
|
+
throw new Error('Transport already started');
|
|
17
|
+
}
|
|
18
|
+
// Create service vector that bridges modbus-serial callbacks to our request handler
|
|
19
|
+
const serviceVector = {
|
|
20
|
+
getHoldingRegister: async (addr, unitID) => {
|
|
21
|
+
return this.handleRegisterRead(unitID, 0x03, addr, 1);
|
|
22
|
+
},
|
|
23
|
+
getInputRegister: async (addr, unitID) => {
|
|
24
|
+
return this.handleRegisterRead(unitID, 0x04, addr, 1);
|
|
25
|
+
},
|
|
26
|
+
getMultipleHoldingRegisters: async (addr, length, unitID) => {
|
|
27
|
+
return this.handleRegisterRead(unitID, 0x03, addr, length);
|
|
28
|
+
},
|
|
29
|
+
getMultipleInputRegisters: async (addr, length, unitID) => {
|
|
30
|
+
return this.handleRegisterRead(unitID, 0x04, addr, length);
|
|
31
|
+
},
|
|
32
|
+
setRegister: async (addr, value, unitID) => {
|
|
33
|
+
return this.handleRegisterWrite(unitID, 0x06, addr, [value]);
|
|
34
|
+
},
|
|
35
|
+
setRegisterArray: async (addr, values, unitID) => {
|
|
36
|
+
return this.handleRegisterWrite(unitID, 0x10, addr, values);
|
|
37
|
+
},
|
|
38
|
+
getCoil: async (addr, unitID) => {
|
|
39
|
+
return this.handleCoilRead(unitID, 0x01, addr, 1);
|
|
40
|
+
},
|
|
41
|
+
getDiscreteInput: async (addr, unitID) => {
|
|
42
|
+
return this.handleCoilRead(unitID, 0x02, addr, 1);
|
|
43
|
+
},
|
|
44
|
+
setCoil: async (addr, value, unitID) => {
|
|
45
|
+
return this.handleCoilWrite(unitID, 0x05, addr, value);
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
// Build options with only defined serial port parameters
|
|
49
|
+
// Filter out undefined values to satisfy exactOptionalPropertyTypes
|
|
50
|
+
const options = Object.fromEntries(Object.entries({
|
|
51
|
+
path: this.config.port,
|
|
52
|
+
unitID: 255, // Listen to all unit IDs
|
|
53
|
+
baudRate: this.config.baudRate,
|
|
54
|
+
parity: this.config.parity,
|
|
55
|
+
dataBits: this.config.dataBits,
|
|
56
|
+
stopBits: this.config.stopBits,
|
|
57
|
+
}).filter(([, value]) => value !== undefined));
|
|
58
|
+
// Create and start server
|
|
59
|
+
return new Promise((resolve, reject) => {
|
|
60
|
+
this.server = new ServerSerial(serviceVector, {
|
|
61
|
+
...options,
|
|
62
|
+
openCallback: (err) => {
|
|
63
|
+
if (err) {
|
|
64
|
+
reject(err);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
this.started = true;
|
|
68
|
+
resolve();
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
// Handle errors
|
|
73
|
+
this.server.on('error', (err) => {
|
|
74
|
+
// Log error but don't stop server
|
|
75
|
+
console.error('RTU transport error:', err);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
19
78
|
}
|
|
20
|
-
stop() {
|
|
21
|
-
if (!this.started) {
|
|
22
|
-
return
|
|
79
|
+
async stop() {
|
|
80
|
+
if (!this.started || !this.server) {
|
|
81
|
+
return;
|
|
23
82
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
83
|
+
return new Promise((resolve, reject) => {
|
|
84
|
+
if (!this.server) {
|
|
85
|
+
resolve();
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
this.server.close((err) => {
|
|
89
|
+
if (err) {
|
|
90
|
+
reject(err);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
this.started = false;
|
|
94
|
+
delete this.server;
|
|
95
|
+
resolve();
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
});
|
|
27
99
|
}
|
|
28
100
|
send(_slaveId, _response) {
|
|
29
101
|
if (!this.started) {
|
|
30
102
|
return Promise.reject(new Error('Transport not started'));
|
|
31
103
|
}
|
|
32
|
-
//
|
|
104
|
+
// Responses are sent automatically by modbus-serial server
|
|
105
|
+
// This method is kept for interface compatibility
|
|
33
106
|
return Promise.resolve();
|
|
34
107
|
}
|
|
35
108
|
onRequest(handler) {
|
|
36
109
|
this.requestHandler = handler;
|
|
37
110
|
}
|
|
38
111
|
/**
|
|
39
|
-
* Handle
|
|
40
|
-
* @internal
|
|
112
|
+
* Handle register read operations
|
|
41
113
|
*/
|
|
42
|
-
async
|
|
43
|
-
// Minimum frame: slave_id + function_code + CRC (4 bytes)
|
|
44
|
-
if (frame.length < 4) {
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
// Verify CRC
|
|
48
|
-
if (!this.verifyCRC(frame)) {
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
// Extract slave ID (safe after length check)
|
|
52
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
53
|
-
const slaveId = frame[0];
|
|
54
|
-
// Remove CRC to get request data
|
|
55
|
-
const request = frame.subarray(0, frame.length - 2);
|
|
114
|
+
async handleRegisterRead(unitID, functionCode, addr, length) {
|
|
56
115
|
if (!this.requestHandler) {
|
|
57
|
-
|
|
116
|
+
throw new Error('No request handler set');
|
|
58
117
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
118
|
+
// Build Modbus request buffer
|
|
119
|
+
const request = Buffer.alloc(6);
|
|
120
|
+
request[0] = unitID;
|
|
121
|
+
request[1] = functionCode;
|
|
122
|
+
request.writeUInt16BE(addr, 2);
|
|
123
|
+
request.writeUInt16BE(length, 4);
|
|
124
|
+
// Call handler
|
|
125
|
+
const response = await this.requestHandler(unitID, request);
|
|
126
|
+
// Parse response
|
|
127
|
+
const byteCount = response[2];
|
|
128
|
+
if (byteCount === undefined || response.length < 3 + byteCount) {
|
|
129
|
+
throw new Error('Invalid response');
|
|
66
130
|
}
|
|
67
|
-
|
|
68
|
-
|
|
131
|
+
// Extract register values
|
|
132
|
+
const values = [];
|
|
133
|
+
for (let i = 0; i < byteCount / 2; i++) {
|
|
134
|
+
values.push(response.readUInt16BE(3 + i * 2));
|
|
69
135
|
}
|
|
136
|
+
return values;
|
|
70
137
|
}
|
|
71
138
|
/**
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* Returns CRC as a 16-bit value that can be written with writeUInt16LE
|
|
139
|
+
* Handle register write operations
|
|
75
140
|
*/
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
141
|
+
async handleRegisterWrite(unitID, functionCode, addr, values) {
|
|
142
|
+
if (!this.requestHandler) {
|
|
143
|
+
throw new Error('No request handler set');
|
|
144
|
+
}
|
|
145
|
+
// Build Modbus request buffer
|
|
146
|
+
let request;
|
|
147
|
+
if (functionCode === 0x06) {
|
|
148
|
+
// Write single register
|
|
149
|
+
request = Buffer.alloc(6);
|
|
150
|
+
request[0] = unitID;
|
|
151
|
+
request[1] = functionCode;
|
|
152
|
+
request.writeUInt16BE(addr, 2);
|
|
153
|
+
request.writeUInt16BE(values[0] ?? 0, 4);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
// Write multiple registers
|
|
157
|
+
const byteCount = values.length * 2;
|
|
158
|
+
request = Buffer.alloc(7 + byteCount);
|
|
159
|
+
request[0] = unitID;
|
|
160
|
+
request[1] = functionCode;
|
|
161
|
+
request.writeUInt16BE(addr, 2);
|
|
162
|
+
request.writeUInt16BE(values.length, 4);
|
|
163
|
+
request[6] = byteCount;
|
|
164
|
+
for (let i = 0; i < values.length; i++) {
|
|
165
|
+
request.writeUInt16BE(values[i] ?? 0, 7 + i * 2);
|
|
88
166
|
}
|
|
89
167
|
}
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
return ((crc & 0xff) << 8) | ((crc >> 8) & 0xff);
|
|
168
|
+
// Call handler and ignore response
|
|
169
|
+
await this.requestHandler(unitID, request);
|
|
93
170
|
}
|
|
94
171
|
/**
|
|
95
|
-
*
|
|
172
|
+
* Handle coil read operations
|
|
96
173
|
*/
|
|
97
|
-
|
|
98
|
-
if (
|
|
99
|
-
|
|
174
|
+
async handleCoilRead(unitID, functionCode, addr, length) {
|
|
175
|
+
if (!this.requestHandler) {
|
|
176
|
+
throw new Error('No request handler set');
|
|
177
|
+
}
|
|
178
|
+
// Build Modbus request buffer
|
|
179
|
+
const request = Buffer.alloc(6);
|
|
180
|
+
request[0] = unitID;
|
|
181
|
+
request[1] = functionCode;
|
|
182
|
+
request.writeUInt16BE(addr, 2);
|
|
183
|
+
request.writeUInt16BE(length, 4);
|
|
184
|
+
// Call handler
|
|
185
|
+
const response = await this.requestHandler(unitID, request);
|
|
186
|
+
// Parse response - get first bit from first byte of coil data
|
|
187
|
+
const byteCount = response[2];
|
|
188
|
+
if (byteCount === undefined || response.length < 4) {
|
|
189
|
+
throw new Error('Invalid response');
|
|
100
190
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
return receivedCRC === calculatedCRC;
|
|
191
|
+
const coilByte = response[3];
|
|
192
|
+
if (coilByte === undefined) {
|
|
193
|
+
throw new Error('Invalid response');
|
|
194
|
+
}
|
|
195
|
+
return (coilByte & 0x01) === 1;
|
|
107
196
|
}
|
|
108
197
|
/**
|
|
109
|
-
*
|
|
110
|
-
* @internal
|
|
198
|
+
* Handle coil write operations
|
|
111
199
|
*/
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
200
|
+
async handleCoilWrite(unitID, functionCode, addr, value) {
|
|
201
|
+
if (!this.requestHandler) {
|
|
202
|
+
throw new Error('No request handler set');
|
|
203
|
+
}
|
|
204
|
+
// Build Modbus request buffer
|
|
205
|
+
const request = Buffer.alloc(6);
|
|
206
|
+
request[0] = unitID;
|
|
207
|
+
request[1] = functionCode;
|
|
208
|
+
request.writeUInt16BE(addr, 2);
|
|
209
|
+
request.writeUInt16BE(value ? 0xff00 : 0x0000, 4);
|
|
210
|
+
// Call handler and ignore response
|
|
211
|
+
await this.requestHandler(unitID, request);
|
|
118
212
|
}
|
|
119
213
|
}
|
|
120
214
|
//# sourceMappingURL=rtu.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rtu.js","sourceRoot":"","sources":["../../../../src/transports/rtu.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"rtu.js","sourceRoot":"","sources":["../../../../src/transports/rtu.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TCP transport for Modbus emulator
|
|
3
|
+
*
|
|
4
|
+
* This implementation uses modbus-serial ServerTCP for protocol handling.
|
|
5
|
+
*/
|
|
6
|
+
import { BaseTransport } from './base.js';
|
|
7
|
+
export interface TcpTransportConfig {
|
|
8
|
+
host: string;
|
|
9
|
+
port: number;
|
|
10
|
+
}
|
|
11
|
+
export declare class TcpTransport extends BaseTransport {
|
|
12
|
+
private config;
|
|
13
|
+
private requestHandler?;
|
|
14
|
+
private server?;
|
|
15
|
+
private started;
|
|
16
|
+
constructor(config: TcpTransportConfig);
|
|
17
|
+
start(): Promise<void>;
|
|
18
|
+
stop(): Promise<void>;
|
|
19
|
+
send(_slaveId: number, _response: Buffer): Promise<void>;
|
|
20
|
+
onRequest(handler: (slaveId: number, request: Buffer) => Promise<Buffer>): void;
|
|
21
|
+
/**
|
|
22
|
+
* Handle register read operations
|
|
23
|
+
*/
|
|
24
|
+
private handleRegisterRead;
|
|
25
|
+
/**
|
|
26
|
+
* Handle register write operations
|
|
27
|
+
*/
|
|
28
|
+
private handleRegisterWrite;
|
|
29
|
+
/**
|
|
30
|
+
* Handle coil read operations
|
|
31
|
+
*/
|
|
32
|
+
private handleCoilRead;
|
|
33
|
+
/**
|
|
34
|
+
* Handle coil write operations
|
|
35
|
+
*/
|
|
36
|
+
private handleCoilWrite;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=tcp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tcp.d.ts","sourceRoot":"","sources":["../../../../src/transports/tcp.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAEzC,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb;AAED,qBAAa,YAAa,SAAQ,aAAa;IAC7C,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,cAAc,CAAC,CAAuD;IAC9E,OAAO,CAAC,MAAM,CAAC,CAAW;IAC1B,OAAO,CAAC,OAAO,CAAQ;gBAEX,MAAM,EAAE,kBAAkB;IAKhC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA8DtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAuB3B,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASxD,SAAS,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI;IAI/E;;OAEG;YACW,kBAAkB;IAmChC;;OAEG;YACW,mBAAmB;IAqCjC;;OAEG;YACW,cAAc;IAiC5B;;OAEG;YACW,eAAe;CAoB9B"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TCP transport for Modbus emulator
|
|
3
|
+
*
|
|
4
|
+
* This implementation uses modbus-serial ServerTCP for protocol handling.
|
|
5
|
+
*/
|
|
6
|
+
import { ServerTCP } from 'modbus-serial';
|
|
7
|
+
import { BaseTransport } from './base.js';
|
|
8
|
+
export class TcpTransport extends BaseTransport {
|
|
9
|
+
constructor(config) {
|
|
10
|
+
super();
|
|
11
|
+
this.started = false;
|
|
12
|
+
this.config = config;
|
|
13
|
+
}
|
|
14
|
+
async start() {
|
|
15
|
+
if (this.started) {
|
|
16
|
+
throw new Error('Transport already started');
|
|
17
|
+
}
|
|
18
|
+
// Create service vector that bridges modbus-serial callbacks to our request handler
|
|
19
|
+
const serviceVector = {
|
|
20
|
+
getHoldingRegister: async (addr, unitID) => {
|
|
21
|
+
return this.handleRegisterRead(unitID, 0x03, addr, 1);
|
|
22
|
+
},
|
|
23
|
+
getInputRegister: async (addr, unitID) => {
|
|
24
|
+
return this.handleRegisterRead(unitID, 0x04, addr, 1);
|
|
25
|
+
},
|
|
26
|
+
getMultipleHoldingRegisters: async (addr, length, unitID) => {
|
|
27
|
+
return this.handleRegisterRead(unitID, 0x03, addr, length);
|
|
28
|
+
},
|
|
29
|
+
getMultipleInputRegisters: async (addr, length, unitID) => {
|
|
30
|
+
return this.handleRegisterRead(unitID, 0x04, addr, length);
|
|
31
|
+
},
|
|
32
|
+
setRegister: async (addr, value, unitID) => {
|
|
33
|
+
return this.handleRegisterWrite(unitID, 0x06, addr, [value]);
|
|
34
|
+
},
|
|
35
|
+
setRegisterArray: async (addr, values, unitID) => {
|
|
36
|
+
return this.handleRegisterWrite(unitID, 0x10, addr, values);
|
|
37
|
+
},
|
|
38
|
+
getCoil: async (addr, unitID) => {
|
|
39
|
+
return this.handleCoilRead(unitID, 0x01, addr, 1);
|
|
40
|
+
},
|
|
41
|
+
getDiscreteInput: async (addr, unitID) => {
|
|
42
|
+
return this.handleCoilRead(unitID, 0x02, addr, 1);
|
|
43
|
+
},
|
|
44
|
+
setCoil: async (addr, value, unitID) => {
|
|
45
|
+
return this.handleCoilWrite(unitID, 0x05, addr, value);
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
// Build options - all values are required for TCP
|
|
49
|
+
const options = {
|
|
50
|
+
host: this.config.host,
|
|
51
|
+
port: this.config.port,
|
|
52
|
+
unitID: 255, // Listen to all unit IDs
|
|
53
|
+
};
|
|
54
|
+
// Create server
|
|
55
|
+
const server = new ServerTCP(serviceVector, options);
|
|
56
|
+
this.server = server;
|
|
57
|
+
// Wait for initialized event
|
|
58
|
+
return new Promise((resolve) => {
|
|
59
|
+
server.on('initialized', () => {
|
|
60
|
+
this.started = true;
|
|
61
|
+
resolve();
|
|
62
|
+
});
|
|
63
|
+
// Handle errors
|
|
64
|
+
server.on('error', (err) => {
|
|
65
|
+
// Log error but don't stop server
|
|
66
|
+
console.error('TCP transport error:', err);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
async stop() {
|
|
71
|
+
if (!this.started || !this.server) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
return new Promise((resolve, reject) => {
|
|
75
|
+
if (!this.server) {
|
|
76
|
+
resolve();
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
this.server.close((err) => {
|
|
80
|
+
if (err) {
|
|
81
|
+
reject(err);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
this.started = false;
|
|
85
|
+
delete this.server;
|
|
86
|
+
resolve();
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
send(_slaveId, _response) {
|
|
92
|
+
if (!this.started) {
|
|
93
|
+
return Promise.reject(new Error('Transport not started'));
|
|
94
|
+
}
|
|
95
|
+
// Responses are sent automatically by modbus-serial server
|
|
96
|
+
// This method is kept for interface compatibility
|
|
97
|
+
return Promise.resolve();
|
|
98
|
+
}
|
|
99
|
+
onRequest(handler) {
|
|
100
|
+
this.requestHandler = handler;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Handle register read operations
|
|
104
|
+
*/
|
|
105
|
+
async handleRegisterRead(unitID, functionCode, addr, length) {
|
|
106
|
+
if (!this.requestHandler) {
|
|
107
|
+
throw new Error('No request handler set');
|
|
108
|
+
}
|
|
109
|
+
// Build Modbus request buffer
|
|
110
|
+
const request = Buffer.alloc(6);
|
|
111
|
+
request[0] = unitID;
|
|
112
|
+
request[1] = functionCode;
|
|
113
|
+
request.writeUInt16BE(addr, 2);
|
|
114
|
+
request.writeUInt16BE(length, 4);
|
|
115
|
+
// Call handler
|
|
116
|
+
const response = await this.requestHandler(unitID, request);
|
|
117
|
+
// Parse response
|
|
118
|
+
const byteCount = response[2];
|
|
119
|
+
if (byteCount === undefined || response.length < 3 + byteCount) {
|
|
120
|
+
throw new Error('Invalid response');
|
|
121
|
+
}
|
|
122
|
+
// Extract register values
|
|
123
|
+
const values = [];
|
|
124
|
+
for (let i = 0; i < byteCount / 2; i++) {
|
|
125
|
+
values.push(response.readUInt16BE(3 + i * 2));
|
|
126
|
+
}
|
|
127
|
+
return values;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Handle register write operations
|
|
131
|
+
*/
|
|
132
|
+
async handleRegisterWrite(unitID, functionCode, addr, values) {
|
|
133
|
+
if (!this.requestHandler) {
|
|
134
|
+
throw new Error('No request handler set');
|
|
135
|
+
}
|
|
136
|
+
// Build Modbus request buffer
|
|
137
|
+
let request;
|
|
138
|
+
if (functionCode === 0x06) {
|
|
139
|
+
// Write single register
|
|
140
|
+
request = Buffer.alloc(6);
|
|
141
|
+
request[0] = unitID;
|
|
142
|
+
request[1] = functionCode;
|
|
143
|
+
request.writeUInt16BE(addr, 2);
|
|
144
|
+
request.writeUInt16BE(values[0] ?? 0, 4);
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
// Write multiple registers
|
|
148
|
+
const byteCount = values.length * 2;
|
|
149
|
+
request = Buffer.alloc(7 + byteCount);
|
|
150
|
+
request[0] = unitID;
|
|
151
|
+
request[1] = functionCode;
|
|
152
|
+
request.writeUInt16BE(addr, 2);
|
|
153
|
+
request.writeUInt16BE(values.length, 4);
|
|
154
|
+
request[6] = byteCount;
|
|
155
|
+
for (let i = 0; i < values.length; i++) {
|
|
156
|
+
request.writeUInt16BE(values[i] ?? 0, 7 + i * 2);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// Call handler and ignore response
|
|
160
|
+
await this.requestHandler(unitID, request);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Handle coil read operations
|
|
164
|
+
*/
|
|
165
|
+
async handleCoilRead(unitID, functionCode, addr, length) {
|
|
166
|
+
if (!this.requestHandler) {
|
|
167
|
+
throw new Error('No request handler set');
|
|
168
|
+
}
|
|
169
|
+
// Build Modbus request buffer
|
|
170
|
+
const request = Buffer.alloc(6);
|
|
171
|
+
request[0] = unitID;
|
|
172
|
+
request[1] = functionCode;
|
|
173
|
+
request.writeUInt16BE(addr, 2);
|
|
174
|
+
request.writeUInt16BE(length, 4);
|
|
175
|
+
// Call handler
|
|
176
|
+
const response = await this.requestHandler(unitID, request);
|
|
177
|
+
// Parse response - get first bit from first byte of coil data
|
|
178
|
+
const byteCount = response[2];
|
|
179
|
+
if (byteCount === undefined || response.length < 4) {
|
|
180
|
+
throw new Error('Invalid response');
|
|
181
|
+
}
|
|
182
|
+
const coilByte = response[3];
|
|
183
|
+
if (coilByte === undefined) {
|
|
184
|
+
throw new Error('Invalid response');
|
|
185
|
+
}
|
|
186
|
+
return (coilByte & 0x01) === 1;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Handle coil write operations
|
|
190
|
+
*/
|
|
191
|
+
async handleCoilWrite(unitID, functionCode, addr, value) {
|
|
192
|
+
if (!this.requestHandler) {
|
|
193
|
+
throw new Error('No request handler set');
|
|
194
|
+
}
|
|
195
|
+
// Build Modbus request buffer
|
|
196
|
+
const request = Buffer.alloc(6);
|
|
197
|
+
request[0] = unitID;
|
|
198
|
+
request[1] = functionCode;
|
|
199
|
+
request.writeUInt16BE(addr, 2);
|
|
200
|
+
request.writeUInt16BE(value ? 0xff00 : 0x0000, 4);
|
|
201
|
+
// Call handler and ignore response
|
|
202
|
+
await this.requestHandler(unitID, request);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=tcp.js.map
|