hamlib 0.1.2 → 0.1.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/src/hamlib.cpp CHANGED
@@ -1,7 +1,12 @@
1
1
  #include "hamlib.h"
2
2
  #include <string>
3
+ #include <vector>
3
4
 
4
-
5
+ // Structure to hold rig information for the callback
6
+ struct RigListData {
7
+ std::vector<Napi::Object> rigList;
8
+ Napi::Env env;
9
+ };
5
10
 
6
11
  using namespace Napi;
7
12
 
@@ -430,6 +435,1002 @@ Napi::Value NodeHamLib::GetConnectionInfo(const Napi::CallbackInfo & info) {
430
435
  return obj;
431
436
  }
432
437
 
438
+ // Memory Channel Management
439
+ Napi::Value NodeHamLib::SetMemoryChannel(const Napi::CallbackInfo & info) {
440
+ Napi::Env env = info.Env();
441
+
442
+ if (!rig_is_open) {
443
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
444
+ return env.Null();
445
+ }
446
+
447
+ if (info.Length() < 2 || !info[0].IsNumber() || !info[1].IsObject()) {
448
+ Napi::TypeError::New(env, "Expected (channelNumber: number, channelData: object)").ThrowAsJavaScriptException();
449
+ return env.Null();
450
+ }
451
+
452
+ int channel_num = info[0].As<Napi::Number>().Int32Value();
453
+ Napi::Object chanObj = info[1].As<Napi::Object>();
454
+
455
+ // Create channel structure
456
+ channel_t chan;
457
+ memset(&chan, 0, sizeof(chan));
458
+
459
+ chan.channel_num = channel_num;
460
+ chan.vfo = RIG_VFO_MEM;
461
+
462
+ // Extract frequency
463
+ if (chanObj.Has("frequency")) {
464
+ chan.freq = chanObj.Get("frequency").As<Napi::Number>().DoubleValue();
465
+ }
466
+
467
+ // Extract mode
468
+ if (chanObj.Has("mode")) {
469
+ std::string modeStr = chanObj.Get("mode").As<Napi::String>().Utf8Value();
470
+ chan.mode = rig_parse_mode(modeStr.c_str());
471
+ }
472
+
473
+ // Extract bandwidth
474
+ if (chanObj.Has("bandwidth")) {
475
+ chan.width = chanObj.Get("bandwidth").As<Napi::Number>().Int32Value();
476
+ } else {
477
+ chan.width = RIG_PASSBAND_NORMAL;
478
+ }
479
+
480
+ // Extract channel description
481
+ if (chanObj.Has("description")) {
482
+ std::string desc = chanObj.Get("description").As<Napi::String>().Utf8Value();
483
+ strncpy(chan.channel_desc, desc.c_str(), sizeof(chan.channel_desc) - 1);
484
+ chan.channel_desc[sizeof(chan.channel_desc) - 1] = '\0';
485
+ }
486
+
487
+ // Extract TX frequency for split operation
488
+ if (chanObj.Has("txFrequency")) {
489
+ chan.tx_freq = chanObj.Get("txFrequency").As<Napi::Number>().DoubleValue();
490
+ chan.split = RIG_SPLIT_ON;
491
+ }
492
+
493
+ // Extract CTCSS tone
494
+ if (chanObj.Has("ctcssTone")) {
495
+ chan.ctcss_tone = chanObj.Get("ctcssTone").As<Napi::Number>().Int32Value();
496
+ }
497
+
498
+ int retcode = rig_set_channel(my_rig, RIG_VFO_MEM, &chan);
499
+ if (retcode != RIG_OK) {
500
+ Napi::Error::New(env, rigerror(retcode)).ThrowAsJavaScriptException();
501
+ return env.Null();
502
+ }
503
+
504
+ return Napi::Number::New(env, retcode);
505
+ }
506
+
507
+ Napi::Value NodeHamLib::GetMemoryChannel(const Napi::CallbackInfo & info) {
508
+ Napi::Env env = info.Env();
509
+
510
+ if (!rig_is_open) {
511
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
512
+ return env.Null();
513
+ }
514
+
515
+ if (info.Length() < 1 || !info[0].IsNumber()) {
516
+ Napi::TypeError::New(env, "Expected channel number").ThrowAsJavaScriptException();
517
+ return env.Null();
518
+ }
519
+
520
+ int channel_num = info[0].As<Napi::Number>().Int32Value();
521
+ bool read_only = true;
522
+
523
+ if (info.Length() >= 2 && info[1].IsBoolean()) {
524
+ read_only = info[1].As<Napi::Boolean>().Value();
525
+ }
526
+
527
+ // Create channel structure
528
+ channel_t chan;
529
+ memset(&chan, 0, sizeof(chan));
530
+ chan.channel_num = channel_num;
531
+ chan.vfo = RIG_VFO_MEM;
532
+
533
+ int retcode = rig_get_channel(my_rig, RIG_VFO_MEM, &chan, read_only);
534
+ if (retcode != RIG_OK) {
535
+ Napi::Error::New(env, rigerror(retcode)).ThrowAsJavaScriptException();
536
+ return env.Null();
537
+ }
538
+
539
+ // Create result object
540
+ Napi::Object result = Napi::Object::New(env);
541
+ result.Set("channelNumber", Napi::Number::New(env, chan.channel_num));
542
+ result.Set("frequency", Napi::Number::New(env, chan.freq));
543
+ result.Set("mode", Napi::String::New(env, rig_strrmode(chan.mode)));
544
+ result.Set("bandwidth", Napi::Number::New(env, chan.width));
545
+ result.Set("description", Napi::String::New(env, chan.channel_desc));
546
+
547
+ if (chan.split == RIG_SPLIT_ON) {
548
+ result.Set("txFrequency", Napi::Number::New(env, chan.tx_freq));
549
+ result.Set("split", Napi::Boolean::New(env, true));
550
+ } else {
551
+ result.Set("split", Napi::Boolean::New(env, false));
552
+ }
553
+
554
+ if (chan.ctcss_tone > 0) {
555
+ result.Set("ctcssTone", Napi::Number::New(env, chan.ctcss_tone));
556
+ }
557
+
558
+ return result;
559
+ }
560
+
561
+ Napi::Value NodeHamLib::SelectMemoryChannel(const Napi::CallbackInfo & info) {
562
+ Napi::Env env = info.Env();
563
+
564
+ if (!rig_is_open) {
565
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
566
+ return env.Null();
567
+ }
568
+
569
+ if (info.Length() < 1 || !info[0].IsNumber()) {
570
+ Napi::TypeError::New(env, "Expected channel number").ThrowAsJavaScriptException();
571
+ return env.Null();
572
+ }
573
+
574
+ int channel_num = info[0].As<Napi::Number>().Int32Value();
575
+
576
+ int retcode = rig_set_mem(my_rig, RIG_VFO_CURR, channel_num);
577
+ if (retcode != RIG_OK) {
578
+ Napi::Error::New(env, rigerror(retcode)).ThrowAsJavaScriptException();
579
+ return env.Null();
580
+ }
581
+
582
+ return Napi::Number::New(env, retcode);
583
+ }
584
+
585
+ // RIT/XIT Control
586
+ Napi::Value NodeHamLib::SetRit(const Napi::CallbackInfo & info) {
587
+ Napi::Env env = info.Env();
588
+
589
+ if (!rig_is_open) {
590
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
591
+ return env.Null();
592
+ }
593
+
594
+ if (info.Length() < 1 || !info[0].IsNumber()) {
595
+ Napi::TypeError::New(env, "Expected RIT offset in Hz").ThrowAsJavaScriptException();
596
+ return env.Null();
597
+ }
598
+
599
+ shortfreq_t rit_offset = info[0].As<Napi::Number>().Int32Value();
600
+
601
+ int retcode = rig_set_rit(my_rig, RIG_VFO_CURR, rit_offset);
602
+ if (retcode != RIG_OK) {
603
+ Napi::Error::New(env, rigerror(retcode)).ThrowAsJavaScriptException();
604
+ return env.Null();
605
+ }
606
+
607
+ return Napi::Number::New(env, retcode);
608
+ }
609
+
610
+ Napi::Value NodeHamLib::GetRit(const Napi::CallbackInfo & info) {
611
+ Napi::Env env = info.Env();
612
+
613
+ if (!rig_is_open) {
614
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
615
+ return env.Null();
616
+ }
617
+
618
+ shortfreq_t rit_offset;
619
+ int retcode = rig_get_rit(my_rig, RIG_VFO_CURR, &rit_offset);
620
+ if (retcode != RIG_OK) {
621
+ Napi::Error::New(env, rigerror(retcode)).ThrowAsJavaScriptException();
622
+ return env.Null();
623
+ }
624
+
625
+ return Napi::Number::New(env, rit_offset);
626
+ }
627
+
628
+ Napi::Value NodeHamLib::SetXit(const Napi::CallbackInfo & info) {
629
+ Napi::Env env = info.Env();
630
+
631
+ if (!rig_is_open) {
632
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
633
+ return env.Null();
634
+ }
635
+
636
+ if (info.Length() < 1 || !info[0].IsNumber()) {
637
+ Napi::TypeError::New(env, "Expected XIT offset in Hz").ThrowAsJavaScriptException();
638
+ return env.Null();
639
+ }
640
+
641
+ shortfreq_t xit_offset = info[0].As<Napi::Number>().Int32Value();
642
+
643
+ int retcode = rig_set_xit(my_rig, RIG_VFO_CURR, xit_offset);
644
+ if (retcode != RIG_OK) {
645
+ Napi::Error::New(env, rigerror(retcode)).ThrowAsJavaScriptException();
646
+ return env.Null();
647
+ }
648
+
649
+ return Napi::Number::New(env, retcode);
650
+ }
651
+
652
+ Napi::Value NodeHamLib::GetXit(const Napi::CallbackInfo & info) {
653
+ Napi::Env env = info.Env();
654
+
655
+ if (!rig_is_open) {
656
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
657
+ return env.Null();
658
+ }
659
+
660
+ shortfreq_t xit_offset;
661
+ int retcode = rig_get_xit(my_rig, RIG_VFO_CURR, &xit_offset);
662
+ if (retcode != RIG_OK) {
663
+ Napi::Error::New(env, rigerror(retcode)).ThrowAsJavaScriptException();
664
+ return env.Null();
665
+ }
666
+
667
+ return Napi::Number::New(env, xit_offset);
668
+ }
669
+
670
+ Napi::Value NodeHamLib::ClearRitXit(const Napi::CallbackInfo & info) {
671
+ Napi::Env env = info.Env();
672
+
673
+ if (!rig_is_open) {
674
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
675
+ return env.Null();
676
+ }
677
+
678
+ // Clear both RIT and XIT by setting them to 0
679
+ int ritCode = rig_set_rit(my_rig, RIG_VFO_CURR, 0);
680
+ int xitCode = rig_set_xit(my_rig, RIG_VFO_CURR, 0);
681
+
682
+ if (ritCode != RIG_OK && ritCode != -RIG_ENAVAIL) {
683
+ Napi::Error::New(env, rigerror(ritCode)).ThrowAsJavaScriptException();
684
+ return env.Null();
685
+ }
686
+
687
+ if (xitCode != RIG_OK && xitCode != -RIG_ENAVAIL) {
688
+ Napi::Error::New(env, rigerror(xitCode)).ThrowAsJavaScriptException();
689
+ return env.Null();
690
+ }
691
+
692
+ return Napi::Boolean::New(env, true);
693
+ }
694
+
695
+ // Scanning Operations
696
+ Napi::Value NodeHamLib::StartScan(const Napi::CallbackInfo & info) {
697
+ Napi::Env env = info.Env();
698
+
699
+ if (!rig_is_open) {
700
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
701
+ return env.Null();
702
+ }
703
+
704
+ if (info.Length() < 1 || !info[0].IsString()) {
705
+ Napi::TypeError::New(env, "Expected scan type (VFO, MEM, PROG, etc.)").ThrowAsJavaScriptException();
706
+ return env.Null();
707
+ }
708
+
709
+ std::string scanTypeStr = info[0].As<Napi::String>().Utf8Value();
710
+ scan_t scanType;
711
+
712
+ if (scanTypeStr == "VFO") {
713
+ scanType = RIG_SCAN_VFO;
714
+ } else if (scanTypeStr == "MEM") {
715
+ scanType = RIG_SCAN_MEM;
716
+ } else if (scanTypeStr == "PROG") {
717
+ scanType = RIG_SCAN_PROG;
718
+ } else if (scanTypeStr == "DELTA") {
719
+ scanType = RIG_SCAN_DELTA;
720
+ } else if (scanTypeStr == "PRIO") {
721
+ scanType = RIG_SCAN_PRIO;
722
+ } else {
723
+ Napi::TypeError::New(env, "Invalid scan type").ThrowAsJavaScriptException();
724
+ return env.Null();
725
+ }
726
+
727
+ int channel = 0;
728
+ if (info.Length() >= 2 && info[1].IsNumber()) {
729
+ channel = info[1].As<Napi::Number>().Int32Value();
730
+ }
731
+
732
+ int retcode = rig_scan(my_rig, RIG_VFO_CURR, scanType, channel);
733
+ if (retcode != RIG_OK) {
734
+ Napi::Error::New(env, rigerror(retcode)).ThrowAsJavaScriptException();
735
+ return env.Null();
736
+ }
737
+
738
+ return Napi::Number::New(env, retcode);
739
+ }
740
+
741
+ Napi::Value NodeHamLib::StopScan(const Napi::CallbackInfo & info) {
742
+ Napi::Env env = info.Env();
743
+
744
+ if (!rig_is_open) {
745
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
746
+ return env.Null();
747
+ }
748
+
749
+ int retcode = rig_scan(my_rig, RIG_VFO_CURR, RIG_SCAN_STOP, 0);
750
+ if (retcode != RIG_OK) {
751
+ Napi::Error::New(env, rigerror(retcode)).ThrowAsJavaScriptException();
752
+ return env.Null();
753
+ }
754
+
755
+ return Napi::Number::New(env, retcode);
756
+ }
757
+
758
+ // Level Controls
759
+ Napi::Value NodeHamLib::SetLevel(const Napi::CallbackInfo & info) {
760
+ Napi::Env env = info.Env();
761
+
762
+ if (!rig_is_open) {
763
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
764
+ return env.Null();
765
+ }
766
+
767
+ if (info.Length() < 2 || !info[0].IsString() || !info[1].IsNumber()) {
768
+ Napi::TypeError::New(env, "Expected (levelType: string, value: number)").ThrowAsJavaScriptException();
769
+ return env.Null();
770
+ }
771
+
772
+ std::string levelTypeStr = info[0].As<Napi::String>().Utf8Value();
773
+ double levelValue = info[1].As<Napi::Number>().DoubleValue();
774
+
775
+ // Map level type strings to hamlib constants
776
+ setting_t levelType;
777
+ if (levelTypeStr == "AF") {
778
+ levelType = RIG_LEVEL_AF;
779
+ } else if (levelTypeStr == "RF") {
780
+ levelType = RIG_LEVEL_RF;
781
+ } else if (levelTypeStr == "SQL") {
782
+ levelType = RIG_LEVEL_SQL;
783
+ } else if (levelTypeStr == "RFPOWER") {
784
+ levelType = RIG_LEVEL_RFPOWER;
785
+ } else if (levelTypeStr == "MICGAIN") {
786
+ levelType = RIG_LEVEL_MICGAIN;
787
+ } else if (levelTypeStr == "IF") {
788
+ levelType = RIG_LEVEL_IF;
789
+ } else if (levelTypeStr == "APF") {
790
+ levelType = RIG_LEVEL_APF;
791
+ } else if (levelTypeStr == "NR") {
792
+ levelType = RIG_LEVEL_NR;
793
+ } else if (levelTypeStr == "PBT_IN") {
794
+ levelType = RIG_LEVEL_PBT_IN;
795
+ } else if (levelTypeStr == "PBT_OUT") {
796
+ levelType = RIG_LEVEL_PBT_OUT;
797
+ } else if (levelTypeStr == "CWPITCH") {
798
+ levelType = RIG_LEVEL_CWPITCH;
799
+ } else if (levelTypeStr == "KEYSPD") {
800
+ levelType = RIG_LEVEL_KEYSPD;
801
+ } else if (levelTypeStr == "NOTCHF") {
802
+ levelType = RIG_LEVEL_NOTCHF;
803
+ } else if (levelTypeStr == "COMP") {
804
+ levelType = RIG_LEVEL_COMP;
805
+ } else if (levelTypeStr == "AGC") {
806
+ levelType = RIG_LEVEL_AGC;
807
+ } else if (levelTypeStr == "BKINDL") {
808
+ levelType = RIG_LEVEL_BKINDL;
809
+ } else if (levelTypeStr == "BALANCE") {
810
+ levelType = RIG_LEVEL_BALANCE;
811
+ } else if (levelTypeStr == "VOXGAIN") {
812
+ levelType = RIG_LEVEL_VOXGAIN;
813
+ } else if (levelTypeStr == "VOXDELAY") {
814
+ levelType = RIG_LEVEL_VOXDELAY;
815
+ } else if (levelTypeStr == "ANTIVOX") {
816
+ levelType = RIG_LEVEL_ANTIVOX;
817
+ } else {
818
+ Napi::TypeError::New(env, "Invalid level type").ThrowAsJavaScriptException();
819
+ return env.Null();
820
+ }
821
+
822
+ // Create value union
823
+ value_t val;
824
+ val.f = levelValue;
825
+
826
+ int retcode = rig_set_level(my_rig, RIG_VFO_CURR, levelType, val);
827
+ if (retcode != RIG_OK) {
828
+ Napi::Error::New(env, rigerror(retcode)).ThrowAsJavaScriptException();
829
+ return env.Null();
830
+ }
831
+
832
+ return Napi::Number::New(env, retcode);
833
+ }
834
+
835
+ Napi::Value NodeHamLib::GetLevel(const Napi::CallbackInfo & info) {
836
+ Napi::Env env = info.Env();
837
+
838
+ if (!rig_is_open) {
839
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
840
+ return env.Null();
841
+ }
842
+
843
+ if (info.Length() < 1 || !info[0].IsString()) {
844
+ Napi::TypeError::New(env, "Expected level type string").ThrowAsJavaScriptException();
845
+ return env.Null();
846
+ }
847
+
848
+ std::string levelTypeStr = info[0].As<Napi::String>().Utf8Value();
849
+
850
+ // Map level type strings to hamlib constants
851
+ setting_t levelType;
852
+ if (levelTypeStr == "AF") {
853
+ levelType = RIG_LEVEL_AF;
854
+ } else if (levelTypeStr == "RF") {
855
+ levelType = RIG_LEVEL_RF;
856
+ } else if (levelTypeStr == "SQL") {
857
+ levelType = RIG_LEVEL_SQL;
858
+ } else if (levelTypeStr == "RFPOWER") {
859
+ levelType = RIG_LEVEL_RFPOWER;
860
+ } else if (levelTypeStr == "MICGAIN") {
861
+ levelType = RIG_LEVEL_MICGAIN;
862
+ } else if (levelTypeStr == "SWR") {
863
+ levelType = RIG_LEVEL_SWR;
864
+ } else if (levelTypeStr == "ALC") {
865
+ levelType = RIG_LEVEL_ALC;
866
+ } else if (levelTypeStr == "STRENGTH") {
867
+ levelType = RIG_LEVEL_STRENGTH;
868
+ } else if (levelTypeStr == "RAWSTR") {
869
+ levelType = RIG_LEVEL_RAWSTR;
870
+ } else if (levelTypeStr == "RFPOWER_METER") {
871
+ levelType = RIG_LEVEL_RFPOWER_METER;
872
+ } else if (levelTypeStr == "COMP_METER") {
873
+ levelType = RIG_LEVEL_COMP_METER;
874
+ } else if (levelTypeStr == "VD_METER") {
875
+ levelType = RIG_LEVEL_VD_METER;
876
+ } else if (levelTypeStr == "ID_METER") {
877
+ levelType = RIG_LEVEL_ID_METER;
878
+ } else if (levelTypeStr == "TEMP_METER") {
879
+ levelType = RIG_LEVEL_TEMP_METER;
880
+ } else {
881
+ Napi::TypeError::New(env, "Invalid level type").ThrowAsJavaScriptException();
882
+ return env.Null();
883
+ }
884
+
885
+ value_t val;
886
+ int retcode = rig_get_level(my_rig, RIG_VFO_CURR, levelType, &val);
887
+ if (retcode != RIG_OK) {
888
+ Napi::Error::New(env, rigerror(retcode)).ThrowAsJavaScriptException();
889
+ return env.Null();
890
+ }
891
+
892
+ // Return the appropriate value based on the level type
893
+ if (levelType == RIG_LEVEL_STRENGTH || levelType == RIG_LEVEL_RAWSTR) {
894
+ return Napi::Number::New(env, val.i);
895
+ } else {
896
+ return Napi::Number::New(env, val.f);
897
+ }
898
+ }
899
+
900
+ Napi::Value NodeHamLib::GetSupportedLevels(const Napi::CallbackInfo & info) {
901
+ Napi::Env env = info.Env();
902
+
903
+ if (!rig_is_open) {
904
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
905
+ return env.Null();
906
+ }
907
+
908
+ setting_t levels = my_rig->state.has_get_level | my_rig->state.has_set_level;
909
+ Napi::Array levelArray = Napi::Array::New(env);
910
+ uint32_t index = 0;
911
+
912
+ // Check each level type
913
+ if (levels & RIG_LEVEL_AF) levelArray[index++] = Napi::String::New(env, "AF");
914
+ if (levels & RIG_LEVEL_RF) levelArray[index++] = Napi::String::New(env, "RF");
915
+ if (levels & RIG_LEVEL_SQL) levelArray[index++] = Napi::String::New(env, "SQL");
916
+ if (levels & RIG_LEVEL_RFPOWER) levelArray[index++] = Napi::String::New(env, "RFPOWER");
917
+ if (levels & RIG_LEVEL_MICGAIN) levelArray[index++] = Napi::String::New(env, "MICGAIN");
918
+ if (levels & RIG_LEVEL_IF) levelArray[index++] = Napi::String::New(env, "IF");
919
+ if (levels & RIG_LEVEL_APF) levelArray[index++] = Napi::String::New(env, "APF");
920
+ if (levels & RIG_LEVEL_NR) levelArray[index++] = Napi::String::New(env, "NR");
921
+ if (levels & RIG_LEVEL_PBT_IN) levelArray[index++] = Napi::String::New(env, "PBT_IN");
922
+ if (levels & RIG_LEVEL_PBT_OUT) levelArray[index++] = Napi::String::New(env, "PBT_OUT");
923
+ if (levels & RIG_LEVEL_CWPITCH) levelArray[index++] = Napi::String::New(env, "CWPITCH");
924
+ if (levels & RIG_LEVEL_KEYSPD) levelArray[index++] = Napi::String::New(env, "KEYSPD");
925
+ if (levels & RIG_LEVEL_NOTCHF) levelArray[index++] = Napi::String::New(env, "NOTCHF");
926
+ if (levels & RIG_LEVEL_COMP) levelArray[index++] = Napi::String::New(env, "COMP");
927
+ if (levels & RIG_LEVEL_AGC) levelArray[index++] = Napi::String::New(env, "AGC");
928
+ if (levels & RIG_LEVEL_BKINDL) levelArray[index++] = Napi::String::New(env, "BKINDL");
929
+ if (levels & RIG_LEVEL_BALANCE) levelArray[index++] = Napi::String::New(env, "BALANCE");
930
+ if (levels & RIG_LEVEL_VOXGAIN) levelArray[index++] = Napi::String::New(env, "VOXGAIN");
931
+ if (levels & RIG_LEVEL_VOXDELAY) levelArray[index++] = Napi::String::New(env, "VOXDELAY");
932
+ if (levels & RIG_LEVEL_ANTIVOX) levelArray[index++] = Napi::String::New(env, "ANTIVOX");
933
+ if (levels & RIG_LEVEL_STRENGTH) levelArray[index++] = Napi::String::New(env, "STRENGTH");
934
+ if (levels & RIG_LEVEL_RAWSTR) levelArray[index++] = Napi::String::New(env, "RAWSTR");
935
+ if (levels & RIG_LEVEL_SWR) levelArray[index++] = Napi::String::New(env, "SWR");
936
+ if (levels & RIG_LEVEL_ALC) levelArray[index++] = Napi::String::New(env, "ALC");
937
+ if (levels & RIG_LEVEL_RFPOWER_METER) levelArray[index++] = Napi::String::New(env, "RFPOWER_METER");
938
+ if (levels & RIG_LEVEL_COMP_METER) levelArray[index++] = Napi::String::New(env, "COMP_METER");
939
+ if (levels & RIG_LEVEL_VD_METER) levelArray[index++] = Napi::String::New(env, "VD_METER");
940
+ if (levels & RIG_LEVEL_ID_METER) levelArray[index++] = Napi::String::New(env, "ID_METER");
941
+ if (levels & RIG_LEVEL_TEMP_METER) levelArray[index++] = Napi::String::New(env, "TEMP_METER");
942
+
943
+ return levelArray;
944
+ }
945
+
946
+ // Function Controls
947
+ Napi::Value NodeHamLib::SetFunction(const Napi::CallbackInfo & info) {
948
+ Napi::Env env = info.Env();
949
+
950
+ if (!rig_is_open) {
951
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
952
+ return env.Null();
953
+ }
954
+
955
+ if (info.Length() < 2 || !info[0].IsString() || !info[1].IsBoolean()) {
956
+ Napi::TypeError::New(env, "Expected (functionType: string, enable: boolean)").ThrowAsJavaScriptException();
957
+ return env.Null();
958
+ }
959
+
960
+ std::string funcTypeStr = info[0].As<Napi::String>().Utf8Value();
961
+ bool enable = info[1].As<Napi::Boolean>().Value();
962
+
963
+ // Map function type strings to hamlib constants
964
+ setting_t funcType;
965
+ if (funcTypeStr == "FAGC") {
966
+ funcType = RIG_FUNC_FAGC;
967
+ } else if (funcTypeStr == "NB") {
968
+ funcType = RIG_FUNC_NB;
969
+ } else if (funcTypeStr == "COMP") {
970
+ funcType = RIG_FUNC_COMP;
971
+ } else if (funcTypeStr == "VOX") {
972
+ funcType = RIG_FUNC_VOX;
973
+ } else if (funcTypeStr == "TONE") {
974
+ funcType = RIG_FUNC_TONE;
975
+ } else if (funcTypeStr == "TSQL") {
976
+ funcType = RIG_FUNC_TSQL;
977
+ } else if (funcTypeStr == "SBKIN") {
978
+ funcType = RIG_FUNC_SBKIN;
979
+ } else if (funcTypeStr == "FBKIN") {
980
+ funcType = RIG_FUNC_FBKIN;
981
+ } else if (funcTypeStr == "ANF") {
982
+ funcType = RIG_FUNC_ANF;
983
+ } else if (funcTypeStr == "NR") {
984
+ funcType = RIG_FUNC_NR;
985
+ } else if (funcTypeStr == "AIP") {
986
+ funcType = RIG_FUNC_AIP;
987
+ } else if (funcTypeStr == "APF") {
988
+ funcType = RIG_FUNC_APF;
989
+ } else if (funcTypeStr == "TUNER") {
990
+ funcType = RIG_FUNC_TUNER;
991
+ } else if (funcTypeStr == "XIT") {
992
+ funcType = RIG_FUNC_XIT;
993
+ } else if (funcTypeStr == "RIT") {
994
+ funcType = RIG_FUNC_RIT;
995
+ } else if (funcTypeStr == "LOCK") {
996
+ funcType = RIG_FUNC_LOCK;
997
+ } else if (funcTypeStr == "MUTE") {
998
+ funcType = RIG_FUNC_MUTE;
999
+ } else if (funcTypeStr == "VSC") {
1000
+ funcType = RIG_FUNC_VSC;
1001
+ } else if (funcTypeStr == "REV") {
1002
+ funcType = RIG_FUNC_REV;
1003
+ } else if (funcTypeStr == "SQL") {
1004
+ funcType = RIG_FUNC_SQL;
1005
+ } else if (funcTypeStr == "ABM") {
1006
+ funcType = RIG_FUNC_ABM;
1007
+ } else if (funcTypeStr == "BC") {
1008
+ funcType = RIG_FUNC_BC;
1009
+ } else if (funcTypeStr == "MBC") {
1010
+ funcType = RIG_FUNC_MBC;
1011
+ } else if (funcTypeStr == "AFC") {
1012
+ funcType = RIG_FUNC_AFC;
1013
+ } else if (funcTypeStr == "SATMODE") {
1014
+ funcType = RIG_FUNC_SATMODE;
1015
+ } else if (funcTypeStr == "SCOPE") {
1016
+ funcType = RIG_FUNC_SCOPE;
1017
+ } else if (funcTypeStr == "RESUME") {
1018
+ funcType = RIG_FUNC_RESUME;
1019
+ } else if (funcTypeStr == "TBURST") {
1020
+ funcType = RIG_FUNC_TBURST;
1021
+ } else {
1022
+ Napi::TypeError::New(env, "Invalid function type").ThrowAsJavaScriptException();
1023
+ return env.Null();
1024
+ }
1025
+
1026
+ int retcode = rig_set_func(my_rig, RIG_VFO_CURR, funcType, enable ? 1 : 0);
1027
+ if (retcode != RIG_OK) {
1028
+ Napi::Error::New(env, rigerror(retcode)).ThrowAsJavaScriptException();
1029
+ return env.Null();
1030
+ }
1031
+
1032
+ return Napi::Number::New(env, retcode);
1033
+ }
1034
+
1035
+ Napi::Value NodeHamLib::GetFunction(const Napi::CallbackInfo & info) {
1036
+ Napi::Env env = info.Env();
1037
+
1038
+ if (!rig_is_open) {
1039
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
1040
+ return env.Null();
1041
+ }
1042
+
1043
+ if (info.Length() < 1 || !info[0].IsString()) {
1044
+ Napi::TypeError::New(env, "Expected function type string").ThrowAsJavaScriptException();
1045
+ return env.Null();
1046
+ }
1047
+
1048
+ std::string funcTypeStr = info[0].As<Napi::String>().Utf8Value();
1049
+
1050
+ // Map function type strings to hamlib constants (same as SetFunction)
1051
+ setting_t funcType;
1052
+ if (funcTypeStr == "FAGC") {
1053
+ funcType = RIG_FUNC_FAGC;
1054
+ } else if (funcTypeStr == "NB") {
1055
+ funcType = RIG_FUNC_NB;
1056
+ } else if (funcTypeStr == "COMP") {
1057
+ funcType = RIG_FUNC_COMP;
1058
+ } else if (funcTypeStr == "VOX") {
1059
+ funcType = RIG_FUNC_VOX;
1060
+ } else if (funcTypeStr == "TONE") {
1061
+ funcType = RIG_FUNC_TONE;
1062
+ } else if (funcTypeStr == "TSQL") {
1063
+ funcType = RIG_FUNC_TSQL;
1064
+ } else if (funcTypeStr == "SBKIN") {
1065
+ funcType = RIG_FUNC_SBKIN;
1066
+ } else if (funcTypeStr == "FBKIN") {
1067
+ funcType = RIG_FUNC_FBKIN;
1068
+ } else if (funcTypeStr == "ANF") {
1069
+ funcType = RIG_FUNC_ANF;
1070
+ } else if (funcTypeStr == "NR") {
1071
+ funcType = RIG_FUNC_NR;
1072
+ } else if (funcTypeStr == "AIP") {
1073
+ funcType = RIG_FUNC_AIP;
1074
+ } else if (funcTypeStr == "APF") {
1075
+ funcType = RIG_FUNC_APF;
1076
+ } else if (funcTypeStr == "TUNER") {
1077
+ funcType = RIG_FUNC_TUNER;
1078
+ } else if (funcTypeStr == "XIT") {
1079
+ funcType = RIG_FUNC_XIT;
1080
+ } else if (funcTypeStr == "RIT") {
1081
+ funcType = RIG_FUNC_RIT;
1082
+ } else if (funcTypeStr == "LOCK") {
1083
+ funcType = RIG_FUNC_LOCK;
1084
+ } else if (funcTypeStr == "MUTE") {
1085
+ funcType = RIG_FUNC_MUTE;
1086
+ } else if (funcTypeStr == "VSC") {
1087
+ funcType = RIG_FUNC_VSC;
1088
+ } else if (funcTypeStr == "REV") {
1089
+ funcType = RIG_FUNC_REV;
1090
+ } else if (funcTypeStr == "SQL") {
1091
+ funcType = RIG_FUNC_SQL;
1092
+ } else if (funcTypeStr == "ABM") {
1093
+ funcType = RIG_FUNC_ABM;
1094
+ } else if (funcTypeStr == "BC") {
1095
+ funcType = RIG_FUNC_BC;
1096
+ } else if (funcTypeStr == "MBC") {
1097
+ funcType = RIG_FUNC_MBC;
1098
+ } else if (funcTypeStr == "AFC") {
1099
+ funcType = RIG_FUNC_AFC;
1100
+ } else if (funcTypeStr == "SATMODE") {
1101
+ funcType = RIG_FUNC_SATMODE;
1102
+ } else if (funcTypeStr == "SCOPE") {
1103
+ funcType = RIG_FUNC_SCOPE;
1104
+ } else if (funcTypeStr == "RESUME") {
1105
+ funcType = RIG_FUNC_RESUME;
1106
+ } else if (funcTypeStr == "TBURST") {
1107
+ funcType = RIG_FUNC_TBURST;
1108
+ } else {
1109
+ Napi::TypeError::New(env, "Invalid function type").ThrowAsJavaScriptException();
1110
+ return env.Null();
1111
+ }
1112
+
1113
+ int state;
1114
+ int retcode = rig_get_func(my_rig, RIG_VFO_CURR, funcType, &state);
1115
+ if (retcode != RIG_OK) {
1116
+ Napi::Error::New(env, rigerror(retcode)).ThrowAsJavaScriptException();
1117
+ return env.Null();
1118
+ }
1119
+
1120
+ return Napi::Boolean::New(env, state != 0);
1121
+ }
1122
+
1123
+ Napi::Value NodeHamLib::GetSupportedFunctions(const Napi::CallbackInfo & info) {
1124
+ Napi::Env env = info.Env();
1125
+
1126
+ if (!rig_is_open) {
1127
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
1128
+ return env.Null();
1129
+ }
1130
+
1131
+ setting_t functions = my_rig->state.has_get_func | my_rig->state.has_set_func;
1132
+ Napi::Array funcArray = Napi::Array::New(env);
1133
+ uint32_t index = 0;
1134
+
1135
+ // Check each function type
1136
+ if (functions & RIG_FUNC_FAGC) funcArray[index++] = Napi::String::New(env, "FAGC");
1137
+ if (functions & RIG_FUNC_NB) funcArray[index++] = Napi::String::New(env, "NB");
1138
+ if (functions & RIG_FUNC_COMP) funcArray[index++] = Napi::String::New(env, "COMP");
1139
+ if (functions & RIG_FUNC_VOX) funcArray[index++] = Napi::String::New(env, "VOX");
1140
+ if (functions & RIG_FUNC_TONE) funcArray[index++] = Napi::String::New(env, "TONE");
1141
+ if (functions & RIG_FUNC_TSQL) funcArray[index++] = Napi::String::New(env, "TSQL");
1142
+ if (functions & RIG_FUNC_SBKIN) funcArray[index++] = Napi::String::New(env, "SBKIN");
1143
+ if (functions & RIG_FUNC_FBKIN) funcArray[index++] = Napi::String::New(env, "FBKIN");
1144
+ if (functions & RIG_FUNC_ANF) funcArray[index++] = Napi::String::New(env, "ANF");
1145
+ if (functions & RIG_FUNC_NR) funcArray[index++] = Napi::String::New(env, "NR");
1146
+ if (functions & RIG_FUNC_AIP) funcArray[index++] = Napi::String::New(env, "AIP");
1147
+ if (functions & RIG_FUNC_APF) funcArray[index++] = Napi::String::New(env, "APF");
1148
+ if (functions & RIG_FUNC_TUNER) funcArray[index++] = Napi::String::New(env, "TUNER");
1149
+ if (functions & RIG_FUNC_XIT) funcArray[index++] = Napi::String::New(env, "XIT");
1150
+ if (functions & RIG_FUNC_RIT) funcArray[index++] = Napi::String::New(env, "RIT");
1151
+ if (functions & RIG_FUNC_LOCK) funcArray[index++] = Napi::String::New(env, "LOCK");
1152
+ if (functions & RIG_FUNC_MUTE) funcArray[index++] = Napi::String::New(env, "MUTE");
1153
+ if (functions & RIG_FUNC_VSC) funcArray[index++] = Napi::String::New(env, "VSC");
1154
+ if (functions & RIG_FUNC_REV) funcArray[index++] = Napi::String::New(env, "REV");
1155
+ if (functions & RIG_FUNC_SQL) funcArray[index++] = Napi::String::New(env, "SQL");
1156
+ if (functions & RIG_FUNC_ABM) funcArray[index++] = Napi::String::New(env, "ABM");
1157
+ if (functions & RIG_FUNC_BC) funcArray[index++] = Napi::String::New(env, "BC");
1158
+ if (functions & RIG_FUNC_MBC) funcArray[index++] = Napi::String::New(env, "MBC");
1159
+ if (functions & RIG_FUNC_AFC) funcArray[index++] = Napi::String::New(env, "AFC");
1160
+ if (functions & RIG_FUNC_SATMODE) funcArray[index++] = Napi::String::New(env, "SATMODE");
1161
+ if (functions & RIG_FUNC_SCOPE) funcArray[index++] = Napi::String::New(env, "SCOPE");
1162
+ if (functions & RIG_FUNC_RESUME) funcArray[index++] = Napi::String::New(env, "RESUME");
1163
+ if (functions & RIG_FUNC_TBURST) funcArray[index++] = Napi::String::New(env, "TBURST");
1164
+
1165
+ return funcArray;
1166
+ }
1167
+
1168
+ // Split Operations
1169
+ Napi::Value NodeHamLib::SetSplitFreq(const Napi::CallbackInfo & info) {
1170
+ Napi::Env env = info.Env();
1171
+
1172
+ if (!rig_is_open) {
1173
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
1174
+ return env.Null();
1175
+ }
1176
+
1177
+ if (info.Length() < 1 || !info[0].IsNumber()) {
1178
+ Napi::TypeError::New(env, "Expected TX frequency").ThrowAsJavaScriptException();
1179
+ return env.Null();
1180
+ }
1181
+
1182
+ freq_t tx_freq = info[0].As<Napi::Number>().DoubleValue();
1183
+
1184
+ int retcode = rig_set_split_freq(my_rig, RIG_VFO_CURR, tx_freq);
1185
+ if (retcode != RIG_OK) {
1186
+ Napi::Error::New(env, rigerror(retcode)).ThrowAsJavaScriptException();
1187
+ return env.Null();
1188
+ }
1189
+
1190
+ return Napi::Number::New(env, retcode);
1191
+ }
1192
+
1193
+ Napi::Value NodeHamLib::GetSplitFreq(const Napi::CallbackInfo & info) {
1194
+ Napi::Env env = info.Env();
1195
+
1196
+ if (!rig_is_open) {
1197
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
1198
+ return env.Null();
1199
+ }
1200
+
1201
+ freq_t tx_freq;
1202
+ int retcode = rig_get_split_freq(my_rig, RIG_VFO_CURR, &tx_freq);
1203
+ if (retcode != RIG_OK) {
1204
+ Napi::Error::New(env, rigerror(retcode)).ThrowAsJavaScriptException();
1205
+ return env.Null();
1206
+ }
1207
+
1208
+ return Napi::Number::New(env, tx_freq);
1209
+ }
1210
+
1211
+ Napi::Value NodeHamLib::SetSplitMode(const Napi::CallbackInfo & info) {
1212
+ Napi::Env env = info.Env();
1213
+
1214
+ if (!rig_is_open) {
1215
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
1216
+ return env.Null();
1217
+ }
1218
+
1219
+ if (info.Length() < 1 || !info[0].IsString()) {
1220
+ Napi::TypeError::New(env, "Expected TX mode string").ThrowAsJavaScriptException();
1221
+ return env.Null();
1222
+ }
1223
+
1224
+ std::string modeStr = info[0].As<Napi::String>().Utf8Value();
1225
+ rmode_t tx_mode = rig_parse_mode(modeStr.c_str());
1226
+
1227
+ pbwidth_t tx_width = RIG_PASSBAND_NORMAL;
1228
+ if (info.Length() >= 2 && info[1].IsNumber()) {
1229
+ tx_width = info[1].As<Napi::Number>().Int32Value();
1230
+ }
1231
+
1232
+ int retcode = rig_set_split_mode(my_rig, RIG_VFO_CURR, tx_mode, tx_width);
1233
+ if (retcode != RIG_OK) {
1234
+ Napi::Error::New(env, rigerror(retcode)).ThrowAsJavaScriptException();
1235
+ return env.Null();
1236
+ }
1237
+
1238
+ return Napi::Number::New(env, retcode);
1239
+ }
1240
+
1241
+ Napi::Value NodeHamLib::GetSplitMode(const Napi::CallbackInfo & info) {
1242
+ Napi::Env env = info.Env();
1243
+
1244
+ if (!rig_is_open) {
1245
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
1246
+ return env.Null();
1247
+ }
1248
+
1249
+ rmode_t tx_mode;
1250
+ pbwidth_t tx_width;
1251
+ int retcode = rig_get_split_mode(my_rig, RIG_VFO_CURR, &tx_mode, &tx_width);
1252
+ if (retcode != RIG_OK) {
1253
+ Napi::Error::New(env, rigerror(retcode)).ThrowAsJavaScriptException();
1254
+ return env.Null();
1255
+ }
1256
+
1257
+ Napi::Object result = Napi::Object::New(env);
1258
+ result.Set("mode", Napi::String::New(env, rig_strrmode(tx_mode)));
1259
+ result.Set("width", Napi::Number::New(env, tx_width));
1260
+ return result;
1261
+ }
1262
+
1263
+ Napi::Value NodeHamLib::SetSplit(const Napi::CallbackInfo & info) {
1264
+ Napi::Env env = info.Env();
1265
+
1266
+ if (!rig_is_open) {
1267
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
1268
+ return env.Null();
1269
+ }
1270
+
1271
+ if (info.Length() < 1 || !info[0].IsBoolean()) {
1272
+ Napi::TypeError::New(env, "Expected boolean split enable state").ThrowAsJavaScriptException();
1273
+ return env.Null();
1274
+ }
1275
+
1276
+ bool split_enabled = info[0].As<Napi::Boolean>().Value();
1277
+
1278
+ vfo_t tx_vfo = RIG_VFO_B;
1279
+ if (info.Length() >= 2 && info[1].IsString()) {
1280
+ std::string vfoStr = info[1].As<Napi::String>().Utf8Value();
1281
+ if (vfoStr == "VFO-A") {
1282
+ tx_vfo = RIG_VFO_A;
1283
+ } else if (vfoStr == "VFO-B") {
1284
+ tx_vfo = RIG_VFO_B;
1285
+ }
1286
+ }
1287
+
1288
+ split_t split = split_enabled ? RIG_SPLIT_ON : RIG_SPLIT_OFF;
1289
+ int retcode = rig_set_split_vfo(my_rig, RIG_VFO_CURR, split, tx_vfo);
1290
+ if (retcode != RIG_OK) {
1291
+ Napi::Error::New(env, rigerror(retcode)).ThrowAsJavaScriptException();
1292
+ return env.Null();
1293
+ }
1294
+
1295
+ return Napi::Number::New(env, retcode);
1296
+ }
1297
+
1298
+ Napi::Value NodeHamLib::GetSplit(const Napi::CallbackInfo & info) {
1299
+ Napi::Env env = info.Env();
1300
+
1301
+ if (!rig_is_open) {
1302
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
1303
+ return env.Null();
1304
+ }
1305
+
1306
+ split_t split;
1307
+ vfo_t tx_vfo;
1308
+ int retcode = rig_get_split_vfo(my_rig, RIG_VFO_CURR, &split, &tx_vfo);
1309
+ if (retcode != RIG_OK) {
1310
+ Napi::Error::New(env, rigerror(retcode)).ThrowAsJavaScriptException();
1311
+ return env.Null();
1312
+ }
1313
+
1314
+ Napi::Object result = Napi::Object::New(env);
1315
+ result.Set("enabled", Napi::Boolean::New(env, split == RIG_SPLIT_ON));
1316
+
1317
+ std::string vfoStr = "VFO-CURR";
1318
+ if (tx_vfo == RIG_VFO_A) {
1319
+ vfoStr = "VFO-A";
1320
+ } else if (tx_vfo == RIG_VFO_B) {
1321
+ vfoStr = "VFO-B";
1322
+ }
1323
+ result.Set("txVfo", Napi::String::New(env, vfoStr));
1324
+
1325
+ return result;
1326
+ }
1327
+
1328
+ // VFO Operations
1329
+ Napi::Value NodeHamLib::VfoOperation(const Napi::CallbackInfo & info) {
1330
+ Napi::Env env = info.Env();
1331
+
1332
+ if (!rig_is_open) {
1333
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
1334
+ return env.Null();
1335
+ }
1336
+
1337
+ if (info.Length() < 1 || !info[0].IsString()) {
1338
+ Napi::TypeError::New(env, "Expected VFO operation string").ThrowAsJavaScriptException();
1339
+ return env.Null();
1340
+ }
1341
+
1342
+ std::string vfoOpStr = info[0].As<Napi::String>().Utf8Value();
1343
+
1344
+ vfo_op_t vfo_op;
1345
+ if (vfoOpStr == "CPY") {
1346
+ vfo_op = RIG_OP_CPY;
1347
+ } else if (vfoOpStr == "XCHG") {
1348
+ vfo_op = RIG_OP_XCHG;
1349
+ } else if (vfoOpStr == "FROM_VFO") {
1350
+ vfo_op = RIG_OP_FROM_VFO;
1351
+ } else if (vfoOpStr == "TO_VFO") {
1352
+ vfo_op = RIG_OP_TO_VFO;
1353
+ } else if (vfoOpStr == "MCL") {
1354
+ vfo_op = RIG_OP_MCL;
1355
+ } else if (vfoOpStr == "UP") {
1356
+ vfo_op = RIG_OP_UP;
1357
+ } else if (vfoOpStr == "DOWN") {
1358
+ vfo_op = RIG_OP_DOWN;
1359
+ } else if (vfoOpStr == "BAND_UP") {
1360
+ vfo_op = RIG_OP_BAND_UP;
1361
+ } else if (vfoOpStr == "BAND_DOWN") {
1362
+ vfo_op = RIG_OP_BAND_DOWN;
1363
+ } else if (vfoOpStr == "LEFT") {
1364
+ vfo_op = RIG_OP_LEFT;
1365
+ } else if (vfoOpStr == "RIGHT") {
1366
+ vfo_op = RIG_OP_RIGHT;
1367
+ } else if (vfoOpStr == "TUNE") {
1368
+ vfo_op = RIG_OP_TUNE;
1369
+ } else if (vfoOpStr == "TOGGLE") {
1370
+ vfo_op = RIG_OP_TOGGLE;
1371
+ } else {
1372
+ Napi::TypeError::New(env, "Invalid VFO operation").ThrowAsJavaScriptException();
1373
+ return env.Null();
1374
+ }
1375
+
1376
+ int retcode = rig_vfo_op(my_rig, RIG_VFO_CURR, vfo_op);
1377
+ if (retcode != RIG_OK) {
1378
+ Napi::Error::New(env, rigerror(retcode)).ThrowAsJavaScriptException();
1379
+ return env.Null();
1380
+ }
1381
+
1382
+ return Napi::Number::New(env, retcode);
1383
+ }
1384
+
1385
+ // Antenna Selection
1386
+ Napi::Value NodeHamLib::SetAntenna(const Napi::CallbackInfo & info) {
1387
+ Napi::Env env = info.Env();
1388
+
1389
+ if (!rig_is_open) {
1390
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
1391
+ return env.Null();
1392
+ }
1393
+
1394
+ if (info.Length() < 1 || !info[0].IsNumber()) {
1395
+ Napi::TypeError::New(env, "Expected antenna number").ThrowAsJavaScriptException();
1396
+ return env.Null();
1397
+ }
1398
+
1399
+ ant_t antenna = info[0].As<Napi::Number>().Int32Value();
1400
+ value_t option = {0}; // Additional option parameter
1401
+
1402
+ int retcode = rig_set_ant(my_rig, RIG_VFO_CURR, antenna, option);
1403
+ if (retcode != RIG_OK) {
1404
+ Napi::Error::New(env, rigerror(retcode)).ThrowAsJavaScriptException();
1405
+ return env.Null();
1406
+ }
1407
+
1408
+ return Napi::Number::New(env, retcode);
1409
+ }
1410
+
1411
+ Napi::Value NodeHamLib::GetAntenna(const Napi::CallbackInfo & info) {
1412
+ Napi::Env env = info.Env();
1413
+
1414
+ if (!rig_is_open) {
1415
+ Napi::TypeError::New(env, "Rig is not open!").ThrowAsJavaScriptException();
1416
+ return env.Null();
1417
+ }
1418
+
1419
+ ant_t antenna = RIG_ANT_CURR;
1420
+ value_t option;
1421
+ ant_t antenna_curr;
1422
+ ant_t antenna_tx;
1423
+ ant_t antenna_rx;
1424
+
1425
+ int retcode = rig_get_ant(my_rig, RIG_VFO_CURR, antenna, &option, &antenna_curr, &antenna_tx, &antenna_rx);
1426
+ if (retcode != RIG_OK) {
1427
+ Napi::Error::New(env, rigerror(retcode)).ThrowAsJavaScriptException();
1428
+ return env.Null();
1429
+ }
1430
+
1431
+ return Napi::Number::New(env, antenna_curr);
1432
+ }
1433
+
433
1434
  Napi::Function NodeHamLib::GetClass(Napi::Env env) {
434
1435
  auto ret = DefineClass(
435
1436
  env,
@@ -444,12 +1445,53 @@ Napi::Function NodeHamLib::GetClass(Napi::Env env) {
444
1445
  NodeHamLib::InstanceMethod("getMode", & NodeHamLib::GetMode),
445
1446
  NodeHamLib::InstanceMethod("getStrength", & NodeHamLib::GetStrength),
446
1447
 
1448
+ // Memory Channel Management
1449
+ NodeHamLib::InstanceMethod("setMemoryChannel", & NodeHamLib::SetMemoryChannel),
1450
+ NodeHamLib::InstanceMethod("getMemoryChannel", & NodeHamLib::GetMemoryChannel),
1451
+ NodeHamLib::InstanceMethod("selectMemoryChannel", & NodeHamLib::SelectMemoryChannel),
1452
+
1453
+ // RIT/XIT Control
1454
+ NodeHamLib::InstanceMethod("setRit", & NodeHamLib::SetRit),
1455
+ NodeHamLib::InstanceMethod("getRit", & NodeHamLib::GetRit),
1456
+ NodeHamLib::InstanceMethod("setXit", & NodeHamLib::SetXit),
1457
+ NodeHamLib::InstanceMethod("getXit", & NodeHamLib::GetXit),
1458
+ NodeHamLib::InstanceMethod("clearRitXit", & NodeHamLib::ClearRitXit),
1459
+
1460
+ // Scanning Operations
1461
+ NodeHamLib::InstanceMethod("startScan", & NodeHamLib::StartScan),
1462
+ NodeHamLib::InstanceMethod("stopScan", & NodeHamLib::StopScan),
1463
+
1464
+ // Level Controls
1465
+ NodeHamLib::InstanceMethod("setLevel", & NodeHamLib::SetLevel),
1466
+ NodeHamLib::InstanceMethod("getLevel", & NodeHamLib::GetLevel),
1467
+ NodeHamLib::InstanceMethod("getSupportedLevels", & NodeHamLib::GetSupportedLevels),
1468
+
1469
+ // Function Controls
1470
+ NodeHamLib::InstanceMethod("setFunction", & NodeHamLib::SetFunction),
1471
+ NodeHamLib::InstanceMethod("getFunction", & NodeHamLib::GetFunction),
1472
+ NodeHamLib::InstanceMethod("getSupportedFunctions", & NodeHamLib::GetSupportedFunctions),
1473
+
1474
+ // Split Operations
1475
+ NodeHamLib::InstanceMethod("setSplitFreq", & NodeHamLib::SetSplitFreq),
1476
+ NodeHamLib::InstanceMethod("getSplitFreq", & NodeHamLib::GetSplitFreq),
1477
+ NodeHamLib::InstanceMethod("setSplitMode", & NodeHamLib::SetSplitMode),
1478
+ NodeHamLib::InstanceMethod("getSplitMode", & NodeHamLib::GetSplitMode),
1479
+ NodeHamLib::InstanceMethod("setSplit", & NodeHamLib::SetSplit),
1480
+ NodeHamLib::InstanceMethod("getSplit", & NodeHamLib::GetSplit),
447
1481
 
1482
+ // VFO Operations
1483
+ NodeHamLib::InstanceMethod("vfoOperation", & NodeHamLib::VfoOperation),
448
1484
 
1485
+ // Antenna Selection
1486
+ NodeHamLib::InstanceMethod("setAntenna", & NodeHamLib::SetAntenna),
1487
+ NodeHamLib::InstanceMethod("getAntenna", & NodeHamLib::GetAntenna),
449
1488
 
450
1489
  NodeHamLib::InstanceMethod("close", & NodeHamLib::Close),
451
1490
  NodeHamLib::InstanceMethod("destroy", & NodeHamLib::Destroy),
452
1491
  NodeHamLib::InstanceMethod("getConnectionInfo", & NodeHamLib::GetConnectionInfo),
1492
+
1493
+ // Static method to get supported rig models
1494
+ NodeHamLib::StaticMethod("getSupportedRigs", & NodeHamLib::GetSupportedRigs),
453
1495
  });
454
1496
  constructor = Napi::Persistent(ret);
455
1497
  constructor.SuppressDestruct();
@@ -474,3 +1516,88 @@ bool NodeHamLib::isNetworkAddress(const char* path) {
474
1516
  return false;
475
1517
  }
476
1518
 
1519
+ // Static callback function for rig_list_foreach
1520
+ int NodeHamLib::rig_list_callback(const struct rig_caps *caps, void *data) {
1521
+ RigListData *rig_data = static_cast<RigListData*>(data);
1522
+
1523
+ // Create rig info object
1524
+ Napi::Object rigInfo = Napi::Object::New(rig_data->env);
1525
+ rigInfo.Set(Napi::String::New(rig_data->env, "rigModel"),
1526
+ Napi::Number::New(rig_data->env, caps->rig_model));
1527
+ rigInfo.Set(Napi::String::New(rig_data->env, "modelName"),
1528
+ Napi::String::New(rig_data->env, caps->model_name ? caps->model_name : ""));
1529
+ rigInfo.Set(Napi::String::New(rig_data->env, "mfgName"),
1530
+ Napi::String::New(rig_data->env, caps->mfg_name ? caps->mfg_name : ""));
1531
+ rigInfo.Set(Napi::String::New(rig_data->env, "version"),
1532
+ Napi::String::New(rig_data->env, caps->version ? caps->version : ""));
1533
+ rigInfo.Set(Napi::String::New(rig_data->env, "status"),
1534
+ Napi::String::New(rig_data->env, rig_strstatus(caps->status)));
1535
+
1536
+ // Determine rig type string
1537
+ const char* rigType = "Unknown";
1538
+ switch (caps->rig_type & RIG_TYPE_MASK) {
1539
+ case RIG_TYPE_TRANSCEIVER:
1540
+ rigType = "Transceiver";
1541
+ break;
1542
+ case RIG_TYPE_HANDHELD:
1543
+ rigType = "Handheld";
1544
+ break;
1545
+ case RIG_TYPE_MOBILE:
1546
+ rigType = "Mobile";
1547
+ break;
1548
+ case RIG_TYPE_RECEIVER:
1549
+ rigType = "Receiver";
1550
+ break;
1551
+ case RIG_TYPE_PCRECEIVER:
1552
+ rigType = "PC Receiver";
1553
+ break;
1554
+ case RIG_TYPE_SCANNER:
1555
+ rigType = "Scanner";
1556
+ break;
1557
+ case RIG_TYPE_TRUNKSCANNER:
1558
+ rigType = "Trunk Scanner";
1559
+ break;
1560
+ case RIG_TYPE_COMPUTER:
1561
+ rigType = "Computer";
1562
+ break;
1563
+ case RIG_TYPE_OTHER:
1564
+ rigType = "Other";
1565
+ break;
1566
+ }
1567
+
1568
+ rigInfo.Set(Napi::String::New(rig_data->env, "rigType"),
1569
+ Napi::String::New(rig_data->env, rigType));
1570
+
1571
+ // Add to list
1572
+ rig_data->rigList.push_back(rigInfo);
1573
+
1574
+ return 1; // Continue iteration (returning 0 would stop)
1575
+ }
1576
+
1577
+ // Static method to get supported rig models
1578
+ Napi::Value NodeHamLib::GetSupportedRigs(const Napi::CallbackInfo& info) {
1579
+ Napi::Env env = info.Env();
1580
+
1581
+ // Load all backends to ensure we get the complete list
1582
+ rig_load_all_backends();
1583
+
1584
+ // Prepare data structure for callback with proper initialization
1585
+ RigListData rigData{std::vector<Napi::Object>(), env};
1586
+
1587
+ // Call hamlib function to iterate through all supported rigs
1588
+ int result = rig_list_foreach(rig_list_callback, &rigData);
1589
+
1590
+ if (result != RIG_OK) {
1591
+ Napi::Error::New(env, "Failed to retrieve supported rig list").ThrowAsJavaScriptException();
1592
+ return env.Null();
1593
+ }
1594
+
1595
+ // Convert std::vector to Napi::Array
1596
+ Napi::Array rigArray = Napi::Array::New(env, rigData.rigList.size());
1597
+ for (size_t i = 0; i < rigData.rigList.size(); i++) {
1598
+ rigArray[i] = rigData.rigList[i];
1599
+ }
1600
+
1601
+ return rigArray;
1602
+ }
1603
+