hamlib 0.4.0 → 0.4.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/index.d.ts CHANGED
@@ -378,6 +378,62 @@ interface SerialConfigOptions {
378
378
  dcd_type: string[];
379
379
  }
380
380
 
381
+ type HamlibConfigFieldType =
382
+ | 'string'
383
+ | 'combo'
384
+ | 'numeric'
385
+ | 'checkbutton'
386
+ | 'button'
387
+ | 'binary'
388
+ | 'int'
389
+ | 'unknown';
390
+
391
+ interface HamlibConfigFieldDescriptor {
392
+ token: number;
393
+ name: string;
394
+ label: string;
395
+ tooltip: string;
396
+ defaultValue: string;
397
+ type: HamlibConfigFieldType;
398
+ numeric?: {
399
+ min: number;
400
+ max: number;
401
+ step: number;
402
+ };
403
+ options?: string[];
404
+ }
405
+
406
+ type HamlibPortType =
407
+ | 'none'
408
+ | 'serial'
409
+ | 'network'
410
+ | 'device'
411
+ | 'packet'
412
+ | 'dtmf'
413
+ | 'ultra'
414
+ | 'rpc'
415
+ | 'parallel'
416
+ | 'usb'
417
+ | 'udp-network'
418
+ | 'cm108'
419
+ | 'gpio'
420
+ | 'gpion'
421
+ | 'other';
422
+
423
+ interface HamlibPortCaps {
424
+ portType: HamlibPortType;
425
+ serialRateMin?: number;
426
+ serialRateMax?: number;
427
+ serialDataBits?: number;
428
+ serialStopBits?: number;
429
+ serialParity?: string;
430
+ serialHandshake?: string;
431
+ writeDelay: number;
432
+ postWriteDelay: number;
433
+ timeout: number;
434
+ retry: number;
435
+ }
436
+
381
437
  /**
382
438
  * HamLib class - for controlling amateur radio devices
383
439
  */
