icom-wlan-node 0.5.1 → 0.6.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 CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Icom WLAN (UDP) protocol implementation in Node.js + TypeScript, featuring:
4
4
 
5
+ CI-V profile support is Hamlib-aligned for modern ICOM radios: WLAN UDP packets carry standard CI-V frames, with model-specific profiles for IC-705, IC-905, IC-7300, IC-9700, IC-7610, and IC-7760.
6
+
5
7
  - Control channel handshake (AreYouThere/AreYouReady), login (0x80/0x60), token confirm/renew (0x40)
6
8
  - CI‑V over UDP encapsulation (open/close keep‑alive + CIV frame transport)
7
9
  - Scope/spectrum data capture over CI‑V `0x27`, with automatic segment assembly into friendly frame events
@@ -35,7 +37,8 @@ import { IcomControl, AUDIO_RATE, DisconnectReason } from 'icom-wlan-node';
35
37
  const rig = new IcomControl({
36
38
  control: { ip: '192.168.1.50', port: 50001 },
37
39
  userName: 'user',
38
- password: 'pass'
40
+ password: 'pass',
41
+ model: 'auto' // or force a profile, e.g. 'IC-705'
39
42
  });
40
43
 
41
44
  rig.events.on('login', (res) => {
@@ -48,7 +51,7 @@ rig.events.on('status', (s) => {
48
51
  });
49
52
 
50
53
  rig.events.on('capabilities', (c) => {
51
- console.log('CIV address:', c.civAddress, 'audio:', c.audioName);
54
+ console.log('CIV address:', c.civAddress, 'audio:', c.audioName, 'profile:', c.profileName);
52
55
  });
53
56
 
54
57
  rig.events.on('civ', (bytes) => {
@@ -87,6 +90,42 @@ rig.events.on('error', (err) => console.error('UDP error', err));
87
90
  rig.sendCiv(Buffer.from([0xfe,0xfe,0xa4,0xe0,0x03,0xfd]));
88
91
  ```
89
92
 
93
+ ### Main Rig Control Usage
94
+
95
+ Modern ICOM LAN/WLAN radios still transport standard serial CI‑V frames inside the UDP CIV payload. `icom-wlan-node` selects a model profile automatically from the radio name or CI‑V address, or you can force one with `model`.
96
+
97
+ ```ts
98
+ const rig = new IcomControl({
99
+ control: { ip: '192.168.1.50', port: 50001 },
100
+ userName: 'icom',
101
+ password: 'icomicom',
102
+ model: 'auto' // 'IC-705', 'IC-905', 'IC-7300', 'IC-9700', 'IC-7610', 'IC-7760'
103
+ });
104
+
105
+ await rig.connect();
106
+
107
+ // Frequency and mode are profile-aware:
108
+ // modern profiles use CI-V 0x25/0x26, legacy fallback uses 0x05/0x06.
109
+ await rig.setFrequency(14074000);
110
+ await rig.setMode('USB', { dataMode: true, filter: 1 }); // USB-D, filter 1
111
+
112
+ const freqHz = await rig.readOperatingFrequency();
113
+ const mode = await rig.readOperatingMode();
114
+ const tx = await rig.readPtt();
115
+ console.log({ freqHz, mode, state: tx ? 'TX' : 'RX' });
116
+
117
+ // Tuner uses Hamlib-aligned CI-V 0x1C/0x01.
118
+ const tuner = await rig.readTunerStatus();
119
+ await rig.setTunerEnabled(true);
120
+
121
+ // Meters use active-profile calibration tables.
122
+ const swr = await rig.readSWR();
123
+ const power = await rig.readPowerLevel();
124
+ console.log({ tuner, swr, watts: power?.watts, powerPercent: power?.percent });
125
+ ```
126
+
127
+ Profile-specific behavior includes IC-905 6-byte frequency BCD above 5.85 GHz, model-specific scope fixed-edge ranges, and calibrated SWR/ALC/RF power/COMP/voltage/current meters. Private connector commands such as WLAN level or connector data mode are only enabled when the active profile declares the vendor extension; unsupported writes throw `UnsupportedCommandError`.
128
+
90
129
  ### PTT and Audio TX
91
130
 
92
131
  ```ts
@@ -136,7 +175,7 @@ await rig.disableScope();
136
175
 
137
176
  ## API Overview
138
177
 
139
- - `new IcomControl(options)`
178
+ - `new IcomControl(options)` — `options.model` may be `'auto'` or a supported model profile such as `'IC-705'`, `'IC-905'`, `'IC-7300'`, `'IC-9700'`, `'IC-7610'`, or `'IC-7760'`
140
179
  - `options.control`: `{ ip, port }` radio control UDP endpoint
141
180
  - `options.userName`, `options.password`
142
181
  - Events (`rig.events.on(...)`)
@@ -160,12 +199,12 @@ await rig.disableScope();
160
199
  - **Scope / Spectrum**: `scope`, `enableScope()`, `disableScope()`, `waitForScopeFrame()`
161
200
  - **Audio TX**: `setPtt(on: boolean)`, `sendAudioFloat32()`, `sendAudioPcm16()`
162
201
  - **Rig Control**: `setFrequency()`, `setMode()`, `setConnectorDataMode()`, `setConnectorWLanLevel()`
163
- - **Rig Query**: `readOperatingFrequency()`, `readOperatingMode()`, `readTransmitFrequency()`, `readTransceiverState()`, `readBandEdges()`
202
+ - **Rig Query**: `readOperatingFrequency()`, `readOperatingMode()`, `readTransmitFrequency()`, `readPtt()`, `readTransceiverState()`, `readBandEdges()`
164
203
  - **Antenna Tuner**: `readTunerStatus()`, `setTunerEnabled()`, `startManualTune()`
165
204
  - **Meters (RX)**: `readSquelchStatus()`, `readAudioSquelch()`, `readOvfStatus()`, `getLevelMeter()`
166
205
  - **Meters (TX)**: `readSWR()`, `readALC()`, `readPowerLevel()`, `readCompLevel()`
167
206
  - **Power Supply**: `readVoltage()`, `readCurrent()`
168
- - **Audio Config**: `getConnectorWLanLevel()`
207
+ - **Audio Config**: `getUsbAfLevel()`, `setUsbAfLevel()`, `getConnectorWLanLevel()`
169
208
  - **Connection Monitoring**: `getConnectionPhase()`, `getConnectionMetrics()`, `getConnectionState()`, `isAnySessionDisconnected()`, `configureMonitoring()`
170
209
 
171
210
  ### Connection Management & Auto-Reconnect
@@ -285,8 +324,8 @@ The library exposes common CI‑V operations as friendly methods. Addresses are
285
324
 
286
325
  #### Rig Control
287
326
 
288
- - `setFrequency(hz: number)` — Set operating frequency in Hz
289
- - `setMode(mode: IcomMode | number, options?: { dataMode?: boolean })` — Set mode (supports string or numeric code)
327
+ - `setFrequency(hz: number)` — Set operating frequency in Hz; modern profiles use targetable CI-V `0x25`, and IC-905 uses 6-byte BCD above 5.85 GHz
328
+ - `setMode(mode: IcomMode | number, options?: { dataMode?: boolean; filter?: 1|2|3 })` — Set mode; modern profiles use CI-V `0x26` with VFO, data-mode and filter
290
329
  - `setPtt(on: boolean)` — Key/unkey transmitter
291
330
 
292
331
  **Supported Modes** (IcomMode string constants):
@@ -296,8 +335,9 @@ The library exposes common CI‑V operations as friendly methods. Addresses are
296
335
  #### Rig Query
297
336
 
298
337
  - `readOperatingFrequency(options?: QueryOptions) => Promise<number|null>`
299
- - `readOperatingMode(options?: QueryOptions) => Promise<{ mode: number; filter?: number; modeName?: string; filterName?: string } | null>`
338
+ - `readOperatingMode(options?: QueryOptions) => Promise<{ mode: number; filter?: number; modeName?: string; filterName?: string; dataMode?: boolean } | null>`
300
339
  - `readTransmitFrequency(options?: QueryOptions) => Promise<number|null>`
340
+ - `readPtt(options?: QueryOptions) => Promise<boolean|null>`
301
341
  - `readTransceiverState(options?: QueryOptions) => Promise<'TX' | 'RX' | 'UNKNOWN' | null>`
302
342
  - `readBandEdges(options?: QueryOptions) => Promise<Buffer|null>`
303
343
 
@@ -309,7 +349,7 @@ The library exposes common CI‑V operations as friendly methods. Addresses are
309
349
  - `readScopeMode(options?: QueryOptions & { receiver?: 0 | 1 }) => Promise<IcomScopeModeInfo | null>` — Read current scope mode using CI‑V `0x27 0x14`
310
350
  - `setScopeMode(mode: IcomScopeMode | 0 | 1 | 2 | 3, options?: { receiver?: 0 | 1 }) => Promise<void>` — Set current scope mode
311
351
  - `readScopeSpan(options?: QueryOptions & { receiver?: 0 | 1 }) => Promise<{ receiver: 0 | 1; spanHz: number } | null>` — Read current scope span
312
- - `setScopeSpan(spanHz: number, options?: { receiver?: 0 | 1 }) => Promise<void>` — Set scope span using CI‑V `0x27 0x15`
352
+ - `setScopeSpan(spanHz: number, options?: { receiver?: 0 | 1 }) => Promise<void>` — Set public scope span using CI‑V `0x27 0x15`; the wire value is `spanHz / 2` per Hamlib
313
353
  - `readScopeEdge(options?: QueryOptions & { receiver?: 0 | 1 }) => Promise<IcomScopeEdgeInfo | null>` — Read active fixed-edge slot using CI‑V `0x27 0x16`
314
354
  - `setScopeEdge(edgeSlot: number, options?: { receiver?: 0 | 1 }) => Promise<void>` — Select active fixed-edge slot
315
355
  - `readScopeFixedEdge(rangeId: number, edgeSlot: number, options?: QueryOptions) => Promise<IcomScopeFixedEdgeInfo | null>` — Read fixed-edge frequencies using CI‑V `0x27 0x1E`
@@ -340,17 +380,17 @@ interface IcomScopeFrame {
340
380
 
341
381
  Current implementation notes:
342
382
 
343
- - Currently implements basic on/off controls, `0x27 0x15` span read/write, and `0x27 00 00` scope data capture
383
+ - Implements basic on/off controls, `0x27 0x15` span read/write, fixed-edge selection/ranges, and `0x27 00 00` scope data capture
344
384
  - The parsing layer is decoupled from the UDP session layer and only depends on complete CI‑V frames
345
- - Frequency fields are currently parsed with `freqLen=5` by default
385
+ - Frequency and fixed-edge ranges are profile-aware; unsupported model-specific variants should be added in `src/rig/IcomProfiles.ts`
346
386
  - LAN aggregate waterfall payload splitting is not implemented yet; standard segment input is supported
347
387
  - The `scope` logic is designed to be reusable for future serial CI‑V or Hamlib CI‑V integration
348
388
 
349
389
  #### Antenna Tuner (ATU)
350
390
 
351
- - `readTunerStatus(options?: QueryOptions) => Promise<{ raw: number; state: 'OFF'|'ON'|'TUNING' } | null>` — Read tuner status (CIV 0x1A/0x00)
352
- - `setTunerEnabled(enabled: boolean) => Promise<void>` — Enable/disable internal tuner (CI‑V 0x1A/0x01)
353
- - `startManualTune() => Promise<void>` — Trigger one manual tune cycle (CI‑V 0x1A/0x02/0x00)
391
+ - `readTunerStatus(options?: QueryOptions) => Promise<{ raw: number; state: 'OFF'|'ON'|'TUNING' } | null>` — Read tuner status (Hamlib-aligned CI-V `0x1C 0x01`)
392
+ - `setTunerEnabled(enabled: boolean) => Promise<void>` — Enable/disable internal tuner (Hamlib-aligned CI‑V `0x1C 0x01 0x00/0x01`)
393
+ - `startManualTune() => Promise<void>` — Trigger one manual tune cycle (Hamlib-aligned CI‑V `0x1C 0x01 0x02`)
354
394
 
355
395
  #### Meters & Levels
356
396
 
@@ -363,20 +403,20 @@ Current implementation notes:
363
403
  **Transmission Meters** (require PTT on):
364
404
  - `readSWR(options?: QueryOptions) => Promise<{ raw: number; swr: number; alert: boolean } | null>` — SWR meter (CI-V 0x15/0x12)
365
405
  - `readALC(options?: QueryOptions) => Promise<{ raw: number; percent: number; alert: boolean } | null>` — ALC meter (CI-V 0x15/0x13)
366
- - `readPowerLevel(options?: QueryOptions) => Promise<{ raw: number; percent: number } | null>` — Output power level (CI-V 0x15/0x11)
367
- - `readCompLevel(options?: QueryOptions) => Promise<{ raw: number; percent: number } | null>` — Voice compression level (CI-V 0x15/0x14)
406
+ - `readPowerLevel(options?: QueryOptions) => Promise<{ raw: number; percent: number; watts?: number } | null>` — Output power level (CI-V 0x15/0x11)
407
+ - `readCompLevel(options?: QueryOptions) => Promise<{ raw: number; percent: number; db?: number } | null>` — Voice compression level (CI-V 0x15/0x14)
368
408
 
369
409
  **Power Supply Monitoring**:
370
410
  - `readVoltage(options?: QueryOptions) => Promise<{ raw: number; volts: number } | null>` — Supply voltage (CI-V 0x15/0x15)
371
411
  - `readCurrent(options?: QueryOptions) => Promise<{ raw: number; amps: number } | null>` — Supply current draw (CI-V 0x15/0x16)
372
412
 
373
413
  **Audio Configuration**:
374
- - `getConnectorWLanLevel(options?: QueryOptions) => Promise<{ raw: number; percent: number } | null>` — Get WLAN audio level (CI-V 0x1A/0x05/0x01/0x17)
375
- - `setConnectorWLanLevel(level: number)` — Set WLAN audio level (0-255)
414
+ - `getUsbAfLevel(options?: QueryOptions) => Promise<{ raw: number; percent: number } | null>` / `setUsbAfLevel(level: number)` Hamlib-aligned USB AF level when the active profile declares it
415
+ - `getConnectorWLanLevel(options?: QueryOptions) => Promise<{ raw: number; percent: number } | null>` / `setConnectorWLanLevel(level: number)` — Private `icom-wlan-node` WLAN level extension; returns `null` or throws `UnsupportedCommandError` when the active profile does not declare it
376
416
 
377
417
  #### Connector Settings
378
418
 
379
- - `setConnectorDataMode(mode: ConnectorDataMode | number)` — Set data routing mode (supports string or numeric)
419
+ - `setConnectorDataMode(mode: ConnectorDataMode | number)` — Private connector routing extension; supported only on profiles that declare the vendor command
380
420
 
381
421
  **Supported Connector Modes** (ConnectorDataMode string constants):
382
422
  - `'MIC'` (0x00), `'ACC'` (0x01), `'USB'` (0x02), `'WLAN'` (0x03)
@@ -457,17 +497,17 @@ if (alc) {
457
497
 
458
498
  const power = await rig.readPowerLevel({ timeout: 2000 });
459
499
  if (power) {
460
- console.log(`Power: ${power.percent.toFixed(1)}%`);
500
+ console.log(`Power: ${power.percent.toFixed(1)}%${power.watts != null ? ` (${power.watts.toFixed(1)} W)` : ''}`);
461
501
  }
462
502
 
463
503
  const comp = await rig.readCompLevel({ timeout: 2000 });
464
504
  if (comp) {
465
- console.log(`COMP: ${comp.percent.toFixed(1)}%`);
505
+ console.log(`COMP: ${comp.percent.toFixed(1)}%${comp.db != null ? ` (${comp.db.toFixed(1)} dB)` : ''}`);
466
506
  }
467
507
 
468
508
  await rig.setPtt(false);
469
509
 
470
- // Configure WLAN connector
510
+ // Configure WLAN connector (private extension; profile-gated)
471
511
  const wlanLevel = await rig.getConnectorWLanLevel({ timeout: 2000 });
472
512
  if (wlanLevel) {
473
513
  console.log(`WLAN Level: ${wlanLevel.percent.toFixed(1)}%`);
package/dist/index.d.ts CHANGED
@@ -5,6 +5,9 @@ export { IcomScopeCommands } from './scope/IcomScopeCommands';
5
5
  export { MODE_MAP, CONNECTOR_MODE_MAP, DEFAULT_CONTROLLER_ADDR, METER_THRESHOLDS, METER_CALIBRATION, getModeCode, getConnectorModeCode, getModeString, getConnectorModeString, getFilterString, rawToPowerPercent, rawToVoltage, rawToCurrent } from './rig/IcomConstants';
6
6
  export { parseTwoByteBcd, intToTwoByteBcd } from './utils/bcd';
7
7
  export { IcomRigCommands } from './rig/IcomRigCommands';
8
+ export { CIV } from './rig/IcomCivSpec';
9
+ export { buildCivFrame, encodeFrequencyBcdLE, decodeFrequencyBcdLE, encodeBcdBE, decodeBcdBE } from './rig/IcomCivFrame';
10
+ export { ICOM_PROFILES, resolveIcomProfile, getProfileByModel, interpolateCalibration } from './rig/IcomProfiles';
8
11
  export { AUDIO_RATE } from './rig/IcomAudio';
9
12
  export { setupGlobalErrorHandlers, setupBasicErrorProtection, GlobalErrorHandlerOptions } from './utils/errorHandling';
10
- export { ConnectionAbortedError, getDisconnectMessage } from './utils/errors';
13
+ export { ConnectionAbortedError, UnsupportedCommandError, getDisconnectMessage } from './utils/errors';
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.getDisconnectMessage = exports.ConnectionAbortedError = exports.setupBasicErrorProtection = exports.setupGlobalErrorHandlers = exports.AUDIO_RATE = exports.IcomRigCommands = exports.intToTwoByteBcd = exports.parseTwoByteBcd = exports.rawToCurrent = exports.rawToVoltage = exports.rawToPowerPercent = exports.getFilterString = exports.getConnectorModeString = exports.getModeString = exports.getConnectorModeCode = exports.getModeCode = exports.METER_CALIBRATION = exports.METER_THRESHOLDS = exports.DEFAULT_CONTROLLER_ADDR = exports.CONNECTOR_MODE_MAP = exports.MODE_MAP = exports.IcomScopeCommands = exports.IcomScopeService = exports.IcomControl = void 0;
17
+ exports.getDisconnectMessage = exports.UnsupportedCommandError = exports.ConnectionAbortedError = exports.setupBasicErrorProtection = exports.setupGlobalErrorHandlers = exports.AUDIO_RATE = exports.interpolateCalibration = exports.getProfileByModel = exports.resolveIcomProfile = exports.ICOM_PROFILES = exports.decodeBcdBE = exports.encodeBcdBE = exports.decodeFrequencyBcdLE = exports.encodeFrequencyBcdLE = exports.buildCivFrame = exports.CIV = exports.IcomRigCommands = exports.intToTwoByteBcd = exports.parseTwoByteBcd = exports.rawToCurrent = exports.rawToVoltage = exports.rawToPowerPercent = exports.getFilterString = exports.getConnectorModeString = exports.getModeString = exports.getConnectorModeCode = exports.getModeCode = exports.METER_CALIBRATION = exports.METER_THRESHOLDS = exports.DEFAULT_CONTROLLER_ADDR = exports.CONNECTOR_MODE_MAP = exports.MODE_MAP = exports.IcomScopeCommands = exports.IcomScopeService = exports.IcomControl = void 0;
18
18
  // Export types (includes ConnectionPhase, ConnectionMetrics, etc.)
19
19
  __exportStar(require("./types"), exports);
20
20
  // Export main class
@@ -46,6 +46,19 @@ Object.defineProperty(exports, "intToTwoByteBcd", { enumerable: true, get: funct
46
46
  // Export low-level utilities (for advanced users)
47
47
  var IcomRigCommands_1 = require("./rig/IcomRigCommands");
48
48
  Object.defineProperty(exports, "IcomRigCommands", { enumerable: true, get: function () { return IcomRigCommands_1.IcomRigCommands; } });
49
+ var IcomCivSpec_1 = require("./rig/IcomCivSpec");
50
+ Object.defineProperty(exports, "CIV", { enumerable: true, get: function () { return IcomCivSpec_1.CIV; } });
51
+ var IcomCivFrame_1 = require("./rig/IcomCivFrame");
52
+ Object.defineProperty(exports, "buildCivFrame", { enumerable: true, get: function () { return IcomCivFrame_1.buildCivFrame; } });
53
+ Object.defineProperty(exports, "encodeFrequencyBcdLE", { enumerable: true, get: function () { return IcomCivFrame_1.encodeFrequencyBcdLE; } });
54
+ Object.defineProperty(exports, "decodeFrequencyBcdLE", { enumerable: true, get: function () { return IcomCivFrame_1.decodeFrequencyBcdLE; } });
55
+ Object.defineProperty(exports, "encodeBcdBE", { enumerable: true, get: function () { return IcomCivFrame_1.encodeBcdBE; } });
56
+ Object.defineProperty(exports, "decodeBcdBE", { enumerable: true, get: function () { return IcomCivFrame_1.decodeBcdBE; } });
57
+ var IcomProfiles_1 = require("./rig/IcomProfiles");
58
+ Object.defineProperty(exports, "ICOM_PROFILES", { enumerable: true, get: function () { return IcomProfiles_1.ICOM_PROFILES; } });
59
+ Object.defineProperty(exports, "resolveIcomProfile", { enumerable: true, get: function () { return IcomProfiles_1.resolveIcomProfile; } });
60
+ Object.defineProperty(exports, "getProfileByModel", { enumerable: true, get: function () { return IcomProfiles_1.getProfileByModel; } });
61
+ Object.defineProperty(exports, "interpolateCalibration", { enumerable: true, get: function () { return IcomProfiles_1.interpolateCalibration; } });
49
62
  var IcomAudio_1 = require("./rig/IcomAudio");
50
63
  Object.defineProperty(exports, "AUDIO_RATE", { enumerable: true, get: function () { return IcomAudio_1.AUDIO_RATE; } });
51
64
  // Export error handling utilities (optional, for robustness)
@@ -55,4 +68,5 @@ Object.defineProperty(exports, "setupBasicErrorProtection", { enumerable: true,
55
68
  // Export disconnect error utilities
56
69
  var errors_1 = require("./utils/errors");
57
70
  Object.defineProperty(exports, "ConnectionAbortedError", { enumerable: true, get: function () { return errors_1.ConnectionAbortedError; } });
71
+ Object.defineProperty(exports, "UnsupportedCommandError", { enumerable: true, get: function () { return errors_1.UnsupportedCommandError; } });
58
72
  Object.defineProperty(exports, "getDisconnectMessage", { enumerable: true, get: function () { return errors_1.getDisconnectMessage; } });
@@ -0,0 +1,13 @@
1
+ export interface CivFrameBuildOptions {
2
+ rigAddr: number;
3
+ ctrlAddr: number;
4
+ cmd: number;
5
+ subcmd?: number | number[];
6
+ payload?: Buffer | number[];
7
+ }
8
+ export declare function buildCivFrame(options: CivFrameBuildOptions): Buffer;
9
+ export declare function encodeFrequencyBcdLE(freqHz: number, byteLength?: number): Buffer;
10
+ export declare function decodeFrequencyBcdLE(bytes: Buffer | Uint8Array): number;
11
+ export declare function encodeBcdBE(value: number, byteLength: number): Buffer;
12
+ export declare function decodeBcdBE(bytes: Buffer | Uint8Array): number;
13
+ export declare function getCivPayload(frame: Buffer): Buffer | null;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildCivFrame = buildCivFrame;
4
+ exports.encodeFrequencyBcdLE = encodeFrequencyBcdLE;
5
+ exports.decodeFrequencyBcdLE = decodeFrequencyBcdLE;
6
+ exports.encodeBcdBE = encodeBcdBE;
7
+ exports.decodeBcdBE = decodeBcdBE;
8
+ exports.getCivPayload = getCivPayload;
9
+ const IcomCivSpec_1 = require("./IcomCivSpec");
10
+ function buildCivFrame(options) {
11
+ const subcmd = options.subcmd === undefined
12
+ ? []
13
+ : Array.isArray(options.subcmd)
14
+ ? options.subcmd
15
+ : [options.subcmd];
16
+ const payload = options.payload ? Array.from(options.payload) : [];
17
+ return Buffer.from([
18
+ IcomCivSpec_1.CIV.PR,
19
+ IcomCivSpec_1.CIV.PR,
20
+ options.rigAddr & 0xff,
21
+ options.ctrlAddr & 0xff,
22
+ options.cmd & 0xff,
23
+ ...subcmd.map((v) => v & 0xff),
24
+ ...payload.map((v) => v & 0xff),
25
+ IcomCivSpec_1.CIV.FI,
26
+ ]);
27
+ }
28
+ function encodeFrequencyBcdLE(freqHz, byteLength = 5) {
29
+ const out = Buffer.alloc(byteLength);
30
+ let remaining = Math.max(0, Math.round(freqHz));
31
+ for (let i = 0; i < byteLength; i++) {
32
+ const twoDigits = remaining % 100;
33
+ out[i] = ((((twoDigits / 10) | 0) & 0x0f) << 4) | (twoDigits % 10);
34
+ remaining = Math.floor(remaining / 100);
35
+ }
36
+ return out;
37
+ }
38
+ function decodeFrequencyBcdLE(bytes) {
39
+ let hz = 0;
40
+ let multiplier = 1;
41
+ for (const byte of bytes) {
42
+ hz += (byte & 0x0f) * multiplier;
43
+ multiplier *= 10;
44
+ hz += ((byte >> 4) & 0x0f) * multiplier;
45
+ multiplier *= 10;
46
+ }
47
+ return hz;
48
+ }
49
+ function encodeBcdBE(value, byteLength) {
50
+ const out = Buffer.alloc(byteLength);
51
+ let remaining = Math.max(0, Math.floor(value));
52
+ for (let i = byteLength - 1; i >= 0; i--) {
53
+ const twoDigits = remaining % 100;
54
+ out[i] = ((((twoDigits / 10) | 0) & 0x0f) << 4) | (twoDigits % 10);
55
+ remaining = Math.floor(remaining / 100);
56
+ }
57
+ return out;
58
+ }
59
+ function decodeBcdBE(bytes) {
60
+ let value = 0;
61
+ for (const byte of bytes) {
62
+ value = value * 100 + (((byte >> 4) & 0x0f) * 10) + (byte & 0x0f);
63
+ }
64
+ return value;
65
+ }
66
+ function getCivPayload(frame) {
67
+ if (frame.length < 6)
68
+ return null;
69
+ if (frame[0] !== IcomCivSpec_1.CIV.PR || frame[1] !== IcomCivSpec_1.CIV.PR || frame[frame.length - 1] !== IcomCivSpec_1.CIV.FI)
70
+ return null;
71
+ return frame.subarray(4, frame.length - 1);
72
+ }
@@ -0,0 +1,54 @@
1
+ /** Hamlib-aligned CI-V command and subcommand constants. */
2
+ export declare const CIV: {
3
+ readonly PR: 254;
4
+ readonly FI: 253;
5
+ readonly ACK: 251;
6
+ readonly NAK: 250;
7
+ readonly CTRLID: 224;
8
+ readonly C_RD_BAND: 2;
9
+ readonly C_RD_FREQ: 3;
10
+ readonly C_RD_MODE: 4;
11
+ readonly C_SET_FREQ: 5;
12
+ readonly C_SET_MODE: 6;
13
+ readonly C_CTL_LVL: 20;
14
+ readonly C_RD_SQSM: 21;
15
+ readonly C_CTL_FUNC: 22;
16
+ readonly C_CTL_MEM: 26;
17
+ readonly C_CTL_PTT: 28;
18
+ readonly C_SEND_SEL_FREQ: 37;
19
+ readonly C_SEND_SEL_MODE: 38;
20
+ readonly C_CTL_SCP: 39;
21
+ readonly S_PTT: 0;
22
+ readonly S_ANT_TUN: 1;
23
+ readonly S_RD_TX_FREQ: 3;
24
+ readonly S_MEM_PARM: 5;
25
+ readonly S_MEM_DATA_MODE: 6;
26
+ readonly S_LVL_AF: 1;
27
+ readonly S_LVL_RF: 2;
28
+ readonly S_LVL_SQL: 3;
29
+ readonly S_LVL_NR: 6;
30
+ readonly S_LVL_RFPOWER: 10;
31
+ readonly S_LVL_MICGAIN: 11;
32
+ readonly S_LVL_COMP: 14;
33
+ readonly S_LVL_BKINDL: 15;
34
+ readonly S_LVL_NB: 18;
35
+ readonly S_LVL_DIGI: 19;
36
+ readonly S_SQL: 1;
37
+ readonly S_SML: 2;
38
+ readonly S_CSQL: 5;
39
+ readonly S_OVF: 7;
40
+ readonly S_RFML: 17;
41
+ readonly S_SWR: 18;
42
+ readonly S_ALC: 19;
43
+ readonly S_CMP: 20;
44
+ readonly S_VD: 21;
45
+ readonly S_ID: 22;
46
+ readonly S_SCP_DAT: 0;
47
+ readonly S_SCP_STS: 16;
48
+ readonly S_SCP_DOP: 17;
49
+ readonly S_SCP_MOD: 20;
50
+ readonly S_SCP_SPN: 21;
51
+ readonly S_SCP_EDG: 22;
52
+ readonly S_SCP_FEF: 30;
53
+ };
54
+ export declare const ICOM_MODE_FILTER_DEFAULT: 1;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ICOM_MODE_FILTER_DEFAULT = exports.CIV = void 0;
4
+ /** Hamlib-aligned CI-V command and subcommand constants. */
5
+ exports.CIV = {
6
+ PR: 0xfe,
7
+ FI: 0xfd,
8
+ ACK: 0xfb,
9
+ NAK: 0xfa,
10
+ CTRLID: 0xe0,
11
+ C_RD_BAND: 0x02,
12
+ C_RD_FREQ: 0x03,
13
+ C_RD_MODE: 0x04,
14
+ C_SET_FREQ: 0x05,
15
+ C_SET_MODE: 0x06,
16
+ C_CTL_LVL: 0x14,
17
+ C_RD_SQSM: 0x15,
18
+ C_CTL_FUNC: 0x16,
19
+ C_CTL_MEM: 0x1a,
20
+ C_CTL_PTT: 0x1c,
21
+ C_SEND_SEL_FREQ: 0x25,
22
+ C_SEND_SEL_MODE: 0x26,
23
+ C_CTL_SCP: 0x27,
24
+ S_PTT: 0x00,
25
+ S_ANT_TUN: 0x01,
26
+ S_RD_TX_FREQ: 0x03,
27
+ S_MEM_PARM: 0x05,
28
+ S_MEM_DATA_MODE: 0x06,
29
+ S_LVL_AF: 0x01,
30
+ S_LVL_RF: 0x02,
31
+ S_LVL_SQL: 0x03,
32
+ S_LVL_NR: 0x06,
33
+ S_LVL_RFPOWER: 0x0a,
34
+ S_LVL_MICGAIN: 0x0b,
35
+ S_LVL_COMP: 0x0e,
36
+ S_LVL_BKINDL: 0x0f,
37
+ S_LVL_NB: 0x12,
38
+ S_LVL_DIGI: 0x13,
39
+ S_SQL: 0x01,
40
+ S_SML: 0x02,
41
+ S_CSQL: 0x05,
42
+ S_OVF: 0x07,
43
+ S_RFML: 0x11,
44
+ S_SWR: 0x12,
45
+ S_ALC: 0x13,
46
+ S_CMP: 0x14,
47
+ S_VD: 0x15,
48
+ S_ID: 0x16,
49
+ S_SCP_DAT: 0x00,
50
+ S_SCP_STS: 0x10,
51
+ S_SCP_DOP: 0x11,
52
+ S_SCP_MOD: 0x14,
53
+ S_SCP_SPN: 0x15,
54
+ S_SCP_EDG: 0x16,
55
+ S_SCP_FEF: 0x1e,
56
+ };
57
+ exports.ICOM_MODE_FILTER_DEFAULT = 1;
@@ -2,6 +2,7 @@ import { IcomRigOptions, RigEventEmitter, IcomMode, ConnectorDataMode, SetModeOp
2
2
  import { IcomCiv } from './IcomCiv';
3
3
  import { IcomAudio } from './IcomAudio';
4
4
  import { IcomScopeService } from '../scope/IcomScopeService';
5
+ import { IcomProfile } from './IcomProfiles';
5
6
  export declare class IcomControl {
6
7
  private ev;
7
8
  private sess;
@@ -16,6 +17,8 @@ export declare class IcomControl {
16
17
  private tokenTimer?;
17
18
  private civAssembleBuf;
18
19
  private meterTimer?;
20
+ private activeProfile;
21
+ private lastFilter;
19
22
  private connectionSession;
20
23
  private nextSessionId;
21
24
  private abortHandlers;
@@ -23,6 +26,9 @@ export declare class IcomControl {
23
26
  private monitorConfig;
24
27
  constructor(options: IcomRigOptions);
25
28
  get events(): RigEventEmitter;
29
+ get profile(): IcomProfile;
30
+ private resolveActiveProfile;
31
+ private getProfileModelId;
26
32
  /**
27
33
  * Transition to a new connection phase with logging
28
34
  * @private
@@ -187,15 +193,14 @@ export declare class IcomControl {
187
193
  filter?: number;
188
194
  modeName?: string;
189
195
  filterName?: string;
196
+ dataMode?: boolean;
190
197
  } | null>;
191
198
  /**
192
199
  * Read current transmit frequency (when TX)
193
200
  */
194
201
  readTransmitFrequency(options?: QueryOptions): Promise<number | null>;
195
- /**
196
- * Read transceiver state (TX/RX) via 0x1A 0x00 0x48
197
- * Note: Java comments mark this as not recommended; use with caution.
198
- */
202
+ readPtt(options?: QueryOptions): Promise<boolean | null>;
203
+ /** Read transceiver state (TX/RX) using standard Hamlib-aligned PTT status. */
199
204
  readTransceiverState(options?: QueryOptions): Promise<'TX' | 'RX' | 'UNKNOWN' | null>;
200
205
  /**
201
206
  * Read band edge data (0x02). Format may vary by rig; returns raw data bytes after command.
@@ -257,6 +262,8 @@ export declare class IcomControl {
257
262
  * @param level - Audio level (0-255)
258
263
  */
259
264
  setConnectorWLanLevel(level: number): Promise<void>;
265
+ getUsbAfLevel(options?: QueryOptions): Promise<WlanLevelReading | null>;
266
+ setUsbAfLevel(level: number): Promise<void>;
260
267
  /**
261
268
  * Set connector data routing mode
262
269
  * @param mode - Data routing mode (MIC, ACC, USB, WLAN)
@@ -271,17 +278,17 @@ export declare class IcomControl {
271
278
  * ==============================
272
279
  */
273
280
  /**
274
- * Read antenna tuner status (CI-V 0x1A/0x00)
281
+ * Read antenna tuner status (CI-V 0x1C/0x01)
275
282
  * 00=OFF, 01=ON, 02=TUNING
276
283
  */
277
284
  readTunerStatus(options?: QueryOptions): Promise<TunerStatusReading | null>;
278
285
  /**
279
- * Enable or disable internal antenna tuner (CI-V 0x1A/0x01)
286
+ * Enable or disable internal antenna tuner (CI-V 0x1C/0x01)
280
287
  * @param enabled true to enable, false to disable
281
288
  */
282
289
  setTunerEnabled(enabled: boolean): Promise<void>;
283
290
  /**
284
- * Start a manual tuning cycle (same as [TUNE] key) (CI-V 0x1A/0x02/0x00)
291
+ * Start a manual tuning cycle (same as [TUNE] key) (CI-V 0x1C/0x01/0x02)
285
292
  */
286
293
  startManualTune(): Promise<void>;
287
294
  /** Get AF (audio output) gain. Returns 0.0–1.0, or null on timeout. */
@@ -300,6 +307,10 @@ export declare class IcomControl {
300
307
  getMicGain(options?: QueryOptions): Promise<LevelReading | null>;
301
308
  /** Set microphone gain. Value 0.0–1.0. */
302
309
  setMicGain(value: number): void;
310
+ /** Get break-in delay. Returns 0.0–1.0, or null on timeout. */
311
+ getBreakInDelay(options?: QueryOptions): Promise<LevelReading | null>;
312
+ /** Set break-in delay. Value 0.0–1.0. */
313
+ setBreakInDelay(value: number): void;
303
314
  /** Get noise blanker level. 0.0 = off, >0.0 = on with strength. */
304
315
  getNBLevel(options?: QueryOptions): Promise<LevelReading | null>;
305
316
  /** Set noise blanker level. Value 0.0 (off) – 1.0. */
@@ -393,9 +404,11 @@ export declare class IcomControl {
393
404
  * @returns Parsed BCD integer value, or null if invalid
394
405
  */
395
406
  private static extractMeterData;
407
+ private static extractTrailingBcd;
396
408
  private static matchCommand;
397
409
  private static matchCommandFrame;
398
410
  private waitForCiv;
411
+ static parseFrequencyReply(frame: Buffer, payloadOffsetAfterCommand: number, byteLength?: number): number | null;
399
412
  static parseIcomFreqFromReply(frame: Buffer): number | null;
400
413
  sendAudioFloat32(samples: Float32Array, addLeadingBuffer?: boolean): void;
401
414
  sendAudioPcm16(samples: Int16Array): void;