njs-modbus 3.0.2 → 3.1.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 +70 -3
- package/README.zh-CN.md +69 -3
- package/dist/index.cjs +2021 -2578
- package/dist/index.d.ts +71 -57
- package/dist/index.mjs +2021 -2579
- package/dist/src/layers/application/abstract-application-layer.d.ts +1 -1
- package/dist/src/layers/application/ascii-application-layer.d.ts +1 -2
- package/dist/src/layers/application/rtu-application-layer.d.ts +2 -6
- package/dist/src/layers/application/tcp-application-layer.d.ts +1 -2
- package/dist/src/layers/physical/abstract-physical-layer.d.ts +5 -4
- package/dist/src/layers/physical/serial-physical-layer.d.ts +7 -9
- package/dist/src/layers/physical/tcp-client-physical-layer.d.ts +4 -5
- package/dist/src/layers/physical/tcp-physical-connection.d.ts +3 -4
- package/dist/src/layers/physical/tcp-server-physical-layer.d.ts +4 -5
- package/dist/src/layers/physical/udp-client-physical-layer.d.ts +7 -9
- package/dist/src/layers/physical/udp-server-physical-layer.d.ts +7 -11
- package/dist/src/master/master-session.d.ts +3 -3
- package/dist/src/master/master.d.ts +10 -2
- package/dist/src/slave/slave.d.ts +1 -0
- package/dist/src/utils/callback.d.ts +8 -0
- package/dist/src/utils/crc.d.ts +1 -1
- package/dist/src/utils/index.d.ts +4 -3
- package/dist/src/utils/predictRtuFrameLength.d.ts +13 -16
- package/dist/src/utils/promisify-cb.d.ts +4 -0
- package/dist/src/utils/rtu-timing.d.ts +25 -11
- package/dist/src/vars.d.ts +2 -0
- package/package.json +8 -1
|
@@ -21,6 +21,6 @@ export declare abstract class AbstractApplicationLayer extends EventEmitter<Abst
|
|
|
21
21
|
flush(): void;
|
|
22
22
|
addCustomFunctionCode(cfc: CustomFunctionCode): void;
|
|
23
23
|
removeCustomFunctionCode(fc: number): void;
|
|
24
|
-
abstract encode(data:
|
|
24
|
+
abstract encode(unit: number, fc: number, data: Buffer, transaction?: number): Buffer;
|
|
25
25
|
}
|
|
26
26
|
export {};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { ApplicationDataUnit } from '../../types';
|
|
2
1
|
import type { AbstractPhysicalConnection } from '../physical';
|
|
3
2
|
import { AbstractApplicationLayer } from './abstract-application-layer';
|
|
4
3
|
export interface AsciiApplicationLayerOptions {
|
|
@@ -20,5 +19,5 @@ export declare class AsciiApplicationLayer extends AbstractApplicationLayer {
|
|
|
20
19
|
constructor(role: 'MASTER' | 'SLAVE', connection: AbstractPhysicalConnection, options?: AsciiApplicationLayerOptions);
|
|
21
20
|
private framing;
|
|
22
21
|
flush(): void;
|
|
23
|
-
encode(data:
|
|
22
|
+
encode(unit: number, fc: number, data: Buffer, transaction?: number): Buffer;
|
|
24
23
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CustomFunctionCode } from '../../types';
|
|
2
2
|
import type { AbstractPhysicalConnection } from '../physical';
|
|
3
3
|
import { AbstractApplicationLayer } from './abstract-application-layer';
|
|
4
4
|
export interface RtuApplicationLayerOptions {
|
|
@@ -27,12 +27,8 @@ export declare class RtuApplicationLayer extends AbstractApplicationLayer {
|
|
|
27
27
|
constructor(role: 'MASTER' | 'SLAVE', connection: AbstractPhysicalConnection, options?: RtuApplicationLayerOptions);
|
|
28
28
|
private clearStateTimers;
|
|
29
29
|
private flushBuffer;
|
|
30
|
-
private deliverFrame;
|
|
31
|
-
private tryExtract;
|
|
32
|
-
private checkExpected;
|
|
33
|
-
private crcMatches;
|
|
34
30
|
flush(): void;
|
|
35
31
|
addCustomFunctionCode(cfc: CustomFunctionCode): void;
|
|
36
32
|
removeCustomFunctionCode(fc: number): void;
|
|
37
|
-
encode(data:
|
|
33
|
+
encode(unit: number, fc: number, data: Buffer, transaction?: number): Buffer;
|
|
38
34
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { ApplicationDataUnit } from '../../types';
|
|
2
1
|
import type { AbstractPhysicalConnection } from '../physical';
|
|
3
2
|
import { AbstractApplicationLayer } from './abstract-application-layer';
|
|
4
3
|
export declare class TcpApplicationLayer extends AbstractApplicationLayer {
|
|
@@ -13,5 +12,5 @@ export declare class TcpApplicationLayer extends AbstractApplicationLayer {
|
|
|
13
12
|
private tryExtract;
|
|
14
13
|
private processFrame;
|
|
15
14
|
flush(): void;
|
|
16
|
-
encode(data:
|
|
15
|
+
encode(unit: number, fc: number, data: Buffer, transaction?: number): Buffer;
|
|
17
16
|
}
|
|
@@ -18,8 +18,8 @@ interface AbstractPhysicalConnectionEvents {
|
|
|
18
18
|
export declare abstract class AbstractPhysicalConnection extends EventEmitter<AbstractPhysicalConnectionEvents> {
|
|
19
19
|
abstract readonly state: PhysicalConnectionState;
|
|
20
20
|
abstract readonly physicalLayer: AbstractPhysicalLayer;
|
|
21
|
-
abstract write(data: Buffer):
|
|
22
|
-
abstract destroy():
|
|
21
|
+
abstract write(data: Buffer, cb?: (err?: Error | null) => void): void;
|
|
22
|
+
abstract destroy(cb?: (err?: Error | null) => void): void;
|
|
23
23
|
}
|
|
24
24
|
export interface AbstractPhysicalLayerEvents {
|
|
25
25
|
open: [];
|
|
@@ -43,7 +43,8 @@ export declare abstract class AbstractPhysicalLayer extends EventEmitter<Abstrac
|
|
|
43
43
|
is(type: 'UDP_CLIENT'): this is UdpClientPhysicalLayer;
|
|
44
44
|
is(type: 'UDP_SERVER'): this is UdpServerPhysicalLayer;
|
|
45
45
|
abstract readonly state: PhysicalState;
|
|
46
|
-
|
|
47
|
-
abstract
|
|
46
|
+
/** Last argument is the callback: `(err?: Error | null) => void`. Callback is optional. */
|
|
47
|
+
abstract open(...args: any[]): void;
|
|
48
|
+
abstract close(cb?: (err?: Error | null) => void): void;
|
|
48
49
|
}
|
|
49
50
|
export {};
|
|
@@ -41,14 +41,13 @@ export declare class SerialPhysicalConnection extends AbstractPhysicalConnection
|
|
|
41
41
|
private _state;
|
|
42
42
|
private _physicalLayer;
|
|
43
43
|
private _serialport;
|
|
44
|
-
private
|
|
45
|
-
private _resolveDestroy;
|
|
44
|
+
private _pendingDestroyCbs;
|
|
46
45
|
private _cleanupFns;
|
|
47
46
|
get state(): PhysicalConnectionState;
|
|
48
47
|
get physicalLayer(): AbstractPhysicalLayer;
|
|
49
48
|
constructor(physicalLayer: SerialPhysicalLayer, serialport: SerialPort);
|
|
50
|
-
write(data: Buffer):
|
|
51
|
-
destroy():
|
|
49
|
+
write(data: Buffer, cb?: (err?: Error | null) => void): void;
|
|
50
|
+
destroy(cb?: (err?: Error | null) => void): void;
|
|
52
51
|
}
|
|
53
52
|
export declare class SerialPhysicalLayer extends AbstractPhysicalLayer {
|
|
54
53
|
readonly TYPE: "SERIAL";
|
|
@@ -58,15 +57,14 @@ export declare class SerialPhysicalLayer extends AbstractPhysicalLayer {
|
|
|
58
57
|
private _serialportOpts;
|
|
59
58
|
private _path;
|
|
60
59
|
private _baudRate;
|
|
61
|
-
private
|
|
62
|
-
private
|
|
63
|
-
private _resolveClose;
|
|
60
|
+
private _pendingOpenCbs;
|
|
61
|
+
private _pendingCloseCbs;
|
|
64
62
|
private _cleanupFns;
|
|
65
63
|
get state(): PhysicalState;
|
|
66
64
|
get serialport(): SerialPort | null;
|
|
67
65
|
get path(): string;
|
|
68
66
|
get baudRate(): number;
|
|
69
67
|
constructor(options: SerialPhysicalLayerOptions);
|
|
70
|
-
open():
|
|
71
|
-
close():
|
|
68
|
+
open(cb?: (err?: Error | null) => void): void;
|
|
69
|
+
close(cb?: (err?: Error | null) => void): void;
|
|
72
70
|
}
|
|
@@ -8,13 +8,12 @@ export declare class TcpClientPhysicalLayer extends AbstractPhysicalLayer {
|
|
|
8
8
|
private _connections;
|
|
9
9
|
private _socket;
|
|
10
10
|
private _socketOpts?;
|
|
11
|
-
private
|
|
12
|
-
private
|
|
13
|
-
private _resolveClose;
|
|
11
|
+
private _pendingOpenCbs;
|
|
12
|
+
private _pendingCloseCbs;
|
|
14
13
|
private _cleanupFns;
|
|
15
14
|
get state(): PhysicalState;
|
|
16
15
|
get socket(): Socket | null;
|
|
17
16
|
constructor(options?: SocketConstructorOpts);
|
|
18
|
-
open(options?: SocketConnectOpts):
|
|
19
|
-
close():
|
|
17
|
+
open(options?: SocketConnectOpts | ((err?: Error | null) => void), cb?: (err?: Error | null) => void): void;
|
|
18
|
+
close(cb?: (err?: Error | null) => void): void;
|
|
20
19
|
}
|
|
@@ -6,12 +6,11 @@ export declare class TcpPhysicalConnection extends AbstractPhysicalConnection {
|
|
|
6
6
|
private _state;
|
|
7
7
|
private _physicalLayer;
|
|
8
8
|
private _socket;
|
|
9
|
-
private
|
|
10
|
-
private _resolveDestroy;
|
|
9
|
+
private _pendingDestroyCbs;
|
|
11
10
|
private _cleanupFns;
|
|
12
11
|
get state(): PhysicalConnectionState;
|
|
13
12
|
get physicalLayer(): AbstractPhysicalLayer;
|
|
14
13
|
constructor(physicalLayer: AbstractPhysicalLayer, socket: Socket);
|
|
15
|
-
write(data: Buffer):
|
|
16
|
-
destroy():
|
|
14
|
+
write(data: Buffer, cb?: (err?: Error | null) => void): void;
|
|
15
|
+
destroy(cb?: (err?: Error | null) => void): void;
|
|
17
16
|
}
|
|
@@ -17,13 +17,12 @@ export declare class TcpServerPhysicalLayer extends AbstractPhysicalLayer {
|
|
|
17
17
|
private _connections;
|
|
18
18
|
private _server;
|
|
19
19
|
private _opts;
|
|
20
|
-
private
|
|
21
|
-
private
|
|
22
|
-
private _resolveClose;
|
|
20
|
+
private _pendingOpenCbs;
|
|
21
|
+
private _pendingCloseCbs;
|
|
23
22
|
private _cleanupFns;
|
|
24
23
|
get state(): PhysicalState;
|
|
25
24
|
get server(): Server | null;
|
|
26
25
|
constructor(options?: TcpServerPhysicalLayerOptions);
|
|
27
|
-
open(options?: ListenOptions):
|
|
28
|
-
close():
|
|
26
|
+
open(options?: ListenOptions | ((err?: Error | null) => void), cb?: (err?: Error | null) => void): void;
|
|
27
|
+
close(cb?: (err?: Error | null) => void): void;
|
|
29
28
|
}
|
|
@@ -5,14 +5,13 @@ export declare class UdpClientPhysicalConnection extends AbstractPhysicalConnect
|
|
|
5
5
|
private _state;
|
|
6
6
|
private _physicalLayer;
|
|
7
7
|
private _socket;
|
|
8
|
-
private
|
|
9
|
-
private _resolveDestroy;
|
|
8
|
+
private _pendingDestroyCbs;
|
|
10
9
|
private _cleanupFns;
|
|
11
10
|
get state(): PhysicalConnectionState;
|
|
12
11
|
get physicalLayer(): AbstractPhysicalLayer;
|
|
13
12
|
constructor(physicalLayer: UdpClientPhysicalLayer, socket: Socket);
|
|
14
|
-
write(data: Buffer):
|
|
15
|
-
destroy():
|
|
13
|
+
write(data: Buffer, cb?: (err?: Error | null) => void): void;
|
|
14
|
+
destroy(cb?: (err?: Error | null) => void): void;
|
|
16
15
|
}
|
|
17
16
|
export declare class UdpClientPhysicalLayer extends AbstractPhysicalLayer {
|
|
18
17
|
readonly TYPE: "UDP_CLIENT";
|
|
@@ -20,9 +19,8 @@ export declare class UdpClientPhysicalLayer extends AbstractPhysicalLayer {
|
|
|
20
19
|
private _connections;
|
|
21
20
|
private _socket;
|
|
22
21
|
private _socketOpts;
|
|
23
|
-
private
|
|
24
|
-
private
|
|
25
|
-
private _resolveClose;
|
|
22
|
+
private _pendingOpenCbs;
|
|
23
|
+
private _pendingCloseCbs;
|
|
26
24
|
private _cleanupFns;
|
|
27
25
|
get state(): PhysicalState;
|
|
28
26
|
get socket(): Socket | null;
|
|
@@ -30,6 +28,6 @@ export declare class UdpClientPhysicalLayer extends AbstractPhysicalLayer {
|
|
|
30
28
|
open(remote?: {
|
|
31
29
|
port?: number;
|
|
32
30
|
address?: string;
|
|
33
|
-
}):
|
|
34
|
-
close():
|
|
31
|
+
} | ((err?: Error | null) => void), cb?: (err?: Error | null) => void): void;
|
|
32
|
+
close(cb?: (err?: Error | null) => void): void;
|
|
35
33
|
}
|
|
@@ -24,8 +24,8 @@ export declare class UdpServerPhysicalConnection extends AbstractPhysicalConnect
|
|
|
24
24
|
add: (listener: (msg: Buffer, rinfo: RemoteInfo) => void) => void;
|
|
25
25
|
remove: (listener: (...args: any[]) => void) => void;
|
|
26
26
|
});
|
|
27
|
-
write(data: Buffer):
|
|
28
|
-
destroy():
|
|
27
|
+
write(data: Buffer, cb?: (err?: Error | null) => void): void;
|
|
28
|
+
destroy(cb?: (err?: Error | null) => void): void;
|
|
29
29
|
}
|
|
30
30
|
export declare class UdpServerPhysicalLayer extends AbstractPhysicalLayer {
|
|
31
31
|
readonly TYPE: "UDP_SERVER";
|
|
@@ -33,9 +33,8 @@ export declare class UdpServerPhysicalLayer extends AbstractPhysicalLayer {
|
|
|
33
33
|
private _connections;
|
|
34
34
|
private _socket;
|
|
35
35
|
private _opts;
|
|
36
|
-
private
|
|
37
|
-
private
|
|
38
|
-
private _resolveClose;
|
|
36
|
+
private _pendingOpenCbs;
|
|
37
|
+
private _pendingCloseCbs;
|
|
39
38
|
private _cleanupFns;
|
|
40
39
|
get state(): PhysicalState;
|
|
41
40
|
get socket(): Socket | null;
|
|
@@ -44,11 +43,8 @@ export declare class UdpServerPhysicalLayer extends AbstractPhysicalLayer {
|
|
|
44
43
|
* Bind the UDP socket and start accepting datagrams.
|
|
45
44
|
*
|
|
46
45
|
* @param options Bind options (port, address, etc.). Defaults to port 502.
|
|
47
|
-
* @param
|
|
48
|
-
* inactive client connection is evicted. Pass `0` to disable eviction
|
|
49
|
-
* (connections never time out). Disabling eviction may cause unbounded
|
|
50
|
-
* memory growth if the server sees many unique clients.
|
|
46
|
+
* @param cb Callback invoked when binding completes or fails.
|
|
51
47
|
*/
|
|
52
|
-
open(options?: BindOptions):
|
|
53
|
-
close():
|
|
48
|
+
open(options?: BindOptions | ((err?: Error | null) => void), cb?: (err?: Error | null) => void): void;
|
|
49
|
+
close(cb?: (err?: Error | null) => void): void;
|
|
54
50
|
}
|
|
@@ -2,17 +2,17 @@ import type { ApplicationDataUnit } from '../types';
|
|
|
2
2
|
type Frame = ApplicationDataUnit & {
|
|
3
3
|
buffer: Buffer;
|
|
4
4
|
};
|
|
5
|
-
type PreCheck = (frame: Frame) => boolean | number | undefined;
|
|
6
5
|
type Callback = (error: Error | null, frame?: Frame) => void;
|
|
7
6
|
export declare const FIFO_KEY: "fifo";
|
|
8
7
|
export declare class MasterSession {
|
|
9
8
|
private _waiters;
|
|
10
|
-
|
|
9
|
+
/** Register a callback for `key`. No timer — timeout is managed by the caller. */
|
|
10
|
+
start(key: string | number, callback: Callback): void;
|
|
11
|
+
/** Cancel a pending waiter without firing its callback. */
|
|
11
12
|
stop(key: string | number): void;
|
|
12
13
|
stopAll(error: Error): void;
|
|
13
14
|
has(key: string | number): boolean;
|
|
14
15
|
handleFrame(frame: Frame): void;
|
|
15
16
|
handleError(error: Error): void;
|
|
16
|
-
private runPreChecks;
|
|
17
17
|
}
|
|
18
18
|
export {};
|
|
@@ -39,7 +39,15 @@ export declare class ModbusMaster<T extends ModbusMasterOptions = ModbusMasterOp
|
|
|
39
39
|
private _protocol;
|
|
40
40
|
private _appLayer?;
|
|
41
41
|
private _customFunctionCodes;
|
|
42
|
-
private
|
|
42
|
+
private _queueUnits;
|
|
43
|
+
private _queueFcs;
|
|
44
|
+
private _queueDatas;
|
|
45
|
+
private _queueTimeouts;
|
|
46
|
+
private _queueBroadcasts;
|
|
47
|
+
private _queueResolves;
|
|
48
|
+
private _queueRejects;
|
|
49
|
+
private _queueHead;
|
|
50
|
+
private _queueLen;
|
|
43
51
|
private _draining;
|
|
44
52
|
private _nextTid;
|
|
45
53
|
private _cleanupFns;
|
|
@@ -50,6 +58,7 @@ export declare class ModbusMaster<T extends ModbusMasterOptions = ModbusMasterOp
|
|
|
50
58
|
private _createAppLayer;
|
|
51
59
|
private send;
|
|
52
60
|
private _drain;
|
|
61
|
+
private _processNext;
|
|
53
62
|
private _exchange;
|
|
54
63
|
private writeFC1Or2;
|
|
55
64
|
writeFC1: this['readCoils'];
|
|
@@ -108,7 +117,6 @@ export declare class ModbusMaster<T extends ModbusMasterOptions = ModbusMasterOp
|
|
|
108
117
|
removeCustomFunctionCode(fc: number): void;
|
|
109
118
|
sendCustomFC(unit: 0, fc: number, data: Buffer | number[], timeout?: number): Promise<void>;
|
|
110
119
|
sendCustomFC(unit: number, fc: number, data: Buffer | number[], timeout?: number): Promise<Buffer>;
|
|
111
|
-
private _clean;
|
|
112
120
|
/**
|
|
113
121
|
* Open the underlying physical layer and begin accepting connections.
|
|
114
122
|
*
|
|
@@ -92,6 +92,7 @@ export declare class ModbusSlave<T extends ModbusSlaveOptions = ModbusSlaveOptio
|
|
|
92
92
|
private _intercept;
|
|
93
93
|
private _withAddressLock;
|
|
94
94
|
private _handleFC;
|
|
95
|
+
private _handleCustomFC;
|
|
95
96
|
add(model: ModbusSlaveModel): void;
|
|
96
97
|
remove(unit: number): void;
|
|
97
98
|
addCustomFunctionCode(cfc: CustomFunctionCode): void;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drain a pending-callback array: invoke each callback with the given error (or null).
|
|
3
|
+
*
|
|
4
|
+
* Handles `null`/`undefined` entries (from optional `cb?` parameters) gracefully.
|
|
5
|
+
* Used by physical layers and connections to resolve queued
|
|
6
|
+
* open / close / destroy callbacks.
|
|
7
|
+
*/
|
|
8
|
+
export declare function drainCbs(cbs: (((err?: Error | null) => void) | undefined)[] | null, err?: Error | null): void;
|
package/dist/src/utils/crc.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function crc(data: Uint8Array,
|
|
1
|
+
export declare function crc(data: Uint8Array, start?: number, end?: number): number;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
export type { PredictResult } from './predictRtuFrameLength';
|
|
2
1
|
export type { RtuProtocolOptions, ResolvedRtuTiming } from './rtu-timing';
|
|
2
|
+
export { bitsToMs } from './bitsToMs';
|
|
3
|
+
export { drainCbs } from './callback';
|
|
3
4
|
export { checkRange } from './checkRange';
|
|
4
5
|
export { crc } from './crc';
|
|
5
|
-
export { bitsToMs } from './bitsToMs';
|
|
6
6
|
export { isUint8 } from './isUint8';
|
|
7
7
|
export { lrc } from './lrc';
|
|
8
|
-
export { predictRtuFrameLength } from './predictRtuFrameLength';
|
|
8
|
+
export { PREDICT_NEED_MORE, PREDICT_UNKNOWN, predictRtuFrameLength } from './predictRtuFrameLength';
|
|
9
|
+
export { promisifyCb } from './promisify-cb';
|
|
9
10
|
export { resolveRtuTiming } from './rtu-timing';
|
|
10
11
|
export { isWhitelisted } from './whitelist';
|
|
@@ -1,20 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
kind: 'need-more';
|
|
6
|
-
} | {
|
|
7
|
-
kind: 'unknown';
|
|
8
|
-
};
|
|
1
|
+
/** Sentinel: caller needs to feed more bytes before length can be determined. */
|
|
2
|
+
export declare const PREDICT_NEED_MORE = 0;
|
|
3
|
+
/** Sentinel: function code is not in the standard tables. */
|
|
4
|
+
export declare const PREDICT_UNKNOWN = -1;
|
|
9
5
|
/**
|
|
10
6
|
* Predict the total RTU frame length (PDU + 2-byte CRC) given the leading bytes.
|
|
11
7
|
*
|
|
12
|
-
* Returns a
|
|
13
|
-
*
|
|
14
|
-
* -
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
8
|
+
* Returns a sentinel-encoded number to avoid per-call object allocation on the
|
|
9
|
+
* RTU decode hot path:
|
|
10
|
+
* - Positive integer (>= 4): total frame length, function code is known.
|
|
11
|
+
* - {@link PREDICT_NEED_MORE} (0): function code is known but more bytes are
|
|
12
|
+
* required (typically waiting on the byteCount byte).
|
|
13
|
+
* - {@link PREDICT_UNKNOWN} (-1): function code is not in the standard tables —
|
|
14
|
+
* the framing layer must defer to a registered `CustomFunctionCode` or treat
|
|
15
|
+
* this as a framing error.
|
|
19
16
|
*/
|
|
20
|
-
export declare function predictRtuFrameLength(buffer: Buffer, isResponse: boolean):
|
|
17
|
+
export declare function predictRtuFrameLength(buffer: Buffer, isResponse: boolean): number;
|
|
@@ -1,29 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RTU timing parameter — accepts either:
|
|
3
|
+
* - a bare `number` in milliseconds (`0` to disable the timer entirely)
|
|
4
|
+
* - `{ unit: 'ms', value: N }` — explicit milliseconds (equivalent to bare `N`)
|
|
5
|
+
* - `{ unit: 'bit', value: N }` — bit-time approximation, derived from `baudRate`
|
|
6
|
+
*
|
|
7
|
+
* The bare-number form is the recommended default; the object form exists for
|
|
8
|
+
* specs that quote bit-time. Pass `0` (or `{ unit: 'ms', value: 0 }`) to disable
|
|
9
|
+
* the timer; either form short-circuits the baudRate-derived fallback.
|
|
10
|
+
*/
|
|
11
|
+
export type RtuTimingValue = number | {
|
|
12
|
+
unit: 'bit' | 'ms';
|
|
13
|
+
value: number;
|
|
14
|
+
};
|
|
1
15
|
/** User-facing RTU protocol options (supports both bit and ms units). */
|
|
2
16
|
export interface RtuProtocolOptions {
|
|
3
17
|
/**
|
|
4
18
|
* Inter-frame silence (Modbus RTU t3.5).
|
|
19
|
+
*
|
|
20
|
+
* - `20` or `{ unit: 'ms', value: 20 }` — 20 ms
|
|
5
21
|
* - `{ unit: 'bit', value: 38.5 }` — spec bit-time approximation (default when `baudRate` is provided)
|
|
6
|
-
* - `
|
|
22
|
+
* - `0` — disable t3.5 timing (immediate parse on every chunk; useful for
|
|
23
|
+
* lossless transports such as RTU-over-TCP or PTY-based tests where the
|
|
24
|
+
* wire's silence semantics do not apply)
|
|
7
25
|
*
|
|
8
26
|
* Per Modbus V1.02 §2.5.1.1, at baud rates > 19200 a fixed 1.75 ms is used
|
|
9
27
|
* regardless of the bit value.
|
|
10
28
|
*/
|
|
11
|
-
intervalBetweenFrames?:
|
|
12
|
-
unit: 'bit' | 'ms';
|
|
13
|
-
value: number;
|
|
14
|
-
};
|
|
29
|
+
intervalBetweenFrames?: RtuTimingValue;
|
|
15
30
|
/**
|
|
16
31
|
* Inter-character timeout (Modbus RTU t1.5). Opt-in; **disabled** by default.
|
|
32
|
+
*
|
|
33
|
+
* - `1` or `{ unit: 'ms', value: 1 }` — 1 ms
|
|
17
34
|
* - `{ unit: 'bit', value: 21 }` — bit-time approximation (~1.5 char times)
|
|
18
|
-
* - `
|
|
35
|
+
* - `0` — disable explicitly
|
|
19
36
|
*
|
|
20
37
|
* Per Modbus V1.02 §2.5.1.1, at baud rates > 19200 a fixed 0.75 ms is used
|
|
21
38
|
* regardless of the bit value.
|
|
22
39
|
*/
|
|
23
|
-
interCharTimeout?:
|
|
24
|
-
unit: 'bit' | 'ms';
|
|
25
|
-
value: number;
|
|
26
|
-
};
|
|
40
|
+
interCharTimeout?: RtuTimingValue;
|
|
27
41
|
/**
|
|
28
42
|
* Buffer pool size per connection (bytes). Defaults to `MAX_FRAME_LENGTH * 2`
|
|
29
43
|
* (512 bytes). Increase this if you expect frames larger than 256 bytes or
|
|
@@ -40,7 +54,7 @@ export interface ResolvedRtuTiming {
|
|
|
40
54
|
* Resolve Modbus RTU timing parameters from user options into milliseconds.
|
|
41
55
|
*
|
|
42
56
|
* - `intervalBetweenFrames` (t3.5): if omitted and `baudRate` is present,
|
|
43
|
-
* defaults to 38.5 bits per Modbus V1.02 §2.5.1.1.
|
|
57
|
+
* defaults to 38.5 bits per Modbus V1.02 §2.5.1.1. Pass `0` to disable.
|
|
44
58
|
* - `interCharTimeout` (t1.5): opt-in; only resolved when explicitly provided.
|
|
45
59
|
*
|
|
46
60
|
* Per the spec, at baud rates > 19200 fixed values are used
|
package/dist/src/vars.d.ts
CHANGED
|
@@ -35,6 +35,8 @@ export declare enum ConformityLevel {
|
|
|
35
35
|
REGULAR = 130,
|
|
36
36
|
EXTENDED = 131
|
|
37
37
|
}
|
|
38
|
+
/** Shared empty Buffer to avoid repeated allocations. */
|
|
39
|
+
export declare const EMPTY_BUFFER: Buffer<ArrayBuffer>;
|
|
38
40
|
/** Modbus V1.1b3 PDU quantity limits. */
|
|
39
41
|
export declare const LIMITS: {
|
|
40
42
|
readonly READ_COILS_MIN: 1;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "njs-modbus",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "A pure JavaScript implementation of Modbus for Node.js.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"modbus",
|
|
@@ -31,6 +31,8 @@
|
|
|
31
31
|
"*.d.ts"
|
|
32
32
|
],
|
|
33
33
|
"scripts": {
|
|
34
|
+
"benchmark": "tsx benchmark/encode-decode.ts && echo && tsx benchmark/tcp-throughput.ts && echo && tsx benchmark/concurrent.ts",
|
|
35
|
+
"benchmark:report": "tsx benchmark/generate-report.ts",
|
|
34
36
|
"build": "node -e \"fs.rmSync('dist', {recursive: true, force: true})\" && rollup -c",
|
|
35
37
|
"test": "tsx --test test/**/*.test.ts",
|
|
36
38
|
"util:sort-package-json": "sort-package-json"
|
|
@@ -50,7 +52,9 @@
|
|
|
50
52
|
"eslint-config-prettier": "^10.1.5",
|
|
51
53
|
"eslint-plugin-import": "2.31.0",
|
|
52
54
|
"eslint-plugin-prettier": "^5.4.1",
|
|
55
|
+
"jsmodbus": "^4.0.10",
|
|
53
56
|
"microbundle": "^0.15.1",
|
|
57
|
+
"modbus-serial": "^8.0.25",
|
|
54
58
|
"nx": "21.1.3",
|
|
55
59
|
"prettier": "^3.5.3",
|
|
56
60
|
"rollup": "^4.43.0",
|
|
@@ -66,5 +70,8 @@
|
|
|
66
70
|
},
|
|
67
71
|
"peerDependencies": {
|
|
68
72
|
"serialport": ">=12.0.0"
|
|
73
|
+
},
|
|
74
|
+
"engines": {
|
|
75
|
+
"node": ">=18.19"
|
|
69
76
|
}
|
|
70
77
|
}
|