hamlib 0.4.1 → 0.4.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/README.md +37 -1
- package/binding.gyp +1 -0
- package/index.d.ts +181 -4
- package/lib/index.js +164 -6
- package/lib/index.mjs +3 -3
- package/package.json +1 -1
- package/prebuilds/darwin-arm64/libhamlib.4.dylib +0 -0
- package/prebuilds/darwin-arm64/node.napi.node +0 -0
- package/prebuilds/darwin-x64/libhamlib.4.dylib +0 -0
- package/prebuilds/darwin-x64/node.napi.node +0 -0
- package/prebuilds/linux-arm64/libhamlib.so +0 -0
- package/prebuilds/linux-arm64/libhamlib.so.4 +0 -0
- package/prebuilds/linux-arm64/libhamlib.so.4.0.7 +0 -0
- package/prebuilds/linux-arm64/node.napi.node +0 -0
- package/prebuilds/linux-x64/libhamlib.so +0 -0
- package/prebuilds/linux-x64/libhamlib.so.4 +0 -0
- package/prebuilds/linux-x64/libhamlib.so.4.0.7 +0 -0
- package/prebuilds/linux-x64/node.napi.node +0 -0
- package/prebuilds/win32-x64/hamlib_shim.dll +0 -0
- package/prebuilds/win32-x64/node.napi.node +0 -0
- package/src/addon.cpp +5 -1
- package/src/hamlib.cpp +215 -24
- package/src/hamlib.h +3 -0
- package/src/node_rotator.cpp +1309 -0
- package/src/node_rotator.h +62 -0
- package/src/shim/hamlib_shim.c +547 -0
- package/src/shim/hamlib_shim.h +159 -2
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) {
|
|
@@ -64,6 +106,27 @@ static int parseVfoString(Napi::Env env, const std::string& vfoToken) {
|
|
|
64
106
|
return vfo;
|
|
65
107
|
}
|
|
66
108
|
|
|
109
|
+
static int antennaOrdinalToMask(Napi::Env env, int antennaOrdinal) {
|
|
110
|
+
if (antennaOrdinal < 1 || antennaOrdinal > 30) {
|
|
111
|
+
Napi::RangeError::New(env, "Antenna number must be between 1 and 30").ThrowAsJavaScriptException();
|
|
112
|
+
return 0;
|
|
113
|
+
}
|
|
114
|
+
return static_cast<int>(1u << (antennaOrdinal - 1));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
static int antennaMaskToOrdinal(int antennaMask) {
|
|
118
|
+
const uint32_t mask = static_cast<uint32_t>(antennaMask);
|
|
119
|
+
if (mask == 0 || (mask & (mask - 1)) != 0) {
|
|
120
|
+
return 0;
|
|
121
|
+
}
|
|
122
|
+
for (int bit = 0; bit < 30; ++bit) {
|
|
123
|
+
if (mask == (1u << bit)) {
|
|
124
|
+
return bit + 1;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return 0;
|
|
128
|
+
}
|
|
129
|
+
|
|
67
130
|
// Base AsyncWorker implementation with Promise support
|
|
68
131
|
HamLibAsyncWorker::HamLibAsyncWorker(Napi::Env env, NodeHamLib* hamlib_instance)
|
|
69
132
|
: AsyncWorker(env), hamlib_instance_(hamlib_instance), result_code_(0), error_message_(""), deferred_(Napi::Promise::Deferred::New(env)) {}
|
|
@@ -1188,9 +1251,9 @@ public:
|
|
|
1188
1251
|
} else {
|
|
1189
1252
|
Napi::Object result = Napi::Object::New(env);
|
|
1190
1253
|
|
|
1191
|
-
result.Set("currentAntenna", Napi::Number::New(env, antenna_curr_));
|
|
1192
|
-
result.Set("txAntenna", Napi::Number::New(env, antenna_tx_));
|
|
1193
|
-
result.Set("rxAntenna", Napi::Number::New(env, antenna_rx_));
|
|
1254
|
+
result.Set("currentAntenna", Napi::Number::New(env, antennaMaskToOrdinal(antenna_curr_)));
|
|
1255
|
+
result.Set("txAntenna", Napi::Number::New(env, antennaMaskToOrdinal(antenna_tx_)));
|
|
1256
|
+
result.Set("rxAntenna", Napi::Number::New(env, antennaMaskToOrdinal(antenna_rx_)));
|
|
1194
1257
|
result.Set("option", Napi::Number::New(env, option_));
|
|
1195
1258
|
|
|
1196
1259
|
deferred_.Resolve(result);
|
|
@@ -3726,18 +3789,39 @@ Napi::Value NodeHamLib::SetAntenna(const Napi::CallbackInfo & info) {
|
|
|
3726
3789
|
return env.Null();
|
|
3727
3790
|
}
|
|
3728
3791
|
|
|
3729
|
-
int
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
if (info.Length() >= 2 && info[1].IsString()) {
|
|
3734
|
-
vfo = parseVfoParameter(info, 1, SHIM_RIG_VFO_CURR);
|
|
3735
|
-
RETURN_NULL_IF_INVALID_VFO(vfo);
|
|
3792
|
+
const int antennaOrdinal = info[0].As<Napi::Number>().Int32Value();
|
|
3793
|
+
const int antenna = antennaOrdinalToMask(env, antennaOrdinal);
|
|
3794
|
+
if (antenna == 0) {
|
|
3795
|
+
return env.Null();
|
|
3736
3796
|
}
|
|
3737
|
-
|
|
3738
|
-
|
|
3797
|
+
|
|
3798
|
+
int vfo = SHIM_RIG_VFO_CURR;
|
|
3739
3799
|
float option = 0.0f;
|
|
3740
3800
|
|
|
3801
|
+
if (info.Length() >= 2) {
|
|
3802
|
+
if (info[1].IsNumber()) {
|
|
3803
|
+
option = info[1].As<Napi::Number>().FloatValue();
|
|
3804
|
+
if (info.Length() >= 3 && info[2].IsString()) {
|
|
3805
|
+
vfo = parseVfoParameter(info, 2, SHIM_RIG_VFO_CURR);
|
|
3806
|
+
RETURN_NULL_IF_INVALID_VFO(vfo);
|
|
3807
|
+
} else if (info.Length() >= 3 && !info[2].IsUndefined()) {
|
|
3808
|
+
Napi::TypeError::New(env, "Expected VFO token as third argument").ThrowAsJavaScriptException();
|
|
3809
|
+
return env.Null();
|
|
3810
|
+
}
|
|
3811
|
+
} else if (info[1].IsString()) {
|
|
3812
|
+
vfo = parseVfoParameter(info, 1, SHIM_RIG_VFO_CURR);
|
|
3813
|
+
RETURN_NULL_IF_INVALID_VFO(vfo);
|
|
3814
|
+
} else if (!info[1].IsUndefined()) {
|
|
3815
|
+
Napi::TypeError::New(env, "Expected antenna option as number or VFO token as string").ThrowAsJavaScriptException();
|
|
3816
|
+
return env.Null();
|
|
3817
|
+
}
|
|
3818
|
+
}
|
|
3819
|
+
|
|
3820
|
+
if (info.Length() >= 3 && info[1].IsString()) {
|
|
3821
|
+
Napi::TypeError::New(env, "Antenna option must come before VFO").ThrowAsJavaScriptException();
|
|
3822
|
+
return env.Null();
|
|
3823
|
+
}
|
|
3824
|
+
|
|
3741
3825
|
SetAntennaAsyncWorker* asyncWorker = new SetAntennaAsyncWorker(env, this, antenna, vfo, option);
|
|
3742
3826
|
asyncWorker->Queue();
|
|
3743
3827
|
return asyncWorker->GetPromise();
|
|
@@ -3832,6 +3916,8 @@ Napi::Function NodeHamLib::GetClass(Napi::Env env) {
|
|
|
3832
3916
|
NodeHamLib::InstanceMethod("setDcdType", & NodeHamLib::SetDcdType),
|
|
3833
3917
|
NodeHamLib::InstanceMethod("getDcdType", & NodeHamLib::GetDcdType),
|
|
3834
3918
|
NodeHamLib::InstanceMethod("getSupportedSerialConfigs", & NodeHamLib::GetSupportedSerialConfigs),
|
|
3919
|
+
NodeHamLib::InstanceMethod("getConfigSchema", & NodeHamLib::GetConfigSchema),
|
|
3920
|
+
NodeHamLib::InstanceMethod("getPortCaps", & NodeHamLib::GetPortCaps),
|
|
3835
3921
|
|
|
3836
3922
|
// Power Control
|
|
3837
3923
|
NodeHamLib::InstanceMethod("setPowerstat", & NodeHamLib::SetPowerstat),
|
|
@@ -4220,7 +4306,7 @@ Napi::Value NodeHamLib::GetSupportedSerialConfigs(const Napi::CallbackInfo& info
|
|
|
4220
4306
|
pttTypeOptions[5u] = Napi::String::New(env, "GPIO");
|
|
4221
4307
|
pttTypeOptions[6u] = Napi::String::New(env, "GPION");
|
|
4222
4308
|
pttTypeOptions[7u] = Napi::String::New(env, "NONE");
|
|
4223
|
-
configs.Set("
|
|
4309
|
+
configs.Set("ptt_type", pttTypeOptions);
|
|
4224
4310
|
|
|
4225
4311
|
// DCD type options
|
|
4226
4312
|
Napi::Array dcdTypeOptions = Napi::Array::New(env, 9);
|
|
@@ -4233,11 +4319,124 @@ Napi::Value NodeHamLib::GetSupportedSerialConfigs(const Napi::CallbackInfo& info
|
|
|
4233
4319
|
dcdTypeOptions[6u] = Napi::String::New(env, "GPIO");
|
|
4234
4320
|
dcdTypeOptions[7u] = Napi::String::New(env, "GPION");
|
|
4235
4321
|
dcdTypeOptions[8u] = Napi::String::New(env, "NONE");
|
|
4236
|
-
configs.Set("
|
|
4322
|
+
configs.Set("dcd_type", dcdTypeOptions);
|
|
4237
4323
|
|
|
4238
4324
|
return configs;
|
|
4239
4325
|
}
|
|
4240
4326
|
|
|
4327
|
+
int NodeHamLib::rig_config_callback(const shim_confparam_info_t* info, void* data) {
|
|
4328
|
+
RigConfigSchemaData* schema_data = static_cast<RigConfigSchemaData*>(data);
|
|
4329
|
+
|
|
4330
|
+
if (!schema_data || !info) {
|
|
4331
|
+
return 0;
|
|
4332
|
+
}
|
|
4333
|
+
|
|
4334
|
+
RigConfigFieldDescriptor field;
|
|
4335
|
+
field.token = info->token;
|
|
4336
|
+
field.name = info->name;
|
|
4337
|
+
field.label = info->label;
|
|
4338
|
+
field.tooltip = info->tooltip;
|
|
4339
|
+
field.defaultValue = info->dflt;
|
|
4340
|
+
field.type = info->type;
|
|
4341
|
+
field.numericMin = info->numeric_min;
|
|
4342
|
+
field.numericMax = info->numeric_max;
|
|
4343
|
+
field.numericStep = info->numeric_step;
|
|
4344
|
+
|
|
4345
|
+
for (int i = 0; i < info->combo_count; ++i) {
|
|
4346
|
+
field.options.emplace_back(info->combo_options[i]);
|
|
4347
|
+
}
|
|
4348
|
+
|
|
4349
|
+
schema_data->fields.push_back(field);
|
|
4350
|
+
return 1;
|
|
4351
|
+
}
|
|
4352
|
+
|
|
4353
|
+
Napi::Value NodeHamLib::GetConfigSchema(const Napi::CallbackInfo& info) {
|
|
4354
|
+
Napi::Env env = info.Env();
|
|
4355
|
+
RETURN_NULL_IF_RIG_HANDLE_INVALID();
|
|
4356
|
+
|
|
4357
|
+
RigConfigSchemaData schemaData{};
|
|
4358
|
+
int result = shim_rig_cfgparams_foreach(my_rig, rig_config_callback, &schemaData);
|
|
4359
|
+
|
|
4360
|
+
if (result != SHIM_RIG_OK) {
|
|
4361
|
+
Napi::Error::New(env, shim_rigerror(result)).ThrowAsJavaScriptException();
|
|
4362
|
+
return env.Null();
|
|
4363
|
+
}
|
|
4364
|
+
|
|
4365
|
+
Napi::Array schemaArray = Napi::Array::New(env, schemaData.fields.size());
|
|
4366
|
+
for (size_t i = 0; i < schemaData.fields.size(); ++i) {
|
|
4367
|
+
const RigConfigFieldDescriptor& descriptor = schemaData.fields[i];
|
|
4368
|
+
Napi::Object field = Napi::Object::New(env);
|
|
4369
|
+
field.Set("token", Napi::Number::New(env, descriptor.token));
|
|
4370
|
+
field.Set("name", Napi::String::New(env, descriptor.name));
|
|
4371
|
+
field.Set("label", Napi::String::New(env, descriptor.label));
|
|
4372
|
+
field.Set("tooltip", Napi::String::New(env, descriptor.tooltip));
|
|
4373
|
+
field.Set("defaultValue", Napi::String::New(env, descriptor.defaultValue));
|
|
4374
|
+
field.Set("type", Napi::String::New(env, publicConfTypeName(descriptor.type)));
|
|
4375
|
+
|
|
4376
|
+
if (descriptor.type == 2 || descriptor.type == 6) {
|
|
4377
|
+
Napi::Object numeric = Napi::Object::New(env);
|
|
4378
|
+
numeric.Set("min", Napi::Number::New(env, descriptor.numericMin));
|
|
4379
|
+
numeric.Set("max", Napi::Number::New(env, descriptor.numericMax));
|
|
4380
|
+
numeric.Set("step", Napi::Number::New(env, descriptor.numericStep));
|
|
4381
|
+
field.Set("numeric", numeric);
|
|
4382
|
+
}
|
|
4383
|
+
|
|
4384
|
+
if (!descriptor.options.empty()) {
|
|
4385
|
+
Napi::Array options = Napi::Array::New(env, descriptor.options.size());
|
|
4386
|
+
for (size_t optionIndex = 0; optionIndex < descriptor.options.size(); ++optionIndex) {
|
|
4387
|
+
options[static_cast<uint32_t>(optionIndex)] =
|
|
4388
|
+
Napi::String::New(env, descriptor.options[optionIndex]);
|
|
4389
|
+
}
|
|
4390
|
+
field.Set("options", options);
|
|
4391
|
+
}
|
|
4392
|
+
|
|
4393
|
+
schemaArray[static_cast<uint32_t>(i)] = field;
|
|
4394
|
+
}
|
|
4395
|
+
|
|
4396
|
+
return schemaArray;
|
|
4397
|
+
}
|
|
4398
|
+
|
|
4399
|
+
Napi::Value NodeHamLib::GetPortCaps(const Napi::CallbackInfo& info) {
|
|
4400
|
+
Napi::Env env = info.Env();
|
|
4401
|
+
RETURN_NULL_IF_RIG_HANDLE_INVALID();
|
|
4402
|
+
|
|
4403
|
+
shim_rig_port_caps_t caps{};
|
|
4404
|
+
int result = shim_rig_get_port_caps(my_rig, &caps);
|
|
4405
|
+
|
|
4406
|
+
if (result != SHIM_RIG_OK) {
|
|
4407
|
+
Napi::Error::New(env, shim_rigerror(result)).ThrowAsJavaScriptException();
|
|
4408
|
+
return env.Null();
|
|
4409
|
+
}
|
|
4410
|
+
|
|
4411
|
+
Napi::Object portCaps = Napi::Object::New(env);
|
|
4412
|
+
portCaps.Set("portType", Napi::String::New(env, caps.port_type));
|
|
4413
|
+
portCaps.Set("writeDelay", Napi::Number::New(env, caps.write_delay));
|
|
4414
|
+
portCaps.Set("postWriteDelay", Napi::Number::New(env, caps.post_write_delay));
|
|
4415
|
+
portCaps.Set("timeout", Napi::Number::New(env, caps.timeout));
|
|
4416
|
+
portCaps.Set("retry", Napi::Number::New(env, caps.retry));
|
|
4417
|
+
|
|
4418
|
+
if (hasPositiveValue(caps.serial_rate_min)) {
|
|
4419
|
+
portCaps.Set("serialRateMin", Napi::Number::New(env, caps.serial_rate_min));
|
|
4420
|
+
}
|
|
4421
|
+
if (hasPositiveValue(caps.serial_rate_max)) {
|
|
4422
|
+
portCaps.Set("serialRateMax", Napi::Number::New(env, caps.serial_rate_max));
|
|
4423
|
+
}
|
|
4424
|
+
if (hasPositiveValue(caps.serial_data_bits)) {
|
|
4425
|
+
portCaps.Set("serialDataBits", Napi::Number::New(env, caps.serial_data_bits));
|
|
4426
|
+
}
|
|
4427
|
+
if (hasPositiveValue(caps.serial_stop_bits)) {
|
|
4428
|
+
portCaps.Set("serialStopBits", Napi::Number::New(env, caps.serial_stop_bits));
|
|
4429
|
+
}
|
|
4430
|
+
if (caps.serial_parity[0] != '\0' && std::string(caps.serial_parity) != "Unknown") {
|
|
4431
|
+
portCaps.Set("serialParity", Napi::String::New(env, caps.serial_parity));
|
|
4432
|
+
}
|
|
4433
|
+
if (caps.serial_handshake[0] != '\0' && std::string(caps.serial_handshake) != "Unknown") {
|
|
4434
|
+
portCaps.Set("serialHandshake", Napi::String::New(env, caps.serial_handshake));
|
|
4435
|
+
}
|
|
4436
|
+
|
|
4437
|
+
return portCaps;
|
|
4438
|
+
}
|
|
4439
|
+
|
|
4241
4440
|
// Power Control Methods
|
|
4242
4441
|
Napi::Value NodeHamLib::SetPowerstat(const Napi::CallbackInfo& info) {
|
|
4243
4442
|
Napi::Env env = info.Env();
|
|
@@ -6156,11 +6355,7 @@ private:
|
|
|
6156
6355
|
|
|
6157
6356
|
Napi::Value NodeHamLib::SetConf(const Napi::CallbackInfo& info) {
|
|
6158
6357
|
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
|
-
}
|
|
6358
|
+
RETURN_NULL_IF_RIG_HANDLE_INVALID();
|
|
6164
6359
|
|
|
6165
6360
|
if (info.Length() < 2 || !info[0].IsString() || !info[1].IsString()) {
|
|
6166
6361
|
Napi::TypeError::New(env, "Expected (name: string, value: string)").ThrowAsJavaScriptException();
|
|
@@ -6212,11 +6407,7 @@ private:
|
|
|
6212
6407
|
|
|
6213
6408
|
Napi::Value NodeHamLib::GetConf(const Napi::CallbackInfo& info) {
|
|
6214
6409
|
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
|
-
}
|
|
6410
|
+
RETURN_NULL_IF_RIG_HANDLE_INVALID();
|
|
6220
6411
|
|
|
6221
6412
|
if (info.Length() < 1 || !info[0].IsString()) {
|
|
6222
6413
|
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();
|