hamlib 0.2.0 → 0.2.1

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/src/hamlib.cpp CHANGED
@@ -3701,6 +3701,46 @@ Napi::Function NodeHamLib::GetClass(Napi::Env env) {
3701
3701
  // Reset Function
3702
3702
  NodeHamLib::InstanceMethod("reset", & NodeHamLib::Reset),
3703
3703
 
3704
+ // Lock Mode (Hamlib >= 4.7.0)
3705
+ NodeHamLib::InstanceMethod("setLockMode", & NodeHamLib::SetLockMode),
3706
+ NodeHamLib::InstanceMethod("getLockMode", & NodeHamLib::GetLockMode),
3707
+
3708
+ // Clock (Hamlib >= 4.7.0)
3709
+ NodeHamLib::InstanceMethod("setClock", & NodeHamLib::SetClock),
3710
+ NodeHamLib::InstanceMethod("getClock", & NodeHamLib::GetClock),
3711
+
3712
+ // VFO Info (Hamlib >= 4.7.0)
3713
+ NodeHamLib::InstanceMethod("getVfoInfo", & NodeHamLib::GetVfoInfo),
3714
+
3715
+ // Rig Info / Raw / Conf (async)
3716
+ NodeHamLib::InstanceMethod("getInfo", & NodeHamLib::GetInfo),
3717
+ NodeHamLib::InstanceMethod("sendRaw", & NodeHamLib::SendRaw),
3718
+ NodeHamLib::InstanceMethod("setConf", & NodeHamLib::SetConf),
3719
+ NodeHamLib::InstanceMethod("getConf", & NodeHamLib::GetConf),
3720
+
3721
+ // Passband / Resolution (sync)
3722
+ NodeHamLib::InstanceMethod("getPassbandNormal", & NodeHamLib::GetPassbandNormal),
3723
+ NodeHamLib::InstanceMethod("getPassbandNarrow", & NodeHamLib::GetPassbandNarrow),
3724
+ NodeHamLib::InstanceMethod("getPassbandWide", & NodeHamLib::GetPassbandWide),
3725
+ NodeHamLib::InstanceMethod("getResolution", & NodeHamLib::GetResolution),
3726
+
3727
+ // Capability queries (sync)
3728
+ NodeHamLib::InstanceMethod("getSupportedParms", & NodeHamLib::GetSupportedParms),
3729
+ NodeHamLib::InstanceMethod("getSupportedVfoOps", & NodeHamLib::GetSupportedVfoOps),
3730
+ NodeHamLib::InstanceMethod("getSupportedScanTypes", & NodeHamLib::GetSupportedScanTypes),
3731
+
3732
+ // Capability queries - batch 2 (sync)
3733
+ NodeHamLib::InstanceMethod("getPreampValues", & NodeHamLib::GetPreampValues),
3734
+ NodeHamLib::InstanceMethod("getAttenuatorValues", & NodeHamLib::GetAttenuatorValues),
3735
+ NodeHamLib::InstanceMethod("getMaxRit", & NodeHamLib::GetMaxRit),
3736
+ NodeHamLib::InstanceMethod("getMaxXit", & NodeHamLib::GetMaxXit),
3737
+ NodeHamLib::InstanceMethod("getMaxIfShift", & NodeHamLib::GetMaxIfShift),
3738
+ NodeHamLib::InstanceMethod("getAvailableCtcssTones", & NodeHamLib::GetAvailableCtcssTones),
3739
+ NodeHamLib::InstanceMethod("getAvailableDcsCodes", & NodeHamLib::GetAvailableDcsCodes),
3740
+ NodeHamLib::InstanceMethod("getFrequencyRanges", & NodeHamLib::GetFrequencyRanges),
3741
+ NodeHamLib::InstanceMethod("getTuningSteps", & NodeHamLib::GetTuningSteps),
3742
+ NodeHamLib::InstanceMethod("getFilterList", & NodeHamLib::GetFilterList),
3743
+
3704
3744
  NodeHamLib::InstanceMethod("close", & NodeHamLib::Close),
3705
3745
  NodeHamLib::InstanceMethod("destroy", & NodeHamLib::Destroy),
3706
3746
  NodeHamLib::InstanceMethod("getConnectionInfo", & NodeHamLib::GetConnectionInfo),
@@ -3710,6 +3750,8 @@ Napi::Function NodeHamLib::GetClass(Napi::Env env) {
3710
3750
  NodeHamLib::StaticMethod("getHamlibVersion", & NodeHamLib::GetHamlibVersion),
3711
3751
  NodeHamLib::StaticMethod("setDebugLevel", & NodeHamLib::SetDebugLevel),
3712
3752
  NodeHamLib::StaticMethod("getDebugLevel", & NodeHamLib::GetDebugLevel),
3753
+ NodeHamLib::StaticMethod("getCopyright", & NodeHamLib::GetCopyright),
3754
+ NodeHamLib::StaticMethod("getLicense", & NodeHamLib::GetLicense),
3713
3755
  });
3714
3756
  constructor = Napi::Persistent(ret);
3715
3757
  constructor.SuppressDestruct();
@@ -5358,3 +5400,774 @@ Napi::Value NodeHamLib::Reset(const Napi::CallbackInfo& info) {
5358
5400
  asyncWorker->Queue();
5359
5401
  return asyncWorker->GetPromise();
5360
5402
  }
