icom-wlan-node 0.2.5 → 0.2.7
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 +30 -2
- package/dist/rig/IcomConstants.d.ts +22 -0
- package/dist/rig/IcomConstants.js +23 -0
- package/dist/rig/IcomControl.d.ts +35 -3
- package/dist/rig/IcomControl.js +60 -6
- package/dist/rig/IcomRigCommands.d.ts +3 -0
- package/dist/rig/IcomRigCommands.js +15 -0
- package/dist/types.d.ts +30 -3
- package/dist/utils/smeter.d.ts +27 -0
- package/dist/utils/smeter.js +138 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -117,6 +117,7 @@ await rig.setPtt(false);
|
|
|
117
117
|
- **Audio TX**: `setPtt(on: boolean)`, `sendAudioFloat32()`, `sendAudioPcm16()`
|
|
118
118
|
- **Rig Control**: `setFrequency()`, `setMode()`, `setConnectorDataMode()`, `setConnectorWLanLevel()`
|
|
119
119
|
- **Rig Query**: `readOperatingFrequency()`, `readOperatingMode()`, `readTransmitFrequency()`, `readTransceiverState()`, `readBandEdges()`
|
|
120
|
+
- **Antenna Tuner**: `readTunerStatus()`, `setTunerEnabled()`, `startManualTune()`
|
|
120
121
|
- **Meters (RX)**: `readSquelchStatus()`, `readAudioSquelch()`, `readOvfStatus()`, `getLevelMeter()`
|
|
121
122
|
- **Meters (TX)**: `readSWR()`, `readALC()`, `readPowerLevel()`, `readCompLevel()`
|
|
122
123
|
- **Power Supply**: `readVoltage()`, `readCurrent()`
|
|
@@ -262,7 +263,7 @@ The library exposes common CI‑V operations as friendly methods. Addresses are
|
|
|
262
263
|
- `readSquelchStatus(options?: QueryOptions) => Promise<{ raw: number; isOpen: boolean } | null>` — Squelch gate state (CI-V 0x15/0x01)
|
|
263
264
|
- `readAudioSquelch(options?: QueryOptions) => Promise<{ raw: number; isOpen: boolean } | null>` — Audio squelch state (CI-V 0x15/0x05)
|
|
264
265
|
- `readOvfStatus(options?: QueryOptions) => Promise<{ raw: number; isOverload: boolean } | null>` — ADC overload detection (CI-V 0x15/0x07)
|
|
265
|
-
- `getLevelMeter(options?: QueryOptions) => Promise<{ raw: number; percent: number } | null>` — S-meter
|
|
266
|
+
- `getLevelMeter(options?: QueryOptions) => Promise<{ raw: number; percent: number; sUnits: number; dbAboveS9?: number; dBm: number; formatted: string } | null>` — S-meter (signal strength) with physical units (CI-V 0x15/0x02)
|
|
266
267
|
|
|
267
268
|
**Transmission Meters** (require PTT on):
|
|
268
269
|
- `readSWR(options?: QueryOptions) => Promise<{ raw: number; swr: number; alert: boolean } | null>` — SWR meter (CI-V 0x15/0x12)
|
|
@@ -330,7 +331,8 @@ if (ovf) {
|
|
|
330
331
|
|
|
331
332
|
const sMeter = await rig.getLevelMeter({ timeout: 2000 });
|
|
332
333
|
if (sMeter) {
|
|
333
|
-
console.log(`S-Meter: ${sMeter.
|
|
334
|
+
console.log(`S-Meter: ${sMeter.formatted} (${sMeter.sUnits.toFixed(1)} S-units, ${sMeter.dBm.toFixed(1)} dBm)`);
|
|
335
|
+
// Example output: "S-Meter: S9+10dB (9.9 S-units, -63.1 dBm)"
|
|
334
336
|
}
|
|
335
337
|
|
|
336
338
|
// Read power supply monitoring
|
|
@@ -420,3 +422,29 @@ ICOM_IP=192.168.31.253 ICOM_PORT=50001 ICOM_USER=icom ICOM_PASS=icomicom npm tes
|
|
|
420
422
|
## License
|
|
421
423
|
|
|
422
424
|
MIT
|
|
425
|
+
#### Antenna Tuner (ATU)
|
|
426
|
+
|
|
427
|
+
- `readTunerStatus(options?: QueryOptions) => Promise<{ raw: number; state: 'OFF'|'ON'|'TUNING' } | null>` — 读取天调状态(CI‑V 0x1A/0x00)
|
|
428
|
+
- `setTunerEnabled(enabled: boolean) => Promise<void>` — 开启/关闭内置天调(CI‑V 0x1A/0x01 00/01)
|
|
429
|
+
- `startManualTune() => Promise<void>` — 触发一次手动调谐(相当于 [TUNE] 键,CI‑V 0x1A/0x02/0x00)
|
|
430
|
+
|
|
431
|
+
示例:
|
|
432
|
+
|
|
433
|
+
```ts
|
|
434
|
+
// 读取天调状态
|
|
435
|
+
const atu = await rig.readTunerStatus({ timeout: 2000 });
|
|
436
|
+
if (atu) console.log('ATU:', atu.state); // OFF / ON / TUNING
|
|
437
|
+
|
|
438
|
+
// 启用内置天调
|
|
439
|
+
await rig.setTunerEnabled(true);
|
|
440
|
+
|
|
441
|
+
// 触发一次手动调谐
|
|
442
|
+
await rig.startManualTune();
|
|
443
|
+
|
|
444
|
+
// 可选:轮询状态直到结束
|
|
445
|
+
let status;
|
|
446
|
+
do {
|
|
447
|
+
await new Promise(r => setTimeout(r, 300));
|
|
448
|
+
status = await rig.readTunerStatus({ timeout: 1000 });
|
|
449
|
+
} while (status && status.state === 'TUNING');
|
|
450
|
+
```
|
|
@@ -135,6 +135,28 @@ export declare const METER_CALIBRATION: {
|
|
|
135
135
|
readonly amps: 4;
|
|
136
136
|
};
|
|
137
137
|
};
|
|
138
|
+
/**
|
|
139
|
+
* S-meter (CI-V 0x15/0x02) calibration points
|
|
140
|
+
* Per-model calibration for signal strength meter
|
|
141
|
+
*/
|
|
142
|
+
readonly SMETER: {
|
|
143
|
+
/**
|
|
144
|
+
* IC-705 S-meter calibration (from official CI-V reference manual)
|
|
145
|
+
* - raw=0 → S0
|
|
146
|
+
* - raw=120 → S9
|
|
147
|
+
* - raw=241 → S9+60dB
|
|
148
|
+
*/
|
|
149
|
+
readonly 'IC-705': {
|
|
150
|
+
/** S0 reference point */
|
|
151
|
+
readonly S0: 0;
|
|
152
|
+
/** S9 reference point */
|
|
153
|
+
readonly S9: 120;
|
|
154
|
+
/** S9+60dB reference point */
|
|
155
|
+
readonly S9_PLUS_60DB: 241;
|
|
156
|
+
/** HF standard: S9 ≈ -73dBm (used for dBm estimation) */
|
|
157
|
+
readonly HF_S9_DBM: -73;
|
|
158
|
+
};
|
|
159
|
+
};
|
|
138
160
|
};
|
|
139
161
|
/**
|
|
140
162
|
* Convert raw power level to percentage
|
|
@@ -147,6 +147,29 @@ exports.METER_CALIBRATION = {
|
|
|
147
147
|
LOW: { raw: 121, amps: 2.0 },
|
|
148
148
|
/** High current reference: 4A (raw=241) */
|
|
149
149
|
HIGH: { raw: 241, amps: 4.0 }
|
|
150
|
+
},
|
|
151
|
+
/**
|
|
152
|
+
* S-meter (CI-V 0x15/0x02) calibration points
|
|
153
|
+
* Per-model calibration for signal strength meter
|
|
154
|
+
*/
|
|
155
|
+
SMETER: {
|
|
156
|
+
/**
|
|
157
|
+
* IC-705 S-meter calibration (from official CI-V reference manual)
|
|
158
|
+
* - raw=0 → S0
|
|
159
|
+
* - raw=120 → S9
|
|
160
|
+
* - raw=241 → S9+60dB
|
|
161
|
+
*/
|
|
162
|
+
'IC-705': {
|
|
163
|
+
/** S0 reference point */
|
|
164
|
+
S0: 0,
|
|
165
|
+
/** S9 reference point */
|
|
166
|
+
S9: 120,
|
|
167
|
+
/** S9+60dB reference point */
|
|
168
|
+
S9_PLUS_60DB: 241,
|
|
169
|
+
/** HF standard: S9 ≈ -73dBm (used for dBm estimation) */
|
|
170
|
+
HF_S9_DBM: -73
|
|
171
|
+
}
|
|
172
|
+
// Future: Add other ICOM models here
|
|
150
173
|
}
|
|
151
174
|
};
|
|
152
175
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IcomRigOptions, RigEventEmitter, IcomMode, ConnectorDataMode, SetModeOptions, QueryOptions, SwrReading, AlcReading, WlanLevelReading, LevelMeterReading, SquelchStatusReading, AudioSquelchReading, OvfStatusReading, PowerLevelReading, CompLevelReading, VoltageReading, CurrentReading, ConnectionState, ConnectionMonitorConfig, ConnectionPhase, ConnectionMetrics, DisconnectReason, DisconnectOptions } from '../types';
|
|
1
|
+
import { IcomRigOptions, RigEventEmitter, IcomMode, ConnectorDataMode, SetModeOptions, QueryOptions, SwrReading, AlcReading, WlanLevelReading, LevelMeterReading, SquelchStatusReading, AudioSquelchReading, OvfStatusReading, PowerLevelReading, CompLevelReading, VoltageReading, CurrentReading, ConnectionState, ConnectionMonitorConfig, ConnectionPhase, ConnectionMetrics, DisconnectReason, DisconnectOptions, TunerStatusReading } from '../types';
|
|
2
2
|
import { IcomCiv } from './IcomCiv';
|
|
3
3
|
import { IcomAudio } from './IcomAudio';
|
|
4
4
|
export declare class IcomControl {
|
|
@@ -160,8 +160,21 @@ export declare class IcomControl {
|
|
|
160
160
|
*/
|
|
161
161
|
getConnectorWLanLevel(options?: QueryOptions): Promise<WlanLevelReading | null>;
|
|
162
162
|
/**
|
|
163
|
-
* Read
|
|
164
|
-
*
|
|
163
|
+
* Read S-meter (signal strength) level (CI-V 0x15/0x02)
|
|
164
|
+
* Returns complete reading with S-units, dB, and dBm conversion
|
|
165
|
+
*
|
|
166
|
+
* @param options - Query options (timeout)
|
|
167
|
+
* @returns S-meter reading with physical units, or null if timeout
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```typescript
|
|
171
|
+
* const reading = await rig.getLevelMeter();
|
|
172
|
+
* if (reading) {
|
|
173
|
+
* console.log(reading.formatted); // "S9+10dB"
|
|
174
|
+
* console.log(reading.sUnits); // 9.99
|
|
175
|
+
* console.log(reading.dBm); // -63.08
|
|
176
|
+
* }
|
|
177
|
+
* ```
|
|
165
178
|
*/
|
|
166
179
|
getLevelMeter(options?: QueryOptions): Promise<LevelMeterReading | null>;
|
|
167
180
|
/**
|
|
@@ -177,6 +190,25 @@ export declare class IcomControl {
|
|
|
177
190
|
* await rig.setConnectorDataMode('WLAN');
|
|
178
191
|
*/
|
|
179
192
|
setConnectorDataMode(mode: ConnectorDataMode | number): Promise<void>;
|
|
193
|
+
/**
|
|
194
|
+
* ==============================
|
|
195
|
+
* Antenna Tuner (ATU) Operations
|
|
196
|
+
* ==============================
|
|
197
|
+
*/
|
|
198
|
+
/**
|
|
199
|
+
* Read antenna tuner status (CI-V 0x1A/0x00)
|
|
200
|
+
* 00=OFF, 01=ON, 02=TUNING
|
|
201
|
+
*/
|
|
202
|
+
readTunerStatus(options?: QueryOptions): Promise<TunerStatusReading | null>;
|
|
203
|
+
/**
|
|
204
|
+
* Enable or disable internal antenna tuner (CI-V 0x1A/0x01)
|
|
205
|
+
* @param enabled true to enable, false to disable
|
|
206
|
+
*/
|
|
207
|
+
setTunerEnabled(enabled: boolean): Promise<void>;
|
|
208
|
+
/**
|
|
209
|
+
* Start a manual tuning cycle (same as [TUNE] key) (CI-V 0x1A/0x02/0x00)
|
|
210
|
+
*/
|
|
211
|
+
startManualTune(): Promise<void>;
|
|
180
212
|
/**
|
|
181
213
|
* Read squelch status (noise/signal gate state)
|
|
182
214
|
* @param options - Query options (timeout in ms, default 3000)
|
package/dist/rig/IcomControl.js
CHANGED
|
@@ -45,6 +45,7 @@ const IcomRigCommands_1 = require("./IcomRigCommands");
|
|
|
45
45
|
const IcomConstants_1 = require("./IcomConstants");
|
|
46
46
|
const bcd_1 = require("../utils/bcd");
|
|
47
47
|
const errors_1 = require("../utils/errors");
|
|
48
|
+
const smeter_1 = require("../utils/smeter");
|
|
48
49
|
class IcomControl {
|
|
49
50
|
constructor(options) {
|
|
50
51
|
this.ev = new events_1.EventEmitter();
|
|
@@ -756,8 +757,21 @@ class IcomControl {
|
|
|
756
757
|
};
|
|
757
758
|
}
|
|
758
759
|
/**
|
|
759
|
-
* Read
|
|
760
|
-
*
|
|
760
|
+
* Read S-meter (signal strength) level (CI-V 0x15/0x02)
|
|
761
|
+
* Returns complete reading with S-units, dB, and dBm conversion
|
|
762
|
+
*
|
|
763
|
+
* @param options - Query options (timeout)
|
|
764
|
+
* @returns S-meter reading with physical units, or null if timeout
|
|
765
|
+
*
|
|
766
|
+
* @example
|
|
767
|
+
* ```typescript
|
|
768
|
+
* const reading = await rig.getLevelMeter();
|
|
769
|
+
* if (reading) {
|
|
770
|
+
* console.log(reading.formatted); // "S9+10dB"
|
|
771
|
+
* console.log(reading.sUnits); // 9.99
|
|
772
|
+
* console.log(reading.dBm); // -63.08
|
|
773
|
+
* }
|
|
774
|
+
* ```
|
|
761
775
|
*/
|
|
762
776
|
async getLevelMeter(options) {
|
|
763
777
|
const timeoutMs = options?.timeout ?? 3000;
|
|
@@ -771,10 +785,9 @@ class IcomControl {
|
|
|
771
785
|
if (data.length === 0)
|
|
772
786
|
return null;
|
|
773
787
|
const raw = data[data.length - 1] & 0xff; // use low byte as 0-255 level
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
};
|
|
788
|
+
// Convert raw value to S-meter reading with physical units
|
|
789
|
+
// Uses IC-705 calibration by default (can be extended to support other models)
|
|
790
|
+
return (0, smeter_1.rawToSMeter)(raw, 'IC-705');
|
|
778
791
|
}
|
|
779
792
|
/**
|
|
780
793
|
* Set WLAN connector audio level
|
|
@@ -798,6 +811,47 @@ class IcomControl {
|
|
|
798
811
|
const modeCode = typeof mode === 'string' ? (0, IcomConstants_1.getConnectorModeCode)(mode) : mode;
|
|
799
812
|
this.sendCiv(IcomRigCommands_1.IcomRigCommands.setConnectorDataMode(ctrAddr, rigAddr, modeCode));
|
|
800
813
|
}
|
|
814
|
+
/**
|
|
815
|
+
* ==============================
|
|
816
|
+
* Antenna Tuner (ATU) Operations
|
|
817
|
+
* ==============================
|
|
818
|
+
*/
|
|
819
|
+
/**
|
|
820
|
+
* Read antenna tuner status (CI-V 0x1A/0x00)
|
|
821
|
+
* 00=OFF, 01=ON, 02=TUNING
|
|
822
|
+
*/
|
|
823
|
+
async readTunerStatus(options) {
|
|
824
|
+
const timeoutMs = options?.timeout ?? 3000;
|
|
825
|
+
const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
|
|
826
|
+
const rigAddr = this.civ.civAddress & 0xff;
|
|
827
|
+
const req = IcomRigCommands_1.IcomRigCommands.getTunerStatus(ctrAddr, rigAddr);
|
|
828
|
+
const resp = await this.waitForCivFrame((frame) => IcomControl.matchCommandFrame(frame, 0x1a, [0x00], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
|
|
829
|
+
if (!resp)
|
|
830
|
+
return null;
|
|
831
|
+
// Expect FE FE [ctr] [rig] 0x1A 0x00 [status] FD
|
|
832
|
+
const raw = resp.length > 6 ? (resp[6] & 0xff) : undefined;
|
|
833
|
+
if (raw === undefined)
|
|
834
|
+
return null;
|
|
835
|
+
const state = raw === 0x00 ? 'OFF' : raw === 0x01 ? 'ON' : raw === 0x02 ? 'TUNING' : 'OFF';
|
|
836
|
+
return { raw, state };
|
|
837
|
+
}
|
|
838
|
+
/**
|
|
839
|
+
* Enable or disable internal antenna tuner (CI-V 0x1A/0x01)
|
|
840
|
+
* @param enabled true to enable, false to disable
|
|
841
|
+
*/
|
|
842
|
+
async setTunerEnabled(enabled) {
|
|
843
|
+
const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
|
|
844
|
+
const rigAddr = this.civ.civAddress & 0xff;
|
|
845
|
+
this.sendCiv(IcomRigCommands_1.IcomRigCommands.setTunerEnabled(ctrAddr, rigAddr, enabled));
|
|
846
|
+
}
|
|
847
|
+
/**
|
|
848
|
+
* Start a manual tuning cycle (same as [TUNE] key) (CI-V 0x1A/0x02/0x00)
|
|
849
|
+
*/
|
|
850
|
+
async startManualTune() {
|
|
851
|
+
const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
|
|
852
|
+
const rigAddr = this.civ.civAddress & 0xff;
|
|
853
|
+
this.sendCiv(IcomRigCommands_1.IcomRigCommands.startManualTune(ctrAddr, rigAddr));
|
|
854
|
+
}
|
|
801
855
|
/**
|
|
802
856
|
* Read squelch status (noise/signal gate state)
|
|
803
857
|
* @param options - Query options (timeout in ms, default 3000)
|
|
@@ -21,4 +21,7 @@ export declare const IcomRigCommands: {
|
|
|
21
21
|
getCompLevel(ctrAddr: number, rigAddr: number): Buffer;
|
|
22
22
|
getVoltage(ctrAddr: number, rigAddr: number): Buffer;
|
|
23
23
|
getCurrent(ctrAddr: number, rigAddr: number): Buffer;
|
|
24
|
+
getTunerStatus(ctrAddr: number, rigAddr: number): Buffer;
|
|
25
|
+
setTunerEnabled(ctrAddr: number, rigAddr: number, on: boolean): Buffer;
|
|
26
|
+
startManualTune(ctrAddr: number, rigAddr: number): Buffer;
|
|
24
27
|
};
|
|
@@ -97,5 +97,20 @@ exports.IcomRigCommands = {
|
|
|
97
97
|
getCurrent(ctrAddr, rigAddr) {
|
|
98
98
|
// FE FE [rig] [ctr] 0x15 0x16 FD
|
|
99
99
|
return Buffer.from([0xfe, 0xfe, rigAddr & 0xff, ctrAddr & 0xff, 0x15, 0x16, 0xfd]);
|
|
100
|
+
},
|
|
101
|
+
// =====================
|
|
102
|
+
// Antenna Tuner (ATU)
|
|
103
|
+
// =====================
|
|
104
|
+
getTunerStatus(ctrAddr, rigAddr) {
|
|
105
|
+
// FE FE [rig] [ctr] 0x1A 0x00 FD
|
|
106
|
+
return Buffer.from([0xfe, 0xfe, rigAddr & 0xff, ctrAddr & 0xff, 0x1a, 0x00, 0xfd]);
|
|
107
|
+
},
|
|
108
|
+
setTunerEnabled(ctrAddr, rigAddr, on) {
|
|
109
|
+
// FE FE [rig] [ctr] 0x1A 0x01 [00|01] FD
|
|
110
|
+
return Buffer.from([0xfe, 0xfe, rigAddr & 0xff, ctrAddr & 0xff, 0x1a, 0x01, on ? 0x01 : 0x00, 0xfd]);
|
|
111
|
+
},
|
|
112
|
+
startManualTune(ctrAddr, rigAddr) {
|
|
113
|
+
// FE FE [rig] [ctr] 0x1A 0x02 0x00 FD
|
|
114
|
+
return Buffer.from([0xfe, 0xfe, rigAddr & 0xff, ctrAddr & 0xff, 0x1a, 0x02, 0x00, 0xfd]);
|
|
100
115
|
}
|
|
101
116
|
};
|
package/dist/types.d.ts
CHANGED
|
@@ -153,14 +153,27 @@ export interface WlanLevelReading {
|
|
|
153
153
|
percent: number;
|
|
154
154
|
}
|
|
155
155
|
/**
|
|
156
|
-
*
|
|
157
|
-
* For CI-V 0x15/0x02
|
|
156
|
+
* S-meter (signal strength) level reading
|
|
157
|
+
* For CI-V 0x15/0x02 command
|
|
158
|
+
*
|
|
159
|
+
* Calibration (IC-705):
|
|
160
|
+
* - raw=0 → S0
|
|
161
|
+
* - raw=120 → S9
|
|
162
|
+
* - raw=241 → S9+60dB
|
|
158
163
|
*/
|
|
159
164
|
export interface LevelMeterReading {
|
|
160
|
-
/** Raw 0-255 value */
|
|
165
|
+
/** Raw 0-255 BCD value */
|
|
161
166
|
raw: number;
|
|
162
167
|
/** Percentage (0-100%) */
|
|
163
168
|
percent: number;
|
|
169
|
+
/** S-unit value (0-9+), supports decimal (e.g., 4.5 = S4.5) */
|
|
170
|
+
sUnits: number;
|
|
171
|
+
/** dB above S9 (only when >S9, e.g., 20 means S9+20dB) */
|
|
172
|
+
dbAboveS9?: number;
|
|
173
|
+
/** Estimated absolute power in dBm (based on HF standard S9 ≈ -73dBm) */
|
|
174
|
+
dBm: number;
|
|
175
|
+
/** Human-readable formatted string (e.g., "S4", "S9+20dB") */
|
|
176
|
+
formatted: string;
|
|
164
177
|
}
|
|
165
178
|
/**
|
|
166
179
|
* Squelch status reading (CI-V 0x15/0x01)
|
|
@@ -241,6 +254,20 @@ export interface CurrentReading {
|
|
|
241
254
|
/** Current in amperes */
|
|
242
255
|
amps: number;
|
|
243
256
|
}
|
|
257
|
+
/**
|
|
258
|
+
* Antenna tuner state (IC-705 CI-V 0x1A/0x00)
|
|
259
|
+
* 00=OFF, 01=ON, 02=TUNING
|
|
260
|
+
*/
|
|
261
|
+
export type TunerState = 'OFF' | 'ON' | 'TUNING';
|
|
262
|
+
/**
|
|
263
|
+
* Antenna tuner status reading
|
|
264
|
+
*/
|
|
265
|
+
export interface TunerStatusReading {
|
|
266
|
+
/** Raw status code (0x00, 0x01, 0x02) */
|
|
267
|
+
raw: number;
|
|
268
|
+
/** Parsed state name */
|
|
269
|
+
state: TunerState;
|
|
270
|
+
}
|
|
244
271
|
/**
|
|
245
272
|
* Connection state enumeration
|
|
246
273
|
* Represents the current state of a UDP session
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S-meter (signal strength meter) conversion utilities
|
|
3
|
+
* Converts raw BCD values from CI-V 0x15/0x02 to physical S-units and dBm
|
|
4
|
+
*/
|
|
5
|
+
import { LevelMeterReading } from '../types';
|
|
6
|
+
/**
|
|
7
|
+
* Convert raw S-meter BCD value to complete reading with S-units, dB, and dBm
|
|
8
|
+
*
|
|
9
|
+
* @param raw - Raw BCD value (0-255) from CI-V 0x15/0x02
|
|
10
|
+
* @param model - Radio model name (default: 'IC-705')
|
|
11
|
+
* @returns Complete LevelMeterReading with all calculated fields
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const reading = rawToSMeter(140, 'IC-705');
|
|
16
|
+
* console.log(reading);
|
|
17
|
+
* // {
|
|
18
|
+
* // raw: 140,
|
|
19
|
+
* // percent: 54.9,
|
|
20
|
+
* // sUnits: 9.99,
|
|
21
|
+
* // dbAboveS9: 9.92,
|
|
22
|
+
* // dBm: -63.08,
|
|
23
|
+
* // formatted: "S9+10dB"
|
|
24
|
+
* // }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function rawToSMeter(raw: number, model?: string): LevelMeterReading;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* S-meter (signal strength meter) conversion utilities
|
|
4
|
+
* Converts raw BCD values from CI-V 0x15/0x02 to physical S-units and dBm
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.rawToSMeter = rawToSMeter;
|
|
8
|
+
const IcomConstants_1 = require("../rig/IcomConstants");
|
|
9
|
+
/**
|
|
10
|
+
* Get S-meter calibration constants for a specific radio model
|
|
11
|
+
* @param model - Radio model name (e.g., 'IC-705')
|
|
12
|
+
* @returns Calibration constants, defaults to IC-705 if model not found
|
|
13
|
+
*/
|
|
14
|
+
function getCalibration(model = 'IC-705') {
|
|
15
|
+
const cal = IcomConstants_1.METER_CALIBRATION.SMETER[model];
|
|
16
|
+
if (!cal) {
|
|
17
|
+
// Default to IC-705 if model not found
|
|
18
|
+
console.warn(`S-meter calibration for model '${model}' not found, using IC-705 defaults`);
|
|
19
|
+
return IcomConstants_1.METER_CALIBRATION.SMETER['IC-705'];
|
|
20
|
+
}
|
|
21
|
+
return cal;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Convert raw S-meter value to S-units (0-9+)
|
|
25
|
+
* Uses linear interpolation based on calibration points
|
|
26
|
+
*
|
|
27
|
+
* @param raw - Raw BCD value (0-255)
|
|
28
|
+
* @param cal - Calibration constants
|
|
29
|
+
* @returns S-unit value (0-9+, supports decimals)
|
|
30
|
+
*/
|
|
31
|
+
function rawToSUnits(raw, cal) {
|
|
32
|
+
// Clamp to valid range
|
|
33
|
+
if (raw <= cal.S0)
|
|
34
|
+
return 0;
|
|
35
|
+
if (raw >= cal.S9_PLUS_60DB) {
|
|
36
|
+
// Maximum S9+60dB = S9 + 60dB/6dB per S-unit = S9 + 10 S-units = S19
|
|
37
|
+
return 9 + 60 / 6;
|
|
38
|
+
}
|
|
39
|
+
// Linear interpolation
|
|
40
|
+
if (raw <= cal.S9) {
|
|
41
|
+
// S0 to S9: linear from 0 to 9
|
|
42
|
+
return (raw - cal.S0) * 9.0 / (cal.S9 - cal.S0);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
// Above S9: each S-unit = 6dB
|
|
46
|
+
const dbAboveS9 = (raw - cal.S9) * 60.0 / (cal.S9_PLUS_60DB - cal.S9);
|
|
47
|
+
return 9 + dbAboveS9 / 6.0;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Convert raw S-meter value to dB above S9
|
|
52
|
+
* Only meaningful when raw > S9 threshold
|
|
53
|
+
*
|
|
54
|
+
* @param raw - Raw BCD value (0-255)
|
|
55
|
+
* @param cal - Calibration constants
|
|
56
|
+
* @returns dB above S9, or undefined if below S9
|
|
57
|
+
*/
|
|
58
|
+
function rawToDbAboveS9(raw, cal) {
|
|
59
|
+
if (raw <= cal.S9) {
|
|
60
|
+
return undefined; // Below S9, no "dB above S9" concept
|
|
61
|
+
}
|
|
62
|
+
// Linear interpolation: S9 to S9+60dB
|
|
63
|
+
const dbAboveS9 = (raw - cal.S9) * 60.0 / (cal.S9_PLUS_60DB - cal.S9);
|
|
64
|
+
return Math.max(0, dbAboveS9); // Clamp to non-negative
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Estimate absolute power in dBm
|
|
68
|
+
* Based on HF standard: S9 ≈ -73dBm
|
|
69
|
+
* NOTE: This is an estimation and may vary by band, filter, and device settings
|
|
70
|
+
*
|
|
71
|
+
* @param sUnits - S-unit value
|
|
72
|
+
* @param cal - Calibration constants
|
|
73
|
+
* @returns Estimated power in dBm
|
|
74
|
+
*/
|
|
75
|
+
function estimateDpm(sUnits, cal) {
|
|
76
|
+
// Each S-unit below S9 = 6dB
|
|
77
|
+
// Each dB above S9 = 1dB
|
|
78
|
+
const dbRelativeToS9 = (sUnits - 9) * 6.0;
|
|
79
|
+
return cal.HF_S9_DBM + dbRelativeToS9;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Format S-meter reading as human-readable string
|
|
83
|
+
* Examples: "S0", "S4", "S9", "S9+10dB", "S9+60dB"
|
|
84
|
+
*
|
|
85
|
+
* @param sUnits - S-unit value
|
|
86
|
+
* @param dbAboveS9 - dB above S9 (if any)
|
|
87
|
+
* @returns Formatted string
|
|
88
|
+
*/
|
|
89
|
+
function formatSMeter(sUnits, dbAboveS9) {
|
|
90
|
+
if (dbAboveS9 !== undefined && dbAboveS9 > 0) {
|
|
91
|
+
// Above S9: show as "S9+XdB"
|
|
92
|
+
const roundedDb = Math.round(dbAboveS9);
|
|
93
|
+
return `S9+${roundedDb}dB`;
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
// S0-S9: show as "SX"
|
|
97
|
+
const roundedS = Math.floor(sUnits);
|
|
98
|
+
return `S${roundedS}`;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Convert raw S-meter BCD value to complete reading with S-units, dB, and dBm
|
|
103
|
+
*
|
|
104
|
+
* @param raw - Raw BCD value (0-255) from CI-V 0x15/0x02
|
|
105
|
+
* @param model - Radio model name (default: 'IC-705')
|
|
106
|
+
* @returns Complete LevelMeterReading with all calculated fields
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```typescript
|
|
110
|
+
* const reading = rawToSMeter(140, 'IC-705');
|
|
111
|
+
* console.log(reading);
|
|
112
|
+
* // {
|
|
113
|
+
* // raw: 140,
|
|
114
|
+
* // percent: 54.9,
|
|
115
|
+
* // sUnits: 9.99,
|
|
116
|
+
* // dbAboveS9: 9.92,
|
|
117
|
+
* // dBm: -63.08,
|
|
118
|
+
* // formatted: "S9+10dB"
|
|
119
|
+
* // }
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
function rawToSMeter(raw, model = 'IC-705') {
|
|
123
|
+
const cal = getCalibration(model);
|
|
124
|
+
// Calculate all fields
|
|
125
|
+
const sUnits = rawToSUnits(raw, cal);
|
|
126
|
+
const dbAboveS9 = rawToDbAboveS9(raw, cal);
|
|
127
|
+
const dBm = estimateDpm(sUnits, cal);
|
|
128
|
+
const formatted = formatSMeter(sUnits, dbAboveS9);
|
|
129
|
+
const percent = (raw / 255) * 100;
|
|
130
|
+
return {
|
|
131
|
+
raw,
|
|
132
|
+
percent: Math.round(percent * 10) / 10, // Round to 1 decimal place
|
|
133
|
+
sUnits: Math.round(sUnits * 100) / 100, // Round to 2 decimal places
|
|
134
|
+
dbAboveS9: dbAboveS9 !== undefined ? Math.round(dbAboveS9 * 100) / 100 : undefined,
|
|
135
|
+
dBm: Math.round(dBm * 100) / 100, // Round to 2 decimal places
|
|
136
|
+
formatted
|
|
137
|
+
};
|
|
138
|
+
}
|