hamlib 0.3.0 → 0.3.2

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
@@ -204,11 +204,29 @@ Spectrum API summary:
204
204
  - `getSpectrumCapabilities()` returns conservative backend metadata exposed by the native addon.
205
205
  - `getSpectrumSupportSummary()` returns a product-oriented summary of whether official spectrum streaming is usable on the current rig/backend.
206
206
  - `configureSpectrum()` applies supported `SPECTRUM_*` levels and optional `SPECTRUM_HOLD`.
207
+ - `getSpectrumDisplayState()` returns a normalized display state with `mode/span/fixed edges/edge slot`.
208
+ - `configureSpectrumDisplay()` applies a normalized display config and reads back the resulting state.
209
+ - `getSpectrumEdgeSlot()` / `setSpectrumEdgeSlot()` expose backend edge-slot control when available.
210
+ - `getSpectrumFixedEdges()` / `setSpectrumFixedEdges()` expose direct fixed-range control using `SPECTRUM_EDGE_LOW/HIGH`.
207
211
  - `startSpectrumStream(callback?)` registers the official Hamlib spectrum callback only.
208
212
  - `stopSpectrumStream()` unregisters the official spectrum callback.
209
213
  - `startManagedSpectrum(config?)` runs the validated startup sequence for Icom/Hamlib async spectrum.
210
214
  - `stopManagedSpectrum()` runs the symmetric shutdown sequence and unregisters the callback.
211
215
 
216
+ Fixed-range example:
217
+
218
+ ```javascript
219
+ await rig.configureSpectrumDisplay({
220
+ mode: 'fixed',
221
+ edgeSlot: 1,
222
+ edgeLowHz: 14074000,
223
+ edgeHighHz: 14077000,
224
+ });
225
+
226
+ const displayState = await rig.getSpectrumDisplayState();
227
+ console.log(displayState);
228
+ ```
229
+
212
230
  Emitted events:
213
231
 
214
232
  - `spectrumLine` carries a single `SpectrumLine` object with frequency edges, mode, and raw bin payload.
package/index.d.ts CHANGED
@@ -200,17 +200,40 @@ interface SpectrumSupportSummary extends SpectrumCapabilities {
200
200
  hasSpectrumHoldFunction: boolean;
201
201
  hasTransceiveFunction: boolean;
202
202
  configurableLevels: string[];
203
+ supportsFixedEdges: boolean;
204
+ supportsEdgeSlotSelection: boolean;
205
+ supportedEdgeSlots: number[];
203
206
  }
204
207
 
208
+ type SpectrumDisplayMode = 'center' | 'fixed' | 'scroll-center' | 'scroll-fixed';
209
+
205
210
  interface SpectrumConfig {
206
211
  hold?: boolean;
207
- mode?: number;
212
+ mode?: number | SpectrumDisplayMode;
208
213
  spanHz?: number;
214
+ edgeSlot?: number;
215
+ edgeLowHz?: number;
216
+ edgeHighHz?: number;
209
217
  speed?: number;
210
218
  referenceLevel?: number;
211
219
  averageMode?: number;
212
220
  }
213
221
 
222
+ interface SpectrumDisplayState {
223
+ mode: SpectrumDisplayMode | null;
224
+ modeId: number | null;
225
+ modeName: string | null;
226
+ spanHz: number | null;
227
+ edgeSlot: number | null;
228
+ edgeLowHz: number | null;
229
+ edgeHighHz: number | null;
230
+ supportedModes: SpectrumModeInfo[];
231
+ supportedSpans: number[];
232
+ supportedEdgeSlots: number[];
233
+ supportsFixedEdges: boolean;
234
+ supportsEdgeSlotSelection: boolean;
235
+ }
236
+
214
237
  /**
215
238
  * Split mode info interface
216
239
  */
