@ya-modbus/emulator 0.6.1 → 0.7.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.
Files changed (125) hide show
  1. package/CHANGELOG.md +4 -2
  2. package/bin/ya-modbus-emulator.js +1 -1
  3. package/dist/cjs/behaviors/function-codes.d.ts.map +1 -0
  4. package/dist/cjs/behaviors/function-codes.js +143 -0
  5. package/dist/cjs/behaviors/function-codes.js.map +1 -0
  6. package/dist/cjs/behaviors/timing.d.ts.map +1 -0
  7. package/dist/cjs/behaviors/timing.js +95 -0
  8. package/dist/cjs/behaviors/timing.js.map +1 -0
  9. package/dist/cjs/cli.d.ts.map +1 -0
  10. package/dist/cjs/cli.js +126 -0
  11. package/dist/cjs/cli.js.map +1 -0
  12. package/dist/cjs/device.d.ts.map +1 -0
  13. package/dist/cjs/device.js +95 -0
  14. package/dist/cjs/device.js.map +1 -0
  15. package/dist/cjs/emulator.d.ts.map +1 -0
  16. package/dist/cjs/emulator.js +152 -0
  17. package/dist/cjs/emulator.js.map +1 -0
  18. package/dist/cjs/index.d.ts.map +1 -0
  19. package/dist/cjs/index.js +11 -0
  20. package/dist/cjs/index.js.map +1 -0
  21. package/dist/cjs/package.json +1 -0
  22. package/dist/cjs/transports/base.d.ts.map +1 -0
  23. package/dist/cjs/transports/base.js +10 -0
  24. package/dist/cjs/transports/base.js.map +1 -0
  25. package/dist/cjs/transports/memory.d.ts.map +1 -0
  26. package/dist/cjs/transports/memory.js +33 -0
  27. package/dist/cjs/transports/memory.js.map +1 -0
  28. package/dist/cjs/transports/rtu.d.ts.map +1 -0
  29. package/dist/cjs/transports/rtu.js +124 -0
  30. package/dist/cjs/transports/rtu.js.map +1 -0
  31. package/dist/cjs/types/config.d.ts.map +1 -0
  32. package/dist/cjs/types/config.js +6 -0
  33. package/dist/cjs/types/config.js.map +1 -0
  34. package/dist/cjs/types/device.d.ts.map +1 -0
  35. package/dist/cjs/types/device.js +6 -0
  36. package/dist/cjs/types/device.js.map +1 -0
  37. package/dist/cjs/utils/config-loader.d.ts.map +1 -0
  38. package/dist/cjs/utils/config-loader.js +57 -0
  39. package/dist/cjs/utils/config-loader.js.map +1 -0
  40. package/dist/esm/behaviors/function-codes.d.ts +12 -0
  41. package/dist/esm/behaviors/function-codes.d.ts.map +1 -0
  42. package/dist/esm/behaviors/function-codes.js.map +1 -0
  43. package/dist/esm/behaviors/timing.d.ts +46 -0
  44. package/dist/esm/behaviors/timing.d.ts.map +1 -0
  45. package/dist/{behaviors → esm/behaviors}/timing.js +0 -2
  46. package/dist/esm/behaviors/timing.js.map +1 -0
  47. package/dist/esm/cli.d.ts +10 -0
  48. package/dist/esm/cli.d.ts.map +1 -0
  49. package/dist/esm/cli.js.map +1 -0
  50. package/dist/esm/device.d.ts +25 -0
  51. package/dist/esm/device.d.ts.map +1 -0
  52. package/dist/{device.js → esm/device.js} +4 -6
  53. package/dist/esm/device.js.map +1 -0
  54. package/dist/esm/emulator.d.ts +24 -0
  55. package/dist/esm/emulator.d.ts.map +1 -0
  56. package/dist/{emulator.js → esm/emulator.js} +2 -3
  57. package/dist/esm/emulator.js.map +1 -0
  58. package/dist/esm/index.d.ts +8 -0
  59. package/dist/esm/index.d.ts.map +1 -0
  60. package/dist/esm/index.js.map +1 -0
  61. package/dist/esm/package.json +1 -0
  62. package/dist/esm/transports/base.d.ts +10 -0
  63. package/dist/esm/transports/base.d.ts.map +1 -0
  64. package/dist/esm/transports/base.js.map +1 -0
  65. package/dist/esm/transports/memory.d.ts +16 -0
  66. package/dist/esm/transports/memory.d.ts.map +1 -0
  67. package/dist/{transports → esm/transports}/memory.js +0 -1
  68. package/dist/esm/transports/memory.js.map +1 -0
  69. package/dist/esm/transports/rtu.d.ts +44 -0
  70. package/dist/esm/transports/rtu.d.ts.map +1 -0
  71. package/dist/{transports → esm/transports}/rtu.js +1 -2
  72. package/dist/esm/transports/rtu.js.map +1 -0
  73. package/dist/esm/types/config.d.ts +54 -0
  74. package/dist/esm/types/config.d.ts.map +1 -0
  75. package/dist/{types → esm/types}/config.js.map +1 -1
  76. package/dist/esm/types/device.d.ts +27 -0
  77. package/dist/esm/types/device.d.ts.map +1 -0
  78. package/dist/{types → esm/types}/device.js.map +1 -1
  79. package/dist/esm/utils/config-loader.d.ts +21 -0
  80. package/dist/esm/utils/config-loader.d.ts.map +1 -0
  81. package/dist/esm/utils/config-loader.js.map +1 -0
  82. package/dist/tsconfig.cjs.tsbuildinfo +1 -0
  83. package/dist/tsconfig.esm.tsbuildinfo +1 -0
  84. package/package.json +23 -6
  85. package/dist/behaviors/function-codes.d.ts.map +0 -1
  86. package/dist/behaviors/function-codes.js.map +0 -1
  87. package/dist/behaviors/timing.d.ts.map +0 -1
  88. package/dist/behaviors/timing.js.map +0 -1
  89. package/dist/cli.d.ts.map +0 -1
  90. package/dist/cli.js.map +0 -1
  91. package/dist/device.d.ts.map +0 -1
  92. package/dist/device.js.map +0 -1
  93. package/dist/emulator.d.ts.map +0 -1
  94. package/dist/emulator.js.map +0 -1
  95. package/dist/index.d.ts.map +0 -1
  96. package/dist/index.js.map +0 -1
  97. package/dist/transports/base.d.ts.map +0 -1
  98. package/dist/transports/base.js.map +0 -1
  99. package/dist/transports/memory.d.ts.map +0 -1
  100. package/dist/transports/memory.js.map +0 -1
  101. package/dist/transports/rtu.d.ts.map +0 -1
  102. package/dist/transports/rtu.js.map +0 -1
  103. package/dist/types/config.d.ts.map +0 -1
  104. package/dist/types/device.d.ts.map +0 -1
  105. package/dist/utils/config-loader.d.ts.map +0 -1
  106. package/dist/utils/config-loader.js.map +0 -1
  107. /package/dist/{behaviors → cjs/behaviors}/function-codes.d.ts +0 -0
  108. /package/dist/{behaviors → cjs/behaviors}/timing.d.ts +0 -0
  109. /package/dist/{cli.d.ts → cjs/cli.d.ts} +0 -0
  110. /package/dist/{device.d.ts → cjs/device.d.ts} +0 -0
  111. /package/dist/{emulator.d.ts → cjs/emulator.d.ts} +0 -0
  112. /package/dist/{index.d.ts → cjs/index.d.ts} +0 -0
  113. /package/dist/{transports → cjs/transports}/base.d.ts +0 -0
  114. /package/dist/{transports → cjs/transports}/memory.d.ts +0 -0
  115. /package/dist/{transports → cjs/transports}/rtu.d.ts +0 -0
  116. /package/dist/{types → cjs/types}/config.d.ts +0 -0
  117. /package/dist/{types → cjs/types}/device.d.ts +0 -0
  118. /package/dist/{utils → cjs/utils}/config-loader.d.ts +0 -0
  119. /package/dist/{behaviors → esm/behaviors}/function-codes.js +0 -0
  120. /package/dist/{cli.js → esm/cli.js} +0 -0
  121. /package/dist/{index.js → esm/index.js} +0 -0
  122. /package/dist/{transports → esm/transports}/base.js +0 -0
  123. /package/dist/{types → esm/types}/config.js +0 -0
  124. /package/dist/{types → esm/types}/device.js +0 -0
  125. /package/dist/{utils → esm/utils}/config-loader.js +0 -0
