njs-modbus 1.5.0 → 2.0.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/README.md +16 -0
- package/dist/index.cjs +1938 -1148
- package/dist/index.d.ts +308 -89
- package/dist/index.mjs +1931 -1149
- 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 +14 -10
- package/dist/src/layers/application/index.d.ts +2 -0
- package/dist/src/layers/application/rtu-application-layer.d.ts +52 -18
- package/dist/src/layers/application/tcp-application-layer.d.ts +4 -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 +27 -5
- package/dist/src/slave/index.d.ts +1 -1
- package/dist/src/slave/slave.d.ts +18 -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,151 @@ 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
|
+
constructor(physicalLayer: SerialPhysicalLayer | TcpServerPhysicalLayer | TcpClientPhysicalLayer | UdpPhysicalLayer, options?: AsciiApplicationLayerOptions);
|
|
317
|
+
private getState;
|
|
318
|
+
flush(): void;
|
|
181
319
|
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
320
|
encode(data: ApplicationDataUnit): Buffer;
|
|
189
321
|
destroy(): void;
|
|
190
322
|
}
|
|
191
323
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
324
|
+
interface RtuApplicationLayerOptions {
|
|
325
|
+
/**
|
|
326
|
+
* Inter-frame silence (Modbus RTU t3.5). Defaults to `{ unit: 'bit', value: 38.5 }`
|
|
327
|
+
* for serial (3.5 character times × 11 bits/char per Modbus V1.02 §2.5.1.1);
|
|
328
|
+
* ignored for TCP/UDP transports.
|
|
329
|
+
* - `{ unit: 'bit', value: 38.5 }` — spec bit-time approximation
|
|
330
|
+
* - `{ unit: 'ms', value: 20 }` — explicit milliseconds
|
|
331
|
+
*
|
|
332
|
+
* Per Modbus V1.02 §2.5.1.1, at baud rates > 19200 the spec uses a fixed
|
|
333
|
+
* 1.75 ms regardless of the bit value supplied.
|
|
334
|
+
*/
|
|
335
|
+
intervalBetweenFrames?: {
|
|
336
|
+
unit: 'bit' | 'ms';
|
|
337
|
+
value: number;
|
|
338
|
+
};
|
|
339
|
+
/**
|
|
340
|
+
* Inter-character timeout (Modbus RTU t1.5). Opt-in; **disabled** by default
|
|
341
|
+
* because Node.js `setTimeout` precision (~1 ms minimum, ~15.6 ms on Windows)
|
|
342
|
+
* is too coarse to reliably honor t1.5 at common baud rates without
|
|
343
|
+
* false-positive frame discards. When set, a mid-frame gap exceeding this
|
|
344
|
+
* duration discards the in-progress buffer and emits `framing-error`.
|
|
345
|
+
* Only takes effect on serial transports.
|
|
346
|
+
*
|
|
347
|
+
* - `{ unit: 'bit', value: 21 }` — bit-time approximation (~1.5 char times)
|
|
348
|
+
* - `{ unit: 'ms', value: 1 }` — explicit milliseconds
|
|
349
|
+
*
|
|
350
|
+
* Per Modbus V1.02 §2.5.1.1, at baud rates > 19200 the spec uses a fixed
|
|
351
|
+
* 0.75 ms regardless of the bit value supplied.
|
|
352
|
+
*/
|
|
353
|
+
interCharTimeout?: {
|
|
354
|
+
unit: 'bit' | 'ms';
|
|
355
|
+
value: number;
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
declare class RtuApplicationLayer extends AbstractApplicationLayer {
|
|
359
|
+
readonly PROTOCOL: "RTU";
|
|
360
|
+
private _states;
|
|
361
|
+
private _customFunctionCodes;
|
|
196
362
|
private _removeAllListeners;
|
|
197
|
-
|
|
198
|
-
private
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
363
|
+
private _threePointFiveT;
|
|
364
|
+
private _onePointFiveT;
|
|
365
|
+
constructor(physicalLayer: SerialPhysicalLayer | TcpServerPhysicalLayer | TcpClientPhysicalLayer | UdpPhysicalLayer, options?: RtuApplicationLayerOptions);
|
|
366
|
+
private getState;
|
|
367
|
+
private clearStateTimers;
|
|
368
|
+
private clearState;
|
|
369
|
+
flush(): void;
|
|
370
|
+
addCustomFunctionCode(cfc: CustomFunctionCode): void;
|
|
371
|
+
removeCustomFunctionCode(fc: number): void;
|
|
372
|
+
private flushBuffer;
|
|
373
|
+
private tryExtract;
|
|
374
|
+
private checkExpected;
|
|
375
|
+
private crcMatches;
|
|
376
|
+
private deliverFrame;
|
|
205
377
|
encode(data: ApplicationDataUnit): Buffer;
|
|
206
378
|
destroy(): void;
|
|
207
379
|
}
|
|
208
380
|
|
|
209
381
|
declare class TcpApplicationLayer extends AbstractApplicationLayer {
|
|
210
|
-
|
|
382
|
+
readonly PROTOCOL: "TCP";
|
|
211
383
|
private _transactionId;
|
|
384
|
+
private _buffers;
|
|
212
385
|
private _removeAllListeners;
|
|
213
386
|
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;
|
|
387
|
+
private tryExtract;
|
|
388
|
+
private processFrame;
|
|
221
389
|
encode(data: ApplicationDataUnit): Buffer;
|
|
222
390
|
destroy(): void;
|
|
223
391
|
}
|
|
@@ -233,14 +401,32 @@ interface ReturnValue<T> {
|
|
|
233
401
|
data: T;
|
|
234
402
|
buffer: Buffer;
|
|
235
403
|
}
|
|
404
|
+
interface ModbusMasterOptions {
|
|
405
|
+
/** Per-request timeout in ms. Default 1000. */
|
|
406
|
+
timeout?: number;
|
|
407
|
+
/**
|
|
408
|
+
* Enable pipelined concurrent requests on a single connection.
|
|
409
|
+
* Only valid for Modbus TCP application layer.
|
|
410
|
+
* Default false (FIFO queue, requests are serialized).
|
|
411
|
+
*/
|
|
412
|
+
concurrent?: boolean;
|
|
413
|
+
}
|
|
236
414
|
declare class ModbusMaster<A extends AbstractApplicationLayer, P extends AbstractPhysicalLayer> extends EventEmitter<ModbusMasterEvents> {
|
|
237
415
|
private applicationLayer;
|
|
238
416
|
private physicalLayer;
|
|
417
|
+
private _masterSession;
|
|
418
|
+
private _queue;
|
|
419
|
+
private _draining;
|
|
420
|
+
private _nextTid;
|
|
421
|
+
private _closed;
|
|
239
422
|
timeout: number;
|
|
423
|
+
readonly concurrent: boolean;
|
|
240
424
|
get isOpen(): boolean;
|
|
241
425
|
get destroyed(): boolean;
|
|
242
|
-
constructor(applicationLayer: A, physicalLayer: P,
|
|
243
|
-
private
|
|
426
|
+
constructor(applicationLayer: A, physicalLayer: P, options?: ModbusMasterOptions);
|
|
427
|
+
private send;
|
|
428
|
+
private _drain;
|
|
429
|
+
private _exchange;
|
|
244
430
|
private writeFC1Or2;
|
|
245
431
|
writeFC1: this['readCoils'];
|
|
246
432
|
readCoils(unit: 0, address: number, length: number, timeout?: number): Promise<void>;
|
|
@@ -268,8 +454,8 @@ declare class ModbusMaster<A extends AbstractApplicationLayer, P extends Abstrac
|
|
|
268
454
|
writeMultipleRegisters(unit: 0, address: number, value: number[], timeout?: number): Promise<void>;
|
|
269
455
|
writeMultipleRegisters(unit: number, address: number, value: number[], timeout?: number): Promise<ReturnValue<number[]>>;
|
|
270
456
|
handleFC17: this['reportServerId'];
|
|
271
|
-
reportServerId(unit: 0, timeout?: number): Promise<void>;
|
|
272
|
-
reportServerId(unit: number, timeout?: number): Promise<ReturnValue<ServerId>>;
|
|
457
|
+
reportServerId(unit: 0, serverIdLength?: number, timeout?: number): Promise<void>;
|
|
458
|
+
reportServerId(unit: number, serverIdLength?: number, timeout?: number): Promise<ReturnValue<ServerId>>;
|
|
273
459
|
handleFC22: this['maskWriteRegister'];
|
|
274
460
|
maskWriteRegister(unit: 0, address: number, andMask: number, orMask: number, timeout?: number): Promise<void>;
|
|
275
461
|
maskWriteRegister(unit: number, address: number, andMask: number, orMask: number, timeout?: number): Promise<ReturnValue<{
|
|
@@ -294,11 +480,31 @@ declare class ModbusMaster<A extends AbstractApplicationLayer, P extends Abstrac
|
|
|
294
480
|
handleFC43_14: this['readDeviceIdentification'];
|
|
295
481
|
readDeviceIdentification(unit: 0, readDeviceIDCode: number, objectId: number, timeout?: number): Promise<void>;
|
|
296
482
|
readDeviceIdentification(unit: number, readDeviceIDCode: number, objectId: number, timeout?: number): Promise<ReturnValue<DeviceIdentification>>;
|
|
483
|
+
addCustomFunctionCode(cfc: CustomFunctionCode): void;
|
|
484
|
+
removeCustomFunctionCode(fc: number): void;
|
|
485
|
+
sendCustomFC(unit: 0, fc: number, data: Buffer | number[], timeout?: number): Promise<void>;
|
|
486
|
+
sendCustomFC(unit: number, fc: number, data: Buffer | number[], timeout?: number): Promise<Buffer>;
|
|
297
487
|
open(...args: Parameters<P['open']>): Promise<void>;
|
|
298
488
|
close(): Promise<void>;
|
|
299
489
|
destroy(): Promise<void>;
|
|
300
490
|
}
|
|
301
491
|
|
|
492
|
+
type Frame = ApplicationDataUnit & {
|
|
493
|
+
buffer: Buffer;
|
|
494
|
+
};
|
|
495
|
+
type PreCheck = (frame: Frame) => boolean | number | undefined;
|
|
496
|
+
type Callback = (error: Error | null, frame?: Frame) => void;
|
|
497
|
+
declare class MasterSession {
|
|
498
|
+
private _waiters;
|
|
499
|
+
start(key: string | number, preCheck: PreCheck[], callback: Callback): void;
|
|
500
|
+
stop(key: string | number): void;
|
|
501
|
+
stopAll(error: Error): void;
|
|
502
|
+
has(key: string | number): boolean;
|
|
503
|
+
handleFrame(frame: Frame): void;
|
|
504
|
+
handleError(error: Error): void;
|
|
505
|
+
private runPreChecks;
|
|
506
|
+
}
|
|
507
|
+
|
|
302
508
|
interface ModbusSlaveModel {
|
|
303
509
|
unit?: number;
|
|
304
510
|
/**
|
|
@@ -307,7 +513,7 @@ interface ModbusSlaveModel {
|
|
|
307
513
|
* If provide the return value, use this value as data of `PDU` to respond.
|
|
308
514
|
* Otherwise keep the default read and write behavior.
|
|
309
515
|
*/
|
|
310
|
-
interceptor?: FConvertPromise<(fc: number, data:
|
|
516
|
+
interceptor?: FConvertPromise<(fc: number, data: Buffer) => Buffer | undefined>;
|
|
311
517
|
readDiscreteInputs?: FConvertPromise<(address: number, length: number) => boolean[]>;
|
|
312
518
|
readCoils?: FConvertPromise<(address: number, length: number) => boolean[]>;
|
|
313
519
|
writeSingleCoil?: FConvertPromise<(address: number, value: boolean) => void>;
|
|
@@ -341,15 +547,25 @@ interface ModbusSlaveEvents {
|
|
|
341
547
|
error: [error: Error];
|
|
342
548
|
close: [];
|
|
343
549
|
}
|
|
550
|
+
interface ModbusSlaveOptions {
|
|
551
|
+
/**
|
|
552
|
+
* Pipelined concurrent processing of requests within one connection.
|
|
553
|
+
* Only valid for Modbus TCP application layer (TID disambiguates responses).
|
|
554
|
+
* Default false — per-connection FIFO. RTU/ASCII + concurrent=true throws.
|
|
555
|
+
*/
|
|
556
|
+
concurrent?: boolean;
|
|
557
|
+
}
|
|
344
558
|
declare class ModbusSlave<A extends AbstractApplicationLayer, P extends AbstractPhysicalLayer> extends EventEmitter<ModbusSlaveEvents> {
|
|
345
559
|
private applicationLayer;
|
|
346
560
|
private physicalLayer;
|
|
347
561
|
models: Map<number, ModbusSlaveModel>;
|
|
348
|
-
|
|
349
|
-
private
|
|
562
|
+
readonly concurrent: boolean;
|
|
563
|
+
private _queues;
|
|
564
|
+
private _customFunctionCodes;
|
|
565
|
+
private _locks;
|
|
350
566
|
get isOpen(): boolean;
|
|
351
567
|
get destroyed(): boolean;
|
|
352
|
-
constructor(applicationLayer: A, physicalLayer: P);
|
|
568
|
+
constructor(applicationLayer: A, physicalLayer: P, options?: ModbusSlaveOptions);
|
|
353
569
|
private handleFC1;
|
|
354
570
|
private handleFC2;
|
|
355
571
|
private handleFC3;
|
|
@@ -366,13 +582,16 @@ declare class ModbusSlave<A extends AbstractApplicationLayer, P extends Abstract
|
|
|
366
582
|
private _drain;
|
|
367
583
|
private _processFrame;
|
|
368
584
|
private _intercept;
|
|
585
|
+
private withAddressLock;
|
|
369
586
|
private _handleFC;
|
|
370
587
|
add(model: ModbusSlaveModel): void;
|
|
371
588
|
remove(unit: number): void;
|
|
589
|
+
addCustomFunctionCode(cfc: CustomFunctionCode): void;
|
|
590
|
+
removeCustomFunctionCode(fc: number): void;
|
|
372
591
|
open(...args: Parameters<P['open']>): Promise<void>;
|
|
373
592
|
close(): Promise<void>;
|
|
374
593
|
destroy(): Promise<void>;
|
|
375
594
|
}
|
|
376
595
|
|
|
377
|
-
export { AbstractApplicationLayer, AbstractPhysicalLayer, AsciiApplicationLayer, ErrorCode, ModbusMaster, ModbusSlave, RtuApplicationLayer, SerialPhysicalLayer, TcpApplicationLayer, TcpClientPhysicalLayer, TcpServerPhysicalLayer, UdpPhysicalLayer, getCodeByError, getErrorByCode };
|
|
378
|
-
export type { ModbusSlaveModel };
|
|
596
|
+
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 };
|
|
597
|
+
export type { ApplicationDataUnit, AsciiApplicationLayerOptions, Callback$1 as Callback, CustomFunctionCode, DeviceIdentification, FConvertPromise, ModbusMasterOptions, ModbusSlaveModel, ModbusSlaveOptions, PhysicalConnection, RtuApplicationLayerOptions, ServerId };
|