@@ -1287,6 +1310,41 @@ declare class HamLib extends EventEmitter {
1287
1310
  */
1288
1311
  configureSpectrum(config?: SpectrumConfig): Promise<SpectrumSupportSummary>;
1289
1312
 
1313
+ /**
1314
+ * Get the current spectrum edge slot if exposed by the backend.
1315
+ */
1316
+ getSpectrumEdgeSlot(): Promise<number>;
1317
+
1318
+ /**
1319
+ * Set the current spectrum edge slot if exposed by the backend.
1320
+ */
1321
+ setSpectrumEdgeSlot(slot: number): Promise<number>;
1322
+
1323
+ /**
1324
+ * Get supported spectrum edge slots.
1325
+ */
1326
+ getSpectrumSupportedEdgeSlots(): Promise<number[]>;
1327
+
1328
+ /**
1329
+ * Read current fixed spectrum edges.
1330
+ */
1331
+ getSpectrumFixedEdges(): Promise<{lowHz: number, highHz: number}>;
1332
+
1333
+ /**
1334
+ * Set current fixed spectrum edges.
1335
+ */
1336
+ setSpectrumFixedEdges(range: {lowHz: number, highHz: number}): Promise<{lowHz: number, highHz: number}>;
1337
+
1338
+ /**
1339
+ * Get a normalized spectrum display state for application use.
1340
+ */
1341
+ getSpectrumDisplayState(): Promise<SpectrumDisplayState>;
1342
+
1343
+ /**
1344
+ * Configure spectrum display state using a normalized application-facing shape.
1345
+ */
1346
+ configureSpectrumDisplay(config?: SpectrumConfig): Promise<SpectrumDisplayState>;
1347
+
1290
1348
  /**
1291
1349
  * Start receiving official Hamlib spectrum line events.
1292
1350
  */
package/lib/index.js CHANGED
@@ -4,6 +4,17 @@ const nodeGypBuild = require('node-gyp-build');
4
4
  // Ensure loader resolves from package root (contains prebuilds/ and build/)
5
5
  const nativeModule = nodeGypBuild(path.join(__dirname, '..'));
6
6
 
7
+ const DEFAULT_SPECTRUM_EDGE_SLOTS = [1, 2, 3, 4];
8
+
9
+ function normalizeSpectrumModeName(name) {
10
+ const normalized = String(name || '').trim().toLowerCase();
11
+ if (normalized === 'center') return 'center';
12
+ if (normalized === 'fixed') return 'fixed';
13
+ if (normalized === 'center scroll' || normalized === 'center-scroll' || normalized === 'scroll-center') return 'scroll-center';
14
+ if (normalized === 'fixed scroll' || normalized === 'fixed-scroll' || normalized === 'scroll-fixed') return 'scroll-fixed';
15
+ return null;
16
+ }
17
+
7
18
  /**
8
19
  * HamLib class for controlling amateur radio devices
9
20
  *
@@ -1180,8 +1191,16 @@ class HamLib extends EventEmitter {
1180
1191
  const hasSpectrumHoldFunction = supportedFunctions.includes('SPECTRUM_HOLD');
1181
1192
  const hasTransceiveFunction = supportedFunctions.includes('TRANSCEIVE');
1182
1193
  const asyncDataSupported = capabilities.asyncDataSupported ?? hasSpectrumFunction;
1183
- const configurableLevels = ['SPECTRUM_MODE', 'SPECTRUM_SPAN', 'SPECTRUM_SPEED', 'SPECTRUM_REF', 'SPECTRUM_AVG']
1194
+ const configurableLevels = ['SPECTRUM_MODE', 'SPECTRUM_SPAN', 'SPECTRUM_EDGE_LOW', 'SPECTRUM_EDGE_HIGH', 'SPECTRUM_SPEED', 'SPECTRUM_REF', 'SPECTRUM_AVG']
1184
1195
  .filter((name) => supportedLevels.includes(name));
1196
+ let supportsEdgeSlotSelection = false;
1197
+
1198
+ try {
1199
+ const edgeSlot = await this.getConf('SPECTRUM_EDGE');
1200
+ supportsEdgeSlotSelection = Number.isFinite(Number.parseInt(String(edgeSlot), 10));
1201
+ } catch (_) {
1202
+ supportsEdgeSlotSelection = false;
1203
+ }
1185
1204
 
1186
1205
  return {
1187
1206
  supported: Boolean(hasSpectrumFunction),
@@ -1190,6 +1209,9 @@ class HamLib extends EventEmitter {
1190
1209
  hasSpectrumHoldFunction,
1191
1210
  hasTransceiveFunction,
1192
1211
  configurableLevels,
1212
+ supportsFixedEdges: configurableLevels.includes('SPECTRUM_EDGE_LOW') && configurableLevels.includes('SPECTRUM_EDGE_HIGH'),
1213
+ supportsEdgeSlotSelection,
1214
+ supportedEdgeSlots: supportsEdgeSlotSelection ? [...DEFAULT_SPECTRUM_EDGE_SLOTS] : [],
1193
1215
  scopes: capabilities.scopes ?? [],
1194
1216
  modes: capabilities.modes ?? [],
1195
1217
  spans: capabilities.spans ?? [],
@@ -1208,13 +1230,32 @@ class HamLib extends EventEmitter {
1208
1230
  if (value === undefined || !summary.configurableLevels.includes(name)) return;
1209
1231
  await this.setLevel(name, value);
1210
1232
  };
1233
+ const resolveModeId = async (mode) => {
1234
+ if (mode === undefined || mode === null) return undefined;
1235
+ if (Number.isFinite(mode)) return mode;
1236
+ const requested = normalizeSpectrumModeName(mode);
1237
+ if (!requested) {
1238
+ throw new Error(`Unsupported spectrum mode: ${mode}`);
1239
+ }
1240
+ const matched = (summary.modes ?? []).find((entry) => normalizeSpectrumModeName(entry?.name) === requested);
1241
+ if (!matched) {
1242
+ throw new Error(`Spectrum mode not supported by this backend: ${mode}`);
1243
+ }
1244
+ return matched.id;
1245
+ };
1211
1246
 
1212
1247
  if (summary.hasSpectrumHoldFunction && config.hold !== undefined) {
1213
1248
  await this.setFunction('SPECTRUM_HOLD', Boolean(config.hold));
1214
1249
  }
1215
1250
 
1216
- await applyLevel('SPECTRUM_MODE', config.mode);
1251
+ if (config.edgeSlot !== undefined && summary.supportsEdgeSlotSelection) {
1252
+ await this.setSpectrumEdgeSlot(config.edgeSlot);
1253
+ }
1254
+
1255
+ await applyLevel('SPECTRUM_MODE', await resolveModeId(config.mode));
1217
1256
  await applyLevel('SPECTRUM_SPAN', config.spanHz);
1257
+ await applyLevel('SPECTRUM_EDGE_LOW', config.edgeLowHz);
1258
+ await applyLevel('SPECTRUM_EDGE_HIGH', config.edgeHighHz);
1218
1259
  await applyLevel('SPECTRUM_SPEED', config.speed);
1219
1260
  await applyLevel('SPECTRUM_REF', config.referenceLevel);
1220
1261
  await applyLevel('SPECTRUM_AVG', config.averageMode);
@@ -1222,6 +1263,89 @@ class HamLib extends EventEmitter {
1222
1263
  return summary;
1223
1264
  }
1224
1265
 
1266
+ async getSpectrumEdgeSlot() {
1267
+ const raw = await this.getConf('SPECTRUM_EDGE');
1268
+ const parsed = Number.parseInt(String(raw), 10);
1269
+ if (!Number.isFinite(parsed)) {
1270
+ throw new Error('Spectrum edge slot is not available');
1271
+ }
1272
+ return parsed;
1273
+ }
1274
+
1275
+ async setSpectrumEdgeSlot(slot) {
1276
+ const parsed = Number.parseInt(String(slot), 10);
1277
+ if (!Number.isFinite(parsed) || parsed < 1) {
1278
+ throw new Error(`Invalid spectrum edge slot: ${slot}`);
1279
+ }
1280
+ await this.setConf('SPECTRUM_EDGE', String(parsed));
1281
+ return parsed;
1282
+ }
1283
+
1284
+ async getSpectrumSupportedEdgeSlots() {
1285
+ const summary = await this.getSpectrumSupportSummary();
1286
+ return summary.supportedEdgeSlots ?? [];
1287
+ }
1288
+
1289
+ async getSpectrumFixedEdges() {
1290
+ const [lowHz, highHz] = await Promise.all([
1291
+ this.getLevel('SPECTRUM_EDGE_LOW'),
1292
+ this.getLevel('SPECTRUM_EDGE_HIGH'),
1293
+ ]);
1294
+ return { lowHz, highHz };
1295
+ }
1296
+
1297
+ async setSpectrumFixedEdges({ lowHz, highHz }) {
1298
+ if (!Number.isFinite(lowHz) || !Number.isFinite(highHz) || lowHz >= highHz) {
1299
+ throw new Error('Spectrum fixed edge range must satisfy lowHz < highHz');
1300
+ }
1301
+ await this.setLevel('SPECTRUM_EDGE_LOW', lowHz);
1302
+ await this.setLevel('SPECTRUM_EDGE_HIGH', highHz);
1303
+ return { lowHz, highHz };
1304
+ }
1305
+
1306
+ async getSpectrumDisplayState() {
1307
+ const summary = await this.getSpectrumSupportSummary();
1308
+ const [modeId, spanHz, fixedEdges, edgeSlot] = await Promise.all([
1309
+ summary.configurableLevels.includes('SPECTRUM_MODE') ? this.getLevel('SPECTRUM_MODE') : Promise.resolve(null),
1310
+ summary.configurableLevels.includes('SPECTRUM_SPAN') ? this.getLevel('SPECTRUM_SPAN') : Promise.resolve(null),
1311
+ summary.supportsFixedEdges ? this.getSpectrumFixedEdges() : Promise.resolve(null),
1312
+ summary.supportsEdgeSlotSelection ? this.getSpectrumEdgeSlot().catch(() => null) : Promise.resolve(null),
1313
+ ]);
1314
+ const modeInfo = (summary.modes ?? []).find((entry) => entry.id === modeId) ?? null;
1315
+ const mode = normalizeSpectrumModeName(modeInfo?.name);
1316
+ const edgeLowHz = fixedEdges?.lowHz ?? null;
1317
+ const edgeHighHz = fixedEdges?.highHz ?? null;
1318
+ const derivedSpanHz = (edgeLowHz !== null && edgeHighHz !== null) ? (edgeHighHz - edgeLowHz) : null;
1319
+
1320
+ return {
1321
+ mode,
1322
+ modeId,
1323
+ modeName: modeInfo?.name ?? null,
1324
+ spanHz: spanHz ?? derivedSpanHz,
1325
+ edgeSlot,
1326
+ edgeLowHz,
1327
+ edgeHighHz,
1328
+ supportedModes: summary.modes ?? [],
1329
+ supportedSpans: summary.spans ?? [],
1330
+ supportedEdgeSlots: summary.supportedEdgeSlots ?? [],
1331
+ supportsFixedEdges: Boolean(summary.supportsFixedEdges),
1332
+ supportsEdgeSlotSelection: Boolean(summary.supportsEdgeSlotSelection),
1333
+ };
1334
+ }
1335
+
1336
+ async configureSpectrumDisplay(config = {}) {
1337
+ const normalizedConfig = { ...config };
1338
+ if ((normalizedConfig.mode === 'fixed' || normalizedConfig.mode === 'scroll-fixed')
1339
+ && normalizedConfig.edgeLowHz !== undefined
1340
+ && normalizedConfig.edgeHighHz !== undefined
1341
+ && normalizedConfig.edgeLowHz >= normalizedConfig.edgeHighHz) {
1342
+ throw new Error('Spectrum fixed edge range must satisfy edgeLowHz < edgeHighHz');
1343
+ }
1344
+
1345
+ await this.configureSpectrum(normalizedConfig);
1346
+ return this.getSpectrumDisplayState();
1347
+ }
1348
+
1225
1349
  /**
1226
1350
  * Start the official Hamlib spectrum callback stream.
1227
1351
  * @param {(line: Object) => void} [callback]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hamlib",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
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
@@ -286,7 +286,11 @@ public:
286
286
  void Execute() override {
287
287
  CHECK_RIG_VALID();
288
288
 
289
- result_code_ = shim_rig_set_level_f(hamlib_instance_->my_rig, SHIM_RIG_VFO_CURR, level_type_, value_);
289
+ if (shim_rig_level_is_float(level_type_)) {
290
+ result_code_ = shim_rig_set_level_f(hamlib_instance_->my_rig, SHIM_RIG_VFO_CURR, level_type_, value_);
291
+ } else {
292
+ result_code_ = shim_rig_set_level_i(hamlib_instance_->my_rig, SHIM_RIG_VFO_CURR, level_type_, static_cast<int>(value_));
293
+ }
290
294
  if (result_code_ != SHIM_RIG_OK) {
291
295
  error_message_ = shim_rigerror(result_code_);
292
296
  }
@@ -3004,11 +3008,33 @@ Napi::Value NodeHamLib::SetLevel(const Napi::CallbackInfo & info) {
3004
3008
  return env.Null();
3005
3009
  }
3006
3010
 
3007
- float val = static_cast<float>(levelValue);
3011
+ const bool isSpectrumLevel =
3012
+ levelType == SHIM_RIG_LEVEL_SPECTRUM_MODE
3013
+ || levelType == SHIM_RIG_LEVEL_SPECTRUM_SPAN
3014
+ || levelType == SHIM_RIG_LEVEL_SPECTRUM_EDGE_LOW
3015
+ || levelType == SHIM_RIG_LEVEL_SPECTRUM_EDGE_HIGH
3016
+ || levelType == SHIM_RIG_LEVEL_SPECTRUM_SPEED
3017
+ || levelType == SHIM_RIG_LEVEL_SPECTRUM_REF
3018
+ || levelType == SHIM_RIG_LEVEL_SPECTRUM_AVG
3019
+ || levelType == SHIM_RIG_LEVEL_SPECTRUM_ATT;
3020
+
3021
+ if (isSpectrumLevel) {
3022
+ Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(env);
3023
+ 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));
3026
+
3027
+ if (result != SHIM_RIG_OK) {
3028
+ deferred.Reject(Napi::Error::New(env, shim_rigerror(result)).Value());
3029
+ } else {
3030
+ deferred.Resolve(Napi::Number::New(env, result));
3031
+ }
3032
+ return deferred.Promise();
3033
+ }
3008
3034
 
3035
+ float val = static_cast<float>(levelValue);
3009
3036
  SetLevelAsyncWorker* worker = new SetLevelAsyncWorker(env, this, levelType, val);
3010
3037
  worker->Queue();
3011
-
3012
3038
  return worker->GetPromise();
3013
3039
  }
3014
3040
 
@@ -5970,11 +5996,60 @@ Napi::Value NodeHamLib::GetSpectrumCapabilities(const Napi::CallbackInfo& info)
5970
5996
  Napi::Env env = info.Env();
5971
5997
  Napi::Object result = Napi::Object::New(env);
5972
5998
 
5973
- result.Set("asyncDataSupported", env.Undefined());
5974
- result.Set("scopes", Napi::Array::New(env));
5975
- result.Set("modes", Napi::Array::New(env));
5976
- result.Set("spans", Napi::Array::New(env));
5977
- result.Set("avgModes", Napi::Array::New(env));
5999
+ result.Set("asyncDataSupported", Napi::Boolean::New(env, shim_rig_is_async_data_supported(my_rig) != 0));
6000
+
6001
+ Napi::Array scopes = Napi::Array::New(env);
6002
+ int scopeCount = shim_rig_get_caps_spectrum_scope_count(my_rig);
6003
+ for (int i = 0; i < scopeCount; ++i) {
6004
+ shim_spectrum_scope_t scope{};
6005
+ if (shim_rig_get_caps_spectrum_scope(my_rig, i, &scope) != SHIM_RIG_OK) {
6006
+ continue;
6007
+ }
6008
+ Napi::Object scopeObject = Napi::Object::New(env);
6009
+ scopeObject.Set("id", Napi::Number::New(env, scope.id));
6010
+ scopeObject.Set("name", Napi::String::New(env, scope.name));
6011
+ scopes.Set(i, scopeObject);
6012
+ }
6013
+ result.Set("scopes", scopes);
6014
+
6015
+ Napi::Array modes = Napi::Array::New(env);
6016
+ int modeCount = shim_rig_get_caps_spectrum_mode_count(my_rig);
6017
+ for (int i = 0; i < modeCount; ++i) {
6018
+ int modeId = 0;
6019
+ if (shim_rig_get_caps_spectrum_mode(my_rig, i, &modeId) != SHIM_RIG_OK) {
6020
+ continue;
6021
+ }
6022
+ Napi::Object modeObject = Napi::Object::New(env);
6023
+ modeObject.Set("id", Napi::Number::New(env, modeId));
6024
+ modeObject.Set("name", Napi::String::New(env, shim_rig_str_spectrum_mode(modeId)));
6025
+ modes.Set(i, modeObject);
6026
+ }
6027
+ result.Set("modes", modes);
6028
+
6029
+ Napi::Array spans = Napi::Array::New(env);
6030
+ int spanCount = shim_rig_get_caps_spectrum_span_count(my_rig);
6031
+ for (int i = 0; i < spanCount; ++i) {
6032
+ double spanHz = 0;
6033
+ if (shim_rig_get_caps_spectrum_span(my_rig, i, &spanHz) != SHIM_RIG_OK) {
6034
+ continue;
6035
+ }
6036
+ spans.Set(i, Napi::Number::New(env, spanHz));
6037
+ }
6038
+ result.Set("spans", spans);
6039
+
6040
+ Napi::Array avgModes = Napi::Array::New(env);
6041
+ int avgModeCount = shim_rig_get_caps_spectrum_avg_mode_count(my_rig);
6042
+ for (int i = 0; i < avgModeCount; ++i) {
6043
+ shim_spectrum_avg_mode_t avgMode{};
6044
+ if (shim_rig_get_caps_spectrum_avg_mode(my_rig, i, &avgMode) != SHIM_RIG_OK) {
6045
+ continue;
6046
+ }
6047
+ Napi::Object avgModeObject = Napi::Object::New(env);
6048
+ avgModeObject.Set("id", Napi::Number::New(env, avgMode.id));
6049
+ avgModeObject.Set("name", Napi::String::New(env, avgMode.name));
6050
+ avgModes.Set(i, avgModeObject);
6051
+ }
6052
+ result.Set("avgModes", avgModes);
5978
6053
 
5979
6054
  return result;
5980
6055
  }
@@ -333,14 +333,20 @@ SHIM_API int shim_rig_get_strength(hamlib_shim_handle_t h, int vfo, int* strengt
333
333
 
334
334
  /* ===== Level control ===== */
335
335
 
336
+ static void shim_ensure_targetable_level(hamlib_shim_handle_t h);
337
+
336
338
  SHIM_API int shim_rig_set_level_f(hamlib_shim_handle_t h, int vfo, uint64_t level, float value) {
339
+ shim_ensure_targetable_level(h);
337
340
  value_t val;
341
+ memset(&val, 0, sizeof(val));
338
342
  val.f = value;
339
343
  return rig_set_level((RIG*)h, (vfo_t)vfo, (setting_t)level, val);
340
344
  }
341
345
 
342
346
  SHIM_API int shim_rig_set_level_i(hamlib_shim_handle_t h, int vfo, uint64_t level, int value) {
347
+ shim_ensure_targetable_level(h);
343
348
  value_t val;
349
+ memset(&val, 0, sizeof(val));
344
350
  val.i = value;
345
351
  return rig_set_level((RIG*)h, (vfo_t)vfo, (setting_t)level, val);
346
352
  }
@@ -383,6 +389,10 @@ SHIM_API int shim_rig_get_level_i(hamlib_shim_handle_t h, int vfo, uint64_t leve
383
389
  return ret;
384
390
  }
385
391
 
392
+ SHIM_API int shim_rig_level_is_float(uint64_t level) {
393
+ return RIG_LEVEL_IS_FLOAT((setting_t)level) ? 1 : 0;
394
+ }
395
+
386
396
  /*
387
397
  * Auto-detect int/float level type using RIG_LEVEL_IS_FLOAT macro.
388
398
  * Returns the value as double regardless of the underlying type.
@@ -434,6 +434,7 @@ SHIM_API int shim_rig_set_level_f(hamlib_shim_handle_t h, int vfo, uint64_t leve
434
434
  SHIM_API int shim_rig_set_level_i(hamlib_shim_handle_t h, int vfo, uint64_t level, int value);
435
435
  SHIM_API int shim_rig_get_level_f(hamlib_shim_handle_t h, int vfo, uint64_t level, float* value);
436
436
  SHIM_API int shim_rig_get_level_i(hamlib_shim_handle_t h, int vfo, uint64_t level, int* value);
437
+ SHIM_API int shim_rig_level_is_float(uint64_t level);
437
438
  /* Auto-detect int/float level type, returns value as double */
438
439
  SHIM_API int shim_rig_get_level_auto(hamlib_shim_handle_t h, int vfo, uint64_t level, double* value);
439
440