package/CHANGELOG.md CHANGED
@@ -3,9 +3,11 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
- ## [0.6.1](https://github.com/groupsky/ya-modbus/compare/@ya-modbus/emulator@0.6.0...@ya-modbus/emulator@0.6.1) (2026-01-08)
6
+ # [0.7.0](https://github.com/groupsky/ya-modbus/compare/@ya-modbus/emulator@0.6.0...@ya-modbus/emulator@0.7.0) (2026-01-11)
7
7
 
8
- **Note:** Version bump only for package @ya-modbus/emulator
8
+ ### Features
9
+
10
+ - **build:** add dual CommonJS/ESM package support ([#187](https://github.com/groupsky/ya-modbus/issues/187)) ([3d78130](https://github.com/groupsky/ya-modbus/commit/3d781304d42edba335cdc320ba25275f3b4ea6c9))
9
11
 
10
12
  # 0.6.0 (2026-01-04)
11
13
 
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // Entry point for CLI - delegates to compiled TypeScript
4
- import { main } from '../dist/cli.js'
4
+ import { main } from '../src/cli.js'
5
5
 
6
6
  // Run the CLI
7
7
  main().catch((error) => {
@@ -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,143 @@
1
+ "use strict";
2
+ /**
3
+ * Modbus function code handlers
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ILLEGAL_DATA_VALUE = exports.ILLEGAL_DATA_ADDRESS = exports.ILLEGAL_FUNCTION = void 0;
7
+ exports.handleModbusRequest = handleModbusRequest;
8
+ // Modbus exception codes
9
+ exports.ILLEGAL_FUNCTION = 0x01;
10
+ exports.ILLEGAL_DATA_ADDRESS = 0x02;
11
+ exports.ILLEGAL_DATA_VALUE = 0x03;
12
+ /**
13
+ * Handle a Modbus request and return the response
14
+ */
15
+ function handleModbusRequest(device, request) {
16
+ if (request.length < 2) {
17
+ return createExceptionResponse(request[0] ?? 0, 0x00, exports.ILLEGAL_DATA_VALUE);
18
+ }
19
+ // Buffer access is safe after length check
20
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
21
+ const slaveId = request[0];
22
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
23
+ const functionCode = request[1];
24
+ try {
25
+ switch (functionCode) {
26
+ case 0x03:
27
+ return handleReadHoldingRegisters(device, request);
28
+ case 0x04:
29
+ return handleReadInputRegisters(device, request);
30
+ case 0x06:
31
+ return handleWriteSingleRegister(device, request);
32
+ case 0x10:
33
+ return handleWriteMultipleRegisters(device, request);
34
+ default:
35
+ return createExceptionResponse(slaveId, functionCode, exports.ILLEGAL_FUNCTION);
36
+ }
37
+ }
38
+ catch {
39
+ // If error occurs, return illegal data value exception
40
+ return createExceptionResponse(slaveId, functionCode, exports.ILLEGAL_DATA_VALUE);
41
+ }
42
+ }
43
+ /**
44
+ * 0x03 - Read Holding Registers
45
+ */
46
+ function handleReadHoldingRegisters(device, request) {
47
+ if (request.length < 6) {
48
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
49
+ return createExceptionResponse(request[0], 0x03, exports.ILLEGAL_DATA_VALUE);
50
+ }
51
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
52
+ const slaveId = request[0];
53
+ const startAddress = request.readUInt16BE(2);
54
+ const quantity = request.readUInt16BE(4);
55
+ const byteCount = quantity * 2;
56
+ const response = Buffer.alloc(3 + byteCount);
57
+ response[0] = slaveId;
58
+ response[1] = 0x03;
59
+ response[2] = byteCount;
60
+ for (let i = 0; i < quantity; i++) {
61
+ const value = device.getHoldingRegister(startAddress + i);
62
+ response.writeUInt16BE(value, 3 + i * 2);
63
+ }
64
+ return response;
65
+ }
66
+ /**
67
+ * 0x04 - Read Input Registers
68
+ */
69
+ function handleReadInputRegisters(device, request) {
70
+ if (request.length < 6) {
71
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
72
+ return createExceptionResponse(request[0], 0x04, exports.ILLEGAL_DATA_VALUE);
73
+ }
74
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
75
+ const slaveId = request[0];
76
+ const startAddress = request.readUInt16BE(2);
77
+ const quantity = request.readUInt16BE(4);
78
+ const byteCount = quantity * 2;
79
+ const response = Buffer.alloc(3 + byteCount);
80
+ response[0] = slaveId;
81
+ response[1] = 0x04;
82
+ response[2] = byteCount;
83
+ for (let i = 0; i < quantity; i++) {
84
+ const value = device.getInputRegister(startAddress + i);
85
+ response.writeUInt16BE(value, 3 + i * 2);
86
+ }
87
+ return response;
88
+ }
89
+ /**
90
+ * 0x06 - Write Single Register
91
+ */
92
+ function handleWriteSingleRegister(device, request) {
93
+ if (request.length < 6) {
94
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
95
+ return createExceptionResponse(request[0], 0x06, exports.ILLEGAL_DATA_VALUE);
96
+ }
97
+ const address = request.readUInt16BE(2);
98
+ const value = request.readUInt16BE(4);
99
+ device.setHoldingRegister(address, value);
100
+ // Echo the request as response
101
+ return request;
102
+ }
103
+ /**
104
+ * 0x10 - Write Multiple Registers
105
+ */
106
+ function handleWriteMultipleRegisters(device, request) {
107
+ if (request.length < 7) {
108
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
109
+ return createExceptionResponse(request[0], 0x10, exports.ILLEGAL_DATA_VALUE);
110
+ }
111
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
112
+ const slaveId = request[0];
113
+ const startAddress = request.readUInt16BE(2);
114
+ const quantity = request.readUInt16BE(4);
115
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
116
+ const byteCount = request[6];
117
+ if (request.length < 7 + byteCount) {
118
+ return createExceptionResponse(slaveId, 0x10, exports.ILLEGAL_DATA_VALUE);
119
+ }
120
+ // Write registers
121
+ for (let i = 0; i < quantity; i++) {
122
+ const value = request.readUInt16BE(7 + i * 2);
123
+ device.setHoldingRegister(startAddress + i, value);
124
+ }
125
+ // Response: slave_id + function_code + start_address + quantity
126
+ const response = Buffer.alloc(6);
127
+ response[0] = slaveId;
128
+ response[1] = 0x10;
129
+ response.writeUInt16BE(startAddress, 2);
130
+ response.writeUInt16BE(quantity, 4);
131
+ return response;
132
+ }
133
+ /**
134
+ * Create a Modbus exception response
135
+ */
136
+ function createExceptionResponse(slaveId, functionCode, exceptionCode) {
137
+ const response = Buffer.alloc(3);
138
+ response[0] = slaveId;
139
+ response[1] = functionCode | 0x80; // Set error bit
140
+ response[2] = exceptionCode;
141
+ return response;
142
+ }
143
+ //# 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 @@
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,95 @@
1
+ "use strict";
2
+ /**
3
+ * Timing behavior simulation
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.TimingSimulator = exports.defaultDelay = void 0;
7
+ exports.calculateDelay = calculateDelay;
8
+ exports.calculateTransmissionDelay = calculateTransmissionDelay;
9
+ /**
10
+ * Calculate a delay value from a fixed number or random range
11
+ */
12
+ function calculateDelay(delay) {
13
+ if (delay === undefined) {
14
+ return 0;
15
+ }
16
+ if (typeof delay === 'number') {
17
+ return delay;
18
+ }
19
+ // Random value in range [min, max]
20
+ const [min, max] = delay;
21
+ return min + Math.random() * (max - min);
22
+ }
23
+ /**
24
+ * Calculate transmission delay based on baud rate and frame size
25
+ * Formula: (frameBytes * 11 bits per byte) / (baudRate / 1000)
26
+ */
27
+ function calculateTransmissionDelay(frameBytes, baudRate) {
28
+ // Each byte requires 11 bits (1 start + 8 data + 1 parity + 1 stop)
29
+ const totalBits = frameBytes * 11;
30
+ // Convert baud rate to bits per millisecond
31
+ const bitsPerMs = baudRate / 1000;
32
+ return totalBits / bitsPerMs;
33
+ }
34
+ /**
35
+ * Default delay implementation using setTimeout
36
+ */
37
+ const defaultDelay = (ms) => {
38
+ if (ms <= 0) {
39
+ return Promise.resolve();
40
+ }
41
+ return new Promise((resolve) => setTimeout(resolve, ms));
42
+ };
43
+ exports.defaultDelay = defaultDelay;
44
+ /**
45
+ * Timing simulator that calculates and applies realistic device delays
46
+ */
47
+ class TimingSimulator {
48
+ constructor(config, delayFn = exports.defaultDelay) {
49
+ this.config = config;
50
+ this.delayFn = delayFn;
51
+ }
52
+ /**
53
+ * Calculate total delay for a request
54
+ * @param request - The Modbus request buffer
55
+ * @param registerCount - Number of registers being accessed
56
+ * @returns Total delay in milliseconds
57
+ */
58
+ calculateTotalDelay(request, registerCount) {
59
+ let totalDelay = 0;
60
+ // 1. Command detection delay (or random value in [0, pollingInterval])
61
+ if (this.config.commandDetectionDelay !== undefined) {
62
+ totalDelay += calculateDelay(this.config.commandDetectionDelay);
63
+ }
64
+ else if (this.config.pollingInterval !== undefined) {
65
+ // Use random value in range [0, pollingInterval] as detection time
66
+ totalDelay += calculateDelay([0, this.config.pollingInterval]);
67
+ }
68
+ // 2. Processing delay
69
+ if (this.config.processingDelay !== undefined) {
70
+ totalDelay += calculateDelay(this.config.processingDelay);
71
+ }
72
+ // 3. Per-register delay
73
+ if (this.config.perRegisterDelay !== undefined) {
74
+ totalDelay += registerCount * this.config.perRegisterDelay;
75
+ }
76
+ // 4. Transmission delay (RTU only, when enabled)
77
+ if (this.config.autoCalculateTransmissionDelay && this.config.baudRate !== undefined) {
78
+ const frameSize = request.length;
79
+ totalDelay += calculateTransmissionDelay(frameSize, this.config.baudRate);
80
+ }
81
+ return totalDelay;
82
+ }
83
+ /**
84
+ * Apply timing delay for a request
85
+ * @param request - The Modbus request buffer
86
+ * @param registerCount - Number of registers being accessed
87
+ * @returns Promise that resolves after the calculated delay
88
+ */
89
+ async delay(request, registerCount) {
90
+ const delayMs = this.calculateTotalDelay(request, registerCount);
91
+ return this.delayFn(delayMs);
92
+ }
93
+ }
94
+ exports.TimingSimulator = TimingSimulator;
95
+ //# 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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"}
@@ -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"}
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * CLI interface for Modbus emulator
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.main = main;
8
+ const commander_1 = require("commander");
9
+ const emulator_js_1 = require("./emulator.js");
10
+ const config_loader_js_1 = require("./utils/config-loader.js");
11
+ const program = new commander_1.Command();
12
+ program
13
+ .name('ya-modbus-emulator')
14
+ .description('Modbus device emulator for testing drivers without physical hardware')
15
+ .version('0.1.0');
16
+ program
17
+ .option('-c, --config <file>', 'Configuration file (YAML or JSON)')
18
+ .option('-t, --transport <type>', 'Transport type: tcp|rtu|memory')
19
+ .option('-p, --port <port>', 'TCP port number or serial port path')
20
+ .option('-H, --host <host>', 'TCP host address (default: 0.0.0.0)')
21
+ .option('-b, --baud-rate <rate>', 'Serial baud rate (default: 9600)', parseInt)
22
+ .option('--parity <type>', 'Serial parity: none|even|odd (default: none)')
23
+ .option('-s, --slave-id <id>', 'Slave ID (required if no config file)', parseInt)
24
+ .option('-v, --verbose', 'Enable verbose logging')
25
+ .option('-q, --quiet', 'Suppress all output except errors')
26
+ .option('--log-requests', 'Log all Modbus requests/responses');
27
+ program.parse();
28
+ // Type assertion needed for TypeScript strict mode with noUncheckedIndexedAccess
29
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
30
+ const options = program.opts();
31
+ /**
32
+ * Main CLI entry point
33
+ */
34
+ async function main() {
35
+ try {
36
+ // Load configuration
37
+ let config;
38
+ let devices = [];
39
+ if (options.config !== undefined) {
40
+ // Load from config file
41
+ const fileConfig = await (0, config_loader_js_1.loadConfig)(options.config);
42
+ // Build config object only with defined properties (exactOptionalPropertyTypes)
43
+ config = {
44
+ transport: fileConfig.transport.type,
45
+ ...(fileConfig.transport.port !== undefined && { port: fileConfig.transport.port }),
46
+ ...(fileConfig.transport.host !== undefined && { host: fileConfig.transport.host }),
47
+ ...(fileConfig.transport.baudRate !== undefined && {
48
+ baudRate: fileConfig.transport.baudRate,
49
+ }),
50
+ ...(fileConfig.transport.parity !== undefined && { parity: fileConfig.transport.parity }),
51
+ ...(fileConfig.transport.dataBits !== undefined && {
52
+ dataBits: fileConfig.transport.dataBits,
53
+ }),
54
+ ...(fileConfig.transport.stopBits !== undefined && {
55
+ stopBits: fileConfig.transport.stopBits,
56
+ }),
57
+ };
58
+ devices = fileConfig.devices;
59
+ }
60
+ else {
61
+ // Build from CLI args
62
+ if (options.transport === undefined) {
63
+ console.error('Error: --transport is required when not using --config');
64
+ process.exit(1);
65
+ }
66
+ if (options.slaveId === undefined) {
67
+ console.error('Error: --slave-id is required when not using --config');
68
+ process.exit(1);
69
+ }
70
+ config = {
71
+ transport: options.transport,
72
+ ...(options.port !== undefined && { port: options.port }),
73
+ ...(options.host !== undefined && { host: options.host }),
74
+ ...(options.baudRate !== undefined && { baudRate: options.baudRate }),
75
+ ...(options.parity !== undefined && {
76
+ parity: options.parity,
77
+ }),
78
+ };
79
+ devices = [{ slaveId: options.slaveId }];
80
+ }
81
+ // Create emulator
82
+ const emulator = new emulator_js_1.ModbusEmulator(config);
83
+ // Add devices
84
+ for (const deviceConfig of devices) {
85
+ emulator.addDevice(deviceConfig);
86
+ }
87
+ // Start emulator
88
+ await emulator.start();
89
+ if (options.quiet !== true) {
90
+ console.log('[INFO] Starting Modbus emulator...');
91
+ console.log(`[INFO] Transport: ${config.transport.toUpperCase()} on ${config.port ?? 'memory'}`);
92
+ console.log(`[INFO] Devices: ${devices.length}`);
93
+ devices.forEach((device) => {
94
+ console.log(`[INFO] - Slave ID ${device.slaveId}`);
95
+ });
96
+ console.log('[INFO] Emulator started successfully');
97
+ console.log('[INFO] Press Ctrl+C to stop');
98
+ }
99
+ // Handle shutdown
100
+ const shutdown = async () => {
101
+ if (options.quiet !== true) {
102
+ console.log('\n[INFO] Shutting down...');
103
+ }
104
+ await emulator.stop();
105
+ if (options.quiet !== true) {
106
+ console.log('[INFO] Emulator stopped');
107
+ }
108
+ process.exit(0);
109
+ };
110
+ process.on('SIGINT', () => {
111
+ void shutdown();
112
+ });
113
+ process.on('SIGTERM', () => {
114
+ void shutdown();
115
+ });
116
+ }
117
+ catch (error) {
118
+ console.error('[ERROR]', error instanceof Error ? error.message : String(error));
119
+ process.exit(1);
120
+ }
121
+ }
122
+ main().catch((error) => {
123
+ console.error('[ERROR]', error instanceof Error ? error.message : String(error));
124
+ process.exit(1);
125
+ });
126
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../src/device.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,KAAK,EAAE,cAAc,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAoB1E,qBAAa,cAAe,YAAW,eAAe;IACpD,SAAgB,OAAO,EAAE,MAAM,CAAA;IAC/B,OAAO,CAAC,gBAAgB,CAAiC;IACzD,OAAO,CAAC,cAAc,CAAiC;IACvD,OAAO,CAAC,KAAK,CAAkC;IAC/C,OAAO,CAAC,cAAc,CAAkC;IACxD,OAAO,CAAC,eAAe,CAAC,CAAiB;gBAE7B,MAAM,EAAE,YAAY;IAwChC,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAI3C,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAMxD,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAIzC,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAMtD,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAIjC,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAI9C,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAI1C,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAIvD,kBAAkB,IAAI,eAAe,GAAG,SAAS;CAGlD"}
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ /**
3
+ * EmulatedDevice class implementation
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.EmulatedDevice = void 0;
7
+ const timing_js_1 = require("./behaviors/timing.js");
8
+ // Modbus register address and value ranges
9
+ const MIN_REGISTER_ADDRESS = 0;
10
+ const MAX_REGISTER_ADDRESS = 65535;
11
+ const MIN_REGISTER_VALUE = 0;
12
+ const MAX_REGISTER_VALUE = 65535;
13
+ function validateRegisterAddress(address) {
14
+ if (address < MIN_REGISTER_ADDRESS || address > MAX_REGISTER_ADDRESS) {
15
+ throw new Error(`Register address ${address} out of range (0-65535)`);
16
+ }
17
+ }
18
+ function validateRegisterValue(value, address) {
19
+ if (value < MIN_REGISTER_VALUE || value > MAX_REGISTER_VALUE) {
20
+ throw new Error(`Register value ${value} at address ${address} out of range (0-65535)`);
21
+ }
22
+ }
23
+ class EmulatedDevice {
24
+ constructor(config) {
25
+ this.holdingRegisters = new Map();
26
+ this.inputRegisters = new Map();
27
+ this.coils = new Map();
28
+ this.discreteInputs = new Map();
29
+ this.slaveId = config.slaveId;
30
+ // Initialize timing behavior
31
+ if (config.timing) {
32
+ this.timingSimulator = new timing_js_1.TimingSimulator(config.timing);
33
+ }
34
+ // Initialize registers from config
35
+ if (config.registers?.holding) {
36
+ for (const [address, value] of Object.entries(config.registers.holding)) {
37
+ const addr = Number(address);
38
+ validateRegisterAddress(addr);
39
+ validateRegisterValue(value, addr);
40
+ this.holdingRegisters.set(addr, value);
41
+ }
42
+ }
43
+ if (config.registers?.input) {
44
+ for (const [address, value] of Object.entries(config.registers.input)) {
45
+ const addr = Number(address);
46
+ validateRegisterAddress(addr);
47
+ validateRegisterValue(value, addr);
48
+ this.inputRegisters.set(addr, value);
49
+ }
50
+ }
51
+ if (config.registers?.coils) {
52
+ for (const [address, value] of Object.entries(config.registers.coils)) {
53
+ this.coils.set(Number(address), value);
54
+ }
55
+ }
56
+ if (config.registers?.discreteInputs) {
57
+ for (const [address, value] of Object.entries(config.registers.discreteInputs)) {
58
+ this.discreteInputs.set(Number(address), value);
59
+ }
60
+ }
61
+ }
62
+ getHoldingRegister(address) {
63
+ return this.holdingRegisters.get(address) ?? 0;
64
+ }
65
+ setHoldingRegister(address, value) {
66
+ validateRegisterAddress(address);
67
+ validateRegisterValue(value, address);
68
+ this.holdingRegisters.set(address, value);
69
+ }
70
+ getInputRegister(address) {
71
+ return this.inputRegisters.get(address) ?? 0;
72
+ }
73
+ setInputRegister(address, value) {
74
+ validateRegisterAddress(address);
75
+ validateRegisterValue(value, address);
76
+ this.inputRegisters.set(address, value);
77
+ }
78
+ getCoil(address) {
79
+ return this.coils.get(address) ?? false;
80
+ }
81
+ setCoil(address, value) {
82
+ this.coils.set(address, value);
83
+ }
84
+ getDiscreteInput(address) {
85
+ return this.discreteInputs.get(address) ?? false;
86
+ }
87
+ setDiscreteInput(address, value) {
88
+ this.discreteInputs.set(address, value);
89
+ }
90
+ getTimingSimulator() {
91
+ return this.timingSimulator;
92
+ }
93
+ }
94
+ exports.EmulatedDevice = EmulatedDevice;
95
+ //# sourceMappingURL=device.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device.js","sourceRoot":"","sources":["../../src/device.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emulator.d.ts","sourceRoot":"","sources":["../../src/emulator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAGzD,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAErE,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAyC;IACxD,OAAO,CAAC,SAAS,CAAe;IAChC,OAAO,CAAC,OAAO,CAAQ;gBAEX,MAAM,EAAE,cAAc;IA+B5B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAQb,aAAa;IA2B3B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAyB1B,YAAY,IAAI,aAAa;IAI7B,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,cAAc;IAU/C,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAOnC,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;CAGvD"}