njs-modbus 3.2.0 → 3.4.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/dist/utils.d.ts CHANGED
@@ -39,11 +39,12 @@ interface RtuProtocolOptions {
39
39
  */
40
40
  interCharTimeout?: RtuTimingValue;
41
41
  /**
42
- * Buffer pool size per connection (bytes). Defaults to `MAX_FRAME_LENGTH * 2`
43
- * (512 bytes). Increase this if you expect frames larger than 256 bytes or
44
- * heavy pipelining on a single connection.
42
+ * Enforces strict Modbus RTU timing. When true, any frame containing a t1.5
43
+ * inter-character timeout event will be discarded immediately, even if the
44
+ * CRC16 is valid.
45
+ * @default false
45
46
  */
46
- poolSize?: number;
47
+ strictTiming?: boolean;
47
48
  }
48
49
  /** Resolved RTU timing values in milliseconds. */
49
50
  interface ResolvedRtuTiming {
@@ -87,66 +88,68 @@ declare function drainCbs(cbs: (((err?: Error | null) => void) | undefined)[] |
87
88
 
88
89
  declare function checkRange(value: number | number[], range?: [number, number] | [number, number][]): boolean;
89
90
 
90
- declare function crc(data: Uint8Array, start?: number, end?: number): number;
91
-
91
+ declare const CRC_TABLE: Uint16Array<ArrayBuffer>;
92
+ /** CRC-16 (Modbus) over a single contiguous buffer. */
93
+ declare function crcFixed(data: Uint8Array, start: number, end: number): number;
92
94
  /**
93
- * Returns true when `n` is an integer in the unsigned-byte range [0, 255].
94
- *
95
- * Used for byte-level Modbus payload validation (function-code values, raw
96
- * byte arrays in FC17/FC43 responses) — rejects negative, fractional, NaN,
97
- * Infinity, and out-of-range values uniformly.
95
+ * CRC-16 (Modbus) over two contiguous buffer segments.
96
+ * Computes CRC(head[headOff:headOff+headLen]) followed by CRC(tail[tailOff:tailOff+tailLen]).
98
97
  */
99
- declare function isUint8(n: number): boolean;
98
+ declare function crcDual(head: Uint8Array, headOff: number, headLen: number, tail: Uint8Array, tailOff: number, tailLen: number): number;
100
99
 
101
- declare function lrc(data: Uint8Array, start?: number, end?: number): number;
100
+ declare function lrc(data: Uint8Array, start: number, end: number): number;
102
101
 
103
- /** Sentinel: caller needs to feed more bytes before length can be determined. */
104
102
  declare const PREDICT_NEED_MORE = 0;
105
- /** Sentinel: function code is not in the standard tables. */
106
103
  declare const PREDICT_UNKNOWN = -1;
107
- /**
108
- * Predict the total RTU frame length (PDU + 2-byte CRC) given the leading bytes.
109
- *
110
- * Returns a sentinel-encoded number to avoid per-call object allocation on the
111
- * RTU decode hot path:
112
- * - Positive integer (>= 4): total frame length, function code is known.
113
- * - {@link PREDICT_NEED_MORE} (0): function code is known but more bytes are
114
- * required (typically waiting on the byteCount byte).
115
- * - {@link PREDICT_UNKNOWN} (-1): function code is not in the standard tables —
116
- * the framing layer must defer to a registered `CustomFunctionCode` or treat
117
- * this as a framing error.
118
- */
119
- declare function predictRtuFrameLength(buffer: Buffer, start: number, end: number, isResponse: boolean): number;
104
+ declare const REQ_TABLE: Int32Array<ArrayBuffer>;
105
+ declare const RES_TABLE: Int32Array<ArrayBuffer>;
106
+ declare function predictRtuFrameLength(residual: Buffer, data: Buffer, residualLen: number, start: number, end: number, isResponse: boolean): number;
120
107
 
121
108
  /**
122
109
  * Convert a callback-style `(cb: (err?) => void) => void` call into a Promise.
123
110
  */
124
111
  declare function promisifyCb(fn: (cb: (err?: Error | null) => void) => void): Promise<void>;
125
112
 
126
- /** @internal
127
- * Zero-allocation binary min-heap for coalescing per-request timeouts.
113
+ /**
114
+ * Hybrid timer manager: uses native `setTimeout` for low concurrency
115
+ * and switches to a binary min-heap when concurrency exceeds the threshold.
116
+ *
117
+ * Benchmarks (add + clear throughput, Node 24, x64):
118
+ * 1 concurrent: setTimeout ~1.7× faster than heap
119
+ * 2 concurrent: setTimeout ~1.6× faster than heap
120
+ * 5 concurrent: setTimeout ~1.5-1.9× faster than heap
121
+ * 10 concurrent: roughly equal
122
+ * 20 concurrent: heap ~1.3× faster than setTimeout[]
123
+ * 50 concurrent: heap ~1.4-1.7× faster than setTimeout[]
128
124
  *
129
- * Uses two parallel numeric arrays (no object allocation per entry).
130
- * Lazy deletion: callers never remove from the heap; expired entries
131
- * are silently dropped when they surface at the top.
125
+ * The crossover point is around 10 concurrent timers, so the default
126
+ * `concurrentThreshold = 2` keeps the common 1-2 request case on the
127
+ * fast direct path while delegating to the heap for larger batches.
132
128
  */
133
129
  declare class TimerHeap {
134
130
  private _deadlines;
135
131
  private _ids;
132
+ private _seqs;
133
+ private _counter;
136
134
  private _timer;
137
135
  private _onFire;
138
- /** Pre-bound tick handler to avoid creating a new arrow function on every setTimeout. */
139
136
  private _boundTick;
140
- constructor(onFire: (id: number) => void);
141
- /** Number of pending timers in the heap. */
137
+ private _threshold;
138
+ private _mode;
139
+ private _directTimers;
140
+ /**
141
+ * @param onFire Callback invoked with the timer id when it expires.
142
+ * @param concurrentThreshold Maximum number of timers kept as individual
143
+ * native `setTimeout` handles. Once exceeded, all timers migrate to
144
+ * the internal heap and share a single native timer. Default is 2.
145
+ */
146
+ constructor(onFire: (id: number) => void, concurrentThreshold?: number);
142
147
  get size(): number;
143
- /** Schedule an entry. If it becomes the new top, the global timer is re-scheduled (pre-emption). */
144
148
  add(id: number, ms: number): void;
145
- /** Dispose without firing callbacks. */
146
149
  clear(): void;
150
+ private _heapAdd;
147
151
  private _refresh;
148
152
  private _onTick;
149
- /** Pop and return the id with the earliest deadline. Assumes heap is non-empty. */
150
153
  private _pop;
151
154
  }
152
155
 
@@ -157,5 +160,5 @@ declare class TimerHeap {
157
160
  */
158
161
  declare function isWhitelisted(address: string | undefined, whitelist: string[] | undefined): boolean;
159
162
 
160
- export { PREDICT_NEED_MORE, PREDICT_UNKNOWN, TimerHeap, bitsToMs, checkRange, crc, drainCbs, isUint8, isWhitelisted, lrc, predictRtuFrameLength, promisifyCb, resolveRtuTiming };
163
+ export { CRC_TABLE, PREDICT_NEED_MORE, PREDICT_UNKNOWN, REQ_TABLE, RES_TABLE, TimerHeap, bitsToMs, checkRange, crcDual, crcFixed, drainCbs, isWhitelisted, lrc, predictRtuFrameLength, promisifyCb, resolveRtuTiming };
161
164
  export type { ResolvedRtuTiming, RtuProtocolOptions };