njs-modbus 1.5.0 → 2.0.1
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/README.md +16 -0
- package/dist/index.cjs +2033 -1136
- package/dist/index.d.ts +315 -89
- package/dist/index.mjs +2026 -1137
- package/dist/src/error-code.d.ts +27 -1
- package/dist/src/index.d.ts +2 -0
- package/dist/src/layers/application/abstract-application-layer.d.ts +11 -8
- package/dist/src/layers/application/ascii-application-layer.d.ts +15 -10
- package/dist/src/layers/application/index.d.ts +2 -0
- package/dist/src/layers/application/rtu-application-layer.d.ts +53 -18
- package/dist/src/layers/application/tcp-application-layer.d.ts +5 -8
- package/dist/src/layers/physical/abstract-physical-layer.d.ts +5 -1
- package/dist/src/layers/physical/index.d.ts +1 -0
- package/dist/src/layers/physical/serial-physical-layer.d.ts +2 -0
- package/dist/src/layers/physical/tcp-client-physical-layer.d.ts +3 -0
- package/dist/src/layers/physical/tcp-server-physical-layer.d.ts +3 -1
- package/dist/src/layers/physical/udp-physical-layer.d.ts +25 -10
- package/dist/src/master/index.d.ts +2 -0
- package/dist/src/master/master-session.d.ts +18 -0
- package/dist/src/master/master.d.ts +29 -5
- package/dist/src/slave/index.d.ts +1 -1
- package/dist/src/slave/slave.d.ts +20 -5
- package/dist/src/types.d.ts +33 -2
- package/dist/src/utils/bitsToMs.d.ts +13 -0
- package/dist/src/utils/crc.d.ts +1 -1
- package/dist/src/utils/genConnectionId.d.ts +2 -0
- package/dist/src/utils/index.d.ts +5 -1
- package/dist/src/utils/isUint8.d.ts +8 -0
- package/dist/src/utils/predictRtuFrameLength.d.ts +20 -0
- package/dist/src/vars.d.ts +47 -0
- package/dist/test/adu-buffer.test.d.ts +1 -0
- package/dist/test/ascii-hex-sentry.test.d.ts +1 -0
- package/dist/test/ascii-hex-validation.test.d.ts +1 -0
- package/dist/test/ascii-tcp-fragmentation.test.d.ts +1 -0
- package/dist/test/check-range.test.d.ts +1 -0
- package/dist/test/fallback-atomic.test.d.ts +1 -0
- package/dist/test/fallback-serial.test.d.ts +1 -0
- package/dist/test/fc17-serverid-validation.test.d.ts +1 -0
- package/dist/test/fc43-conformity.test.d.ts +1 -0
- package/dist/test/fc43-utf8-objects.test.d.ts +1 -0
- package/dist/test/gen-connection-id.test.d.ts +1 -0
- package/dist/test/helpers/raw-tcp.d.ts +38 -0
- package/dist/test/master-concurrent.test.d.ts +1 -0
- package/dist/test/modbus-error.test.d.ts +1 -0
- package/dist/test/physical-lifecycle.test.d.ts +1 -0
- package/dist/test/predict-rtu.test.d.ts +1 -0
- package/dist/test/rtu-custom-fc.test.d.ts +1 -0
- package/dist/test/rtu-pool-overflow.test.d.ts +1 -0
- package/dist/test/rtu-t15-timing.test.d.ts +1 -0
- package/dist/test/rtu-t35-default.test.d.ts +1 -0
- package/dist/test/rtu-t35-strict.test.d.ts +1 -0
- package/dist/test/rtu-tcp-fragmentation.test.d.ts +1 -0
- package/dist/test/serial-e2e.test.d.ts +1 -0
- package/dist/test/slave-multi-connection.test.d.ts +1 -0
- package/dist/test/tcp-fragmentation.test.d.ts +1 -0
- package/dist/test/udp-multi-client.test.d.ts +1 -0
- package/package.json +4 -2
- package/dist/src/utils/getThreePointFiveT.d.ts +0 -7
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,61 @@ import EventEmitter from 'node:events';
|
|
|
2
2
|
import { SocketConstructorOpts, SocketConnectOpts, NetConnectOpts, ListenOptions } from 'node:net';
|
|
3
3
|
import { SocketOptions, BindOptions } from 'node:dgram';
|
|
4
4
|
|
|
5
|
+
type Callback$1<T> = (error: Error | null, value: T) => void;
|
|
6
|
+
type FConvertPromise<F extends (...args: any) => any> = F extends (...args: infer A) => infer R ? ((...args: A) => Promise<R>) | ((...args: A) => R) : never;
|
|
7
|
+
interface ApplicationDataUnit {
|
|
8
|
+
transaction?: number;
|
|
9
|
+
unit: number;
|
|
10
|
+
fc: number;
|
|
11
|
+
data: Buffer;
|
|
12
|
+
}
|
|
13
|
+
interface ServerId {
|
|
14
|
+
/** Server ID; may be 1 byte (number) or multi-byte (number[]) per device spec. */
|
|
15
|
+
serverId?: number | number[];
|
|
16
|
+
runIndicatorStatus?: boolean;
|
|
17
|
+
additionalData?: number[];
|
|
18
|
+
}
|
|
19
|
+
interface DeviceIdentification {
|
|
20
|
+
readDeviceIDCode: number;
|
|
21
|
+
conformityLevel: number;
|
|
22
|
+
moreFollows: boolean;
|
|
23
|
+
nextObjectId: number;
|
|
24
|
+
objects: {
|
|
25
|
+
id: number;
|
|
26
|
+
value: string;
|
|
27
|
+
}[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Defines a non-standard / user-defined Modbus function code.
|
|
31
|
+
*
|
|
32
|
+
* Registration paths:
|
|
33
|
+
* - `RtuApplicationLayer.addCustomFunctionCode(cfc)` — framing only.
|
|
34
|
+
* - `ModbusSlave.addCustomFunctionCode(cfc)` — framing + slave-side dispatch via `handle`.
|
|
35
|
+
* - `ModbusMaster.addCustomFunctionCode(cfc)` + `ModbusMaster.sendCustomFC(...)` — framing + request issuance.
|
|
36
|
+
*
|
|
37
|
+
* The two `predict*` callbacks declare how to derive the total RTU frame length
|
|
38
|
+
* (PDU + 2-byte CRC) from leading bytes; they are required so the framing FSM
|
|
39
|
+
* can advance without the deleted sliding-window CRC fallback.
|
|
40
|
+
*
|
|
41
|
+
* Return `null` from a predictor to signal "need more bytes before I can decide".
|
|
42
|
+
* Return a positive integer (>= 4, <= 256) for the total frame length.
|
|
43
|
+
*/
|
|
44
|
+
interface CustomFunctionCode {
|
|
45
|
+
fc: number;
|
|
46
|
+
/** Predict total RTU frame length for an incoming request (slave-side framing). */
|
|
47
|
+
predictRequestLength: (buffer: Buffer) => number | null;
|
|
48
|
+
/** Predict total RTU frame length for an incoming response (master-side framing). */
|
|
49
|
+
predictResponseLength: (buffer: Buffer) => number | null;
|
|
50
|
+
/**
|
|
51
|
+
* Slave-side handler. Receives PDU payload (bytes after `fc`, before CRC) and
|
|
52
|
+
* the unit ID being addressed; must return the PDU payload of the response.
|
|
53
|
+
*
|
|
54
|
+
* Throwing inside `handle` is turned into a Modbus exception response by the slave.
|
|
55
|
+
* If `handle` is omitted, the slave returns an ILLEGAL_FUNCTION exception for this FC.
|
|
56
|
+
*/
|
|
57
|
+
handle?: FConvertPromise<(data: Buffer, unit: number) => Buffer>;
|
|
58
|
+
}
|
|
59
|
+
|
|
5
60
|
declare enum ErrorCode {
|
|
6
61
|
ILLEGAL_FUNCTION = 1,
|
|
7
62
|
ILLEGAL_DATA_ADDRESS = 2,
|
|
@@ -13,13 +68,91 @@ declare enum ErrorCode {
|
|
|
13
68
|
GATEWAY_PATH_UNAVAILABLE = 10,
|
|
14
69
|
GATEWAY_TARGET_DEVICE_FAILED_TO_RESPOND = 11
|
|
15
70
|
}
|
|
16
|
-
|
|
71
|
+
/** Internal error codes for programmatic error handling. */
|
|
72
|
+
declare const ModbusErrorCode: {
|
|
73
|
+
readonly TIMEOUT: "ETIMEOUT";
|
|
74
|
+
readonly INVALID_RESPONSE: "EINVALID_RESPONSE";
|
|
75
|
+
readonly INSUFFICIENT_DATA: "EINSUFFICIENT_DATA";
|
|
76
|
+
readonly MASTER_CLOSED: "EMASTER_CLOSED";
|
|
77
|
+
readonly MASTER_DESTROYED: "EMASTER_DESTROYED";
|
|
78
|
+
readonly CONCURRENT_NOT_TCP: "ECONCURRENT_NOT_TCP";
|
|
79
|
+
readonly PORT_DESTROYED: "EPORT_DESTROYED";
|
|
80
|
+
readonly PORT_ALREADY_OPEN: "EPORT_ALREADY_OPEN";
|
|
81
|
+
readonly PORT_NOT_OPEN: "EPORT_NOT_OPEN";
|
|
82
|
+
readonly NOT_SUPPORTED: "ENOT_SUPPORTED";
|
|
83
|
+
readonly INVALID_DATA: "EINVALID_DATA";
|
|
84
|
+
readonly INVALID_HEX: "EINVALID_HEX";
|
|
85
|
+
readonly CRC_MISMATCH: "ECRC_MISMATCH";
|
|
86
|
+
readonly LRC_MISMATCH: "ELRC_MISMATCH";
|
|
87
|
+
readonly INCOMPLETE_FRAME: "EINCOMPLETE_FRAME";
|
|
88
|
+
readonly T1_5_EXCEEDED: "ET1_5_EXCEEDED";
|
|
89
|
+
readonly UNKNOWN_FC: "EUNKNOWN_FC";
|
|
90
|
+
readonly INVALID_ROLE: "EINVALID_ROLE";
|
|
91
|
+
readonly RANGE: "ERANGE";
|
|
92
|
+
};
|
|
93
|
+
declare class ModbusError extends Error {
|
|
94
|
+
readonly code: string;
|
|
95
|
+
constructor(code: string, message?: string);
|
|
96
|
+
}
|
|
97
|
+
declare function getErrorByCode(code: ErrorCode): ModbusError;
|
|
17
98
|
declare function getCodeByError(err: Error): ErrorCode;
|
|
18
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Standard Modbus function codes (V1.1b3 §6).
|
|
102
|
+
*/
|
|
103
|
+
declare enum FunctionCode {
|
|
104
|
+
READ_COILS = 1,
|
|
105
|
+
READ_DISCRETE_INPUTS = 2,
|
|
106
|
+
READ_HOLDING_REGISTERS = 3,
|
|
107
|
+
READ_INPUT_REGISTERS = 4,
|
|
108
|
+
WRITE_SINGLE_COIL = 5,
|
|
109
|
+
WRITE_SINGLE_REGISTER = 6,
|
|
110
|
+
WRITE_MULTIPLE_COILS = 15,
|
|
111
|
+
WRITE_MULTIPLE_REGISTERS = 16,
|
|
112
|
+
REPORT_SERVER_ID = 17,
|
|
113
|
+
MASK_WRITE_REGISTER = 22,
|
|
114
|
+
READ_WRITE_MULTIPLE_REGISTERS = 23,
|
|
115
|
+
READ_DEVICE_IDENTIFICATION = 43
|
|
116
|
+
}
|
|
117
|
+
/** Exception response FC = request FC | EXCEPTION_OFFSET (V1.1b3 §7). */
|
|
118
|
+
declare const EXCEPTION_OFFSET = 128;
|
|
119
|
+
/** Coil value encoding for FC 5 / FC 15 (V1.1b3 §6.5/§6.11). */
|
|
120
|
+
declare const COIL_ON = 65280;
|
|
121
|
+
declare const COIL_OFF = 0;
|
|
122
|
+
/** FC 0x2B MEI sub-function selecting Read Device Identification (V1.1b3 §6.21). */
|
|
123
|
+
declare const MEI_READ_DEVICE_ID = 14;
|
|
124
|
+
/** Read Device ID code values inside an FC 0x2B / MEI 0x0E request. */
|
|
125
|
+
declare enum ReadDeviceIDCode {
|
|
126
|
+
BASIC_STREAM = 1,
|
|
127
|
+
REGULAR_STREAM = 2,
|
|
128
|
+
EXTENDED_STREAM = 3,
|
|
129
|
+
SPECIFIC_ACCESS = 4
|
|
130
|
+
}
|
|
131
|
+
/** Conformity level reported in an FC 0x2B / MEI 0x0E response. */
|
|
132
|
+
declare enum ConformityLevel {
|
|
133
|
+
BASIC = 129,
|
|
134
|
+
REGULAR = 130,
|
|
135
|
+
EXTENDED = 131
|
|
136
|
+
}
|
|
137
|
+
/** Modbus V1.1b3 PDU quantity limits. */
|
|
138
|
+
declare const LIMITS: {
|
|
139
|
+
readonly READ_COILS_MIN: 1;
|
|
140
|
+
readonly READ_COILS_MAX: 2000;
|
|
141
|
+
readonly READ_REGISTERS_MIN: 1;
|
|
142
|
+
readonly READ_REGISTERS_MAX: 125;
|
|
143
|
+
readonly WRITE_COILS_MAX: 1968;
|
|
144
|
+
readonly WRITE_REGISTERS_MAX: 123;
|
|
145
|
+
readonly RW_REGISTERS_WRITE_MAX: 121;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
interface PhysicalConnection {
|
|
149
|
+
readonly id: string | number;
|
|
150
|
+
}
|
|
19
151
|
interface AbstractPhysicalLayerEvents {
|
|
20
|
-
data: [data: Buffer, response: (data: Buffer) => Promise<void
|
|
152
|
+
data: [data: Buffer, response: (data: Buffer) => Promise<void>, connection: PhysicalConnection];
|
|
21
153
|
write: [data: Buffer];
|
|
22
154
|
error: [error: Error];
|
|
155
|
+
'connection-close': [connection: PhysicalConnection];
|
|
23
156
|
close: [];
|
|
24
157
|
}
|
|
25
158
|
declare abstract class AbstractPhysicalLayer extends EventEmitter<AbstractPhysicalLayerEvents> {
|
|
@@ -60,6 +193,8 @@ interface SerialPhysicalLayerOptions {
|
|
|
60
193
|
declare class SerialPhysicalLayer extends AbstractPhysicalLayer {
|
|
61
194
|
TYPE: 'SERIAL' | 'NET';
|
|
62
195
|
private _serialport;
|
|
196
|
+
private _connection;
|
|
197
|
+
private _isOpening;
|
|
63
198
|
private _destroyed;
|
|
64
199
|
private _baudRate;
|
|
65
200
|
get isOpen(): boolean;
|
|
@@ -75,8 +210,11 @@ declare class SerialPhysicalLayer extends AbstractPhysicalLayer {
|
|
|
75
210
|
declare class TcpClientPhysicalLayer extends AbstractPhysicalLayer {
|
|
76
211
|
TYPE: 'SERIAL' | 'NET';
|
|
77
212
|
private _socket;
|
|
213
|
+
private _connection;
|
|
78
214
|
private _isOpen;
|
|
215
|
+
private _isOpening;
|
|
79
216
|
private _destroyed;
|
|
217
|
+
private _socketOptions?;
|
|
80
218
|
get isOpen(): boolean;
|
|
81
219
|
get destroyed(): boolean;
|
|
82
220
|
constructor(options?: SocketConstructorOpts);
|
|
@@ -90,8 +228,10 @@ declare class TcpServerPhysicalLayer extends AbstractPhysicalLayer {
|
|
|
90
228
|
TYPE: 'SERIAL' | 'NET';
|
|
91
229
|
private _server;
|
|
92
230
|
private _isOpen;
|
|
231
|
+
private _isOpening;
|
|
93
232
|
private _destroyed;
|
|
94
|
-
private
|
|
233
|
+
private _connections;
|
|
234
|
+
private _serverOptions?;
|
|
95
235
|
get isOpen(): boolean;
|
|
96
236
|
get destroyed(): boolean;
|
|
97
237
|
constructor(options?: NetConnectOpts);
|
|
@@ -101,123 +241,154 @@ declare class TcpServerPhysicalLayer extends AbstractPhysicalLayer {
|
|
|
101
241
|
destroy(): Promise<void>;
|
|
102
242
|
}
|
|
103
243
|
|
|
244
|
+
interface UdpPhysicalLayerOptions {
|
|
245
|
+
/** dgram Socket creation options. */
|
|
246
|
+
socket?: Partial<SocketOptions>;
|
|
247
|
+
/**
|
|
248
|
+
* Provided → client mode (send to this single remote, filter inbound).
|
|
249
|
+
* Omitted → server mode (bind locally, accept from any rinfo).
|
|
250
|
+
*/
|
|
251
|
+
remote?: {
|
|
252
|
+
port?: number;
|
|
253
|
+
address?: string;
|
|
254
|
+
};
|
|
255
|
+
/**
|
|
256
|
+
* Server mode only. Each unique rinfo (`address:port`) gets its own
|
|
257
|
+
* `PhysicalConnection`; if no datagram arrives within this many ms, the
|
|
258
|
+
* connection is evicted (`connection-close` emitted, upper-layer framing
|
|
259
|
+
* state released). Default 30000. Set 0 to disable eviction.
|
|
260
|
+
*/
|
|
261
|
+
idleTimeout?: number;
|
|
262
|
+
}
|
|
104
263
|
declare class UdpPhysicalLayer extends AbstractPhysicalLayer {
|
|
105
264
|
TYPE: 'SERIAL' | 'NET';
|
|
106
265
|
private _socket;
|
|
266
|
+
private _connections;
|
|
107
267
|
private _isOpen;
|
|
268
|
+
private _isOpening;
|
|
108
269
|
private _destroyed;
|
|
270
|
+
private _socketOptions?;
|
|
109
271
|
private _port;
|
|
110
272
|
private _address?;
|
|
273
|
+
private _idleTimeout;
|
|
111
274
|
isServer: boolean;
|
|
112
275
|
get isOpen(): boolean;
|
|
113
276
|
get destroyed(): boolean;
|
|
114
|
-
|
|
115
|
-
*
|
|
116
|
-
* @param options
|
|
117
|
-
* @param remote If omitted, as server.
|
|
118
|
-
* Otherwise as client.
|
|
119
|
-
*/
|
|
120
|
-
constructor(options?: Partial<SocketOptions>, remote?: {
|
|
121
|
-
port?: number;
|
|
122
|
-
address?: string;
|
|
123
|
-
});
|
|
277
|
+
constructor(options?: UdpPhysicalLayerOptions);
|
|
124
278
|
open(options?: BindOptions): Promise<void>;
|
|
279
|
+
private _handleMessage;
|
|
125
280
|
write(data: Buffer): Promise<void>;
|
|
126
281
|
close(): Promise<void>;
|
|
127
282
|
destroy(): Promise<void>;
|
|
128
283
|
}
|
|
129
284
|
|
|
130
|
-
type FConvertPromise<F extends (...args: any) => any> = F extends (...args: infer A) => infer R ? ((...args: A) => Promise<R>) | ((...args: A) => R) : never;
|
|
131
|
-
interface ApplicationDataUnit {
|
|
132
|
-
transaction?: number;
|
|
133
|
-
unit: number;
|
|
134
|
-
fc: number;
|
|
135
|
-
data: number[];
|
|
136
|
-
}
|
|
137
|
-
interface ServerId {
|
|
138
|
-
serverId?: number;
|
|
139
|
-
runIndicatorStatus?: boolean;
|
|
140
|
-
additionalData?: number[];
|
|
141
|
-
}
|
|
142
|
-
interface DeviceIdentification {
|
|
143
|
-
readDeviceIDCode: number;
|
|
144
|
-
conformityLevel: number;
|
|
145
|
-
moreFollows: boolean;
|
|
146
|
-
nextObjectId: number;
|
|
147
|
-
objects: {
|
|
148
|
-
id: number;
|
|
149
|
-
value: string;
|
|
150
|
-
}[];
|
|
151
|
-
}
|
|
152
|
-
|
|
153
285
|
interface AbstractApplicationLayerEvents {
|
|
154
286
|
framing: [frame: ApplicationDataUnit & {
|
|
155
287
|
buffer: Buffer;
|
|
156
|
-
}, response: (data: Buffer) => Promise<void
|
|
288
|
+
}, response: (data: Buffer) => Promise<void>, connection: PhysicalConnection];
|
|
289
|
+
'framing-error': [error: Error];
|
|
157
290
|
}
|
|
158
291
|
declare abstract class AbstractApplicationLayer extends EventEmitter<AbstractApplicationLayerEvents> {
|
|
159
|
-
abstract
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
292
|
+
abstract readonly PROTOCOL: 'TCP' | 'RTU' | 'ASCII';
|
|
293
|
+
private _role?;
|
|
294
|
+
get role(): 'MASTER' | 'SLAVE';
|
|
295
|
+
set role(value: 'MASTER' | 'SLAVE');
|
|
296
|
+
flush(): void;
|
|
297
|
+
addCustomFunctionCode(cfc: CustomFunctionCode): void;
|
|
298
|
+
removeCustomFunctionCode(fc: number): void;
|
|
165
299
|
abstract encode(data: ApplicationDataUnit): Buffer;
|
|
166
300
|
abstract destroy(): void;
|
|
167
301
|
}
|
|
168
302
|
|
|
169
|
-
|
|
170
|
-
private _waitingResponse?;
|
|
171
|
-
private _timerThreePointFive?;
|
|
172
|
-
private _bufferRx;
|
|
173
|
-
private _removeAllListeners;
|
|
174
|
-
constructor(physicalLayer: SerialPhysicalLayer | TcpServerPhysicalLayer | TcpClientPhysicalLayer | UdpPhysicalLayer,
|
|
303
|
+
interface AsciiApplicationLayerOptions {
|
|
175
304
|
/**
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
* -
|
|
305
|
+
* Accept lowercase hex digits (`a-f`) in addition to uppercase (`A-F`).
|
|
306
|
+
* Default false (strict per Modbus V1.1b3 §2.2 — uppercase only).
|
|
307
|
+
* Non-hex characters are always rejected with a `framing-error`.
|
|
179
308
|
*/
|
|
180
|
-
|
|
309
|
+
lenientHex?: boolean;
|
|
310
|
+
}
|
|
311
|
+
declare class AsciiApplicationLayer extends AbstractApplicationLayer {
|
|
312
|
+
readonly PROTOCOL: "ASCII";
|
|
313
|
+
readonly lenientHex: boolean;
|
|
314
|
+
private _states;
|
|
315
|
+
private _removeAllListeners;
|
|
316
|
+
private _destroyed;
|
|
317
|
+
constructor(physicalLayer: SerialPhysicalLayer | TcpServerPhysicalLayer | TcpClientPhysicalLayer | UdpPhysicalLayer, options?: AsciiApplicationLayerOptions);
|
|
318
|
+
private getState;
|
|
319
|
+
flush(): void;
|
|
181
320
|
private framing;
|
|
182
|
-
startWaitingResponse(preCheck: ((frame: ApplicationDataUnit & {
|
|
183
|
-
buffer: Buffer;
|
|
184
|
-
}) => boolean | number | undefined)[], callback: (error: Error | null, frame?: ApplicationDataUnit & {
|
|
185
|
-
buffer: Buffer;
|
|
186
|
-
}) => void): void;
|
|
187
|
-
stopWaitingResponse(): void;
|
|
188
321
|
encode(data: ApplicationDataUnit): Buffer;
|
|
189
322
|
destroy(): void;
|
|
190
323
|
}
|
|
191
324
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
325
|
+
interface RtuApplicationLayerOptions {
|
|
326
|
+
/**
|
|
327
|
+
* Inter-frame silence (Modbus RTU t3.5). Defaults to `{ unit: 'bit', value: 38.5 }`
|
|
328
|
+
* for serial (3.5 character times × 11 bits/char per Modbus V1.02 §2.5.1.1);
|
|
329
|
+
* ignored for TCP/UDP transports.
|
|
330
|
+
* - `{ unit: 'bit', value: 38.5 }` — spec bit-time approximation
|
|
331
|
+
* - `{ unit: 'ms', value: 20 }` — explicit milliseconds
|
|
332
|
+
*
|
|
333
|
+
* Per Modbus V1.02 §2.5.1.1, at baud rates > 19200 the spec uses a fixed
|
|
334
|
+
* 1.75 ms regardless of the bit value supplied.
|
|
335
|
+
*/
|
|
336
|
+
intervalBetweenFrames?: {
|
|
337
|
+
unit: 'bit' | 'ms';
|
|
338
|
+
value: number;
|
|
339
|
+
};
|
|
340
|
+
/**
|
|
341
|
+
* Inter-character timeout (Modbus RTU t1.5). Opt-in; **disabled** by default
|
|
342
|
+
* because Node.js `setTimeout` precision (~1 ms minimum, ~15.6 ms on Windows)
|
|
343
|
+
* is too coarse to reliably honor t1.5 at common baud rates without
|
|
344
|
+
* false-positive frame discards. When set, a mid-frame gap exceeding this
|
|
345
|
+
* duration discards the in-progress buffer and emits `framing-error`.
|
|
346
|
+
* Only takes effect on serial transports.
|
|
347
|
+
*
|
|
348
|
+
* - `{ unit: 'bit', value: 21 }` — bit-time approximation (~1.5 char times)
|
|
349
|
+
* - `{ unit: 'ms', value: 1 }` — explicit milliseconds
|
|
350
|
+
*
|
|
351
|
+
* Per Modbus V1.02 §2.5.1.1, at baud rates > 19200 the spec uses a fixed
|
|
352
|
+
* 0.75 ms regardless of the bit value supplied.
|
|
353
|
+
*/
|
|
354
|
+
interCharTimeout?: {
|
|
355
|
+
unit: 'bit' | 'ms';
|
|
356
|
+
value: number;
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
declare class RtuApplicationLayer extends AbstractApplicationLayer {
|
|
360
|
+
readonly PROTOCOL: "RTU";
|
|
361
|
+
private _states;
|
|
362
|
+
private _customFunctionCodes;
|
|
196
363
|
private _removeAllListeners;
|
|
197
|
-
|
|
198
|
-
private
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
364
|
+
private _threePointFiveT;
|
|
365
|
+
private _onePointFiveT;
|
|
366
|
+
private _destroyed;
|
|
367
|
+
constructor(physicalLayer: SerialPhysicalLayer | TcpServerPhysicalLayer | TcpClientPhysicalLayer | UdpPhysicalLayer, options?: RtuApplicationLayerOptions);
|
|
368
|
+
private getState;
|
|
369
|
+
private clearStateTimers;
|
|
370
|
+
private clearState;
|
|
371
|
+
flush(): void;
|
|
372
|
+
addCustomFunctionCode(cfc: CustomFunctionCode): void;
|
|
373
|
+
removeCustomFunctionCode(fc: number): void;
|
|
374
|
+
private flushBuffer;
|
|
375
|
+
private tryExtract;
|
|
376
|
+
private checkExpected;
|
|
377
|
+
private crcMatches;
|
|
378
|
+
private deliverFrame;
|
|
205
379
|
encode(data: ApplicationDataUnit): Buffer;
|
|
206
380
|
destroy(): void;
|
|
207
381
|
}
|
|
208
382
|
|
|
209
383
|
declare class TcpApplicationLayer extends AbstractApplicationLayer {
|
|
210
|
-
|
|
384
|
+
readonly PROTOCOL: "TCP";
|
|
211
385
|
private _transactionId;
|
|
386
|
+
private _buffers;
|
|
212
387
|
private _removeAllListeners;
|
|
388
|
+
private _destroyed;
|
|
213
389
|
constructor(physicalLayer: TcpServerPhysicalLayer | TcpClientPhysicalLayer | UdpPhysicalLayer);
|
|
214
|
-
private
|
|
215
|
-
|
|
216
|
-
buffer: Buffer;
|
|
217
|
-
}) => boolean | number | undefined)[], callback: (error: Error | null, frame?: ApplicationDataUnit & {
|
|
218
|
-
buffer: Buffer;
|
|
219
|
-
}) => void): void;
|
|
220
|
-
stopWaitingResponse(): void;
|
|
390
|
+
private tryExtract;
|
|
391
|
+
private processFrame;
|
|
221
392
|
encode(data: ApplicationDataUnit): Buffer;
|
|
222
393
|
destroy(): void;
|
|
223
394
|
}
|
|
@@ -233,14 +404,33 @@ interface ReturnValue<T> {
|
|
|
233
404
|
data: T;
|
|
234
405
|
buffer: Buffer;
|
|
235
406
|
}
|
|
407
|
+
interface ModbusMasterOptions {
|
|
408
|
+
/** Per-request timeout in ms. Default 1000. */
|
|
409
|
+
timeout?: number;
|
|
410
|
+
/**
|
|
411
|
+
* Enable pipelined concurrent requests on a single connection.
|
|
412
|
+
* Only valid for Modbus TCP application layer.
|
|
413
|
+
* Default false (FIFO queue, requests are serialized).
|
|
414
|
+
*/
|
|
415
|
+
concurrent?: boolean;
|
|
416
|
+
}
|
|
236
417
|
declare class ModbusMaster<A extends AbstractApplicationLayer, P extends AbstractPhysicalLayer> extends EventEmitter<ModbusMasterEvents> {
|
|
237
418
|
private applicationLayer;
|
|
238
419
|
private physicalLayer;
|
|
420
|
+
private _masterSession;
|
|
421
|
+
private _queue;
|
|
422
|
+
private _draining;
|
|
423
|
+
private _nextTid;
|
|
424
|
+
private _closed;
|
|
425
|
+
private _cleanLevel;
|
|
239
426
|
timeout: number;
|
|
427
|
+
readonly concurrent: boolean;
|
|
240
428
|
get isOpen(): boolean;
|
|
241
429
|
get destroyed(): boolean;
|
|
242
|
-
constructor(applicationLayer: A, physicalLayer: P,
|
|
243
|
-
private
|
|
430
|
+
constructor(applicationLayer: A, physicalLayer: P, options?: ModbusMasterOptions);
|
|
431
|
+
private send;
|
|
432
|
+
private _drain;
|
|
433
|
+
private _exchange;
|
|
244
434
|
private writeFC1Or2;
|
|
245
435
|
writeFC1: this['readCoils'];
|
|
246
436
|
readCoils(unit: 0, address: number, length: number, timeout?: number): Promise<void>;
|
|
@@ -268,8 +458,8 @@ declare class ModbusMaster<A extends AbstractApplicationLayer, P extends Abstrac
|
|
|
268
458
|
writeMultipleRegisters(unit: 0, address: number, value: number[], timeout?: number): Promise<void>;
|
|
269
459
|
writeMultipleRegisters(unit: number, address: number, value: number[], timeout?: number): Promise<ReturnValue<number[]>>;
|
|
270
460
|
handleFC17: this['reportServerId'];
|
|
271
|
-
reportServerId(unit: 0, timeout?: number): Promise<void>;
|
|
272
|
-
reportServerId(unit: number, timeout?: number): Promise<ReturnValue<ServerId>>;
|
|
461
|
+
reportServerId(unit: 0, serverIdLength?: number, timeout?: number): Promise<void>;
|
|
462
|
+
reportServerId(unit: number, serverIdLength?: number, timeout?: number): Promise<ReturnValue<ServerId>>;
|
|
273
463
|
handleFC22: this['maskWriteRegister'];
|
|
274
464
|
maskWriteRegister(unit: 0, address: number, andMask: number, orMask: number, timeout?: number): Promise<void>;
|
|
275
465
|
maskWriteRegister(unit: number, address: number, andMask: number, orMask: number, timeout?: number): Promise<ReturnValue<{
|
|
@@ -294,11 +484,32 @@ declare class ModbusMaster<A extends AbstractApplicationLayer, P extends Abstrac
|
|
|
294
484
|
handleFC43_14: this['readDeviceIdentification'];
|
|
295
485
|
readDeviceIdentification(unit: 0, readDeviceIDCode: number, objectId: number, timeout?: number): Promise<void>;
|
|
296
486
|
readDeviceIdentification(unit: number, readDeviceIDCode: number, objectId: number, timeout?: number): Promise<ReturnValue<DeviceIdentification>>;
|
|
487
|
+
addCustomFunctionCode(cfc: CustomFunctionCode): void;
|
|
488
|
+
removeCustomFunctionCode(fc: number): void;
|
|
489
|
+
sendCustomFC(unit: 0, fc: number, data: Buffer | number[], timeout?: number): Promise<void>;
|
|
490
|
+
sendCustomFC(unit: number, fc: number, data: Buffer | number[], timeout?: number): Promise<Buffer>;
|
|
491
|
+
private _clean;
|
|
297
492
|
open(...args: Parameters<P['open']>): Promise<void>;
|
|
298
493
|
close(): Promise<void>;
|
|
299
494
|
destroy(): Promise<void>;
|
|
300
495
|
}
|
|
301
496
|
|
|
497
|
+
type Frame = ApplicationDataUnit & {
|
|
498
|
+
buffer: Buffer;
|
|
499
|
+
};
|
|
500
|
+
type PreCheck = (frame: Frame) => boolean | number | undefined;
|
|
501
|
+
type Callback = (error: Error | null, frame?: Frame) => void;
|
|
502
|
+
declare class MasterSession {
|
|
503
|
+
private _waiters;
|
|
504
|
+
start(key: string | number, preCheck: PreCheck[], callback: Callback): void;
|
|
505
|
+
stop(key: string | number): void;
|
|
506
|
+
stopAll(error: Error): void;
|
|
507
|
+
has(key: string | number): boolean;
|
|
508
|
+
handleFrame(frame: Frame): void;
|
|
509
|
+
handleError(error: Error): void;
|
|
510
|
+
private runPreChecks;
|
|
511
|
+
}
|
|
512
|
+
|
|
302
513
|
interface ModbusSlaveModel {
|
|
303
514
|
unit?: number;
|
|
304
515
|
/**
|
|
@@ -307,7 +518,7 @@ interface ModbusSlaveModel {
|
|
|
307
518
|
* If provide the return value, use this value as data of `PDU` to respond.
|
|
308
519
|
* Otherwise keep the default read and write behavior.
|
|
309
520
|
*/
|
|
310
|
-
interceptor?: FConvertPromise<(fc: number, data:
|
|
521
|
+
interceptor?: FConvertPromise<(fc: number, data: Buffer) => Buffer | undefined>;
|
|
311
522
|
readDiscreteInputs?: FConvertPromise<(address: number, length: number) => boolean[]>;
|
|
312
523
|
readCoils?: FConvertPromise<(address: number, length: number) => boolean[]>;
|
|
313
524
|
writeSingleCoil?: FConvertPromise<(address: number, value: boolean) => void>;
|
|
@@ -341,15 +552,26 @@ interface ModbusSlaveEvents {
|
|
|
341
552
|
error: [error: Error];
|
|
342
553
|
close: [];
|
|
343
554
|
}
|
|
555
|
+
interface ModbusSlaveOptions {
|
|
556
|
+
/**
|
|
557
|
+
* Pipelined concurrent processing of requests within one connection.
|
|
558
|
+
* Only valid for Modbus TCP application layer (TID disambiguates responses).
|
|
559
|
+
* Default false — per-connection FIFO. RTU/ASCII + concurrent=true throws.
|
|
560
|
+
*/
|
|
561
|
+
concurrent?: boolean;
|
|
562
|
+
}
|
|
344
563
|
declare class ModbusSlave<A extends AbstractApplicationLayer, P extends AbstractPhysicalLayer> extends EventEmitter<ModbusSlaveEvents> {
|
|
345
564
|
private applicationLayer;
|
|
346
565
|
private physicalLayer;
|
|
347
566
|
models: Map<number, ModbusSlaveModel>;
|
|
348
|
-
|
|
349
|
-
private
|
|
567
|
+
readonly concurrent: boolean;
|
|
568
|
+
private _queues;
|
|
569
|
+
private _customFunctionCodes;
|
|
570
|
+
private _locks;
|
|
571
|
+
private _cleanLevel;
|
|
350
572
|
get isOpen(): boolean;
|
|
351
573
|
get destroyed(): boolean;
|
|
352
|
-
constructor(applicationLayer: A, physicalLayer: P);
|
|
574
|
+
constructor(applicationLayer: A, physicalLayer: P, options?: ModbusSlaveOptions);
|
|
353
575
|
private handleFC1;
|
|
354
576
|
private handleFC2;
|
|
355
577
|
private handleFC3;
|
|
@@ -366,13 +588,17 @@ declare class ModbusSlave<A extends AbstractApplicationLayer, P extends Abstract
|
|
|
366
588
|
private _drain;
|
|
367
589
|
private _processFrame;
|
|
368
590
|
private _intercept;
|
|
591
|
+
private withAddressLock;
|
|
369
592
|
private _handleFC;
|
|
370
593
|
add(model: ModbusSlaveModel): void;
|
|
371
594
|
remove(unit: number): void;
|
|
595
|
+
addCustomFunctionCode(cfc: CustomFunctionCode): void;
|
|
596
|
+
removeCustomFunctionCode(fc: number): void;
|
|
597
|
+
private _clean;
|
|
372
598
|
open(...args: Parameters<P['open']>): Promise<void>;
|
|
373
599
|
close(): Promise<void>;
|
|
374
600
|
destroy(): Promise<void>;
|
|
375
601
|
}
|
|
376
602
|
|
|
377
|
-
export { AbstractApplicationLayer, AbstractPhysicalLayer, AsciiApplicationLayer, ErrorCode, ModbusMaster, ModbusSlave, RtuApplicationLayer, SerialPhysicalLayer, TcpApplicationLayer, TcpClientPhysicalLayer, TcpServerPhysicalLayer, UdpPhysicalLayer, getCodeByError, getErrorByCode };
|
|
378
|
-
export type { ModbusSlaveModel };
|
|
603
|
+
export { AbstractApplicationLayer, AbstractPhysicalLayer, AsciiApplicationLayer, COIL_OFF, COIL_ON, ConformityLevel, EXCEPTION_OFFSET, ErrorCode, FunctionCode, LIMITS, MEI_READ_DEVICE_ID, MasterSession, ModbusError, ModbusErrorCode, ModbusMaster, ModbusSlave, ReadDeviceIDCode, RtuApplicationLayer, SerialPhysicalLayer, TcpApplicationLayer, TcpClientPhysicalLayer, TcpServerPhysicalLayer, UdpPhysicalLayer, getCodeByError, getErrorByCode };
|
|
604
|
+
export type { ApplicationDataUnit, AsciiApplicationLayerOptions, Callback$1 as Callback, CustomFunctionCode, DeviceIdentification, FConvertPromise, ModbusMasterOptions, ModbusSlaveModel, ModbusSlaveOptions, PhysicalConnection, RtuApplicationLayerOptions, ServerId };
|