@ya-modbus/emulator 0.4.1-refactor-scope-driver-packages.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 +23 -0
- package/LICENSE +674 -0
- package/README.md +226 -0
- package/bin/ya-modbus-emulator.js +10 -0
- package/dist/behaviors/function-codes.d.ts +12 -0
- package/dist/behaviors/function-codes.d.ts.map +1 -0
- package/dist/behaviors/function-codes.js +139 -0
- package/dist/behaviors/function-codes.js.map +1 -0
- package/dist/behaviors/timing.d.ts +46 -0
- package/dist/behaviors/timing.d.ts.map +1 -0
- package/dist/behaviors/timing.js +90 -0
- package/dist/behaviors/timing.js.map +1 -0
- package/dist/cli.d.ts +10 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +124 -0
- package/dist/cli.js.map +1 -0
- package/dist/device.d.ts +25 -0
- package/dist/device.d.ts.map +1 -0
- package/dist/device.js +93 -0
- package/dist/device.js.map +1 -0
- package/dist/emulator.d.ts +24 -0
- package/dist/emulator.d.ts.map +1 -0
- package/dist/emulator.js +116 -0
- package/dist/emulator.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/transports/base.d.ts +10 -0
- package/dist/transports/base.d.ts.map +1 -0
- package/dist/transports/base.js +6 -0
- package/dist/transports/base.js.map +1 -0
- package/dist/transports/memory.d.ts +16 -0
- package/dist/transports/memory.d.ts.map +1 -0
- package/dist/transports/memory.js +30 -0
- package/dist/transports/memory.js.map +1 -0
- package/dist/transports/rtu.d.ts +44 -0
- package/dist/transports/rtu.d.ts.map +1 -0
- package/dist/transports/rtu.js +121 -0
- package/dist/transports/rtu.js.map +1 -0
- package/dist/types/config.d.ts +54 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +5 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/device.d.ts +27 -0
- package/dist/types/device.d.ts.map +1 -0
- package/dist/types/device.js +5 -0
- package/dist/types/device.js.map +1 -0
- package/dist/utils/config-loader.d.ts +21 -0
- package/dist/utils/config-loader.d.ts.map +1 -0
- package/dist/utils/config-loader.js +53 -0
- package/dist/utils/config-loader.js.map +1 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# @ya-modbus/emulator
|
|
2
|
+
|
|
3
|
+
Software Modbus device emulator for testing device drivers without physical hardware.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Realistic device simulation**: Mimic actual device constraints and timing characteristics
|
|
8
|
+
- **Test acceleration**: Enable fast, deterministic testing without hardware
|
|
9
|
+
- **Edge case coverage**: Simulate error conditions and edge cases
|
|
10
|
+
- **Multiple transports**: TCP, RTU (virtual/real serial ports), and in-memory
|
|
11
|
+
- **Custom function codes**: Support vendor-specific Modbus extensions
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @ya-modbus/emulator
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { ModbusEmulator } from '@ya-modbus/emulator'
|
|
23
|
+
|
|
24
|
+
// Create emulator with TCP transport
|
|
25
|
+
const emulator = new ModbusEmulator({
|
|
26
|
+
transport: 'tcp',
|
|
27
|
+
port: 5502,
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
// Add a device
|
|
31
|
+
emulator.addDevice({
|
|
32
|
+
slaveId: 1,
|
|
33
|
+
registers: {
|
|
34
|
+
holding: {
|
|
35
|
+
0: 230, // Voltage * 10 = 23.0V
|
|
36
|
+
1: 52, // Current * 10 = 5.2A
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
// Start emulator
|
|
42
|
+
await emulator.start()
|
|
43
|
+
|
|
44
|
+
// Use with your driver tests
|
|
45
|
+
// ...
|
|
46
|
+
|
|
47
|
+
// Stop emulator
|
|
48
|
+
await emulator.stop()
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## CLI Usage
|
|
52
|
+
|
|
53
|
+
The emulator can be used from the command line for quick testing:
|
|
54
|
+
|
|
55
|
+
### Basic Usage
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# Start with config file
|
|
59
|
+
ya-modbus-emulator --config config.yaml
|
|
60
|
+
|
|
61
|
+
# Or specify parameters directly
|
|
62
|
+
ya-modbus-emulator --transport rtu --port /dev/ttyUSB0 --slave-id 1
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Command Line Options
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
Options:
|
|
69
|
+
-c, --config <file> Configuration file (YAML or JSON)
|
|
70
|
+
-t, --transport <type> Transport type: tcp|rtu|memory
|
|
71
|
+
-p, --port <port> TCP port number or serial port path
|
|
72
|
+
-H, --host <host> TCP host address (default: 0.0.0.0)
|
|
73
|
+
-b, --baud-rate <rate> Serial baud rate (default: 9600)
|
|
74
|
+
--parity <type> Serial parity: none|even|odd (default: none)
|
|
75
|
+
-s, --slave-id <id> Slave ID (required if no config file)
|
|
76
|
+
-v, --verbose Enable verbose logging
|
|
77
|
+
-q, --quiet Suppress all output except errors
|
|
78
|
+
--log-requests Log all Modbus requests/responses
|
|
79
|
+
-V, --version output the version number
|
|
80
|
+
-h, --help display help for command
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Configuration Files
|
|
84
|
+
|
|
85
|
+
Create a YAML or JSON configuration file to define devices and behaviors:
|
|
86
|
+
|
|
87
|
+
**Basic RTU Example** (`basic-rtu.yaml`):
|
|
88
|
+
|
|
89
|
+
```yaml
|
|
90
|
+
transport:
|
|
91
|
+
type: rtu
|
|
92
|
+
port: /dev/ttyUSB0
|
|
93
|
+
baudRate: 9600
|
|
94
|
+
parity: none
|
|
95
|
+
|
|
96
|
+
devices:
|
|
97
|
+
- slaveId: 1
|
|
98
|
+
registers:
|
|
99
|
+
holding:
|
|
100
|
+
0: 230 # Voltage * 10 = 23.0V
|
|
101
|
+
1: 52 # Current * 10 = 5.2A
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Power Meter with Timing** (`power-meter.yaml`):
|
|
105
|
+
|
|
106
|
+
```yaml
|
|
107
|
+
transport:
|
|
108
|
+
type: rtu
|
|
109
|
+
port: /dev/ttyUSB0
|
|
110
|
+
|
|
111
|
+
devices:
|
|
112
|
+
- slaveId: 1
|
|
113
|
+
registers:
|
|
114
|
+
holding:
|
|
115
|
+
0: 2300 # Voltage * 10 = 230.0V
|
|
116
|
+
1: 52 # Current * 10 = 5.2A
|
|
117
|
+
2: 11960 # Power = 1196W
|
|
118
|
+
timing:
|
|
119
|
+
pollingInterval: 10
|
|
120
|
+
commandDetectionDelay: [3, 8]
|
|
121
|
+
processingDelay: [2, 5]
|
|
122
|
+
perRegisterDelay: 0.1
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Multiple Devices** (`multi-device.yaml`):
|
|
126
|
+
|
|
127
|
+
```yaml
|
|
128
|
+
transport:
|
|
129
|
+
type: rtu
|
|
130
|
+
port: /dev/ttyUSB0
|
|
131
|
+
|
|
132
|
+
devices:
|
|
133
|
+
- slaveId: 1
|
|
134
|
+
registers:
|
|
135
|
+
holding: { 0: 100, 1: 200 }
|
|
136
|
+
- slaveId: 2
|
|
137
|
+
registers:
|
|
138
|
+
holding: { 0: 300, 1: 400 }
|
|
139
|
+
- slaveId: 3
|
|
140
|
+
registers:
|
|
141
|
+
holding: { 0: 500, 1: 600 }
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
See `examples/config-files/` for more examples.
|
|
145
|
+
|
|
146
|
+
### Testing with Virtual Serial Ports
|
|
147
|
+
|
|
148
|
+
> **⚠️ Note**: RTU transport is currently a placeholder for v0.1.0. Serial port communication will be implemented in v0.2.0. Use the memory transport for testing in this version.
|
|
149
|
+
|
|
150
|
+
For testing without physical hardware, create virtual serial port pairs:
|
|
151
|
+
|
|
152
|
+
**Linux/macOS** (using socat):
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
# Terminal 1: Create virtual serial port pair
|
|
156
|
+
socat -d -d pty,raw,echo=0 pty,raw,echo=0
|
|
157
|
+
# Note the output: /dev/pts/3 <-> /dev/pts/4
|
|
158
|
+
|
|
159
|
+
# Terminal 2: Start emulator on first port
|
|
160
|
+
ya-modbus-emulator --transport rtu --port /dev/pts/3 --slave-id 1
|
|
161
|
+
|
|
162
|
+
# Terminal 3: Run your driver tests against second port
|
|
163
|
+
node test-driver.js --port /dev/pts/4
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Windows** (using com0com):
|
|
167
|
+
|
|
168
|
+
1. Install [com0com](https://sourceforge.net/projects/com0com/)
|
|
169
|
+
2. Create a pair: COM10 <-> COM11
|
|
170
|
+
3. Start emulator: `ya-modbus-emulator --transport rtu --port COM10 --slave-id 1`
|
|
171
|
+
4. Run tests: `node test-driver.js --port COM11`
|
|
172
|
+
|
|
173
|
+
See `examples/virtual-serial-test.md` for detailed virtual serial port testing guide.
|
|
174
|
+
|
|
175
|
+
## Configuration
|
|
176
|
+
|
|
177
|
+
### Timing Behaviors
|
|
178
|
+
|
|
179
|
+
Simulate realistic device response times:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
emulator.addDevice({
|
|
183
|
+
slaveId: 1,
|
|
184
|
+
timing: {
|
|
185
|
+
pollingInterval: 10, // Device checks for commands every 10ms
|
|
186
|
+
commandDetectionDelay: [3, 8], // 3-8ms to notice command
|
|
187
|
+
processingDelay: [2, 5], // 2-5ms to process
|
|
188
|
+
perRegisterDelay: 0.1, // 0.1ms per register
|
|
189
|
+
},
|
|
190
|
+
})
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Register Constraints
|
|
194
|
+
|
|
195
|
+
> **🚧 Planned for v0.2.0**: Define forbidden ranges and batch size limits
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
// Coming in v0.2.0
|
|
199
|
+
emulator.addDevice({
|
|
200
|
+
slaveId: 1,
|
|
201
|
+
constraints: {
|
|
202
|
+
maxReadRegisters: 80,
|
|
203
|
+
maxWriteRegisters: 50,
|
|
204
|
+
forbiddenReadRanges: [{ type: 'holding', start: 100, end: 199, reason: 'Protected' }],
|
|
205
|
+
},
|
|
206
|
+
})
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Error Simulation
|
|
210
|
+
|
|
211
|
+
> **🚧 Planned for v0.2.0**: Inject errors for testing error handling
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
// Coming in v0.2.0
|
|
215
|
+
emulator.addDevice({
|
|
216
|
+
slaveId: 1,
|
|
217
|
+
errors: {
|
|
218
|
+
timeoutProbability: 0.05, // 5% timeout rate
|
|
219
|
+
crcErrorProbability: 0.01, // 1% CRC error rate
|
|
220
|
+
},
|
|
221
|
+
})
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## License
|
|
225
|
+
|
|
226
|
+
GPL-3.0-or-later
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// Entry point for CLI - delegates to compiled TypeScript
|
|
4
|
+
import { main } from '../dist/cli.js'
|
|
5
|
+
|
|
6
|
+
// Run the CLI
|
|
7
|
+
main().catch((error) => {
|
|
8
|
+
console.error('[ERROR]', error instanceof Error ? error.message : String(error))
|
|
9
|
+
process.exit(1)
|
|
10
|
+
})
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Modbus function code handlers
|
|
3
|
+
*/
|
|
4
|
+
import type { EmulatedDevice } from '../device.js';
|
|
5
|
+
export declare const ILLEGAL_FUNCTION = 1;
|
|
6
|
+
export declare const ILLEGAL_DATA_ADDRESS = 2;
|
|
7
|
+
export declare const ILLEGAL_DATA_VALUE = 3;
|
|
8
|
+
/**
|
|
9
|
+
* Handle a Modbus request and return the response
|
|
10
|
+
*/
|
|
11
|
+
export declare function handleModbusRequest(device: EmulatedDevice, request: Buffer): Buffer;
|
|
12
|
+
//# sourceMappingURL=function-codes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"function-codes.d.ts","sourceRoot":"","sources":["../../src/behaviors/function-codes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAGlD,eAAO,MAAM,gBAAgB,IAAO,CAAA;AACpC,eAAO,MAAM,oBAAoB,IAAO,CAAA;AACxC,eAAO,MAAM,kBAAkB,IAAO,CAAA;AAEtC;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CA4BnF"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Modbus function code handlers
|
|
3
|
+
*/
|
|
4
|
+
// Modbus exception codes
|
|
5
|
+
export const ILLEGAL_FUNCTION = 0x01;
|
|
6
|
+
export const ILLEGAL_DATA_ADDRESS = 0x02;
|
|
7
|
+
export const ILLEGAL_DATA_VALUE = 0x03;
|
|
8
|
+
/**
|
|
9
|
+
* Handle a Modbus request and return the response
|
|
10
|
+
*/
|
|
11
|
+
export function handleModbusRequest(device, request) {
|
|
12
|
+
if (request.length < 2) {
|
|
13
|
+
return createExceptionResponse(request[0] ?? 0, 0x00, ILLEGAL_DATA_VALUE);
|
|
14
|
+
}
|
|
15
|
+
// Buffer access is safe after length check
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
17
|
+
const slaveId = request[0];
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
19
|
+
const functionCode = request[1];
|
|
20
|
+
try {
|
|
21
|
+
switch (functionCode) {
|
|
22
|
+
case 0x03:
|
|
23
|
+
return handleReadHoldingRegisters(device, request);
|
|
24
|
+
case 0x04:
|
|
25
|
+
return handleReadInputRegisters(device, request);
|
|
26
|
+
case 0x06:
|
|
27
|
+
return handleWriteSingleRegister(device, request);
|
|
28
|
+
case 0x10:
|
|
29
|
+
return handleWriteMultipleRegisters(device, request);
|
|
30
|
+
default:
|
|
31
|
+
return createExceptionResponse(slaveId, functionCode, ILLEGAL_FUNCTION);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// If error occurs, return illegal data value exception
|
|
36
|
+
return createExceptionResponse(slaveId, functionCode, ILLEGAL_DATA_VALUE);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 0x03 - Read Holding Registers
|
|
41
|
+
*/
|
|
42
|
+
function handleReadHoldingRegisters(device, request) {
|
|
43
|
+
if (request.length < 6) {
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
45
|
+
return createExceptionResponse(request[0], 0x03, ILLEGAL_DATA_VALUE);
|
|
46
|
+
}
|
|
47
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
48
|
+
const slaveId = request[0];
|
|
49
|
+
const startAddress = request.readUInt16BE(2);
|
|
50
|
+
const quantity = request.readUInt16BE(4);
|
|
51
|
+
const byteCount = quantity * 2;
|
|
52
|
+
const response = Buffer.alloc(3 + byteCount);
|
|
53
|
+
response[0] = slaveId;
|
|
54
|
+
response[1] = 0x03;
|
|
55
|
+
response[2] = byteCount;
|
|
56
|
+
for (let i = 0; i < quantity; i++) {
|
|
57
|
+
const value = device.getHoldingRegister(startAddress + i);
|
|
58
|
+
response.writeUInt16BE(value, 3 + i * 2);
|
|
59
|
+
}
|
|
60
|
+
return response;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 0x04 - Read Input Registers
|
|
64
|
+
*/
|
|
65
|
+
function handleReadInputRegisters(device, request) {
|
|
66
|
+
if (request.length < 6) {
|
|
67
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
68
|
+
return createExceptionResponse(request[0], 0x04, ILLEGAL_DATA_VALUE);
|
|
69
|
+
}
|
|
70
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
71
|
+
const slaveId = request[0];
|
|
72
|
+
const startAddress = request.readUInt16BE(2);
|
|
73
|
+
const quantity = request.readUInt16BE(4);
|
|
74
|
+
const byteCount = quantity * 2;
|
|
75
|
+
const response = Buffer.alloc(3 + byteCount);
|
|
76
|
+
response[0] = slaveId;
|
|
77
|
+
response[1] = 0x04;
|
|
78
|
+
response[2] = byteCount;
|
|
79
|
+
for (let i = 0; i < quantity; i++) {
|
|
80
|
+
const value = device.getInputRegister(startAddress + i);
|
|
81
|
+
response.writeUInt16BE(value, 3 + i * 2);
|
|
82
|
+
}
|
|
83
|
+
return response;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 0x06 - Write Single Register
|
|
87
|
+
*/
|
|
88
|
+
function handleWriteSingleRegister(device, request) {
|
|
89
|
+
if (request.length < 6) {
|
|
90
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
91
|
+
return createExceptionResponse(request[0], 0x06, ILLEGAL_DATA_VALUE);
|
|
92
|
+
}
|
|
93
|
+
const address = request.readUInt16BE(2);
|
|
94
|
+
const value = request.readUInt16BE(4);
|
|
95
|
+
device.setHoldingRegister(address, value);
|
|
96
|
+
// Echo the request as response
|
|
97
|
+
return request;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* 0x10 - Write Multiple Registers
|
|
101
|
+
*/
|
|
102
|
+
function handleWriteMultipleRegisters(device, request) {
|
|
103
|
+
if (request.length < 7) {
|
|
104
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
105
|
+
return createExceptionResponse(request[0], 0x10, ILLEGAL_DATA_VALUE);
|
|
106
|
+
}
|
|
107
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
108
|
+
const slaveId = request[0];
|
|
109
|
+
const startAddress = request.readUInt16BE(2);
|
|
110
|
+
const quantity = request.readUInt16BE(4);
|
|
111
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
112
|
+
const byteCount = request[6];
|
|
113
|
+
if (request.length < 7 + byteCount) {
|
|
114
|
+
return createExceptionResponse(slaveId, 0x10, ILLEGAL_DATA_VALUE);
|
|
115
|
+
}
|
|
116
|
+
// Write registers
|
|
117
|
+
for (let i = 0; i < quantity; i++) {
|
|
118
|
+
const value = request.readUInt16BE(7 + i * 2);
|
|
119
|
+
device.setHoldingRegister(startAddress + i, value);
|
|
120
|
+
}
|
|
121
|
+
// Response: slave_id + function_code + start_address + quantity
|
|
122
|
+
const response = Buffer.alloc(6);
|
|
123
|
+
response[0] = slaveId;
|
|
124
|
+
response[1] = 0x10;
|
|
125
|
+
response.writeUInt16BE(startAddress, 2);
|
|
126
|
+
response.writeUInt16BE(quantity, 4);
|
|
127
|
+
return response;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Create a Modbus exception response
|
|
131
|
+
*/
|
|
132
|
+
function createExceptionResponse(slaveId, functionCode, exceptionCode) {
|
|
133
|
+
const response = Buffer.alloc(3);
|
|
134
|
+
response[0] = slaveId;
|
|
135
|
+
response[1] = functionCode | 0x80; // Set error bit
|
|
136
|
+
response[2] = exceptionCode;
|
|
137
|
+
return response;
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=function-codes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"function-codes.js","sourceRoot":"","sources":["../../src/behaviors/function-codes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timing behavior simulation
|
|
3
|
+
*/
|
|
4
|
+
import type { TimingBehavior } from '../types/config.js';
|
|
5
|
+
/**
|
|
6
|
+
* Calculate a delay value from a fixed number or random range
|
|
7
|
+
*/
|
|
8
|
+
export declare function calculateDelay(delay: number | [number, number] | undefined): number;
|
|
9
|
+
/**
|
|
10
|
+
* Calculate transmission delay based on baud rate and frame size
|
|
11
|
+
* Formula: (frameBytes * 11 bits per byte) / (baudRate / 1000)
|
|
12
|
+
*/
|
|
13
|
+
export declare function calculateTransmissionDelay(frameBytes: number, baudRate: number): number;
|
|
14
|
+
/**
|
|
15
|
+
* Thin abstraction over setTimeout for dependency injection
|
|
16
|
+
*/
|
|
17
|
+
export interface DelayFunction {
|
|
18
|
+
(ms: number): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Default delay implementation using setTimeout
|
|
22
|
+
*/
|
|
23
|
+
export declare const defaultDelay: DelayFunction;
|
|
24
|
+
/**
|
|
25
|
+
* Timing simulator that calculates and applies realistic device delays
|
|
26
|
+
*/
|
|
27
|
+
export declare class TimingSimulator {
|
|
28
|
+
private config;
|
|
29
|
+
private delayFn;
|
|
30
|
+
constructor(config: TimingBehavior, delayFn?: DelayFunction);
|
|
31
|
+
/**
|
|
32
|
+
* Calculate total delay for a request
|
|
33
|
+
* @param request - The Modbus request buffer
|
|
34
|
+
* @param registerCount - Number of registers being accessed
|
|
35
|
+
* @returns Total delay in milliseconds
|
|
36
|
+
*/
|
|
37
|
+
calculateTotalDelay(request: Buffer, registerCount: number): number;
|
|
38
|
+
/**
|
|
39
|
+
* Apply timing delay for a request
|
|
40
|
+
* @param request - The Modbus request buffer
|
|
41
|
+
* @param registerCount - Number of registers being accessed
|
|
42
|
+
* @returns Promise that resolves after the calculated delay
|
|
43
|
+
*/
|
|
44
|
+
delay(request: Buffer, registerCount: number): Promise<void>;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=timing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timing.d.ts","sourceRoot":"","sources":["../../src/behaviors/timing.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAExD;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,GAAG,MAAM,CAYnF;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMvF;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC5B;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,aAK1B,CAAA;AAED;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,OAAO,CAAe;gBAElB,MAAM,EAAE,cAAc,EAAE,OAAO,GAAE,aAA4B;IAKzE;;;;;OAKG;IACH,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM;IA8BnE;;;;;OAKG;IACG,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAInE"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timing behavior simulation
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Calculate a delay value from a fixed number or random range
|
|
6
|
+
*/
|
|
7
|
+
export function calculateDelay(delay) {
|
|
8
|
+
if (delay === undefined) {
|
|
9
|
+
return 0;
|
|
10
|
+
}
|
|
11
|
+
if (typeof delay === 'number') {
|
|
12
|
+
return delay;
|
|
13
|
+
}
|
|
14
|
+
// Random value in range [min, max]
|
|
15
|
+
const [min, max] = delay;
|
|
16
|
+
return min + Math.random() * (max - min);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Calculate transmission delay based on baud rate and frame size
|
|
20
|
+
* Formula: (frameBytes * 11 bits per byte) / (baudRate / 1000)
|
|
21
|
+
*/
|
|
22
|
+
export function calculateTransmissionDelay(frameBytes, baudRate) {
|
|
23
|
+
// Each byte requires 11 bits (1 start + 8 data + 1 parity + 1 stop)
|
|
24
|
+
const totalBits = frameBytes * 11;
|
|
25
|
+
// Convert baud rate to bits per millisecond
|
|
26
|
+
const bitsPerMs = baudRate / 1000;
|
|
27
|
+
return totalBits / bitsPerMs;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Default delay implementation using setTimeout
|
|
31
|
+
*/
|
|
32
|
+
export const defaultDelay = (ms) => {
|
|
33
|
+
if (ms <= 0) {
|
|
34
|
+
return Promise.resolve();
|
|
35
|
+
}
|
|
36
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Timing simulator that calculates and applies realistic device delays
|
|
40
|
+
*/
|
|
41
|
+
export class TimingSimulator {
|
|
42
|
+
config;
|
|
43
|
+
delayFn;
|
|
44
|
+
constructor(config, delayFn = defaultDelay) {
|
|
45
|
+
this.config = config;
|
|
46
|
+
this.delayFn = delayFn;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Calculate total delay for a request
|
|
50
|
+
* @param request - The Modbus request buffer
|
|
51
|
+
* @param registerCount - Number of registers being accessed
|
|
52
|
+
* @returns Total delay in milliseconds
|
|
53
|
+
*/
|
|
54
|
+
calculateTotalDelay(request, registerCount) {
|
|
55
|
+
let totalDelay = 0;
|
|
56
|
+
// 1. Command detection delay (or random value in [0, pollingInterval])
|
|
57
|
+
if (this.config.commandDetectionDelay !== undefined) {
|
|
58
|
+
totalDelay += calculateDelay(this.config.commandDetectionDelay);
|
|
59
|
+
}
|
|
60
|
+
else if (this.config.pollingInterval !== undefined) {
|
|
61
|
+
// Use random value in range [0, pollingInterval] as detection time
|
|
62
|
+
totalDelay += calculateDelay([0, this.config.pollingInterval]);
|
|
63
|
+
}
|
|
64
|
+
// 2. Processing delay
|
|
65
|
+
if (this.config.processingDelay !== undefined) {
|
|
66
|
+
totalDelay += calculateDelay(this.config.processingDelay);
|
|
67
|
+
}
|
|
68
|
+
// 3. Per-register delay
|
|
69
|
+
if (this.config.perRegisterDelay !== undefined) {
|
|
70
|
+
totalDelay += registerCount * this.config.perRegisterDelay;
|
|
71
|
+
}
|
|
72
|
+
// 4. Transmission delay (RTU only, when enabled)
|
|
73
|
+
if (this.config.autoCalculateTransmissionDelay && this.config.baudRate !== undefined) {
|
|
74
|
+
const frameSize = request.length;
|
|
75
|
+
totalDelay += calculateTransmissionDelay(frameSize, this.config.baudRate);
|
|
76
|
+
}
|
|
77
|
+
return totalDelay;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Apply timing delay for a request
|
|
81
|
+
* @param request - The Modbus request buffer
|
|
82
|
+
* @param registerCount - Number of registers being accessed
|
|
83
|
+
* @returns Promise that resolves after the calculated delay
|
|
84
|
+
*/
|
|
85
|
+
async delay(request, registerCount) {
|
|
86
|
+
const delayMs = this.calculateTotalDelay(request, registerCount);
|
|
87
|
+
return this.delayFn(delayMs);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=timing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timing.js","sourceRoot":"","sources":["../../src/behaviors/timing.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;GAEG;AA8CH;;GAEG;AACH,iBAAe,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAmGnC;AAOD,OAAO,EAAE,IAAI,EAAE,CAAA"}
|