icom-wlan-node 0.1.0 → 0.2.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 +157 -16
- package/dist/core/Session.d.ts +9 -0
- package/dist/core/Session.js +34 -5
- package/dist/index.js +1 -1
- package/dist/rig/IcomCiv.js +6 -1
- package/dist/rig/IcomControl.d.ts +108 -7
- package/dist/rig/IcomControl.js +651 -67
- package/dist/transport/UdpClient.js +18 -4
- package/dist/types.d.ts +175 -0
- package/dist/types.js +46 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# icom-wlan-node
|
|
2
2
|
|
|
3
3
|
Icom WLAN (UDP) protocol implementation in Node.js + TypeScript, featuring:
|
|
4
4
|
|
|
@@ -16,7 +16,7 @@ Acknowledgements: Thanks to FT8CN (https://github.com/N0BOY/FT8CN) for sharing p
|
|
|
16
16
|
## Install
|
|
17
17
|
|
|
18
18
|
```
|
|
19
|
-
npm install
|
|
19
|
+
npm install icom-wlan-node
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
Build from source:
|
|
@@ -29,7 +29,7 @@ npm run build
|
|
|
29
29
|
## Quick Start
|
|
30
30
|
|
|
31
31
|
```ts
|
|
32
|
-
import { IcomControl, AUDIO_RATE } from '
|
|
32
|
+
import { IcomControl, AUDIO_RATE } from 'icom-wlan-node';
|
|
33
33
|
|
|
34
34
|
const rig = new IcomControl({
|
|
35
35
|
control: { ip: '192.168.1.50', port: 50001 },
|
|
@@ -106,37 +106,175 @@ await rig.setPtt(false);
|
|
|
106
106
|
- `civFrame(Buffer)` — one complete CI‑V frame (FE FE ... FD)
|
|
107
107
|
- `audio({ pcm16: Buffer })` — audio frames
|
|
108
108
|
- `error(Error)` — UDP errors
|
|
109
|
+
- `connectionLost(ConnectionLostInfo)` — session timeout detected
|
|
110
|
+
- `connectionRestored(ConnectionRestoredInfo)` — reconnected successfully
|
|
111
|
+
- `reconnectAttempting(ReconnectAttemptInfo)` — reconnect attempt started
|
|
112
|
+
- `reconnectFailed(ReconnectFailedInfo)` — reconnect attempt failed
|
|
109
113
|
- Methods
|
|
110
114
|
- `connect()` / `disconnect()` — connects control + CIV + audio sub‑sessions; resolves when all ready
|
|
111
115
|
- `sendCiv(buf: Buffer)` — send a raw CI‑V frame
|
|
112
116
|
- `setPtt(on: boolean)` — key/unkey; also manages TX meter polling and audio tailing
|
|
113
117
|
- `sendAudioFloat32(samples: Float32Array, addLeadingBuffer?: boolean)` / `sendAudioPcm16(samples: Int16Array)`
|
|
118
|
+
- `getConnectionPhase()` — returns current ConnectionPhase (IDLE, CONNECTING, CONNECTED, DISCONNECTING, RECONNECTING)
|
|
119
|
+
- `getConnectionMetrics()` — returns detailed ConnectionMetrics (phase, uptime, session states, etc.)
|
|
120
|
+
- `getConnectionState()` — returns per‑session ConnectionState (control, civ, audio)
|
|
121
|
+
- `isAnySessionDisconnected()` — returns true if any session is disconnected
|
|
122
|
+
- `configureMonitoring(config)` — configure connection monitoring and auto‑reconnect behavior
|
|
123
|
+
|
|
124
|
+
### Connection Management & Auto-Reconnect
|
|
125
|
+
|
|
126
|
+
The library features a robust state machine for connection lifecycle management with automatic reconnection support.
|
|
127
|
+
|
|
128
|
+
#### Connection State Machine
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
ConnectionPhase: IDLE → CONNECTING → CONNECTED → DISCONNECTING
|
|
132
|
+
↓ ↓
|
|
133
|
+
RECONNECTING ←────────────┘
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
#### Basic Usage
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
// Connect (idempotent - safe to call multiple times)
|
|
140
|
+
await rig.connect();
|
|
141
|
+
|
|
142
|
+
// Query connection phase
|
|
143
|
+
const phase = rig.getConnectionPhase(); // 'IDLE' | 'CONNECTING' | 'CONNECTED' | ...
|
|
144
|
+
|
|
145
|
+
// Get detailed metrics
|
|
146
|
+
const metrics = rig.getConnectionMetrics();
|
|
147
|
+
console.log(metrics.phase); // Current phase
|
|
148
|
+
console.log(metrics.uptime); // Milliseconds since connected
|
|
149
|
+
console.log(metrics.sessions); // Per-session states {control, civ, audio}
|
|
150
|
+
|
|
151
|
+
// Disconnect (also idempotent)
|
|
152
|
+
await rig.disconnect();
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
#### Connection Monitoring Events
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
// Connection lost (any session timeout)
|
|
159
|
+
rig.events.on('connectionLost', (info) => {
|
|
160
|
+
console.error(`Lost: ${info.sessionType}, idle: ${info.timeSinceLastData}ms`);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Connection restored after reconnect
|
|
164
|
+
rig.events.on('connectionRestored', (info) => {
|
|
165
|
+
console.log(`Restored after ${info.downtime}ms downtime`);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// Reconnect attempt started
|
|
169
|
+
rig.events.on('reconnectAttempting', (info) => {
|
|
170
|
+
console.log(`Reconnect attempt #${info.attemptNumber}, delay: ${info.delay}ms`);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// Reconnect attempt failed
|
|
174
|
+
rig.events.on('reconnectFailed', (info) => {
|
|
175
|
+
console.error(`Attempt #${info.attemptNumber} failed: ${info.error}`);
|
|
176
|
+
if (!info.willRetry) console.error('Giving up - max retries reached');
|
|
177
|
+
});
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
#### Auto-Reconnect Configuration
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
rig.configureMonitoring({
|
|
184
|
+
timeout: 8000, // Session timeout: 8s (default: 5s)
|
|
185
|
+
checkInterval: 1000, // Check every 1s (default: 1s)
|
|
186
|
+
autoReconnect: true, // Enable auto-reconnect (default: false)
|
|
187
|
+
maxReconnectAttempts: 10, // Max retries (default: undefined = infinite)
|
|
188
|
+
reconnectBaseDelay: 2000, // Base delay: 2s (default: 2s)
|
|
189
|
+
reconnectMaxDelay: 30000 // Max delay: 30s (default: 30s, uses exponential backoff)
|
|
190
|
+
});
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Exponential Backoff**: Delays are `baseDelay × 2^(attempt-1)`, capped at `maxDelay`.
|
|
194
|
+
Example: 2s → 4s → 8s → 16s → 30s (capped) → 30s ...
|
|
195
|
+
|
|
196
|
+
#### Error Handling
|
|
197
|
+
|
|
198
|
+
**Common Errors**:
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
try {
|
|
202
|
+
await rig.connect();
|
|
203
|
+
} catch (err) {
|
|
204
|
+
if (err.message.includes('timeout')) {
|
|
205
|
+
// Connection timeout (no response from radio)
|
|
206
|
+
} else if (err.message.includes('Login failed')) {
|
|
207
|
+
// Authentication error (check userName/password)
|
|
208
|
+
} else if (err.message.includes('Radio reported connected=false')) {
|
|
209
|
+
// Radio rejected connection (may be busy with another client)
|
|
210
|
+
} else if (err.message.includes('Cannot connect while disconnecting')) {
|
|
211
|
+
// Invalid state transition (wait for disconnect to complete)
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Listen for UDP errors
|
|
216
|
+
rig.events.on('error', (err) => {
|
|
217
|
+
console.error('UDP error:', err.message);
|
|
218
|
+
// Network issues, invalid packets, etc.
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**Connection States to Handle**:
|
|
223
|
+
- **CONNECTING**: Wait or show "connecting..." UI
|
|
224
|
+
- **CONNECTED**: Normal operation
|
|
225
|
+
- **RECONNECTING**: Show "reconnecting..." UI, disable TX
|
|
226
|
+
- **DISCONNECTING**: Cleanup in progress
|
|
227
|
+
- **IDLE**: Not connected
|
|
114
228
|
|
|
115
229
|
### High‑Level API
|
|
116
230
|
|
|
117
231
|
The library exposes common CI‑V operations as friendly methods. Addresses are handled internally (`ctrAddr=0xe0`, `rigAddr` discovered via capabilities).
|
|
118
232
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
- `
|
|
233
|
+
#### Rig Control
|
|
234
|
+
|
|
235
|
+
- `setFrequency(hz: number)` — Set operating frequency in Hz
|
|
236
|
+
- `setMode(mode: IcomMode | number, options?: { dataMode?: boolean })` — Set mode (supports string or numeric code)
|
|
237
|
+
- `setPtt(on: boolean)` — Key/unkey transmitter
|
|
238
|
+
|
|
239
|
+
**Supported Modes** (IcomMode string constants):
|
|
240
|
+
- `'LSB'`, `'USB'`, `'AM'`, `'CW'`, `'RTTY'`, `'FM'`, `'WFM'`, `'CW_R'`, `'RTTY_R'`, `'DV'`
|
|
241
|
+
- Or use numeric codes: `0x00` (LSB), `0x01` (USB), `0x02` (AM), etc.
|
|
242
|
+
|
|
243
|
+
#### Rig Query
|
|
244
|
+
|
|
122
245
|
- `readOperatingFrequency(options?: QueryOptions) => Promise<number|null>`
|
|
123
246
|
- `readOperatingMode(options?: QueryOptions) => Promise<{ mode: number; filter?: number; modeName?: string; filterName?: string } | null>`
|
|
124
247
|
- `readTransmitFrequency(options?: QueryOptions) => Promise<number|null>`
|
|
125
248
|
- `readTransceiverState(options?: QueryOptions) => Promise<'TX' | 'RX' | 'UNKNOWN' | null>`
|
|
126
249
|
- `readBandEdges(options?: QueryOptions) => Promise<Buffer|null>`
|
|
250
|
+
|
|
251
|
+
#### Meters & Levels
|
|
252
|
+
|
|
127
253
|
- `readSWR(options?: QueryOptions) => Promise<{ raw: number; swr: number; alert: boolean } | null>`
|
|
128
254
|
- `readALC(options?: QueryOptions) => Promise<{ raw: number; percent: number; alert: boolean } | null>`
|
|
129
255
|
- `getConnectorWLanLevel(options?: QueryOptions) => Promise<{ raw: number; percent: number } | null>`
|
|
130
256
|
- `getLevelMeter(options?: QueryOptions) => Promise<{ raw: number; percent: number } | null>`
|
|
131
|
-
- `setConnectorWLanLevel(level: number)`
|
|
132
|
-
|
|
257
|
+
- `setConnectorWLanLevel(level: number)` — Set WLAN audio level (0-255)
|
|
258
|
+
|
|
259
|
+
#### Connector Settings
|
|
133
260
|
|
|
134
|
-
|
|
261
|
+
- `setConnectorDataMode(mode: ConnectorDataMode | number)` — Set data routing mode (supports string or numeric)
|
|
262
|
+
|
|
263
|
+
**Supported Connector Modes** (ConnectorDataMode string constants):
|
|
264
|
+
- `'MIC'` (0x00), `'ACC'` (0x01), `'USB'` (0x02), `'WLAN'` (0x03)
|
|
265
|
+
|
|
266
|
+
#### Examples
|
|
135
267
|
|
|
136
268
|
```ts
|
|
137
|
-
// Set frequency and mode
|
|
269
|
+
// Set frequency and mode using string constants
|
|
138
270
|
await rig.setFrequency(14074000);
|
|
139
|
-
await rig.setMode(
|
|
271
|
+
await rig.setMode('USB', { dataMode: true }); // USB-D for FT8
|
|
272
|
+
|
|
273
|
+
// Or use numeric codes
|
|
274
|
+
await rig.setMode(0x01, { dataMode: true }); // USB=0x01
|
|
275
|
+
|
|
276
|
+
// Set LSB mode
|
|
277
|
+
await rig.setMode('LSB');
|
|
140
278
|
|
|
141
279
|
// Query current frequency (Hz)
|
|
142
280
|
const hz = await rig.readOperatingFrequency({ timeout: 3000 });
|
|
@@ -156,12 +294,15 @@ await rig.setPtt(false);
|
|
|
156
294
|
const swr = await rig.readSWR({ timeout: 2000 });
|
|
157
295
|
const alc = await rig.readALC({ timeout: 2000 });
|
|
158
296
|
const wlanLevel = await rig.getConnectorWLanLevel({ timeout: 2000 });
|
|
159
|
-
const level = await rig.getLevelMeter({ timeout: 1500 });
|
|
160
|
-
await rig.setConnectorWLanLevel(0x0120);
|
|
161
|
-
await rig.setConnectorDataMode(0x01); // e.g., DATA
|
|
162
297
|
|
|
163
|
-
|
|
164
|
-
|
|
298
|
+
// Set connector to WLAN mode using string constant
|
|
299
|
+
await rig.setConnectorDataMode('WLAN');
|
|
300
|
+
// Or numeric: await rig.setConnectorDataMode(0x03);
|
|
301
|
+
|
|
302
|
+
await rig.setConnectorWLanLevel(120); // Set WLAN audio level
|
|
303
|
+
|
|
304
|
+
if (wlanLevel) {
|
|
305
|
+
console.log(`WLAN Level: ${wlanLevel.percent.toFixed(1)}%`);
|
|
165
306
|
}
|
|
166
307
|
```
|
|
167
308
|
|
package/dist/core/Session.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { UdpClient } from '../transport/UdpClient';
|
|
2
|
+
import { SessionType } from '../types';
|
|
2
3
|
export interface SessionOptions {
|
|
3
4
|
ip: string;
|
|
4
5
|
port: number;
|
|
@@ -19,10 +20,12 @@ export declare class Session {
|
|
|
19
20
|
lastSentTime: number;
|
|
20
21
|
lastReceivedTime: number;
|
|
21
22
|
private address;
|
|
23
|
+
private handlers;
|
|
22
24
|
private txHistory;
|
|
23
25
|
private areYouThereTimer?;
|
|
24
26
|
private pingTimer?;
|
|
25
27
|
private destroyed;
|
|
28
|
+
sessionType?: SessionType;
|
|
26
29
|
constructor(address: SessionOptions, handlers: SessionHandlers);
|
|
27
30
|
open(): void;
|
|
28
31
|
close(): void;
|
|
@@ -40,4 +43,10 @@ export declare class Session {
|
|
|
40
43
|
stopPing(): void;
|
|
41
44
|
stopTimers(): void;
|
|
42
45
|
setRemote(ip: string, port: number): void;
|
|
46
|
+
/**
|
|
47
|
+
* Reset session state to initial values
|
|
48
|
+
* Call this before reconnecting to ensure clean state
|
|
49
|
+
* (especially important after radio restart)
|
|
50
|
+
*/
|
|
51
|
+
resetState(): void;
|
|
43
52
|
}
|
package/dist/core/Session.js
CHANGED
|
@@ -19,21 +19,24 @@ class Session {
|
|
|
19
19
|
this.txHistory = new Map();
|
|
20
20
|
this.destroyed = false;
|
|
21
21
|
this.address = address;
|
|
22
|
+
this.handlers = handlers;
|
|
22
23
|
this.udp.on('data', (rinfo, data) => {
|
|
23
24
|
if (this.destroyed)
|
|
24
25
|
return;
|
|
25
26
|
this.lastReceivedTime = Date.now();
|
|
26
27
|
try {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
(0, debug_1.dbgV)(`RX port=${this.localPort} from ${rinfo.address}:${rinfo.port} len=${data.length} type=${t >= 0 ? '0x' + t.toString(16) : 'n/a'}`);
|
|
28
|
+
const type = data.length >= 6 ? data.readUInt16LE(4) : -1;
|
|
29
|
+
(0, debug_1.dbgV)(`RX port=${this.localPort} from ${rinfo.address}:${rinfo.port} len=${data.length} type=${type >= 0 ? '0x' + type.toString(16) : 'n/a'}`);
|
|
30
30
|
}
|
|
31
31
|
catch { }
|
|
32
32
|
handlers.onData(data);
|
|
33
33
|
});
|
|
34
34
|
this.udp.on('error', handlers.onSendError);
|
|
35
35
|
}
|
|
36
|
-
open() {
|
|
36
|
+
open() {
|
|
37
|
+
this.destroyed = false; // Reset destroyed flag to allow sending data after reconnection
|
|
38
|
+
this.udp.open();
|
|
39
|
+
}
|
|
37
40
|
close() {
|
|
38
41
|
this.stopTimers();
|
|
39
42
|
this.destroyed = true;
|
|
@@ -78,8 +81,9 @@ class Session {
|
|
|
78
81
|
} }
|
|
79
82
|
startAreYouThere() {
|
|
80
83
|
this.stopAreYouThere();
|
|
84
|
+
(0, debug_1.dbg)(`Starting AreYouThere timer for ${this.address.ip}:${this.address.port}`);
|
|
81
85
|
this.areYouThereTimer = setInterval(() => {
|
|
82
|
-
(0, debug_1.
|
|
86
|
+
(0, debug_1.dbg)(`AYT -> ${this.address.ip}:${this.address.port} localId=${this.localId}`);
|
|
83
87
|
this.sendUntracked(IcomPackets_1.ControlPacket.toBytes(IcomPackets_1.Cmd.ARE_YOU_THERE, 0, this.localId, 0));
|
|
84
88
|
}, 500);
|
|
85
89
|
}
|
|
@@ -101,5 +105,30 @@ class Session {
|
|
|
101
105
|
setRemote(ip, port) {
|
|
102
106
|
this.address = { ip, port };
|
|
103
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Reset session state to initial values
|
|
110
|
+
* Call this before reconnecting to ensure clean state
|
|
111
|
+
* (especially important after radio restart)
|
|
112
|
+
*/
|
|
113
|
+
resetState() {
|
|
114
|
+
// Reset destroyed flag to ensure session is usable after state reset
|
|
115
|
+
this.destroyed = false;
|
|
116
|
+
// Generate new IDs
|
|
117
|
+
this.localId = Date.now() >>> 0;
|
|
118
|
+
this.remoteId = 0;
|
|
119
|
+
// Reset sequence numbers
|
|
120
|
+
this.trackedSeq = 1;
|
|
121
|
+
this.pingSeq = 0;
|
|
122
|
+
this.innerSeq = 0x30;
|
|
123
|
+
// Reset tokens
|
|
124
|
+
this.rigToken = 0;
|
|
125
|
+
this.localToken = (Date.now() & 0xffff) >>> 0;
|
|
126
|
+
// Reset timestamps
|
|
127
|
+
this.lastSentTime = Date.now();
|
|
128
|
+
this.lastReceivedTime = Date.now();
|
|
129
|
+
// Clear history
|
|
130
|
+
this.txHistory.clear();
|
|
131
|
+
(0, debug_1.dbgV)(`Session state reset: localId=${this.localId}, localToken=${this.localToken}`);
|
|
132
|
+
}
|
|
104
133
|
}
|
|
105
134
|
exports.Session = Session;
|
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
exports.AUDIO_RATE = exports.IcomRigCommands = exports.intToTwoByteBcd = exports.parseTwoByteBcd = exports.getFilterString = exports.getConnectorModeString = exports.getModeString = exports.getConnectorModeCode = exports.getModeCode = exports.METER_THRESHOLDS = exports.DEFAULT_CONTROLLER_ADDR = exports.CONNECTOR_MODE_MAP = exports.MODE_MAP = exports.IcomControl = void 0;
|
|
18
|
-
// Export types
|
|
18
|
+
// Export types (includes ConnectionPhase, ConnectionMetrics, etc.)
|
|
19
19
|
__exportStar(require("./types"), exports);
|
|
20
20
|
// Export main class
|
|
21
21
|
var IcomControl_1 = require("./rig/IcomControl");
|
package/dist/rig/IcomCiv.js
CHANGED
|
@@ -12,9 +12,14 @@ class IcomCiv {
|
|
|
12
12
|
}
|
|
13
13
|
start() {
|
|
14
14
|
this.stop();
|
|
15
|
-
//
|
|
15
|
+
// CIV session watchdog: Keep-alive mechanism to maintain CIV connection
|
|
16
|
+
// Matches FT8CN's startCivDataTimer() implementation:
|
|
17
|
+
// - Checks every 500ms if CIV session is receiving data
|
|
18
|
+
// - If no data received for >2000ms, sends OpenClose(true) to re-establish connection
|
|
19
|
+
// - This prevents silent disconnection where radio stops responding without error
|
|
16
20
|
this.openTimer = setInterval(() => {
|
|
17
21
|
if (Date.now() - this.sess.lastReceivedTime > 2000) {
|
|
22
|
+
(0, debug_1.dbg)('CIV watchdog: No data for >2s, sending OpenClose to keep alive');
|
|
18
23
|
this.sendOpenClose(true);
|
|
19
24
|
}
|
|
20
25
|
}, 500);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IcomRigOptions, RigEventEmitter, IcomMode, ConnectorDataMode, SetModeOptions, QueryOptions, SwrReading, AlcReading, WlanLevelReading, LevelMeterReading } from '../types';
|
|
1
|
+
import { IcomRigOptions, RigEventEmitter, IcomMode, ConnectorDataMode, SetModeOptions, QueryOptions, SwrReading, AlcReading, WlanLevelReading, LevelMeterReading, ConnectionState, ConnectionMonitorConfig, ConnectionPhase, ConnectionMetrics } from '../types';
|
|
2
2
|
import { IcomCiv } from './IcomCiv';
|
|
3
3
|
import { IcomAudio } from './IcomAudio';
|
|
4
4
|
export declare class IcomControl {
|
|
@@ -14,15 +14,58 @@ export declare class IcomControl {
|
|
|
14
14
|
private tokenTimer?;
|
|
15
15
|
private civAssembleBuf;
|
|
16
16
|
private meterTimer?;
|
|
17
|
-
private
|
|
18
|
-
private
|
|
19
|
-
private
|
|
20
|
-
private
|
|
21
|
-
private
|
|
22
|
-
private resolveAudioReady;
|
|
17
|
+
private connectionSession;
|
|
18
|
+
private nextSessionId;
|
|
19
|
+
private abortHandlers;
|
|
20
|
+
private monitorTimer?;
|
|
21
|
+
private monitorConfig;
|
|
23
22
|
constructor(options: IcomRigOptions);
|
|
24
23
|
get events(): RigEventEmitter;
|
|
24
|
+
/**
|
|
25
|
+
* Transition to a new connection phase with logging
|
|
26
|
+
* @private
|
|
27
|
+
*/
|
|
28
|
+
private transitionTo;
|
|
29
|
+
/**
|
|
30
|
+
* Validate if a state transition is legal
|
|
31
|
+
* @private
|
|
32
|
+
*/
|
|
33
|
+
private canTransitionTo;
|
|
34
|
+
/**
|
|
35
|
+
* Abort an ongoing connection attempt by session ID
|
|
36
|
+
* @private
|
|
37
|
+
*/
|
|
38
|
+
private abortConnectionAttempt;
|
|
39
|
+
/**
|
|
40
|
+
* Connect to the rig
|
|
41
|
+
* Idempotent: multiple calls during CONNECTING phase are safe
|
|
42
|
+
* @throws Error if called during DISCONNECTING phase
|
|
43
|
+
*/
|
|
25
44
|
connect(): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Internal connection implementation
|
|
47
|
+
* Uses local promises to avoid race conditions
|
|
48
|
+
* Uses phased timeout: 30s for overall, 10s for sub-sessions after login
|
|
49
|
+
* @param sessionId - Unique session ID to prevent race conditions
|
|
50
|
+
*/
|
|
51
|
+
private _doConnect;
|
|
52
|
+
/**
|
|
53
|
+
* Create local promises for connection readiness
|
|
54
|
+
* This avoids race conditions with instance variables
|
|
55
|
+
* @param sessionId - Connection session ID for abort handler tracking
|
|
56
|
+
*/
|
|
57
|
+
private createReadyPromises;
|
|
58
|
+
/**
|
|
59
|
+
* Start unified connection monitoring
|
|
60
|
+
* Monitors all three sessions from a single timer to avoid race conditions
|
|
61
|
+
* @private
|
|
62
|
+
*/
|
|
63
|
+
private startUnifiedMonitoring;
|
|
64
|
+
/**
|
|
65
|
+
* Stop unified connection monitoring
|
|
66
|
+
* @private
|
|
67
|
+
*/
|
|
68
|
+
private stopUnifiedMonitoring;
|
|
26
69
|
disconnect(): Promise<void>;
|
|
27
70
|
sendCiv(data: Buffer): void;
|
|
28
71
|
/**
|
|
@@ -152,4 +195,62 @@ export declare class IcomControl {
|
|
|
152
195
|
private stopMeterPolling;
|
|
153
196
|
private onAudioData;
|
|
154
197
|
private sendConnectionRequest;
|
|
198
|
+
/**
|
|
199
|
+
* Configure unified connection monitoring
|
|
200
|
+
* @param config - Monitoring configuration options
|
|
201
|
+
* @example
|
|
202
|
+
* rig.configureMonitoring({ timeout: 10000, checkInterval: 2000, autoReconnect: true });
|
|
203
|
+
*/
|
|
204
|
+
configureMonitoring(config: ConnectionMonitorConfig): void;
|
|
205
|
+
/**
|
|
206
|
+
* Get current connection state for all sessions
|
|
207
|
+
* @returns Object with connection state for each session
|
|
208
|
+
*/
|
|
209
|
+
getConnectionState(): {
|
|
210
|
+
control: ConnectionState;
|
|
211
|
+
civ: ConnectionState;
|
|
212
|
+
audio: ConnectionState;
|
|
213
|
+
};
|
|
214
|
+
/**
|
|
215
|
+
* Check if any session has lost connection
|
|
216
|
+
* @returns true if any session is disconnected
|
|
217
|
+
*/
|
|
218
|
+
isAnySessionDisconnected(): boolean;
|
|
219
|
+
/**
|
|
220
|
+
* Handle connection lost event from a session
|
|
221
|
+
* Simplified strategy: any session loss triggers full reconnect
|
|
222
|
+
* @private
|
|
223
|
+
*/
|
|
224
|
+
private handleConnectionLost;
|
|
225
|
+
/**
|
|
226
|
+
* Schedule a full reconnection (all sessions)
|
|
227
|
+
* Uses simple while loop with exponential backoff
|
|
228
|
+
* @private
|
|
229
|
+
*/
|
|
230
|
+
private scheduleFullReconnect;
|
|
231
|
+
/**
|
|
232
|
+
* Connect with timeout (helper for reconnection)
|
|
233
|
+
* @private
|
|
234
|
+
*/
|
|
235
|
+
private connectWithTimeout;
|
|
236
|
+
/**
|
|
237
|
+
* Sleep helper (returns a Promise)
|
|
238
|
+
* @private
|
|
239
|
+
*/
|
|
240
|
+
private sleep;
|
|
241
|
+
/**
|
|
242
|
+
* Calculate reconnect delay using exponential backoff
|
|
243
|
+
* @private
|
|
244
|
+
*/
|
|
245
|
+
private calculateReconnectDelay;
|
|
246
|
+
/**
|
|
247
|
+
* Get current connection phase
|
|
248
|
+
* @returns Current connection phase (IDLE, CONNECTING, CONNECTED, etc.)
|
|
249
|
+
*/
|
|
250
|
+
getConnectionPhase(): ConnectionPhase;
|
|
251
|
+
/**
|
|
252
|
+
* Get detailed connection metrics for monitoring and diagnostics
|
|
253
|
+
* @returns Connection metrics including phase, uptime, session states
|
|
254
|
+
*/
|
|
255
|
+
getConnectionMetrics(): ConnectionMetrics;
|
|
155
256
|
}
|