hamlib 0.3.2 → 0.3.3

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/index.d.ts CHANGED
@@ -622,7 +622,7 @@ declare class HamLib extends EventEmitter {
622
622
  * @param levelType Level type ('AF', 'RF', 'SQL', 'RFPOWER', etc.)
623
623
  * @param value Level value (0.0-1.0 typically)
624
624
  */
625
- setLevel(levelType: LevelType, value: number): Promise<number>;
625
+ setLevel(levelType: LevelType, value: number, vfo?: string): Promise<number>;
626
626
 
627
627
  /**
628
628
  * Get radio level
package/lib/index.js CHANGED
@@ -33,6 +33,29 @@ class HamLib extends EventEmitter {
33
33
  super();
34
34
  this._nativeInstance = new nativeModule.HamLib(model, port);
35
35
  this._managedSpectrumRunning = false;
36
+ this._lastSpectrumLine = null;
37
+ }
38
+
39
+ _recordSpectrumLine(line) {
40
+ if (!line || typeof line !== 'object') {
41
+ return line;
42
+ }
43
+ this._lastSpectrumLine = line;
44
+ return line;
45
+ }
46
+
47
+ _getLastSpectrumDisplayStateFromLine() {
48
+ const line = this._lastSpectrumLine;
49
+ if (!line || typeof line !== 'object') {
50
+ return null;
51
+ }
52
+
53
+ return {
54
+ modeId: Number.isFinite(line.mode) ? line.mode : null,
55
+ spanHz: Number.isFinite(line.spanHz) ? line.spanHz : null,
56
+ edgeLowHz: Number.isFinite(line.lowEdgeFreq) ? line.lowEdgeFreq : null,
57
+ edgeHighHz: Number.isFinite(line.highEdgeFreq) ? line.highEdgeFreq : null,
58
+ };
36
59
  }
37
60
 
38
61
  /**
@@ -322,7 +345,10 @@ class HamLib extends EventEmitter {
322
345
  * @param {string} levelType - Level type ('AF', 'RF', 'SQL', 'RFPOWER', etc.)
323
346
  * @param {number} value - Level value (0.0-1.0 typically)
324
347
  */
325
- async setLevel(levelType, value) {
348
+ async setLevel(levelType, value, vfo) {
349
+ if (vfo) {
350
+ return this._nativeInstance.setLevel(levelType, value, vfo);
351
+ }
326
352
  return this._nativeInstance.setLevel(levelType, value);
327
353
  }
328
354
 
@@ -1254,8 +1280,12 @@ class HamLib extends EventEmitter {
1254
1280
 
1255
1281
  await applyLevel('SPECTRUM_MODE', await resolveModeId(config.mode));
1256
1282
  await applyLevel('SPECTRUM_SPAN', config.spanHz);
1257
- await applyLevel('SPECTRUM_EDGE_LOW', config.edgeLowHz);
1258
- await applyLevel('SPECTRUM_EDGE_HIGH', config.edgeHighHz);
1283
+ if (config.edgeLowHz !== undefined || config.edgeHighHz !== undefined) {
1284
+ await this.setSpectrumFixedEdges({
1285
+ lowHz: config.edgeLowHz,
1286
+ highHz: config.edgeHighHz,
1287
+ });
1288
+ }
1259
1289
  await applyLevel('SPECTRUM_SPEED', config.speed);
1260
1290
  await applyLevel('SPECTRUM_REF', config.referenceLevel);
1261
1291
  await applyLevel('SPECTRUM_AVG', config.averageMode);
@@ -1287,9 +1317,15 @@ class HamLib extends EventEmitter {
1287
1317
  }
1288
1318
 
1289
1319
  async getSpectrumFixedEdges() {
1320
+ const lineState = this._getLastSpectrumDisplayStateFromLine();
1321
+ if (lineState?.edgeLowHz !== null && lineState?.edgeHighHz !== null) {
1322
+ return { lowHz: lineState.edgeLowHz, highHz: lineState.edgeHighHz };
1323
+ }
1324
+
1325
+ const targetVfo = 'VFO-A';
1290
1326
  const [lowHz, highHz] = await Promise.all([
1291
- this.getLevel('SPECTRUM_EDGE_LOW'),
1292
- this.getLevel('SPECTRUM_EDGE_HIGH'),
1327
+ this.getLevel('SPECTRUM_EDGE_LOW', targetVfo),
1328
+ this.getLevel('SPECTRUM_EDGE_HIGH', targetVfo),
1293
1329
  ]);
1294
1330
  return { lowHz, highHz };
1295
1331
  }
@@ -1298,23 +1334,28 @@ class HamLib extends EventEmitter {
1298
1334
  if (!Number.isFinite(lowHz) || !Number.isFinite(highHz) || lowHz >= highHz) {
1299
1335
  throw new Error('Spectrum fixed edge range must satisfy lowHz < highHz');
1300
1336
  }
1301
- await this.setLevel('SPECTRUM_EDGE_LOW', lowHz);
1302
- await this.setLevel('SPECTRUM_EDGE_HIGH', highHz);
1337
+ const targetVfo = 'VFO-A';
1338
+ await this.setLevel('SPECTRUM_EDGE_LOW', lowHz, targetVfo);
1339
+ await this.setLevel('SPECTRUM_EDGE_HIGH', highHz, targetVfo);
1303
1340
  return { lowHz, highHz };
1304
1341
  }
1305
1342
 
1306
1343
  async getSpectrumDisplayState() {
1307
1344
  const summary = await this.getSpectrumSupportSummary();
1308
- const [modeId, spanHz, fixedEdges, edgeSlot] = await Promise.all([
1345
+ const lineState = this._getLastSpectrumDisplayStateFromLine();
1346
+ const [queriedModeId, queriedSpanHz, fixedEdges, edgeSlot] = await Promise.all([
1309
1347
  summary.configurableLevels.includes('SPECTRUM_MODE') ? this.getLevel('SPECTRUM_MODE') : Promise.resolve(null),
1310
1348
  summary.configurableLevels.includes('SPECTRUM_SPAN') ? this.getLevel('SPECTRUM_SPAN') : Promise.resolve(null),
1311
- summary.supportsFixedEdges ? this.getSpectrumFixedEdges() : Promise.resolve(null),
1349
+ summary.supportsFixedEdges ? this.getSpectrumFixedEdges().catch(() => null) : Promise.resolve(null),
1312
1350
  summary.supportsEdgeSlotSelection ? this.getSpectrumEdgeSlot().catch(() => null) : Promise.resolve(null),
1313
1351
  ]);
1352
+
1353
+ const modeId = queriedModeId ?? lineState?.modeId ?? null;
1354
+ const spanHz = queriedSpanHz ?? lineState?.spanHz ?? null;
1314
1355
  const modeInfo = (summary.modes ?? []).find((entry) => entry.id === modeId) ?? null;
1315
1356
  const mode = normalizeSpectrumModeName(modeInfo?.name);
1316
- const edgeLowHz = fixedEdges?.lowHz ?? null;
1317
- const edgeHighHz = fixedEdges?.highHz ?? null;
1357
+ const edgeLowHz = fixedEdges?.lowHz ?? lineState?.edgeLowHz ?? null;
1358
+ const edgeHighHz = fixedEdges?.highHz ?? lineState?.edgeHighHz ?? null;
1318
1359
  const derivedSpanHz = (edgeLowHz !== null && edgeHighHz !== null) ? (edgeHighHz - edgeLowHz) : null;
1319
1360
 
1320
1361
  return {
@@ -1352,9 +1393,14 @@ class HamLib extends EventEmitter {
1352
1393
  * @returns {Promise<boolean>}
1353
1394
  */
1354
1395
  async startSpectrumStream(callback) {
1355
- const listener = typeof callback === 'function'
1356
- ? callback
1357
- : (line) => this.emit('spectrumLine', line);
1396
+ const listener = (line) => {
1397
+ const recorded = this._recordSpectrumLine(line);
1398
+ if (typeof callback === 'function') {
1399
+ callback(recorded);
1400
+ return;
1401
+ }
1402
+ this.emit('spectrumLine', recorded);
1403
+ };
1358
1404
  return this._nativeInstance.startSpectrumStream(listener);
1359
1405
  }
1360
1406
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hamlib",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "Node.js bindings for Hamlib rig control with official spectrum streaming support",
5
5
  "main": "index.js",
6
6
  "module": "lib/index.mjs",
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/src/hamlib.cpp CHANGED
@@ -2938,12 +2938,21 @@ Napi::Value NodeHamLib::SetLevel(const Napi::CallbackInfo & info) {
2938
2938
  }
2939
2939
 
2940
2940
  if (info.Length() < 2 || !info[0].IsString() || !info[1].IsNumber()) {
2941
- Napi::TypeError::New(env, "Expected (levelType: string, value: number)").ThrowAsJavaScriptException();
2941
+ Napi::TypeError::New(env, "Expected (levelType: string, value: number, vfo?: string)").ThrowAsJavaScriptException();
2942
2942
  return env.Null();
2943
2943
  }
2944
2944
 
2945
2945
  std::string levelTypeStr = info[0].As<Napi::String>().Utf8Value();
2946
2946
  double levelValue = info[1].As<Napi::Number>().DoubleValue();
2947
+ int vfo = SHIM_RIG_VFO_CURR;
2948
+ if (info.Length() >= 3 && info[2].IsString()) {
2949
+ std::string vfoStr = info[2].As<Napi::String>().Utf8Value();
2950
+ if (vfoStr == "VFO-A") {
2951
+ vfo = SHIM_RIG_VFO_A;
2952
+ } else if (vfoStr == "VFO-B") {
2953
+ vfo = SHIM_RIG_VFO_B;
2954
+ }
2955
+ }
2947
2956
 
2948
2957
  // Map level type strings to hamlib constants
2949
2958
  uint64_t levelType;
@@ -3021,8 +3030,8 @@ Napi::Value NodeHamLib::SetLevel(const Napi::CallbackInfo & info) {
3021
3030
  if (isSpectrumLevel) {
3022
3031
  Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(env);
3023
3032
  int result = shim_rig_level_is_float(levelType)
3024
- ? shim_rig_set_level_f(my_rig, SHIM_RIG_VFO_CURR, levelType, static_cast<float>(levelValue))
3025
- : shim_rig_set_level_i(my_rig, SHIM_RIG_VFO_CURR, levelType, static_cast<int>(levelValue));
3033
+ ? shim_rig_set_level_f(my_rig, vfo, levelType, static_cast<float>(levelValue))
3034
+ : shim_rig_set_level_i(my_rig, vfo, levelType, static_cast<int>(levelValue));
3026
3035
 
3027
3036
  if (result != SHIM_RIG_OK) {
3028
3037
  deferred.Reject(Napi::Error::New(env, shim_rigerror(result)).Value());