5403
+
5404
+ // ===== Lock Mode (Hamlib >= 4.7.0) =====
5405
+
5406
+ class SetLockModeAsyncWorker : public HamLibAsyncWorker {
5407
+ public:
5408
+ SetLockModeAsyncWorker(Napi::Env env, NodeHamLib* hamlib_instance, int lock)
5409
+ : HamLibAsyncWorker(env, hamlib_instance), lock_(lock) {}
5410
+
5411
+ void Execute() override {
5412
+ CHECK_RIG_VALID();
5413
+ result_code_ = shim_rig_set_lock_mode(hamlib_instance_->my_rig, lock_);
5414
+ if (result_code_ != SHIM_RIG_OK) {
5415
+ error_message_ = shim_rigerror(result_code_);
5416
+ }
5417
+ }
5418
+
5419
+ void OnOK() override {
5420
+ Napi::Env env = Env();
5421
+ if (result_code_ != SHIM_RIG_OK && !error_message_.empty()) {
5422
+ deferred_.Reject(Napi::Error::New(env, error_message_).Value());
5423
+ } else {
5424
+ deferred_.Resolve(Napi::Number::New(env, result_code_));
5425
+ }
5426
+ }
5427
+
5428
+ void OnError(const Napi::Error& e) override {
5429
+ deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
5430
+ }
5431
+
5432
+ private:
5433
+ int lock_;
5434
+ };
5435
+
5436
+ class GetLockModeAsyncWorker : public HamLibAsyncWorker {
5437
+ public:
5438
+ GetLockModeAsyncWorker(Napi::Env env, NodeHamLib* hamlib_instance)
5439
+ : HamLibAsyncWorker(env, hamlib_instance), lock_(0) {}
5440
+
5441
+ void Execute() override {
5442
+ CHECK_RIG_VALID();
5443
+ result_code_ = shim_rig_get_lock_mode(hamlib_instance_->my_rig, &lock_);
5444
+ if (result_code_ != SHIM_RIG_OK) {
5445
+ error_message_ = shim_rigerror(result_code_);
5446
+ }
5447
+ }
5448
+
5449
+ void OnOK() override {
5450
+ Napi::Env env = Env();
5451
+ if (result_code_ != SHIM_RIG_OK && !error_message_.empty()) {
5452
+ deferred_.Reject(Napi::Error::New(env, error_message_).Value());
5453
+ } else {
5454
+ deferred_.Resolve(Napi::Number::New(env, lock_));
5455
+ }
5456
+ }
5457
+
5458
+ void OnError(const Napi::Error& e) override {
5459
+ deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
5460
+ }
5461
+
5462
+ private:
5463
+ int lock_;
5464
+ };
5465
+
5466
+ Napi::Value NodeHamLib::SetLockMode(const Napi::CallbackInfo& info) {
5467
+ Napi::Env env = info.Env();
5468
+
5469
+ if (info.Length() < 1 || !info[0].IsNumber()) {
5470
+ Napi::TypeError::New(env, "Expected lock mode as number").ThrowAsJavaScriptException();
5471
+ return env.Null();
5472
+ }
5473
+
5474
+ int lock = info[0].As<Napi::Number>().Int32Value();
5475
+
5476
+ SetLockModeAsyncWorker* asyncWorker = new SetLockModeAsyncWorker(env, this, lock);
5477
+ asyncWorker->Queue();
5478
+ return asyncWorker->GetPromise();
5479
+ }
5480
+
5481
+ Napi::Value NodeHamLib::GetLockMode(const Napi::CallbackInfo& info) {
5482
+ Napi::Env env = info.Env();
5483
+
5484
+ GetLockModeAsyncWorker* asyncWorker = new GetLockModeAsyncWorker(env, this);
5485
+ asyncWorker->Queue();
5486
+ return asyncWorker->GetPromise();
5487
+ }
5488
+
5489
+ // ===== Clock (Hamlib >= 4.7.0) =====
5490
+
5491
+ class SetClockAsyncWorker : public HamLibAsyncWorker {
5492
+ public:
5493
+ SetClockAsyncWorker(Napi::Env env, NodeHamLib* hamlib_instance,
5494
+ int year, int month, int day,
5495
+ int hour, int min, int sec, double msec, int utc_offset)
5496
+ : HamLibAsyncWorker(env, hamlib_instance),
5497
+ year_(year), month_(month), day_(day),
5498
+ hour_(hour), min_(min), sec_(sec), msec_(msec), utc_offset_(utc_offset) {}
5499
+
5500
+ void Execute() override {
5501
+ CHECK_RIG_VALID();
5502
+ result_code_ = shim_rig_set_clock(hamlib_instance_->my_rig,
5503
+ year_, month_, day_,
5504
+ hour_, min_, sec_, msec_, utc_offset_);
5505
+ if (result_code_ != SHIM_RIG_OK) {
5506
+ error_message_ = shim_rigerror(result_code_);
5507
+ }
5508
+ }
5509
+
5510
+ void OnOK() override {
5511
+ Napi::Env env = Env();
5512
+ if (result_code_ != SHIM_RIG_OK && !error_message_.empty()) {
5513
+ deferred_.Reject(Napi::Error::New(env, error_message_).Value());
5514
+ } else {
5515
+ deferred_.Resolve(Napi::Number::New(env, result_code_));
5516
+ }
5517
+ }
5518
+
5519
+ void OnError(const Napi::Error& e) override {
5520
+ deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
5521
+ }
5522
+
5523
+ private:
5524
+ int year_, month_, day_, hour_, min_, sec_;
5525
+ double msec_;
5526
+ int utc_offset_;
5527
+ };
5528
+
5529
+ class GetClockAsyncWorker : public HamLibAsyncWorker {
5530
+ public:
5531
+ GetClockAsyncWorker(Napi::Env env, NodeHamLib* hamlib_instance)
5532
+ : HamLibAsyncWorker(env, hamlib_instance),
5533
+ year_(0), month_(0), day_(0),
5534
+ hour_(0), min_(0), sec_(0), msec_(0.0), utc_offset_(0) {}
5535
+
5536
+ void Execute() override {
5537
+ CHECK_RIG_VALID();
5538
+ result_code_ = shim_rig_get_clock(hamlib_instance_->my_rig,
5539
+ &year_, &month_, &day_,
5540
+ &hour_, &min_, &sec_, &msec_, &utc_offset_);
5541
+ if (result_code_ != SHIM_RIG_OK) {
5542
+ error_message_ = shim_rigerror(result_code_);
5543
+ }
5544
+ }
5545
+
5546
+ void OnOK() override {
5547
+ Napi::Env env = Env();
5548
+ if (result_code_ != SHIM_RIG_OK && !error_message_.empty()) {
5549
+ deferred_.Reject(Napi::Error::New(env, error_message_).Value());
5550
+ } else {
5551
+ Napi::Object obj = Napi::Object::New(env);
5552
+ obj.Set("year", Napi::Number::New(env, year_));
5553
+ obj.Set("month", Napi::Number::New(env, month_));
5554
+ obj.Set("day", Napi::Number::New(env, day_));
5555
+ obj.Set("hour", Napi::Number::New(env, hour_));
5556
+ obj.Set("min", Napi::Number::New(env, min_));
5557
+ obj.Set("sec", Napi::Number::New(env, sec_));
5558
+ obj.Set("msec", Napi::Number::New(env, msec_));
5559
+ obj.Set("utcOffset", Napi::Number::New(env, utc_offset_));
5560
+ deferred_.Resolve(obj);
5561
+ }
5562
+ }
5563
+
5564
+ void OnError(const Napi::Error& e) override {
5565
+ deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
5566
+ }
5567
+
5568
+ private:
5569
+ int year_, month_, day_, hour_, min_, sec_;
5570
+ double msec_;
5571
+ int utc_offset_;
5572
+ };
5573
+
5574
+ Napi::Value NodeHamLib::SetClock(const Napi::CallbackInfo& info) {
5575
+ Napi::Env env = info.Env();
5576
+
5577
+ if (info.Length() < 1 || !info[0].IsObject()) {
5578
+ Napi::TypeError::New(env, "Expected clock object with year, month, day, hour, min, sec, msec, utcOffset").ThrowAsJavaScriptException();
5579
+ return env.Null();
5580
+ }
5581
+
5582
+ Napi::Object obj = info[0].As<Napi::Object>();
5583
+
5584
+ auto getInt = [&](const char* key, int defaultVal) -> int {
5585
+ if (obj.Has(key) && obj.Get(key).IsNumber()) {
5586
+ return obj.Get(key).As<Napi::Number>().Int32Value();
5587
+ }
5588
+ return defaultVal;
5589
+ };
5590
+ auto getDouble = [&](const char* key, double defaultVal) -> double {
5591
+ if (obj.Has(key) && obj.Get(key).IsNumber()) {
5592
+ return obj.Get(key).As<Napi::Number>().DoubleValue();
5593
+ }
5594
+ return defaultVal;
5595
+ };
5596
+
5597
+ int year = getInt("year", 0);
5598
+ int month = getInt("month", 0);
5599
+ int day = getInt("day", 0);
5600
+ int hour = getInt("hour", 0);
5601
+ int min = getInt("min", 0);
5602
+ int sec = getInt("sec", 0);
5603
+ double msec = getDouble("msec", 0.0);
5604
+ int utcOffset = getInt("utcOffset", 0);
5605
+
5606
+ SetClockAsyncWorker* asyncWorker = new SetClockAsyncWorker(env, this,
5607
+ year, month, day, hour, min, sec, msec, utcOffset);
5608
+ asyncWorker->Queue();
5609
+ return asyncWorker->GetPromise();
5610
+ }
5611
+
5612
+ Napi::Value NodeHamLib::GetClock(const Napi::CallbackInfo& info) {
5613
+ Napi::Env env = info.Env();
5614
+
5615
+ GetClockAsyncWorker* asyncWorker = new GetClockAsyncWorker(env, this);
5616
+ asyncWorker->Queue();
5617
+ return asyncWorker->GetPromise();
5618
+ }
5619
+
5620
+ // ===== VFO Info (Hamlib >= 4.7.0) =====
5621
+
5622
+ class GetVfoInfoAsyncWorker : public HamLibAsyncWorker {
5623
+ public:
5624
+ GetVfoInfoAsyncWorker(Napi::Env env, NodeHamLib* hamlib_instance, int vfo)
5625
+ : HamLibAsyncWorker(env, hamlib_instance),
5626
+ vfo_(vfo), freq_(0.0), mode_(0), width_(0), split_(0), satmode_(0) {}
5627
+
5628
+ void Execute() override {
5629
+ CHECK_RIG_VALID();
5630
+ result_code_ = shim_rig_get_vfo_info(hamlib_instance_->my_rig, vfo_,
5631
+ &freq_, &mode_, &width_, &split_, &satmode_);
5632
+ if (result_code_ != SHIM_RIG_OK) {
5633
+ error_message_ = shim_rigerror(result_code_);
5634
+ }
5635
+ }
5636
+
5637
+ void OnOK() override {
5638
+ Napi::Env env = Env();
5639
+ if (result_code_ != SHIM_RIG_OK && !error_message_.empty()) {
5640
+ deferred_.Reject(Napi::Error::New(env, error_message_).Value());
5641
+ } else {
5642
+ Napi::Object obj = Napi::Object::New(env);
5643
+ obj.Set("frequency", Napi::Number::New(env, freq_));
5644
+ obj.Set("mode", Napi::String::New(env, shim_rig_strrmode(static_cast<int>(mode_))));
5645
+ obj.Set("bandwidth", Napi::Number::New(env, static_cast<double>(width_)));
5646
+ obj.Set("split", Napi::Boolean::New(env, split_ != 0));
5647
+ obj.Set("satMode", Napi::Boolean::New(env, satmode_ != 0));
5648
+ deferred_.Resolve(obj);
5649
+ }
5650
+ }
5651
+
5652
+ void OnError(const Napi::Error& e) override {
5653
+ deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
5654
+ }
5655
+
5656
+ private:
5657
+ int vfo_;
5658
+ double freq_;
5659
+ uint64_t mode_;
5660
+ long width_;
5661
+ int split_;
5662
+ int satmode_;
5663
+ };
5664
+
5665
+ Napi::Value NodeHamLib::GetVfoInfo(const Napi::CallbackInfo& info) {
5666
+ Napi::Env env = info.Env();
5667
+
5668
+ int vfo = parseVfoParameter(info, 0, SHIM_RIG_VFO_CURR);
5669
+
5670
+ GetVfoInfoAsyncWorker* asyncWorker = new GetVfoInfoAsyncWorker(env, this, vfo);
5671
+ asyncWorker->Queue();
5672
+ return asyncWorker->GetPromise();
5673
+ }
5674
+
5675
+ // ===== GetInfo (async) =====
5676
+
5677
+ class GetInfoAsyncWorker : public HamLibAsyncWorker {
5678
+ public:
5679
+ GetInfoAsyncWorker(Napi::Env env, NodeHamLib* hamlib_instance)
5680
+ : HamLibAsyncWorker(env, hamlib_instance) {}
5681
+
5682
+ void Execute() override {
5683
+ CHECK_RIG_VALID();
5684
+ const char* info = shim_rig_get_info(hamlib_instance_->my_rig);
5685
+ info_str_ = info ? info : "";
5686
+ }
5687
+
5688
+ void OnOK() override {
5689
+ Napi::Env env = Env();
5690
+ deferred_.Resolve(Napi::String::New(env, info_str_));
5691
+ }
5692
+
5693
+ void OnError(const Napi::Error& e) override {
5694
+ deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
5695
+ }
5696
+
5697
+ private:
5698
+ std::string info_str_;
5699
+ };
5700
+
5701
+ Napi::Value NodeHamLib::GetInfo(const Napi::CallbackInfo& info) {
5702
+ Napi::Env env = info.Env();
5703
+
5704
+ if (!rig_is_open) {
5705
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
5706
+ return env.Null();
5707
+ }
5708
+
5709
+ GetInfoAsyncWorker* asyncWorker = new GetInfoAsyncWorker(env, this);
5710
+ asyncWorker->Queue();
5711
+ return asyncWorker->GetPromise();
5712
+ }
5713
+
5714
+ // ===== SendRaw (async) =====
5715
+
5716
+ class SendRawAsyncWorker : public HamLibAsyncWorker {
5717
+ public:
5718
+ SendRawAsyncWorker(Napi::Env env, NodeHamLib* hamlib_instance,
5719
+ std::vector<unsigned char> send_data, int reply_max_len,
5720
+ std::vector<unsigned char> terminator, bool has_terminator)
5721
+ : HamLibAsyncWorker(env, hamlib_instance),
5722
+ send_data_(std::move(send_data)), reply_max_len_(reply_max_len),
5723
+ terminator_(std::move(terminator)), has_terminator_(has_terminator),
5724
+ reply_len_(0) {
5725
+ reply_buf_.resize(reply_max_len > 0 ? reply_max_len : 1);
5726
+ }
5727
+
5728
+ void Execute() override {
5729
+ CHECK_RIG_VALID();
5730
+ const unsigned char* term = has_terminator_ ? terminator_.data() : nullptr;
5731
+ result_code_ = shim_rig_send_raw(hamlib_instance_->my_rig,
5732
+ send_data_.data(), (int)send_data_.size(),
5733
+ reply_buf_.data(), reply_max_len_, term);
5734
+ if (result_code_ < 0) {
5735
+ error_message_ = shim_rigerror(result_code_);
5736
+ } else {
5737
+ reply_len_ = result_code_;
5738
+ result_code_ = SHIM_RIG_OK;
5739
+ }
5740
+ }
5741
+
5742
+ void OnOK() override {
5743
+ Napi::Env env = Env();
5744
+ if (!error_message_.empty()) {
5745
+ deferred_.Reject(Napi::Error::New(env, error_message_).Value());
5746
+ } else {
5747
+ deferred_.Resolve(Napi::Buffer<unsigned char>::Copy(env, reply_buf_.data(), reply_len_));
5748
+ }
5749
+ }
5750
+
5751
+ void OnError(const Napi::Error& e) override {
5752
+ deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
5753
+ }
5754
+
5755
+ private:
5756
+ std::vector<unsigned char> send_data_;
5757
+ int reply_max_len_;
5758
+ std::vector<unsigned char> terminator_;
5759
+ bool has_terminator_;
5760
+ std::vector<unsigned char> reply_buf_;
5761
+ int reply_len_;
5762
+ };
5763
+
5764
+ Napi::Value NodeHamLib::SendRaw(const Napi::CallbackInfo& info) {
5765
+ Napi::Env env = info.Env();
5766
+
5767
+ if (!rig_is_open) {
5768
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
5769
+ return env.Null();
5770
+ }
5771
+
5772
+ if (info.Length() < 2 || !info[0].IsBuffer() || !info[1].IsNumber()) {
5773
+ Napi::TypeError::New(env, "Expected (data: Buffer, replyMaxLen: number, terminator?: Buffer)").ThrowAsJavaScriptException();
5774
+ return env.Null();
5775
+ }
5776
+
5777
+ Napi::Buffer<unsigned char> dataBuf = info[0].As<Napi::Buffer<unsigned char>>();
5778
+ std::vector<unsigned char> send_data(dataBuf.Data(), dataBuf.Data() + dataBuf.Length());
5779
+ int replyMaxLen = info[1].As<Napi::Number>().Int32Value();
5780
+
5781
+ std::vector<unsigned char> terminator;
5782
+ bool has_terminator = false;
5783
+ if (info.Length() >= 3 && info[2].IsBuffer()) {
5784
+ Napi::Buffer<unsigned char> termBuf = info[2].As<Napi::Buffer<unsigned char>>();
5785
+ terminator.assign(termBuf.Data(), termBuf.Data() + termBuf.Length());
5786
+ has_terminator = true;
5787
+ }
5788
+
5789
+ SendRawAsyncWorker* asyncWorker = new SendRawAsyncWorker(env, this, std::move(send_data), replyMaxLen, std::move(terminator), has_terminator);
5790
+ asyncWorker->Queue();
5791
+ return asyncWorker->GetPromise();
5792
+ }
5793
+
5794
+ // ===== SetConf (async) =====
5795
+
5796
+ class SetConfAsyncWorker : public HamLibAsyncWorker {
5797
+ public:
5798
+ SetConfAsyncWorker(Napi::Env env, NodeHamLib* hamlib_instance,
5799
+ std::string name, std::string value)
5800
+ : HamLibAsyncWorker(env, hamlib_instance),
5801
+ name_(std::move(name)), value_(std::move(value)) {}
5802
+
5803
+ void Execute() override {
5804
+ CHECK_RIG_VALID();
5805
+ result_code_ = shim_rig_set_conf(hamlib_instance_->my_rig, name_.c_str(), value_.c_str());
5806
+ if (result_code_ != SHIM_RIG_OK) {
5807
+ error_message_ = shim_rigerror(result_code_);
5808
+ }
5809
+ }
5810
+
5811
+ void OnOK() override {
5812
+ Napi::Env env = Env();
5813
+ if (result_code_ != SHIM_RIG_OK && !error_message_.empty()) {
5814
+ deferred_.Reject(Napi::Error::New(env, error_message_).Value());
5815
+ } else {
5816
+ deferred_.Resolve(Napi::Number::New(env, result_code_));
5817
+ }
5818
+ }
5819
+
5820
+ void OnError(const Napi::Error& e) override {
5821
+ deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
5822
+ }
5823
+
5824
+ private:
5825
+ std::string name_;
5826
+ std::string value_;
5827
+ };
5828
+
5829
+ Napi::Value NodeHamLib::SetConf(const Napi::CallbackInfo& info) {
5830
+ Napi::Env env = info.Env();
5831
+
5832
+ if (!rig_is_open) {
5833
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
5834
+ return env.Null();
5835
+ }
5836
+
5837
+ if (info.Length() < 2 || !info[0].IsString() || !info[1].IsString()) {
5838
+ Napi::TypeError::New(env, "Expected (name: string, value: string)").ThrowAsJavaScriptException();
5839
+ return env.Null();
5840
+ }
5841
+
5842
+ std::string name = info[0].As<Napi::String>().Utf8Value();
5843
+ std::string value = info[1].As<Napi::String>().Utf8Value();
5844
+
5845
+ SetConfAsyncWorker* asyncWorker = new SetConfAsyncWorker(env, this, std::move(name), std::move(value));
5846
+ asyncWorker->Queue();
5847
+ return asyncWorker->GetPromise();
5848
+ }
5849
+
5850
+ // ===== GetConf (async) =====
5851
+
5852
+ class GetConfAsyncWorker : public HamLibAsyncWorker {
5853
+ public:
5854
+ GetConfAsyncWorker(Napi::Env env, NodeHamLib* hamlib_instance, std::string name)
5855
+ : HamLibAsyncWorker(env, hamlib_instance), name_(std::move(name)) {
5856
+ memset(buf_, 0, sizeof(buf_));
5857
+ }
5858
+
5859
+ void Execute() override {
5860
+ CHECK_RIG_VALID();
5861
+ result_code_ = shim_rig_get_conf(hamlib_instance_->my_rig, name_.c_str(), buf_, sizeof(buf_));
5862
+ if (result_code_ != SHIM_RIG_OK) {
5863
+ error_message_ = shim_rigerror(result_code_);
5864
+ }
5865
+ }
5866
+
5867
+ void OnOK() override {
5868
+ Napi::Env env = Env();
5869
+ if (result_code_ != SHIM_RIG_OK && !error_message_.empty()) {
5870
+ deferred_.Reject(Napi::Error::New(env, error_message_).Value());
5871
+ } else {
5872
+ deferred_.Resolve(Napi::String::New(env, buf_));
5873
+ }
5874
+ }
5875
+
5876
+ void OnError(const Napi::Error& e) override {
5877
+ deferred_.Reject(Napi::Error::New(Env(), error_message_).Value());
5878
+ }
5879
+
5880
+ private:
5881
+ std::string name_;
5882
+ char buf_[256];
5883
+ };
5884
+
5885
+ Napi::Value NodeHamLib::GetConf(const Napi::CallbackInfo& info) {
5886
+ Napi::Env env = info.Env();
5887
+
5888
+ if (!rig_is_open) {
5889
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
5890
+ return env.Null();
5891
+ }
5892
+
5893
+ if (info.Length() < 1 || !info[0].IsString()) {
5894
+ Napi::TypeError::New(env, "Expected (name: string)").ThrowAsJavaScriptException();
5895
+ return env.Null();
5896
+ }
5897
+
5898
+ std::string name = info[0].As<Napi::String>().Utf8Value();
5899
+
5900
+ GetConfAsyncWorker* asyncWorker = new GetConfAsyncWorker(env, this, std::move(name));
5901
+ asyncWorker->Queue();
5902
+ return asyncWorker->GetPromise();
5903
+ }
5904
+
5905
+ // ===== Passband methods (sync) =====
5906
+
5907
+ Napi::Value NodeHamLib::GetPassbandNormal(const Napi::CallbackInfo& info) {
5908
+ Napi::Env env = info.Env();
5909
+
5910
+ if (info.Length() < 1 || !info[0].IsString()) {
5911
+ Napi::TypeError::New(env, "Expected (mode: string)").ThrowAsJavaScriptException();
5912
+ return env.Null();
5913
+ }
5914
+
5915
+ std::string modeStr = info[0].As<Napi::String>().Utf8Value();
5916
+ int mode = shim_rig_parse_mode(modeStr.c_str());
5917
+ int pb = shim_rig_passband_normal(my_rig, mode);
5918
+ return Napi::Number::New(env, pb);
5919
+ }
5920
+
5921
+ Napi::Value NodeHamLib::GetPassbandNarrow(const Napi::CallbackInfo& info) {
5922
+ Napi::Env env = info.Env();
5923
+
5924
+ if (info.Length() < 1 || !info[0].IsString()) {
5925
+ Napi::TypeError::New(env, "Expected (mode: string)").ThrowAsJavaScriptException();
5926
+ return env.Null();
5927
+ }
5928
+
5929
+ std::string modeStr = info[0].As<Napi::String>().Utf8Value();
5930
+ int mode = shim_rig_parse_mode(modeStr.c_str());
5931
+ int pb = shim_rig_passband_narrow(my_rig, mode);
5932
+ return Napi::Number::New(env, pb);
5933
+ }
5934
+
5935
+ Napi::Value NodeHamLib::GetPassbandWide(const Napi::CallbackInfo& info) {
5936
+ Napi::Env env = info.Env();
5937
+
5938
+ if (info.Length() < 1 || !info[0].IsString()) {
5939
+ Napi::TypeError::New(env, "Expected (mode: string)").ThrowAsJavaScriptException();
5940
+ return env.Null();
5941
+ }
5942
+
5943
+ std::string modeStr = info[0].As<Napi::String>().Utf8Value();
5944
+ int mode = shim_rig_parse_mode(modeStr.c_str());
5945
+ int pb = shim_rig_passband_wide(my_rig, mode);
5946
+ return Napi::Number::New(env, pb);
5947
+ }
5948
+
5949
+ // ===== Resolution (sync) =====
5950
+
5951
+ Napi::Value NodeHamLib::GetResolution(const Napi::CallbackInfo& info) {
5952
+ Napi::Env env = info.Env();
5953
+
5954
+ if (info.Length() < 1 || !info[0].IsString()) {
5955
+ Napi::TypeError::New(env, "Expected (mode: string)").ThrowAsJavaScriptException();
5956
+ return env.Null();
5957
+ }
5958
+
5959
+ std::string modeStr = info[0].As<Napi::String>().Utf8Value();
5960
+ int mode = shim_rig_parse_mode(modeStr.c_str());
5961
+ int res = shim_rig_get_resolution(my_rig, mode);
5962
+ return Napi::Number::New(env, res);
5963
+ }
5964
+
5965
+ // ===== getSupportedParms (sync) =====
5966
+
5967
+ Napi::Value NodeHamLib::GetSupportedParms(const Napi::CallbackInfo& info) {
5968
+ Napi::Env env = info.Env();
5969
+
5970
+ uint64_t parms = shim_rig_get_caps_has_get_parm(my_rig) | shim_rig_get_caps_has_set_parm(my_rig);
5971
+ Napi::Array parmArray = Napi::Array::New(env);
5972
+ uint32_t index = 0;
5973
+
5974
+ if (parms & SHIM_RIG_PARM_ANN) parmArray[index++] = Napi::String::New(env, "ANN");
5975
+ if (parms & SHIM_RIG_PARM_APO) parmArray[index++] = Napi::String::New(env, "APO");
5976
+ if (parms & SHIM_RIG_PARM_BACKLIGHT) parmArray[index++] = Napi::String::New(env, "BACKLIGHT");
5977
+ if (parms & SHIM_RIG_PARM_BEEP) parmArray[index++] = Napi::String::New(env, "BEEP");
5978
+ if (parms & SHIM_RIG_PARM_TIME) parmArray[index++] = Napi::String::New(env, "TIME");
5979
+ if (parms & SHIM_RIG_PARM_BAT) parmArray[index++] = Napi::String::New(env, "BAT");
5980
+ if (parms & SHIM_RIG_PARM_KEYLIGHT) parmArray[index++] = Napi::String::New(env, "KEYLIGHT");
5981
+ if (parms & SHIM_RIG_PARM_SCREENSAVER) parmArray[index++] = Napi::String::New(env, "SCREENSAVER");
5982
+
5983
+ return parmArray;
5984
+ }
5985
+
5986
+ // ===== getSupportedVfoOps (sync) =====
5987
+
5988
+ Napi::Value NodeHamLib::GetSupportedVfoOps(const Napi::CallbackInfo& info) {
5989
+ Napi::Env env = info.Env();
5990
+
5991
+ int ops = shim_rig_get_caps_vfo_ops(my_rig);
5992
+ Napi::Array opsArray = Napi::Array::New(env);
5993
+ uint32_t index = 0;
5994
+
5995
+ if (ops & SHIM_RIG_OP_CPY) opsArray[index++] = Napi::String::New(env, "CPY");
5996
+ if (ops & SHIM_RIG_OP_XCHG) opsArray[index++] = Napi::String::New(env, "XCHG");
5997
+ if (ops & SHIM_RIG_OP_FROM_VFO) opsArray[index++] = Napi::String::New(env, "FROM_VFO");
5998
+ if (ops & SHIM_RIG_OP_TO_VFO) opsArray[index++] = Napi::String::New(env, "TO_VFO");
5999
+ if (ops & SHIM_RIG_OP_MCL) opsArray[index++] = Napi::String::New(env, "MCL");
6000
+ if (ops & SHIM_RIG_OP_UP) opsArray[index++] = Napi::String::New(env, "UP");
6001
+ if (ops & SHIM_RIG_OP_DOWN) opsArray[index++] = Napi::String::New(env, "DOWN");
6002
+ if (ops & SHIM_RIG_OP_BAND_UP) opsArray[index++] = Napi::String::New(env, "BAND_UP");
6003
+ if (ops & SHIM_RIG_OP_BAND_DOWN) opsArray[index++] = Napi::String::New(env, "BAND_DOWN");
6004
+ if (ops & SHIM_RIG_OP_LEFT) opsArray[index++] = Napi::String::New(env, "LEFT");
6005
+ if (ops & SHIM_RIG_OP_RIGHT) opsArray[index++] = Napi::String::New(env, "RIGHT");
6006
+ if (ops & SHIM_RIG_OP_TUNE) opsArray[index++] = Napi::String::New(env, "TUNE");
6007
+ if (ops & SHIM_RIG_OP_TOGGLE) opsArray[index++] = Napi::String::New(env, "TOGGLE");
6008
+
6009
+ return opsArray;
6010
+ }
6011
+
6012
+ // ===== getSupportedScanTypes (sync) =====
6013
+
6014
+ Napi::Value NodeHamLib::GetSupportedScanTypes(const Napi::CallbackInfo& info) {
6015
+ Napi::Env env = info.Env();
6016
+
6017
+ int scan = shim_rig_get_caps_has_scan(my_rig);
6018
+ Napi::Array scanArray = Napi::Array::New(env);
6019
+ uint32_t index = 0;
6020
+
6021
+ if (scan & SHIM_RIG_SCAN_MEM) scanArray[index++] = Napi::String::New(env, "MEM");
6022
+ if (scan & SHIM_RIG_SCAN_VFO) scanArray[index++] = Napi::String::New(env, "VFO");
6023
+ if (scan & SHIM_RIG_SCAN_PROG) scanArray[index++] = Napi::String::New(env, "PROG");
6024
+ if (scan & SHIM_RIG_SCAN_DELTA) scanArray[index++] = Napi::String::New(env, "DELTA");
6025
+ if (scan & SHIM_RIG_SCAN_PRIO) scanArray[index++] = Napi::String::New(env, "PRIO");
6026
+
6027
+ return scanArray;
6028
+ }
6029
+
6030
+ // ===== Capability Query Batch 2 (sync) =====
6031
+
6032
+ // Helper: convert mode bitmask to array of mode strings
6033
+ static Napi::Array ModeBitmaskToArray(Napi::Env env, uint64_t modes) {
6034
+ Napi::Array arr = Napi::Array::New(env);
6035
+ uint32_t idx = 0;
6036
+ for (unsigned int i = 0; i < SHIM_HAMLIB_MAX_MODES; i++) {
6037
+ uint64_t bit = modes & (1ULL << i);
6038
+ if (bit) {
6039
+ const char* name = shim_rig_strrmode(bit);
6040
+ if (name && name[0] != '\0') {
6041
+ arr[idx++] = Napi::String::New(env, name);
6042
+ }
6043
+ }
6044
+ }
6045
+ return arr;
6046
+ }
6047
+
6048
+ Napi::Value NodeHamLib::GetPreampValues(const Napi::CallbackInfo& info) {
6049
+ Napi::Env env = info.Env();
6050
+ int buf[SHIM_HAMLIB_MAX_MODES];
6051
+ int count = shim_rig_get_caps_preamp(my_rig, buf, SHIM_HAMLIB_MAX_MODES);
6052
+ Napi::Array arr = Napi::Array::New(env, count);
6053
+ for (int i = 0; i < count; i++) {
6054
+ arr[(uint32_t)i] = Napi::Number::New(env, buf[i]);
6055
+ }
6056
+ return arr;
6057
+ }
6058
+
6059
+ Napi::Value NodeHamLib::GetAttenuatorValues(const Napi::CallbackInfo& info) {
6060
+ Napi::Env env = info.Env();
6061
+ int buf[SHIM_HAMLIB_MAX_MODES];
6062
+ int count = shim_rig_get_caps_attenuator(my_rig, buf, SHIM_HAMLIB_MAX_MODES);
6063
+ Napi::Array arr = Napi::Array::New(env, count);
6064
+ for (int i = 0; i < count; i++) {
6065
+ arr[(uint32_t)i] = Napi::Number::New(env, buf[i]);
6066
+ }
6067
+ return arr;
6068
+ }
6069
+
6070
+ Napi::Value NodeHamLib::GetMaxRit(const Napi::CallbackInfo& info) {
6071
+ return Napi::Number::New(info.Env(), (double)shim_rig_get_caps_max_rit(my_rig));
6072
+ }
6073
+
6074
+ Napi::Value NodeHamLib::GetMaxXit(const Napi::CallbackInfo& info) {
6075
+ return Napi::Number::New(info.Env(), (double)shim_rig_get_caps_max_xit(my_rig));
6076
+ }
6077
+
6078
+ Napi::Value NodeHamLib::GetMaxIfShift(const Napi::CallbackInfo& info) {
6079
+ return Napi::Number::New(info.Env(), (double)shim_rig_get_caps_max_ifshift(my_rig));
6080
+ }
6081
+
6082
+ Napi::Value NodeHamLib::GetAvailableCtcssTones(const Napi::CallbackInfo& info) {
6083
+ Napi::Env env = info.Env();
6084
+ unsigned int buf[256];
6085
+ int count = shim_rig_get_caps_ctcss_list(my_rig, buf, 256);
6086
+ Napi::Array arr = Napi::Array::New(env, count);
6087
+ for (int i = 0; i < count; i++) {
6088
+ // CTCSS tones stored as tenths of Hz, convert to Hz
6089
+ arr[(uint32_t)i] = Napi::Number::New(env, buf[i] / 10.0);
6090
+ }
6091
+ return arr;
6092
+ }
6093
+
6094
+ Napi::Value NodeHamLib::GetAvailableDcsCodes(const Napi::CallbackInfo& info) {
6095
+ Napi::Env env = info.Env();
6096
+ unsigned int buf[256];
6097
+ int count = shim_rig_get_caps_dcs_list(my_rig, buf, 256);
6098
+ Napi::Array arr = Napi::Array::New(env, count);
6099
+ for (int i = 0; i < count; i++) {
6100
+ arr[(uint32_t)i] = Napi::Number::New(env, buf[i]);
6101
+ }
6102
+ return arr;
6103
+ }
6104
+
6105
+ Napi::Value NodeHamLib::GetFrequencyRanges(const Napi::CallbackInfo& info) {
6106
+ Napi::Env env = info.Env();
6107
+
6108
+ shim_freq_range_t rx_buf[30];
6109
+ shim_freq_range_t tx_buf[30];
6110
+ int rx_count = shim_rig_get_caps_rx_range(my_rig, rx_buf, 30);
6111
+ int tx_count = shim_rig_get_caps_tx_range(my_rig, tx_buf, 30);
6112
+
6113
+ auto buildArray = [&](shim_freq_range_t* buf, int count) -> Napi::Array {
6114
+ Napi::Array arr = Napi::Array::New(env, count);
6115
+ for (int i = 0; i < count; i++) {
6116
+ Napi::Object obj = Napi::Object::New(env);
6117
+ obj.Set("startFreq", Napi::Number::New(env, buf[i].start_freq));
6118
+ obj.Set("endFreq", Napi::Number::New(env, buf[i].end_freq));
6119
+ obj.Set("modes", ModeBitmaskToArray(env, buf[i].modes));
6120
+ obj.Set("lowPower", Napi::Number::New(env, buf[i].low_power));
6121
+ obj.Set("highPower", Napi::Number::New(env, buf[i].high_power));
6122
+ obj.Set("vfo", Napi::Number::New(env, buf[i].vfo));
6123
+ obj.Set("antenna", Napi::Number::New(env, buf[i].ant));
6124
+ arr[(uint32_t)i] = obj;
6125
+ }
6126
+ return arr;
6127
+ };
6128
+
6129
+ Napi::Object result = Napi::Object::New(env);
6130
+ result.Set("rx", buildArray(rx_buf, rx_count));
6131
+ result.Set("tx", buildArray(tx_buf, tx_count));
6132
+ return result;
6133
+ }
6134
+
6135
+ Napi::Value NodeHamLib::GetTuningSteps(const Napi::CallbackInfo& info) {
6136
+ Napi::Env env = info.Env();
6137
+ shim_mode_value_t buf[20];
6138
+ int count = shim_rig_get_caps_tuning_steps(my_rig, buf, 20);
6139
+ Napi::Array arr = Napi::Array::New(env, count);
6140
+ for (int i = 0; i < count; i++) {
6141
+ Napi::Object obj = Napi::Object::New(env);
6142
+ obj.Set("modes", ModeBitmaskToArray(env, buf[i].modes));
6143
+ obj.Set("stepHz", Napi::Number::New(env, buf[i].value));
6144
+ arr[(uint32_t)i] = obj;
6145
+ }
6146
+ return arr;
6147
+ }
6148
+
6149
+ Napi::Value NodeHamLib::GetFilterList(const Napi::CallbackInfo& info) {
6150
+ Napi::Env env = info.Env();
6151
+ shim_mode_value_t buf[60];
6152
+ int count = shim_rig_get_caps_filters(my_rig, buf, 60);
6153
+ Napi::Array arr = Napi::Array::New(env, count);
6154
+ for (int i = 0; i < count; i++) {
6155
+ Napi::Object obj = Napi::Object::New(env);
6156
+ obj.Set("modes", ModeBitmaskToArray(env, buf[i].modes));
6157
+ obj.Set("width", Napi::Number::New(env, buf[i].value));
6158
+ arr[(uint32_t)i] = obj;
6159
+ }
6160
+ return arr;
6161
+ }
6162
+
6163
+ // ===== Static: getCopyright / getLicense =====
6164
+
6165
+ Napi::Value NodeHamLib::GetCopyright(const Napi::CallbackInfo& info) {
6166
+ Napi::Env env = info.Env();
6167
+ return Napi::String::New(env, shim_rig_copyright());
6168
+ }
6169
+
6170
+ Napi::Value NodeHamLib::GetLicense(const Napi::CallbackInfo& info) {
6171
+ Napi::Env env = info.Env();
6172
+ return Napi::String::New(env, shim_rig_license());
6173
+ }