@@ -856,6 +912,18 @@ declare class HamLib extends EventEmitter {
856
912
  */
857
913
  getSupportedSerialConfigs(): SerialConfigOptions;
858
914
 
915
+ /**
916
+ * Get backend-specific configuration schema for the current rig model.
917
+ * This can be queried before opening the connection and is suitable for
918
+ * driving dynamic configuration UIs.
919
+ */
920
+ getConfigSchema(): HamlibConfigFieldDescriptor[];
921
+
922
+ /**
923
+ * Get backend port capabilities and effective connection defaults.
924
+ */
925
+ getPortCaps(): HamlibPortCaps;
926
+
859
927
  // Power Control
860
928
 
861
929
  /**
@@ -1543,6 +1611,7 @@ export { ConnectionInfo, ModeInfo, SupportedRigInfo, AntennaInfo, VFO, RadioMode
1543
1611
  MemoryChannelInfo, SplitModeInfo, SplitStatusInfo, LevelType, FunctionType,
1544
1612
  ScanType, VfoOperationType, SerialConfigParam, SerialBaudRate, SerialParity,
1545
1613
  SerialHandshake, SerialControlState, PttType, DcdType, SerialConfigOptions,
1614
+ HamlibConfigFieldType, HamlibConfigFieldDescriptor, HamlibPortType, HamlibPortCaps,
1546
1615
  SpectrumScopeInfo, SpectrumModeInfo, SpectrumAverageModeInfo, SpectrumLine,
1547
1616
  SpectrumCapabilities, SpectrumSupportSummary, SpectrumConfig, SpectrumDisplayState,
1548
1617
  ClockInfo, VfoInfo, HamLib };
package/lib/index.js CHANGED
@@ -589,6 +589,25 @@ class HamLib extends EventEmitter {
589
589
  return this._nativeInstance.getSupportedSerialConfigs();
590
590
  }
591
591
 
592
+ /**
593
+ * Get backend-specific configuration schema for the selected rig model.
594
+ * This can be queried before opening the connection and is intended for
595
+ * dynamic configuration UIs.
596
+ * @returns {Array<Object>} List of config field descriptors
597
+ */
598
+ getConfigSchema() {
599
+ return this._nativeInstance.getConfigSchema();
600
+ }
601
+
602
+ /**
603
+ * Get backend port capabilities and effective connection defaults derived
604
+ * from Hamlib rig caps for the selected model.
605
+ * @returns {Object} Port type and default connection parameters
606
+ */
607
+ getPortCaps() {
608
+ return this._nativeInstance.getPortCaps();
609
+ }
610
+
592
611
  // Power Control
593
612
 
594
613
  /**
package/lib/spectrum.d.ts CHANGED
@@ -60,6 +60,4 @@ export type {
60
60
  SpectrumSupportSummary,
61
61
  };
62
62
 
63
- // @ts-ignore
64
- export = spectrumModule;
65
63
  export default spectrumModule;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hamlib",
3
- "version": "0.4.0",
3
+ "version": "0.4.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",
@@ -12,9 +12,16 @@
12
12
  "types": "./index.d.ts"
13
13
  },
14
14
  "./spectrum": {
15
- "import": "./lib/spectrum.mjs",
16
- "require": "./lib/spectrum.js",
17
- "types": "./lib/spectrum.d.ts"
15
+ "import": "./spectrum.mjs",
16
+ "require": "./spectrum.js",
17
+ "types": "./spectrum.d.ts"
18
+ }
19
+ },
20
+ "typesVersions": {
21
+ "*": {
22
+ "spectrum": [
23
+ "spectrum.d.ts"
24
+ ]
18
25
  }
19
26
  },
20
27
  "gypfile": true,
@@ -38,6 +45,9 @@
38
45
  "docs/",
39
46
  "index.js",
40
47
  "index.d.ts",
48
+ "spectrum.js",
49
+ "spectrum.mjs",
50
+ "spectrum.d.ts",
41
51
  "binding.gyp",
42
52
  "COPYING",
43
53
  "README.md"
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/spectrum.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './lib/spectrum';
2
+ export { default } from './lib/spectrum';
package/spectrum.js ADDED
@@ -0,0 +1 @@
1
+ module.exports = require('./lib/spectrum.js');
package/spectrum.mjs ADDED
@@ -0,0 +1,2 @@
1
+ export * from './lib/spectrum.mjs';
2
+ export { default } from './lib/spectrum.mjs';
package/src/hamlib.cpp CHANGED
@@ -40,6 +40,23 @@ struct RigListData {
40
40
  Napi::Env env;
41
41
  };
42
42
 
43
+ struct RigConfigFieldDescriptor {
44
+ int token;
45
+ std::string name;
46
+ std::string label;
47
+ std::string tooltip;
48
+ std::string defaultValue;
49
+ int type;
50
+ double numericMin;
51
+ double numericMax;
52
+ double numericStep;
53
+ std::vector<std::string> options;
54
+ };
55
+
56
+ struct RigConfigSchemaData {
57
+ std::vector<RigConfigFieldDescriptor> fields;
58
+ };
59
+
43
60
  using namespace Napi;
44
61
 
45
62
  Napi::FunctionReference NodeHamLib::constructor;
@@ -55,6 +72,31 @@ static std::string publicVfoToken(int vfo) {
55
72
  return rawToken;
56
73
  }
57
74
 
75
+ static const char* publicConfTypeName(int type) {
76
+ switch (type) {
77
+ case 0:
78
+ return "string";
79
+ case 1:
80
+ return "combo";
81
+ case 2:
82
+ return "numeric";
83
+ case 3:
84
+ return "checkbutton";
85
+ case 4:
86
+ return "button";
87
+ case 5:
88
+ return "binary";
89
+ case 6:
90
+ return "int";
91
+ default:
92
+ return "unknown";
93
+ }
94
+ }
95
+
96
+ static bool hasPositiveValue(int value) {
97
+ return value > 0;
98
+ }
99
+
58
100
  static int parseVfoString(Napi::Env env, const std::string& vfoToken) {
59
101
  int vfo = shim_rig_parse_vfo(vfoToken.c_str());
60
102
  if (vfo == SHIM_RIG_VFO_NONE) {
@@ -3832,6 +3874,8 @@ Napi::Function NodeHamLib::GetClass(Napi::Env env) {
3832
3874
  NodeHamLib::InstanceMethod("setDcdType", & NodeHamLib::SetDcdType),
3833
3875
  NodeHamLib::InstanceMethod("getDcdType", & NodeHamLib::GetDcdType),
3834
3876
  NodeHamLib::InstanceMethod("getSupportedSerialConfigs", & NodeHamLib::GetSupportedSerialConfigs),
3877
+ NodeHamLib::InstanceMethod("getConfigSchema", & NodeHamLib::GetConfigSchema),
3878
+ NodeHamLib::InstanceMethod("getPortCaps", & NodeHamLib::GetPortCaps),
3835
3879
 
3836
3880
  // Power Control
3837
3881
  NodeHamLib::InstanceMethod("setPowerstat", & NodeHamLib::SetPowerstat),
@@ -4220,7 +4264,7 @@ Napi::Value NodeHamLib::GetSupportedSerialConfigs(const Napi::CallbackInfo& info
4220
4264
  pttTypeOptions[5u] = Napi::String::New(env, "GPIO");
4221
4265
  pttTypeOptions[6u] = Napi::String::New(env, "GPION");
4222
4266
  pttTypeOptions[7u] = Napi::String::New(env, "NONE");
4223
- configs.Set("intype", pttTypeOptions);
4267
+ configs.Set("ptt_type", pttTypeOptions);
4224
4268
 
4225
4269
  // DCD type options
4226
4270
  Napi::Array dcdTypeOptions = Napi::Array::New(env, 9);
@@ -4233,11 +4277,124 @@ Napi::Value NodeHamLib::GetSupportedSerialConfigs(const Napi::CallbackInfo& info
4233
4277
  dcdTypeOptions[6u] = Napi::String::New(env, "GPIO");
4234
4278
  dcdTypeOptions[7u] = Napi::String::New(env, "GPION");
4235
4279
  dcdTypeOptions[8u] = Napi::String::New(env, "NONE");
4236
- configs.Set("intype", dcdTypeOptions);
4280
+ configs.Set("dcd_type", dcdTypeOptions);
4237
4281
 
4238
4282
  return configs;
4239
4283
  }
4240
4284
 
4285
+ int NodeHamLib::rig_config_callback(const shim_confparam_info_t* info, void* data) {
4286
+ RigConfigSchemaData* schema_data = static_cast<RigConfigSchemaData*>(data);
4287
+
4288
+ if (!schema_data || !info) {
4289
+ return 0;
4290
+ }
4291
+
4292
+ RigConfigFieldDescriptor field;
4293
+ field.token = info->token;
4294
+ field.name = info->name;
4295
+ field.label = info->label;
4296
+ field.tooltip = info->tooltip;
4297
+ field.defaultValue = info->dflt;
4298
+ field.type = info->type;
4299
+ field.numericMin = info->numeric_min;
4300
+ field.numericMax = info->numeric_max;
4301
+ field.numericStep = info->numeric_step;
4302
+
4303
+ for (int i = 0; i < info->combo_count; ++i) {
4304
+ field.options.emplace_back(info->combo_options[i]);
4305
+ }
4306
+
4307
+ schema_data->fields.push_back(field);
4308
+ return 1;
4309
+ }
4310
+
4311
+ Napi::Value NodeHamLib::GetConfigSchema(const Napi::CallbackInfo& info) {
4312
+ Napi::Env env = info.Env();
4313
+ RETURN_NULL_IF_RIG_HANDLE_INVALID();
4314
+
4315
+ RigConfigSchemaData schemaData{};
4316
+ int result = shim_rig_cfgparams_foreach(my_rig, rig_config_callback, &schemaData);
4317
+
4318
+ if (result != SHIM_RIG_OK) {
4319
+ Napi::Error::New(env, shim_rigerror(result)).ThrowAsJavaScriptException();
4320
+ return env.Null();
4321
+ }
4322
+
4323
+ Napi::Array schemaArray = Napi::Array::New(env, schemaData.fields.size());
4324
+ for (size_t i = 0; i < schemaData.fields.size(); ++i) {
4325
+ const RigConfigFieldDescriptor& descriptor = schemaData.fields[i];
4326
+ Napi::Object field = Napi::Object::New(env);
4327
+ field.Set("token", Napi::Number::New(env, descriptor.token));
4328
+ field.Set("name", Napi::String::New(env, descriptor.name));
4329
+ field.Set("label", Napi::String::New(env, descriptor.label));
4330
+ field.Set("tooltip", Napi::String::New(env, descriptor.tooltip));
4331
+ field.Set("defaultValue", Napi::String::New(env, descriptor.defaultValue));
4332
+ field.Set("type", Napi::String::New(env, publicConfTypeName(descriptor.type)));
4333
+
4334
+ if (descriptor.type == 2 || descriptor.type == 6) {
4335
+ Napi::Object numeric = Napi::Object::New(env);
4336
+ numeric.Set("min", Napi::Number::New(env, descriptor.numericMin));
4337
+ numeric.Set("max", Napi::Number::New(env, descriptor.numericMax));
4338
+ numeric.Set("step", Napi::Number::New(env, descriptor.numericStep));
4339
+ field.Set("numeric", numeric);
4340
+ }
4341
+
4342
+ if (!descriptor.options.empty()) {
4343
+ Napi::Array options = Napi::Array::New(env, descriptor.options.size());
4344
+ for (size_t optionIndex = 0; optionIndex < descriptor.options.size(); ++optionIndex) {
4345
+ options[static_cast<uint32_t>(optionIndex)] =
4346
+ Napi::String::New(env, descriptor.options[optionIndex]);
4347
+ }
4348
+ field.Set("options", options);
4349
+ }
4350
+
4351
+ schemaArray[static_cast<uint32_t>(i)] = field;
4352
+ }
4353
+
4354
+ return schemaArray;
4355
+ }
4356
+
4357
+ Napi::Value NodeHamLib::GetPortCaps(const Napi::CallbackInfo& info) {
4358
+ Napi::Env env = info.Env();
4359
+ RETURN_NULL_IF_RIG_HANDLE_INVALID();
4360
+
4361
+ shim_rig_port_caps_t caps{};
4362
+ int result = shim_rig_get_port_caps(my_rig, &caps);
4363
+
4364
+ if (result != SHIM_RIG_OK) {
4365
+ Napi::Error::New(env, shim_rigerror(result)).ThrowAsJavaScriptException();
4366
+ return env.Null();
4367
+ }
4368
+
4369
+ Napi::Object portCaps = Napi::Object::New(env);
4370
+ portCaps.Set("portType", Napi::String::New(env, caps.port_type));
4371
+ portCaps.Set("writeDelay", Napi::Number::New(env, caps.write_delay));
4372
+ portCaps.Set("postWriteDelay", Napi::Number::New(env, caps.post_write_delay));
4373
+ portCaps.Set("timeout", Napi::Number::New(env, caps.timeout));
4374
+ portCaps.Set("retry", Napi::Number::New(env, caps.retry));
4375
+
4376
+ if (hasPositiveValue(caps.serial_rate_min)) {
4377
+ portCaps.Set("serialRateMin", Napi::Number::New(env, caps.serial_rate_min));
4378
+ }
4379
+ if (hasPositiveValue(caps.serial_rate_max)) {
4380
+ portCaps.Set("serialRateMax", Napi::Number::New(env, caps.serial_rate_max));
4381
+ }
4382
+ if (hasPositiveValue(caps.serial_data_bits)) {
4383
+ portCaps.Set("serialDataBits", Napi::Number::New(env, caps.serial_data_bits));
4384
+ }
4385
+ if (hasPositiveValue(caps.serial_stop_bits)) {
4386
+ portCaps.Set("serialStopBits", Napi::Number::New(env, caps.serial_stop_bits));
4387
+ }
4388
+ if (caps.serial_parity[0] != '\0' && std::string(caps.serial_parity) != "Unknown") {
4389
+ portCaps.Set("serialParity", Napi::String::New(env, caps.serial_parity));
4390
+ }
4391
+ if (caps.serial_handshake[0] != '\0' && std::string(caps.serial_handshake) != "Unknown") {
4392
+ portCaps.Set("serialHandshake", Napi::String::New(env, caps.serial_handshake));
4393
+ }
4394
+
4395
+ return portCaps;
4396
+ }
4397
+
4241
4398
  // Power Control Methods
4242
4399
  Napi::Value NodeHamLib::SetPowerstat(const Napi::CallbackInfo& info) {
4243
4400
  Napi::Env env = info.Env();
@@ -6156,11 +6313,7 @@ private:
6156
6313
 
6157
6314
  Napi::Value NodeHamLib::SetConf(const Napi::CallbackInfo& info) {
6158
6315
  Napi::Env env = info.Env();
6159
-
6160
- if (!rig_is_open) {
6161
- Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
6162
- return env.Null();
6163
- }
6316
+ RETURN_NULL_IF_RIG_HANDLE_INVALID();
6164
6317
 
6165
6318
  if (info.Length() < 2 || !info[0].IsString() || !info[1].IsString()) {
6166
6319
  Napi::TypeError::New(env, "Expected (name: string, value: string)").ThrowAsJavaScriptException();
@@ -6212,11 +6365,7 @@ private:
6212
6365
 
6213
6366
  Napi::Value NodeHamLib::GetConf(const Napi::CallbackInfo& info) {
6214
6367
  Napi::Env env = info.Env();
6215
-
6216
- if (!rig_is_open) {
6217
- Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
6218
- return env.Null();
6219
- }
6368
+ RETURN_NULL_IF_RIG_HANDLE_INVALID();
6220
6369
 
6221
6370
  if (info.Length() < 1 || !info[0].IsString()) {
6222
6371
  Napi::TypeError::New(env, "Expected (name: string)").ThrowAsJavaScriptException();
package/src/hamlib.h CHANGED
@@ -99,6 +99,8 @@ class NodeHamLib : public Napi::ObjectWrap<NodeHamLib> {
99
99
  Napi::Value SetDcdType(const Napi::CallbackInfo&);
100
100
  Napi::Value GetDcdType(const Napi::CallbackInfo&);
101
101
  Napi::Value GetSupportedSerialConfigs(const Napi::CallbackInfo&);
102
+ Napi::Value GetConfigSchema(const Napi::CallbackInfo&);
103
+ Napi::Value GetPortCaps(const Napi::CallbackInfo&);
102
104
 
103
105
  // Power Control
104
106
  Napi::Value SetPowerstat(const Napi::CallbackInfo&);
@@ -242,6 +244,7 @@ class NodeHamLib : public Napi::ObjectWrap<NodeHamLib> {
242
244
 
243
245
  // Static callback helper for shim_rig_list_foreach
244
246
  static int rig_list_callback(const shim_rig_info_t* info, void* data);
247
+ static int rig_config_callback(const shim_confparam_info_t* info, void* data);
245
248
 
246
249
  void EmitSpectrumLine(const shim_spectrum_line_t& line);
247
250
  void StopSpectrumStreamInternal();
@@ -66,6 +66,19 @@ struct shim_list_adapter {
66
66
  void* user_data;
67
67
  };
68
68
 
69
+ struct shim_cfg_adapter {
70
+ RIG* rig;
71
+ shim_rig_cfg_cb_t user_cb;
72
+ void* user_data;
73
+ };
74
+
75
+ static void shim_copy_string(char* dest, size_t dest_size, const char* src) {
76
+ if (!dest || dest_size == 0) return;
77
+ if (!src) src = "";
78
+ strncpy(dest, src, dest_size - 1);
79
+ dest[dest_size - 1] = '\0';
80
+ }
81
+
69
82
  static int shim_list_foreach_adapter(const struct rig_caps *caps, void *data) {
70
83
  struct shim_list_adapter *adapter = (struct shim_list_adapter*)data;
71
84
  shim_rig_info_t info;
@@ -85,6 +98,137 @@ SHIM_API int shim_rig_list_foreach(shim_rig_list_cb_t cb, void* data) {
85
98
  return rig_list_foreach(shim_list_foreach_adapter, &adapter);
86
99
  }
87
100
 
101
+ static int shim_cfg_foreach_adapter(const struct confparams* param, rig_ptr_t data) {
102
+ struct shim_cfg_adapter* adapter = (struct shim_cfg_adapter*)data;
103
+ const struct confparams* lookup;
104
+ shim_confparam_info_t info;
105
+ int i;
106
+
107
+ if (!adapter || !adapter->user_cb || !param) {
108
+ return 0;
109
+ }
110
+
111
+ if (!adapter->rig || !param->name) {
112
+ return 1;
113
+ }
114
+
115
+ lookup = rig_confparam_lookup(adapter->rig, param->name);
116
+ if (!lookup || lookup->token != param->token) {
117
+ return 1;
118
+ }
119
+
120
+ memset(&info, 0, sizeof(info));
121
+ info.token = (int)param->token;
122
+ info.type = (int)param->type;
123
+
124
+ shim_copy_string(info.name, sizeof(info.name), param->name);
125
+ shim_copy_string(info.label, sizeof(info.label), param->label);
126
+ shim_copy_string(info.tooltip, sizeof(info.tooltip), param->tooltip);
127
+ shim_copy_string(info.dflt, sizeof(info.dflt), param->dflt);
128
+
129
+ if (param->type == RIG_CONF_NUMERIC || param->type == RIG_CONF_INT) {
130
+ info.numeric_min = param->u.n.min;
131
+ info.numeric_max = param->u.n.max;
132
+ info.numeric_step = param->u.n.step;
133
+ } else if (param->type == RIG_CONF_COMBO) {
134
+ for (i = 0; i < RIG_COMBO_MAX && i < SHIM_CONF_COMBO_MAX; ++i) {
135
+ if (!param->u.c.combostr[i] || !*param->u.c.combostr[i]) {
136
+ break;
137
+ }
138
+
139
+ shim_copy_string(
140
+ info.combo_options[i],
141
+ sizeof(info.combo_options[i]),
142
+ param->u.c.combostr[i]
143
+ );
144
+ info.combo_count++;
145
+ }
146
+ }
147
+
148
+ return adapter->user_cb(&info, adapter->user_data);
149
+ }
150
+
151
+ SHIM_API int shim_rig_cfgparams_foreach(hamlib_shim_handle_t h, shim_rig_cfg_cb_t cb, void* data) {
152
+ RIG* rig = (RIG*)h;
153
+ struct shim_cfg_adapter adapter;
154
+
155
+ if (!rig || !cb) {
156
+ return -RIG_EINVAL;
157
+ }
158
+
159
+ adapter.rig = rig;
160
+ adapter.user_cb = cb;
161
+ adapter.user_data = data;
162
+
163
+ return rig_token_foreach(rig, shim_cfg_foreach_adapter, &adapter);
164
+ }
165
+
166
+ static const char* shim_port_type_name(enum rig_port_e port_type) {
167
+ switch (port_type) {
168
+ case RIG_PORT_NONE: return "none";
169
+ case RIG_PORT_SERIAL: return "serial";
170
+ case RIG_PORT_NETWORK: return "network";
171
+ case RIG_PORT_DEVICE: return "device";
172
+ case RIG_PORT_PACKET: return "packet";
173
+ case RIG_PORT_DTMF: return "dtmf";
174
+ case RIG_PORT_ULTRA: return "ultra";
175
+ case RIG_PORT_RPC: return "rpc";
176
+ case RIG_PORT_PARALLEL: return "parallel";
177
+ case RIG_PORT_USB: return "usb";
178
+ case RIG_PORT_UDP_NETWORK: return "udp-network";
179
+ case RIG_PORT_CM108: return "cm108";
180
+ case RIG_PORT_GPIO: return "gpio";
181
+ case RIG_PORT_GPION: return "gpion";
182
+ default: return "other";
183
+ }
184
+ }
185
+
186
+ static const char* shim_serial_parity_name(enum serial_parity_e parity) {
187
+ switch (parity) {
188
+ case RIG_PARITY_NONE: return "None";
189
+ case RIG_PARITY_ODD: return "Odd";
190
+ case RIG_PARITY_EVEN: return "Even";
191
+ case RIG_PARITY_MARK: return "Mark";
192
+ case RIG_PARITY_SPACE: return "Space";
193
+ default: return "Unknown";
194
+ }
195
+ }
196
+
197
+ static const char* shim_serial_handshake_name(enum serial_handshake_e handshake) {
198
+ switch (handshake) {
199
+ case RIG_HANDSHAKE_NONE: return "None";
200
+ case RIG_HANDSHAKE_XONXOFF: return "XONXOFF";
201
+ case RIG_HANDSHAKE_HARDWARE: return "Hardware";
202
+ default: return "Unknown";
203
+ }
204
+ }
205
+
206
+ SHIM_API int shim_rig_get_port_caps(hamlib_shim_handle_t h, shim_rig_port_caps_t* out_caps) {
207
+ RIG* rig = (RIG*)h;
208
+ const struct rig_caps* caps;
209
+
210
+ if (!rig || !out_caps || !rig->caps) {
211
+ return -RIG_EINVAL;
212
+ }
213
+
214
+ caps = rig->caps;
215
+ memset(out_caps, 0, sizeof(*out_caps));
216
+
217
+ shim_copy_string(out_caps->port_type, sizeof(out_caps->port_type), shim_port_type_name(caps->port_type));
218
+ out_caps->serial_rate_min = caps->serial_rate_min;
219
+ out_caps->serial_rate_max = caps->serial_rate_max;
220
+ out_caps->serial_data_bits = caps->serial_data_bits;
221
+ out_caps->serial_stop_bits = caps->serial_stop_bits;
222
+ shim_copy_string(out_caps->serial_parity, sizeof(out_caps->serial_parity), shim_serial_parity_name(caps->serial_parity));
223
+ shim_copy_string(out_caps->serial_handshake, sizeof(out_caps->serial_handshake), shim_serial_handshake_name(caps->serial_handshake));
224
+ out_caps->write_delay = caps->write_delay;
225
+ out_caps->post_write_delay = caps->post_write_delay;
226
+ out_caps->timeout = caps->timeout;
227
+ out_caps->retry = caps->retry;
228
+
229
+ return RIG_OK;
230
+ }
231
+
88
232
  SHIM_API const char* shim_rig_strstatus(int status) {
89
233
  return rig_strstatus((enum rig_status_e)status);
90
234
  }
@@ -293,6 +293,44 @@ typedef struct {
293
293
  int rig_type;
294
294
  } shim_rig_info_t;
295
295
 
296
+ #define SHIM_CONF_NAME_MAX 64
297
+ #define SHIM_CONF_LABEL_MAX 128
298
+ #define SHIM_CONF_TOOLTIP_MAX 256
299
+ #define SHIM_CONF_DEFAULT_MAX 128
300
+ #define SHIM_CONF_COMBO_MAX 16
301
+ #define SHIM_CONF_COMBO_VALUE_MAX 64
302
+ #define SHIM_PORT_TYPE_MAX 32
303
+ #define SHIM_PARITY_MAX 32
304
+ #define SHIM_HANDSHAKE_MAX 32
305
+
306
+ typedef struct {
307
+ int token;
308
+ char name[SHIM_CONF_NAME_MAX];
309
+ char label[SHIM_CONF_LABEL_MAX];
310
+ char tooltip[SHIM_CONF_TOOLTIP_MAX];
311
+ char dflt[SHIM_CONF_DEFAULT_MAX];
312
+ int type;
313
+ double numeric_min;
314
+ double numeric_max;
315
+ double numeric_step;
316
+ int combo_count;
317
+ char combo_options[SHIM_CONF_COMBO_MAX][SHIM_CONF_COMBO_VALUE_MAX];
318
+ } shim_confparam_info_t;
319
+
320
+ typedef struct {
321
+ char port_type[SHIM_PORT_TYPE_MAX];
322
+ int serial_rate_min;
323
+ int serial_rate_max;
324
+ int serial_data_bits;
325
+ int serial_stop_bits;
326
+ char serial_parity[SHIM_PARITY_MAX];
327
+ char serial_handshake[SHIM_HANDSHAKE_MAX];
328
+ int write_delay;
329
+ int post_write_delay;
330
+ int timeout;
331
+ int retry;
332
+ } shim_rig_port_caps_t;
333
+
296
334
  typedef struct {
297
335
  int id;
298
336
  char name[64];
@@ -331,6 +369,8 @@ typedef int (*shim_spectrum_cb_t)(void* handle, const shim_spectrum_line_t* line
331
369
 
332
370
  /* Rig list callback: (info, data) -> int */
333
371
  typedef int (*shim_rig_list_cb_t)(const shim_rig_info_t* info, void* data);
372
+ /* Rig config callback: (info, data) -> int */
373
+ typedef int (*shim_rig_cfg_cb_t)(const shim_confparam_info_t* info, void* data);
334
374
 
335
375
  /* ===== Lifecycle functions ===== */
336
376
 
@@ -347,6 +387,8 @@ SHIM_API int shim_rig_get_debug(void);
347
387
  SHIM_API const char* shim_rig_get_version(void);
348
388
  SHIM_API int shim_rig_load_all_backends(void);
349
389
  SHIM_API int shim_rig_list_foreach(shim_rig_list_cb_t cb, void* data);
390
+ SHIM_API int shim_rig_cfgparams_foreach(hamlib_shim_handle_t h, shim_rig_cfg_cb_t cb, void* data);
391
+ SHIM_API int shim_rig_get_port_caps(hamlib_shim_handle_t h, shim_rig_port_caps_t* out_caps);
350
392
  SHIM_API const char* shim_rig_strstatus(int status);
351
393
 
352
394
  /* ===== Port configuration (before open) ===== */