icom-wlan-node 0.2.5 → 0.2.6
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 +3 -2
- package/dist/rig/IcomConstants.d.ts +22 -0
- package/dist/rig/IcomConstants.js +23 -0
- package/dist/rig/IcomControl.d.ts +15 -2
- package/dist/rig/IcomControl.js +19 -6
- package/dist/types.d.ts +16 -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
|
@@ -262,7 +262,7 @@ The library exposes common CI‑V operations as friendly methods. Addresses are
|
|
|
262
262
|
- `readSquelchStatus(options?: QueryOptions) => Promise<{ raw: number; isOpen: boolean } | null>` — Squelch gate state (CI-V 0x15/0x01)
|
|
263
263
|
- `readAudioSquelch(options?: QueryOptions) => Promise<{ raw: number; isOpen: boolean } | null>` — Audio squelch state (CI-V 0x15/0x05)
|
|
264
264
|
- `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
|
|
265
|
+
- `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
266
|
|
|
267
267
|
**Transmission Meters** (require PTT on):
|
|
268
268
|
- `readSWR(options?: QueryOptions) => Promise<{ raw: number; swr: number; alert: boolean } | null>` — SWR meter (CI-V 0x15/0x12)
|
|
@@ -330,7 +330,8 @@ if (ovf) {
|
|
|
330
330
|
|
|
331
331
|
const sMeter = await rig.getLevelMeter({ timeout: 2000 });
|
|
332
332
|
if (sMeter) {
|
|
333
|
-
console.log(`S-Meter: ${sMeter.
|
|
333
|
+
console.log(`S-Meter: ${sMeter.formatted} (${sMeter.sUnits.toFixed(1)} S-units, ${sMeter.dBm.toFixed(1)} dBm)`);
|
|
334
|
+
// Example output: "S-Meter: S9+10dB (9.9 S-units, -63.1 dBm)"
|
|
334
335
|
}
|
|
335
336
|
|
|
336
337
|
// Read power supply monitoring
|
|
@@ -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
|
/**
|
|
@@ -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
|
/**
|
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
|
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)
|
|
@@ -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
|
+
}
|