icom-wlan-node 0.6.0 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -52,6 +52,7 @@ const IcomScopeService_1 = require("../scope/IcomScopeService");
52
52
  const IcomCivFrame_1 = require("./IcomCivFrame");
53
53
  const IcomCivSpec_1 = require("./IcomCivSpec");
54
54
  const IcomProfiles_1 = require("./IcomProfiles");
55
+ const IcomCivRequestManager_1 = require("./IcomCivRequestManager");
55
56
  const DEFAULT_SCOPE_SPANS_HZ = [25000000, 10000000, 5000000, 2500000, 1000000, 500000, 250000, 100000, 50000, 25000, 10000, 5000, 2500];
56
57
  function modeCodeToName(mode) {
57
58
  switch (mode) {
@@ -69,6 +70,78 @@ function modeNameToCode(mode) {
69
70
  case 'scroll-fixed': return 3;
70
71
  }
71
72
  }
73
+ const FUNCTION_SPECS = {
74
+ NB: { command: IcomCivSpec_1.CIV.C_CTL_FUNC, subcmd: IcomCivSpec_1.CIV.S_FUNC_NB },
75
+ NR: { command: IcomCivSpec_1.CIV.C_CTL_FUNC, subcmd: IcomCivSpec_1.CIV.S_FUNC_NR },
76
+ COMP: { command: IcomCivSpec_1.CIV.C_CTL_FUNC, subcmd: IcomCivSpec_1.CIV.S_FUNC_COMP },
77
+ VOX: { command: IcomCivSpec_1.CIV.C_CTL_FUNC, subcmd: IcomCivSpec_1.CIV.S_FUNC_VOX },
78
+ TONE: { command: IcomCivSpec_1.CIV.C_CTL_FUNC, subcmd: IcomCivSpec_1.CIV.S_FUNC_TONE },
79
+ TSQL: { command: IcomCivSpec_1.CIV.C_CTL_FUNC, subcmd: IcomCivSpec_1.CIV.S_FUNC_TSQL },
80
+ SBKIN: { command: IcomCivSpec_1.CIV.C_CTL_FUNC, subcmd: IcomCivSpec_1.CIV.S_FUNC_BKIN },
81
+ FBKIN: { command: IcomCivSpec_1.CIV.C_CTL_FUNC, subcmd: IcomCivSpec_1.CIV.S_FUNC_BKIN },
82
+ MON: { command: IcomCivSpec_1.CIV.C_CTL_FUNC, subcmd: IcomCivSpec_1.CIV.S_FUNC_MON },
83
+ ANF: { command: IcomCivSpec_1.CIV.C_CTL_FUNC, subcmd: IcomCivSpec_1.CIV.S_FUNC_ANF },
84
+ MN: { command: IcomCivSpec_1.CIV.C_CTL_FUNC, subcmd: IcomCivSpec_1.CIV.S_FUNC_MN },
85
+ LOCK: { command: IcomCivSpec_1.CIV.C_CTL_FUNC, subcmd: IcomCivSpec_1.CIV.S_FUNC_DIAL_LK },
86
+ RIT: { command: IcomCivSpec_1.CIV.C_CTL_RIT, subcmd: IcomCivSpec_1.CIV.S_RIT },
87
+ XIT: { command: IcomCivSpec_1.CIV.C_CTL_RIT, subcmd: IcomCivSpec_1.CIV.S_XIT },
88
+ TUNER: { command: IcomCivSpec_1.CIV.C_CTL_PTT, subcmd: IcomCivSpec_1.CIV.S_ANT_TUN },
89
+ APF: { command: IcomCivSpec_1.CIV.C_CTL_FUNC, subcmd: IcomCivSpec_1.CIV.S_FUNC_APF },
90
+ AFC: { command: IcomCivSpec_1.CIV.C_CTL_FUNC, subcmd: IcomCivSpec_1.CIV.S_FUNC_AFC },
91
+ VSC: { command: IcomCivSpec_1.CIV.C_CTL_FUNC, subcmd: IcomCivSpec_1.CIV.S_FUNC_VSC },
92
+ DUAL_WATCH: { command: IcomCivSpec_1.CIV.C_CTL_FUNC, subcmd: IcomCivSpec_1.CIV.S_MEM_DUALMODE },
93
+ SATMODE: { command: IcomCivSpec_1.CIV.C_CTL_FUNC, subcmd: IcomCivSpec_1.CIV.S_MEM_SATMODE },
94
+ SCOPE: { command: IcomCivSpec_1.CIV.C_CTL_SCP, subcmd: IcomCivSpec_1.CIV.S_SCP_STS },
95
+ SPECTRUM: { command: IcomCivSpec_1.CIV.C_CTL_SCP, subcmd: IcomCivSpec_1.CIV.S_SCP_DOP },
96
+ SPECTRUM_HOLD: { command: IcomCivSpec_1.CIV.C_CTL_SCP, subcmd: IcomCivSpec_1.CIV.S_SCP_HLD, payloadPrefix: [0], readPrefix: [0] },
97
+ OVF_STATUS: { command: IcomCivSpec_1.CIV.C_RD_SQSM, subcmd: IcomCivSpec_1.CIV.S_OVF },
98
+ DIGI_SEL: { command: IcomCivSpec_1.CIV.C_CTL_FUNC, subcmd: IcomCivSpec_1.CIV.S_FUNC_DIGISEL },
99
+ IPP: { command: IcomCivSpec_1.CIV.C_CTL_FUNC, subcmd: IcomCivSpec_1.CIV.S_FUNC_IPP },
100
+ TX_INHIBIT: { command: IcomCivSpec_1.CIV.C_CTL_FUNC, subcmd: IcomCivSpec_1.CIV.S_FUNC_TX_INHIBIT },
101
+ DPP: { command: IcomCivSpec_1.CIV.C_CTL_FUNC, subcmd: IcomCivSpec_1.CIV.S_FUNC_DPP },
102
+ };
103
+ function keySpeedWpmToRaw(wpm) {
104
+ const target = Math.max(6, Math.min(48, Math.round(wpm)));
105
+ return CW_LOOKUP.find(([, speed]) => speed === target)?.[0] ?? CW_LOOKUP[0][0];
106
+ }
107
+ function keySpeedRawToWpm(raw) {
108
+ return CW_LOOKUP.find(([rigValue]) => rigValue >= raw)?.[1] ?? 48;
109
+ }
110
+ const LEVEL_SPECS = {
111
+ AF: { command: IcomCivSpec_1.CIV.C_CTL_LVL, subcmd: IcomCivSpec_1.CIV.S_LVL_AF, dataBytes: 2, dataType: 'level' },
112
+ RF: { command: IcomCivSpec_1.CIV.C_CTL_LVL, subcmd: IcomCivSpec_1.CIV.S_LVL_RF, dataBytes: 2, dataType: 'level' },
113
+ SQL: { command: IcomCivSpec_1.CIV.C_CTL_LVL, subcmd: IcomCivSpec_1.CIV.S_LVL_SQL, dataBytes: 2, dataType: 'level' },
114
+ IF: { command: IcomCivSpec_1.CIV.C_CTL_LVL, subcmd: IcomCivSpec_1.CIV.S_LVL_IF, dataBytes: 2, dataType: 'level' },
115
+ APF: { command: IcomCivSpec_1.CIV.C_CTL_LVL, subcmd: IcomCivSpec_1.CIV.S_LVL_APF, dataBytes: 2, dataType: 'level' },
116
+ NR: { command: IcomCivSpec_1.CIV.C_CTL_LVL, subcmd: IcomCivSpec_1.CIV.S_LVL_NR, dataBytes: 2, dataType: 'level' },
117
+ NB: { command: IcomCivSpec_1.CIV.C_CTL_LVL, subcmd: IcomCivSpec_1.CIV.S_LVL_NB, dataBytes: 2, dataType: 'level' },
118
+ PBT_IN: { command: IcomCivSpec_1.CIV.C_CTL_LVL, subcmd: IcomCivSpec_1.CIV.S_LVL_PBTIN, dataBytes: 2, dataType: 'level' },
119
+ PBT_OUT: { command: IcomCivSpec_1.CIV.C_CTL_LVL, subcmd: IcomCivSpec_1.CIV.S_LVL_PBTOUT, dataBytes: 2, dataType: 'level' },
120
+ CWPITCH: { command: IcomCivSpec_1.CIV.C_CTL_LVL, subcmd: IcomCivSpec_1.CIV.S_LVL_CWPITCH, dataBytes: 2, dataType: 'int', publicToRaw: (hz) => Math.round((Math.max(300, Math.min(900, hz)) - 300) * 255 / 600), rawToPublic: (raw) => Math.round(300 + raw * 600 / 255) },
121
+ RFPOWER: { command: IcomCivSpec_1.CIV.C_CTL_LVL, subcmd: IcomCivSpec_1.CIV.S_LVL_RFPOWER, dataBytes: 2, dataType: 'level' },
122
+ MICGAIN: { command: IcomCivSpec_1.CIV.C_CTL_LVL, subcmd: IcomCivSpec_1.CIV.S_LVL_MICGAIN, dataBytes: 2, dataType: 'level' },
123
+ KEYSPD: { command: IcomCivSpec_1.CIV.C_CTL_LVL, subcmd: IcomCivSpec_1.CIV.S_LVL_KEYSPD, dataBytes: 2, dataType: 'int', publicToRaw: keySpeedWpmToRaw, rawToPublic: keySpeedRawToWpm },
124
+ NOTCHF_RAW: { command: IcomCivSpec_1.CIV.C_CTL_LVL, subcmd: IcomCivSpec_1.CIV.S_LVL_NOTCHF, dataBytes: 2, dataType: 'level' },
125
+ COMP: { command: IcomCivSpec_1.CIV.C_CTL_LVL, subcmd: IcomCivSpec_1.CIV.S_LVL_COMP, dataBytes: 2, dataType: 'level' },
126
+ BKINDL: { command: IcomCivSpec_1.CIV.C_CTL_LVL, subcmd: IcomCivSpec_1.CIV.S_LVL_BKINDL, dataBytes: 2, dataType: 'level' },
127
+ BALANCE: { command: IcomCivSpec_1.CIV.C_CTL_LVL, subcmd: IcomCivSpec_1.CIV.S_LVL_BALANCE, dataBytes: 2, dataType: 'level' },
128
+ VOXGAIN: { command: IcomCivSpec_1.CIV.C_CTL_LVL, subcmd: IcomCivSpec_1.CIV.S_LVL_VOXGAIN, dataBytes: 2, dataType: 'level' },
129
+ ANTIVOX: { command: IcomCivSpec_1.CIV.C_CTL_LVL, subcmd: IcomCivSpec_1.CIV.S_LVL_ANTIVOX, dataBytes: 2, dataType: 'level' },
130
+ MONITOR_GAIN: { command: IcomCivSpec_1.CIV.C_CTL_LVL, subcmd: IcomCivSpec_1.CIV.S_LVL_MON, dataBytes: 2, dataType: 'level' },
131
+ DRIVE_GAIN: { command: IcomCivSpec_1.CIV.C_CTL_LVL, subcmd: IcomCivSpec_1.CIV.S_LVL_DRIVE, dataBytes: 2, dataType: 'level' },
132
+ DIGI_SEL_LEVEL: { command: IcomCivSpec_1.CIV.C_CTL_LVL, subcmd: IcomCivSpec_1.CIV.S_LVL_DIGI, dataBytes: 2, dataType: 'level' },
133
+ AGC: { command: IcomCivSpec_1.CIV.C_CTL_FUNC, subcmd: IcomCivSpec_1.CIV.S_FUNC_AGC, dataBytes: 1, dataType: 'int' },
134
+ AGC_TIME: { command: IcomCivSpec_1.CIV.C_CTL_MEM, subcmd: 0x04, dataBytes: 1, dataType: 'int' },
135
+ };
136
+ const CW_LOOKUP = [
137
+ [0, 6], [7, 7], [12, 8], [19, 9], [25, 10], [31, 11], [37, 12], [43, 13],
138
+ [49, 14], [55, 15], [61, 16], [67, 17], [73, 18], [79, 19], [84, 20],
139
+ [91, 21], [97, 22], [103, 23], [108, 24], [114, 25], [121, 26], [128, 27],
140
+ [134, 28], [140, 29], [144, 30], [151, 31], [156, 32], [164, 33],
141
+ [169, 34], [175, 35], [182, 36], [188, 37], [192, 38], [199, 39],
142
+ [203, 40], [211, 41], [215, 42], [224, 43], [229, 44], [234, 45],
143
+ [239, 46], [244, 47], [250, 48],
144
+ ];
72
145
  class IcomControl {
73
146
  constructor(options) {
74
147
  this.ev = new events_1.EventEmitter();
@@ -119,6 +192,7 @@ class IcomControl {
119
192
  this.civ = new IcomCiv_1.IcomCiv(this.civSess);
120
193
  this.audio = new IcomAudio_1.IcomAudio(this.audioSess);
121
194
  this.scope = new IcomScopeService_1.IcomScopeService();
195
+ this.civRequestManager = new IcomCivRequestManager_1.IcomCivRequestManager(this.ev);
122
196
  this.scope.on('scopeSegment', (segment) => this.ev.emit('scopeSegment', segment));
123
197
  this.scope.on('scopeFrame', (frame) => this.ev.emit('scopeFrame', frame));
124
198
  }
@@ -576,7 +650,7 @@ class IcomControl {
576
650
  const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
577
651
  const rigAddr = this.civ.civAddress & 0xff;
578
652
  const req = IcomScopeCommands_1.IcomScopeCommands.readScopeSpan(ctrAddr, rigAddr, receiver);
579
- const resp = await this.waitForCivFrame((frame) => IcomControl.matchCommandFrame(frame, 0x27, [0x15, receiver], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
653
+ const resp = await this.waitForCivFrame(`scope:0x27:0x15:${receiver}`, (frame) => IcomControl.matchCommandFrame(frame, 0x27, [0x15, receiver], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
580
654
  if (!resp || resp.length < 13) {
581
655
  return null;
582
656
  }
@@ -598,7 +672,7 @@ class IcomControl {
598
672
  const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
599
673
  const rigAddr = this.civ.civAddress & 0xff;
600
674
  const req = IcomScopeCommands_1.IcomScopeCommands.readScopeMode(ctrAddr, rigAddr, receiver);
601
- const resp = await this.waitForCivFrame((frame) => IcomControl.matchCommandFrame(frame, 0x27, [0x14, receiver], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
675
+ const resp = await this.waitForCivFrame(`scope:0x27:0x14:${receiver}`, (frame) => IcomControl.matchCommandFrame(frame, 0x27, [0x14, receiver], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
602
676
  if (!resp || resp.length < 9) {
603
677
  return null;
604
678
  }
@@ -622,7 +696,7 @@ class IcomControl {
622
696
  const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
623
697
  const rigAddr = this.civ.civAddress & 0xff;
624
698
  const req = IcomScopeCommands_1.IcomScopeCommands.readScopeEdge(ctrAddr, rigAddr, receiver);
625
- const resp = await this.waitForCivFrame((frame) => IcomControl.matchCommandFrame(frame, 0x27, [0x16, receiver], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
699
+ const resp = await this.waitForCivFrame(`scope:0x27:0x16:${receiver}`, (frame) => IcomControl.matchCommandFrame(frame, 0x27, [0x16, receiver], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
626
700
  if (!resp || resp.length < 9) {
627
701
  return null;
628
702
  }
@@ -645,7 +719,7 @@ class IcomControl {
645
719
  const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
646
720
  const rigAddr = this.civ.civAddress & 0xff;
647
721
  const req = IcomScopeCommands_1.IcomScopeCommands.readScopeFixedEdge(ctrAddr, rigAddr, rangeId, edgeSlot);
648
- const resp = await this.waitForCivFrame((frame) => IcomControl.matchCommandFrame(frame, 0x27, [0x1e, rangeId, edgeSlot], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
722
+ const resp = await this.waitForCivFrame(`scope:0x27:0x1e:${rangeId}:${edgeSlot}`, (frame) => IcomControl.matchCommandFrame(frame, 0x27, [0x1e, rangeId, edgeSlot], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
649
723
  if (!resp || resp.length < 18) {
650
724
  return null;
651
725
  }
@@ -855,7 +929,7 @@ class IcomControl {
855
929
  const req = useX25
856
930
  ? IcomRigCommands_1.IcomRigCommands.readSelectedFrequency(ctrAddr, rigAddr, 0)
857
931
  : IcomRigCommands_1.IcomRigCommands.readOperatingFrequency(ctrAddr, rigAddr);
858
- const resp = await this.waitForCivFrame((frame) => useX25
932
+ const resp = await this.waitForCivFrame(useX25 ? 'freq:0x25:0' : 'freq:0x03', (frame) => useX25
859
933
  ? IcomControl.matchCommandFrame(frame, IcomCivSpec_1.CIV.C_SEND_SEL_FREQ, [0x00], ctrAddr, rigAddr)
860
934
  : IcomControl.matchCommandFrame(frame, IcomCivSpec_1.CIV.C_RD_FREQ, [], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
861
935
  if (!resp)
@@ -872,7 +946,7 @@ class IcomControl {
872
946
  const rigAddr = this.civ.civAddress & 0xff;
873
947
  const useX26 = this.activeProfile.supportsX25X26 && this.activeProfile.modeWithFilter;
874
948
  const req = useX26 ? IcomRigCommands_1.IcomRigCommands.readSelectedMode(ctrAddr, rigAddr, 0) : IcomRigCommands_1.IcomRigCommands.readOperatingMode(ctrAddr, rigAddr);
875
- const resp = await this.waitForCivFrame((frame) => useX26
949
+ const resp = await this.waitForCivFrame(useX26 ? 'mode:0x26:0' : 'mode:0x04', (frame) => useX26
876
950
  ? IcomControl.matchCommandFrame(frame, IcomCivSpec_1.CIV.C_SEND_SEL_MODE, [0x00], ctrAddr, rigAddr)
877
951
  : IcomControl.matchCommandFrame(frame, IcomCivSpec_1.CIV.C_RD_MODE, [], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
878
952
  if (!resp)
@@ -899,7 +973,7 @@ class IcomControl {
899
973
  const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
900
974
  const rigAddr = this.civ.civAddress & 0xff;
901
975
  const req = IcomRigCommands_1.IcomRigCommands.readTransmitFrequency(ctrAddr, rigAddr);
902
- const resp = await this.waitForCivFrame((frame) => IcomControl.matchCommandFrame(frame, IcomCivSpec_1.CIV.C_CTL_PTT, [IcomCivSpec_1.CIV.S_RD_TX_FREQ], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
976
+ const resp = await this.waitForCivFrame('freq:0x1c:0x03', (frame) => IcomControl.matchCommandFrame(frame, IcomCivSpec_1.CIV.C_CTL_PTT, [IcomCivSpec_1.CIV.S_RD_TX_FREQ], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
903
977
  if (!resp)
904
978
  return null;
905
979
  return IcomControl.parseFrequencyReply(resp, 1);
@@ -909,7 +983,7 @@ class IcomControl {
909
983
  const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
910
984
  const rigAddr = this.civ.civAddress & 0xff;
911
985
  const req = IcomRigCommands_1.IcomRigCommands.readPTT(ctrAddr, rigAddr);
912
- const resp = await this.waitForCivFrame((frame) => IcomControl.matchCommandFrame(frame, IcomCivSpec_1.CIV.C_CTL_PTT, [IcomCivSpec_1.CIV.S_PTT], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
986
+ const resp = await this.waitForCivFrame('ptt:0x1c:0x00', (frame) => IcomControl.matchCommandFrame(frame, IcomCivSpec_1.CIV.C_CTL_PTT, [IcomCivSpec_1.CIV.S_PTT], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
913
987
  if (!resp || resp.length < 7)
914
988
  return null;
915
989
  return resp[6] !== 0x00;
@@ -929,7 +1003,7 @@ class IcomControl {
929
1003
  const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
930
1004
  const rigAddr = this.civ.civAddress & 0xff;
931
1005
  const req = IcomRigCommands_1.IcomRigCommands.readBandEdges(ctrAddr, rigAddr);
932
- const resp = await this.waitForCivFrame((frame) => IcomControl.matchCommandFrame(frame, 0x02, [], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1006
+ const resp = await this.waitForCivFrame('band:0x02', (frame) => IcomControl.matchCommandFrame(frame, 0x02, [], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
933
1007
  if (!resp)
934
1008
  return null;
935
1009
  // Return raw payload bytes after command
@@ -950,7 +1024,7 @@ class IcomControl {
950
1024
  const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
951
1025
  const rigAddr = this.civ.civAddress & 0xff;
952
1026
  const req = IcomRigCommands_1.IcomRigCommands.getSWRState(ctrAddr, rigAddr);
953
- const resp = await this.waitForCivFrame((frame) => IcomControl.isMeterReply(frame, 0x12, ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1027
+ const resp = await this.waitForCivFrame('meter:0x15:0x12', (frame) => IcomControl.isMeterReply(frame, 0x12, ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
954
1028
  const raw = IcomControl.extractMeterData(resp);
955
1029
  if (raw === null)
956
1030
  return null;
@@ -975,7 +1049,7 @@ class IcomControl {
975
1049
  const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
976
1050
  const rigAddr = this.civ.civAddress & 0xff;
977
1051
  const req = IcomRigCommands_1.IcomRigCommands.getALCState(ctrAddr, rigAddr);
978
- const resp = await this.waitForCivFrame((frame) => IcomControl.isMeterReply(frame, 0x13, ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1052
+ const resp = await this.waitForCivFrame('meter:0x15:0x13', (frame) => IcomControl.isMeterReply(frame, 0x13, ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
979
1053
  const raw = IcomControl.extractMeterData(resp);
980
1054
  if (raw === null)
981
1055
  return null;
@@ -1003,7 +1077,7 @@ class IcomControl {
1003
1077
  const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1004
1078
  const rigAddr = this.civ.civAddress & 0xff;
1005
1079
  const req = IcomRigCommands_1.IcomRigCommands.getConnectorWLanLevel(ctrAddr, rigAddr, ext.subext);
1006
- const resp = await this.waitForCivFrame((frame) => IcomControl.matchCommandFrame(frame, ext.command, [ext.subcmd, ...ext.subext], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1080
+ const resp = await this.waitForCivFrame(`ext:0x${ext.command.toString(16)}:0x${ext.subcmd.toString(16)}:${ext.subext.join('.')}`, (frame) => IcomControl.matchCommandFrame(frame, ext.command, [ext.subcmd, ...ext.subext], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1007
1081
  const raw = IcomControl.extractTrailingBcd(resp, ext.dataBytes);
1008
1082
  if (raw === null)
1009
1083
  return null;
@@ -1034,7 +1108,7 @@ class IcomControl {
1034
1108
  const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1035
1109
  const rigAddr = this.civ.civAddress & 0xff;
1036
1110
  const req = IcomRigCommands_1.IcomRigCommands.getLevelMeter(ctrAddr, rigAddr);
1037
- const resp = await this.waitForCivFrame((frame) => IcomControl.isMeterReply(frame, 0x02, ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1111
+ const resp = await this.waitForCivFrame('meter:0x15:0x02', (frame) => IcomControl.isMeterReply(frame, 0x02, ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1038
1112
  if (!resp)
1039
1113
  return null;
1040
1114
  const data = resp.subarray(6, resp.length - 1);
@@ -1064,7 +1138,7 @@ class IcomControl {
1064
1138
  const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1065
1139
  const rigAddr = this.civ.civAddress & 0xff;
1066
1140
  const req = IcomRigCommands_1.IcomRigCommands.getUsbAfLevel(ctrAddr, rigAddr, ext.subext);
1067
- const resp = await this.waitForCivFrame((frame) => IcomControl.matchCommandFrame(frame, ext.command, [ext.subcmd, ...ext.subext], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1141
+ const resp = await this.waitForCivFrame(`ext:0x${ext.command.toString(16)}:0x${ext.subcmd.toString(16)}:${ext.subext.join('.')}`, (frame) => IcomControl.matchCommandFrame(frame, ext.command, [ext.subcmd, ...ext.subext], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1068
1142
  const raw = IcomControl.extractTrailingBcd(resp, ext.dataBytes);
1069
1143
  if (raw === null)
1070
1144
  return null;
@@ -1111,7 +1185,7 @@ class IcomControl {
1111
1185
  const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1112
1186
  const rigAddr = this.civ.civAddress & 0xff;
1113
1187
  const req = IcomRigCommands_1.IcomRigCommands.getTunerStatus(ctrAddr, rigAddr);
1114
- const resp = await this.waitForCivFrame((frame) => IcomControl.matchCommandFrame(frame, IcomCivSpec_1.CIV.C_CTL_PTT, [IcomCivSpec_1.CIV.S_ANT_TUN], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1188
+ const resp = await this.waitForCivFrame('tuner:0x1c:0x01', (frame) => IcomControl.matchCommandFrame(frame, IcomCivSpec_1.CIV.C_CTL_PTT, [IcomCivSpec_1.CIV.S_ANT_TUN], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1115
1189
  if (!resp)
1116
1190
  return null;
1117
1191
  // Expect FE FE [ctr] [rig] 0x1C 0x01 [status] FD
@@ -1233,7 +1307,7 @@ class IcomControl {
1233
1307
  const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1234
1308
  const rigAddr = this.civ.civAddress & 0xff;
1235
1309
  const req = IcomRigCommands_1.IcomRigCommands.getSquelchStatus(ctrAddr, rigAddr);
1236
- const resp = await this.waitForCivFrame((frame) => IcomControl.isMeterReply(frame, 0x01, ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1310
+ const resp = await this.waitForCivFrame('meter:0x15:0x01', (frame) => IcomControl.isMeterReply(frame, 0x01, ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1237
1311
  const raw = IcomControl.extractMeterData(resp);
1238
1312
  if (raw === null)
1239
1313
  return null;
@@ -1257,7 +1331,7 @@ class IcomControl {
1257
1331
  const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1258
1332
  const rigAddr = this.civ.civAddress & 0xff;
1259
1333
  const req = IcomRigCommands_1.IcomRigCommands.getAudioSquelch(ctrAddr, rigAddr);
1260
- const resp = await this.waitForCivFrame((frame) => IcomControl.isMeterReply(frame, 0x05, ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1334
+ const resp = await this.waitForCivFrame('meter:0x15:0x05', (frame) => IcomControl.isMeterReply(frame, 0x05, ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1261
1335
  const raw = IcomControl.extractMeterData(resp);
1262
1336
  if (raw === null)
1263
1337
  return null;
@@ -1281,7 +1355,7 @@ class IcomControl {
1281
1355
  const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1282
1356
  const rigAddr = this.civ.civAddress & 0xff;
1283
1357
  const req = IcomRigCommands_1.IcomRigCommands.getOvfStatus(ctrAddr, rigAddr);
1284
- const resp = await this.waitForCivFrame((frame) => IcomControl.isMeterReply(frame, 0x07, ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1358
+ const resp = await this.waitForCivFrame('meter:0x15:0x07', (frame) => IcomControl.isMeterReply(frame, 0x07, ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1285
1359
  const raw = IcomControl.extractMeterData(resp);
1286
1360
  if (raw === null)
1287
1361
  return null;
@@ -1305,7 +1379,7 @@ class IcomControl {
1305
1379
  const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1306
1380
  const rigAddr = this.civ.civAddress & 0xff;
1307
1381
  const req = IcomRigCommands_1.IcomRigCommands.getPowerLevel(ctrAddr, rigAddr);
1308
- const resp = await this.waitForCivFrame((frame) => IcomControl.isMeterReply(frame, 0x11, ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1382
+ const resp = await this.waitForCivFrame('meter:0x15:0x11', (frame) => IcomControl.isMeterReply(frame, 0x11, ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1309
1383
  const raw = IcomControl.extractMeterData(resp);
1310
1384
  if (raw === null)
1311
1385
  return null;
@@ -1332,7 +1406,7 @@ class IcomControl {
1332
1406
  const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1333
1407
  const rigAddr = this.civ.civAddress & 0xff;
1334
1408
  const req = IcomRigCommands_1.IcomRigCommands.getCompLevel(ctrAddr, rigAddr);
1335
- const resp = await this.waitForCivFrame((frame) => IcomControl.isMeterReply(frame, 0x14, ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1409
+ const resp = await this.waitForCivFrame('meter:0x15:0x14', (frame) => IcomControl.isMeterReply(frame, 0x14, ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1336
1410
  const raw = IcomControl.extractMeterData(resp);
1337
1411
  if (raw === null)
1338
1412
  return null;
@@ -1358,7 +1432,7 @@ class IcomControl {
1358
1432
  const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1359
1433
  const rigAddr = this.civ.civAddress & 0xff;
1360
1434
  const req = IcomRigCommands_1.IcomRigCommands.getVoltage(ctrAddr, rigAddr);
1361
- const resp = await this.waitForCivFrame((frame) => IcomControl.isMeterReply(frame, 0x15, ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1435
+ const resp = await this.waitForCivFrame('meter:0x15:0x15', (frame) => IcomControl.isMeterReply(frame, 0x15, ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1362
1436
  const raw = IcomControl.extractMeterData(resp);
1363
1437
  if (raw === null)
1364
1438
  return null;
@@ -1382,7 +1456,7 @@ class IcomControl {
1382
1456
  const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1383
1457
  const rigAddr = this.civ.civAddress & 0xff;
1384
1458
  const req = IcomRigCommands_1.IcomRigCommands.getCurrent(ctrAddr, rigAddr);
1385
- const resp = await this.waitForCivFrame((frame) => IcomControl.isMeterReply(frame, 0x16, ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1459
+ const resp = await this.waitForCivFrame('meter:0x15:0x16', (frame) => IcomControl.isMeterReply(frame, 0x16, ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1386
1460
  const raw = IcomControl.extractMeterData(resp);
1387
1461
  if (raw === null)
1388
1462
  return null;
@@ -1391,6 +1465,595 @@ class IcomControl {
1391
1465
  amps: (0, IcomProfiles_1.interpolateCalibration)(raw, this.activeProfile.calibrations.current)
1392
1466
  };
1393
1467
  }
1468
+ async getFunction(name, options) {
1469
+ if (!this.activeProfile.functions.includes(name))
1470
+ return null;
1471
+ const ext = this.activeProfile.extParamSpecs[name];
1472
+ if (ext) {
1473
+ const value = await this.readExtParamValue(ext, `func-ext:${name}`, options);
1474
+ return value === null ? null : value !== 0;
1475
+ }
1476
+ const spec = FUNCTION_SPECS[name];
1477
+ if (!spec)
1478
+ return null;
1479
+ const raw = await this.readFunctionRaw(name, spec, options);
1480
+ if (raw === null)
1481
+ return null;
1482
+ if (name === 'SBKIN')
1483
+ return raw === 1;
1484
+ if (name === 'FBKIN')
1485
+ return raw === 2;
1486
+ return raw !== 0;
1487
+ }
1488
+ setFunction(name, enabled) {
1489
+ if (!this.activeProfile.functions.includes(name)) {
1490
+ throw this.unsupported(name, 'setFunction', 'Function is not enabled for active profile');
1491
+ }
1492
+ const ext = this.activeProfile.extParamSpecs[name];
1493
+ if (ext) {
1494
+ this.writeExtParamValue(ext, enabled ? 1 : 0);
1495
+ return;
1496
+ }
1497
+ const spec = FUNCTION_SPECS[name];
1498
+ if (!spec || name === 'OVF_STATUS') {
1499
+ throw this.unsupported(name, 'setFunction', 'Function is read-only or has no CI-V writer');
1500
+ }
1501
+ let value = enabled ? 1 : 0;
1502
+ if (name === 'SBKIN')
1503
+ value = enabled ? 1 : 0;
1504
+ if (name === 'FBKIN')
1505
+ value = enabled ? 2 : 0;
1506
+ this.writeFunctionRaw(spec, value);
1507
+ }
1508
+ async getLevel(name, options) {
1509
+ if (!this.activeProfile.levels.includes(name))
1510
+ return null;
1511
+ const ext = this.activeProfile.extParamSpecs[name];
1512
+ if (ext) {
1513
+ return this.readExtParamValue(ext, `level-ext:${name}`, options);
1514
+ }
1515
+ const spec = LEVEL_SPECS[name];
1516
+ if (!spec)
1517
+ return null;
1518
+ const raw = await this.readLevelRaw(name, spec, options);
1519
+ if (raw === null)
1520
+ return null;
1521
+ return spec.rawToPublic ? spec.rawToPublic(raw) : spec.dataType === 'level' ? raw / 255 : raw;
1522
+ }
1523
+ setLevel(name, value) {
1524
+ if (!this.activeProfile.levels.includes(name)) {
1525
+ throw this.unsupported(name, 'setLevel', 'Level is not enabled for active profile');
1526
+ }
1527
+ const ext = this.activeProfile.extParamSpecs[name];
1528
+ if (ext) {
1529
+ this.writeExtParamValue(ext, value);
1530
+ return;
1531
+ }
1532
+ const spec = LEVEL_SPECS[name];
1533
+ if (!spec) {
1534
+ throw this.unsupported(name, 'setLevel', 'No level command mapping');
1535
+ }
1536
+ const raw = spec.publicToRaw
1537
+ ? spec.publicToRaw(value)
1538
+ : spec.dataType === 'level'
1539
+ ? Math.round(Math.max(0, Math.min(1, value)) * 255)
1540
+ : Math.round(value);
1541
+ this.writeLevelRaw(spec, raw);
1542
+ }
1543
+ async getParameter(name, options) {
1544
+ if (!this.activeProfile.parameters.includes(name))
1545
+ return null;
1546
+ const ext = this.activeProfile.extParamSpecs[name];
1547
+ if (!ext)
1548
+ return null;
1549
+ const value = await this.readExtParamValue(ext, `parm:${name}`, options);
1550
+ if (value === null)
1551
+ return null;
1552
+ return ext.dataType === 'bool' ? value !== 0 : value;
1553
+ }
1554
+ setParameter(name, value) {
1555
+ if (!this.activeProfile.parameters.includes(name)) {
1556
+ throw this.unsupported(name, 'setParameter', 'Parameter is not enabled for active profile');
1557
+ }
1558
+ const ext = this.activeProfile.extParamSpecs[name];
1559
+ if (!ext) {
1560
+ throw this.unsupported(name, 'setParameter', 'No parameter command mapping');
1561
+ }
1562
+ this.writeExtParamValue(ext, typeof value === 'boolean' ? (value ? 1 : 0) : value);
1563
+ }
1564
+ async getNoiseBlankerEnabled(options) { return this.getFunction('NB', options); }
1565
+ setNoiseBlankerEnabled(enabled) { this.setFunction('NB', enabled); }
1566
+ async getNoiseReductionEnabled(options) { return this.getFunction('NR', options); }
1567
+ setNoiseReductionEnabled(enabled) { this.setFunction('NR', enabled); }
1568
+ async getCompressorEnabled(options) { return this.getFunction('COMP', options); }
1569
+ setCompressorEnabled(enabled) { this.setFunction('COMP', enabled); }
1570
+ async getVoxEnabled(options) { return this.getFunction('VOX', options); }
1571
+ setVoxEnabled(enabled) { this.setFunction('VOX', enabled); }
1572
+ async getMonitorEnabled(options) { return this.getFunction('MON', options); }
1573
+ setMonitorEnabled(enabled) { this.setFunction('MON', enabled); }
1574
+ async getAutoNotchEnabled(options) { return this.getFunction('ANF', options); }
1575
+ setAutoNotchEnabled(enabled) { this.setFunction('ANF', enabled); }
1576
+ async getManualNotchEnabled(options) { return this.getFunction('MN', options); }
1577
+ setManualNotchEnabled(enabled) { this.setFunction('MN', enabled); }
1578
+ async getDialLockEnabled(options) { return this.getFunction('LOCK', options); }
1579
+ setDialLockEnabled(enabled) { this.setFunction('LOCK', enabled); }
1580
+ async getBreakInMode(options) {
1581
+ const spec = FUNCTION_SPECS.SBKIN;
1582
+ if (!spec || !this.activeProfile.functions.includes('SBKIN'))
1583
+ return null;
1584
+ const raw = await this.readFunctionRaw('SBKIN', spec, options);
1585
+ if (raw === null)
1586
+ return null;
1587
+ return raw === 1 ? 'semi' : raw === 2 ? 'full' : 'off';
1588
+ }
1589
+ setBreakInMode(mode) {
1590
+ const spec = FUNCTION_SPECS.SBKIN;
1591
+ if (!spec || !this.activeProfile.functions.includes('SBKIN')) {
1592
+ throw this.unsupported('SBKIN', 'setBreakInMode', 'Break-in function is not enabled for active profile');
1593
+ }
1594
+ this.writeFunctionRaw(spec, mode === 'semi' ? 1 : mode === 'full' ? 2 : 0);
1595
+ }
1596
+ async getRFGain(options) { return this.getLevel('RF', options); }
1597
+ setRFGain(value) { this.setLevel('RF', value); }
1598
+ async getIFShift(options) { return this.getLevel('IF', options); }
1599
+ setIFShift(value) { this.setLevel('IF', value); }
1600
+ async getPbtIn(options) { return this.getLevel('PBT_IN', options); }
1601
+ setPbtIn(value) { this.setLevel('PBT_IN', value); }
1602
+ async getPbtOut(options) { return this.getLevel('PBT_OUT', options); }
1603
+ setPbtOut(value) { this.setLevel('PBT_OUT', value); }
1604
+ async getCwPitch(options) { return this.getLevel('CWPITCH', options); }
1605
+ setCwPitch(hz) { this.setLevel('CWPITCH', hz); }
1606
+ async getKeySpeed(options) { return this.getLevel('KEYSPD', options); }
1607
+ setKeySpeed(wpm) { this.setLevel('KEYSPD', wpm); }
1608
+ async getNotchRaw(options) { return this.getLevel('NOTCHF_RAW', options); }
1609
+ setNotchRaw(value) { this.setLevel('NOTCHF_RAW', value); }
1610
+ async getCompressionLevel(options) { return this.getLevel('COMP', options); }
1611
+ setCompressionLevel(value) { this.setLevel('COMP', value); }
1612
+ async getMonitorGain(options) { return this.getLevel('MONITOR_GAIN', options); }
1613
+ setMonitorGain(value) { this.setLevel('MONITOR_GAIN', value); }
1614
+ async getVoxGain(options) { return this.getLevel('VOXGAIN', options); }
1615
+ setVoxGain(value) { this.setLevel('VOXGAIN', value); }
1616
+ async getAntiVox(options) { return this.getLevel('ANTIVOX', options); }
1617
+ setAntiVox(value) { this.setLevel('ANTIVOX', value); }
1618
+ async getRitOffset(options) { return this.readRitOffset(options); }
1619
+ setRitOffset(offsetHz) { this.writeRitOffset(offsetHz); }
1620
+ async getXitOffset(options) { return this.readRitOffset(options); }
1621
+ setXitOffset(offsetHz) { this.writeRitOffset(offsetHz); }
1622
+ async getRitEnabled(options) { return this.getFunction('RIT', options); }
1623
+ setRitEnabled(enabled) { this.setFunction('RIT', enabled); }
1624
+ async getXitEnabled(options) { return this.getFunction('XIT', options); }
1625
+ setXitEnabled(enabled) { this.setFunction('XIT', enabled); }
1626
+ async getVfo(options) {
1627
+ const timeoutMs = options?.timeout ?? 3000;
1628
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1629
+ const rigAddr = this.civ.civAddress & 0xff;
1630
+ const req = IcomRigCommands_1.IcomRigCommands.readCommand(ctrAddr, rigAddr, IcomCivSpec_1.CIV.C_SET_VFO, IcomCivSpec_1.CIV.S_BAND_SEL);
1631
+ const resp = await this.waitForCivFrame('vfo:0x07:0xd2', (frame) => IcomControl.matchCommandFrame(frame, IcomCivSpec_1.CIV.C_SET_VFO, [IcomCivSpec_1.CIV.S_BAND_SEL], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1632
+ if (!resp || resp.length < 8)
1633
+ return null;
1634
+ return resp[6] === 0 ? 'MAIN' : 'SUB';
1635
+ }
1636
+ setVfo(vfo) {
1637
+ const subcmd = this.vfoToSubcmd(vfo);
1638
+ if (subcmd === null) {
1639
+ throw this.unsupported(vfo, 'setVfo', 'VFO cannot be directly selected');
1640
+ }
1641
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1642
+ const rigAddr = this.civ.civAddress & 0xff;
1643
+ this.sendCiv(IcomRigCommands_1.IcomRigCommands.writeCommand(ctrAddr, rigAddr, IcomCivSpec_1.CIV.C_SET_VFO, subcmd));
1644
+ }
1645
+ vfoOperation(op) {
1646
+ if (!this.activeProfile.vfoOps.includes(op)) {
1647
+ throw this.unsupported(op, 'vfoOperation', 'VFO operation is not enabled for active profile');
1648
+ }
1649
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1650
+ const rigAddr = this.civ.civAddress & 0xff;
1651
+ switch (op) {
1652
+ case 'copy':
1653
+ this.sendCiv(IcomRigCommands_1.IcomRigCommands.writeCommand(ctrAddr, rigAddr, IcomCivSpec_1.CIV.C_SET_VFO, IcomCivSpec_1.CIV.S_BTOA));
1654
+ return;
1655
+ case 'exchange':
1656
+ this.sendCiv(IcomRigCommands_1.IcomRigCommands.writeCommand(ctrAddr, rigAddr, IcomCivSpec_1.CIV.C_SET_VFO, IcomCivSpec_1.CIV.S_XCHNG));
1657
+ return;
1658
+ case 'from-vfo':
1659
+ this.sendCiv(IcomRigCommands_1.IcomRigCommands.writeCommand(ctrAddr, rigAddr, IcomCivSpec_1.CIV.C_WR_MEM, undefined));
1660
+ return;
1661
+ case 'to-vfo':
1662
+ this.sendCiv(IcomRigCommands_1.IcomRigCommands.writeCommand(ctrAddr, rigAddr, IcomCivSpec_1.CIV.C_MEM2VFO, undefined));
1663
+ return;
1664
+ case 'memory-clear':
1665
+ this.sendCiv(IcomRigCommands_1.IcomRigCommands.writeCommand(ctrAddr, rigAddr, IcomCivSpec_1.CIV.C_CLR_MEM, undefined));
1666
+ return;
1667
+ case 'tune':
1668
+ this.sendCiv(IcomRigCommands_1.IcomRigCommands.startManualTune(ctrAddr, rigAddr));
1669
+ return;
1670
+ }
1671
+ }
1672
+ async getSplitEnabled(options) {
1673
+ const raw = await this.readSplitRaw(options);
1674
+ if (raw === null)
1675
+ return null;
1676
+ return raw === IcomCivSpec_1.CIV.S_SPLT_ON;
1677
+ }
1678
+ setSplitEnabled(enabled) {
1679
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1680
+ const rigAddr = this.civ.civAddress & 0xff;
1681
+ this.sendCiv(IcomRigCommands_1.IcomRigCommands.setSplit(ctrAddr, rigAddr, enabled));
1682
+ }
1683
+ async getSplitFrequency(options) {
1684
+ const timeoutMs = options?.timeout ?? 3000;
1685
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1686
+ const rigAddr = this.civ.civAddress & 0xff;
1687
+ const req = IcomRigCommands_1.IcomRigCommands.readSelectedFrequency(ctrAddr, rigAddr, 1);
1688
+ const resp = await this.waitForCivFrame('freq:0x25:1', (frame) => IcomControl.matchCommandFrame(frame, IcomCivSpec_1.CIV.C_SEND_SEL_FREQ, [0x01], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1689
+ return resp ? IcomControl.parseFrequencyReply(resp, 1) : null;
1690
+ }
1691
+ setSplitFrequency(hz) {
1692
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1693
+ const rigAddr = this.civ.civAddress & 0xff;
1694
+ this.sendCiv(IcomRigCommands_1.IcomRigCommands.setSelectedFrequency(ctrAddr, rigAddr, hz, this.activeProfile.frequencyBcdBytes(hz), 1));
1695
+ }
1696
+ async getSplitMode(options) {
1697
+ const timeoutMs = options?.timeout ?? 3000;
1698
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1699
+ const rigAddr = this.civ.civAddress & 0xff;
1700
+ const req = IcomRigCommands_1.IcomRigCommands.readSelectedMode(ctrAddr, rigAddr, 1);
1701
+ const resp = await this.waitForCivFrame('mode:0x26:1', (frame) => IcomControl.matchCommandFrame(frame, IcomCivSpec_1.CIV.C_SEND_SEL_MODE, [0x01], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1702
+ if (!resp || resp.length < 10)
1703
+ return null;
1704
+ const { getModeString, getFilterString } = await Promise.resolve().then(() => __importStar(require('./IcomConstants')));
1705
+ const mode = resp[6];
1706
+ const dataMode = resp[7] !== 0x00;
1707
+ const filter = resp[8];
1708
+ return { mode, filter, dataMode, modeName: getModeString(mode), filterName: getFilterString(filter) };
1709
+ }
1710
+ setSplitMode(mode, options) {
1711
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1712
+ const rigAddr = this.civ.civAddress & 0xff;
1713
+ const modeCode = typeof mode === 'string' ? (0, IcomConstants_1.getModeCode)(mode) : mode;
1714
+ const filter = options?.filter ?? this.lastFilter ?? this.activeProfile.defaultFilter;
1715
+ this.sendCiv(IcomRigCommands_1.IcomRigCommands.setSelectedMode(ctrAddr, rigAddr, modeCode, !!options?.dataMode, filter, 1));
1716
+ }
1717
+ async getTuningStep(options) {
1718
+ const timeoutMs = options?.timeout ?? 3000;
1719
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1720
+ const rigAddr = this.civ.civAddress & 0xff;
1721
+ const req = IcomRigCommands_1.IcomRigCommands.readTuningStep(ctrAddr, rigAddr);
1722
+ const resp = await this.waitForCivFrame('ts:0x10', (frame) => IcomControl.matchCommandFrame(frame, IcomCivSpec_1.CIV.C_SET_TS, [], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1723
+ if (!resp || resp.length < 7)
1724
+ return null;
1725
+ return this.activeProfile.tuningSteps.find((step) => step.code === resp[5])?.hz ?? null;
1726
+ }
1727
+ setTuningStep(hz) {
1728
+ const matched = this.activeProfile.tuningSteps.find((step) => step.hz === hz);
1729
+ if (!matched) {
1730
+ throw this.unsupported(String(hz), 'setTuningStep', 'Tuning step is not enabled for active profile');
1731
+ }
1732
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1733
+ const rigAddr = this.civ.civAddress & 0xff;
1734
+ this.sendCiv(IcomRigCommands_1.IcomRigCommands.setTuningStep(ctrAddr, rigAddr, matched.code));
1735
+ }
1736
+ async getRepeaterShift(options) {
1737
+ const raw = await this.readSplitRaw(options);
1738
+ if (raw === null)
1739
+ return null;
1740
+ if (raw === IcomCivSpec_1.CIV.S_DUP_M)
1741
+ return 'minus';
1742
+ if (raw === IcomCivSpec_1.CIV.S_DUP_P)
1743
+ return 'plus';
1744
+ return 'none';
1745
+ }
1746
+ setRepeaterShift(shift) {
1747
+ if (!this.activeProfile.repeater) {
1748
+ throw this.unsupported(shift, 'setRepeaterShift', 'Repeater controls are not enabled for active profile');
1749
+ }
1750
+ const code = shift === 'minus' ? IcomCivSpec_1.CIV.S_DUP_M : shift === 'plus' ? IcomCivSpec_1.CIV.S_DUP_P : IcomCivSpec_1.CIV.S_DUP_OFF;
1751
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1752
+ const rigAddr = this.civ.civAddress & 0xff;
1753
+ this.sendCiv(IcomRigCommands_1.IcomRigCommands.setRepeaterShift(ctrAddr, rigAddr, code));
1754
+ }
1755
+ async getRepeaterOffset(options) {
1756
+ const timeoutMs = options?.timeout ?? 3000;
1757
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1758
+ const rigAddr = this.civ.civAddress & 0xff;
1759
+ const req = IcomRigCommands_1.IcomRigCommands.readCommand(ctrAddr, rigAddr, IcomCivSpec_1.CIV.C_RD_OFFS);
1760
+ const resp = await this.waitForCivFrame('rptr:offset', (frame) => IcomControl.matchCommandFrame(frame, IcomCivSpec_1.CIV.C_RD_OFFS, [], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1761
+ if (!resp || resp.length < 9)
1762
+ return null;
1763
+ return (0, IcomCivFrame_1.decodeFrequencyBcdLE)(resp.subarray(5, 8)) * 100;
1764
+ }
1765
+ setRepeaterOffset(offsetHz) {
1766
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1767
+ const rigAddr = this.civ.civAddress & 0xff;
1768
+ this.sendCiv(IcomRigCommands_1.IcomRigCommands.writeCommand(ctrAddr, rigAddr, IcomCivSpec_1.CIV.C_SET_OFFS, undefined, (0, IcomCivFrame_1.encodeFrequencyBcdLE)(Math.round(offsetHz / 100), 3)));
1769
+ }
1770
+ async getToneFrequency(options) { return this.readTone(IcomCivSpec_1.CIV.S_TONE_RPTR, options); }
1771
+ setToneFrequency(hz) { this.writeTone(IcomCivSpec_1.CIV.S_TONE_RPTR, hz); }
1772
+ async getToneSquelchFrequency(options) { return this.readTone(IcomCivSpec_1.CIV.S_TONE_SQL, options); }
1773
+ setToneSquelchFrequency(hz) { this.writeTone(IcomCivSpec_1.CIV.S_TONE_SQL, hz); }
1774
+ async getBeepEnabled(options) { return this.getParameter('BEEP', options); }
1775
+ setBeepEnabled(enabled) { this.setParameter('BEEP', enabled); }
1776
+ async getBacklight(options) { return this.getParameter('BACKLIGHT', options); }
1777
+ setBacklight(value) { this.setParameter('BACKLIGHT', value); }
1778
+ async getScreenSaver(options) { return this.getParameter('SCREENSAVER', options); }
1779
+ setScreenSaver(value) { this.setParameter('SCREENSAVER', value); }
1780
+ async getKeyerType(options) { return this.getParameter('KEYERTYPE', options); }
1781
+ setKeyerType(value) { this.setParameter('KEYERTYPE', value); }
1782
+ async getAudioIfMode(options) {
1783
+ for (const source of ['wlan', 'lan', 'acc']) {
1784
+ const parm = this.audioIfSourceToParameter(source);
1785
+ if (parm && this.activeProfile.parameters.includes(parm)) {
1786
+ const enabled = await this.getParameter(parm, options);
1787
+ if (enabled === true)
1788
+ return source;
1789
+ }
1790
+ }
1791
+ return this.activeProfile.audioIfSources.includes('default') ? 'default' : null;
1792
+ }
1793
+ setAudioIfMode(source) {
1794
+ if (!this.activeProfile.audioIfSources.includes(source)) {
1795
+ throw this.unsupported(source, 'setAudioIfMode', 'Audio IF source is not enabled for active profile');
1796
+ }
1797
+ for (const candidate of ['wlan', 'lan', 'acc']) {
1798
+ const parm = this.audioIfSourceToParameter(candidate);
1799
+ if (parm && this.activeProfile.parameters.includes(parm)) {
1800
+ this.setParameter(parm, source === candidate);
1801
+ }
1802
+ }
1803
+ if (this.activeProfile.parameters.includes('AFIF')) {
1804
+ this.setParameter('AFIF', source !== 'default');
1805
+ }
1806
+ }
1807
+ async getSpectrumDataOutput(options) {
1808
+ return this.getScopeBoolean(IcomCivSpec_1.CIV.S_SCP_DOP, [], 'spectrum:data-output', options);
1809
+ }
1810
+ setSpectrumDataOutput(enabled) { this.writeScopeSimple(IcomCivSpec_1.CIV.S_SCP_DOP, [enabled ? 1 : 0]); }
1811
+ async getSpectrumHold(options) {
1812
+ const receiver = options?.receiver ?? 0;
1813
+ return this.getScopeBoolean(IcomCivSpec_1.CIV.S_SCP_HLD, [receiver], `spectrum:hold:${receiver}`, options);
1814
+ }
1815
+ setSpectrumHold(enabled, options) {
1816
+ const receiver = options?.receiver ?? 0;
1817
+ this.writeScopeSimple(IcomCivSpec_1.CIV.S_SCP_HLD, [receiver, enabled ? 1 : 0]);
1818
+ }
1819
+ async getSpectrumSpeed(options) {
1820
+ const receiver = options?.receiver ?? 0;
1821
+ const raw = await this.getScopeByte(IcomCivSpec_1.CIV.S_SCP_SWP, [receiver], `spectrum:speed:${receiver}`, options);
1822
+ if (raw === null)
1823
+ return null;
1824
+ return raw === 0 ? 'fast' : raw === 1 ? 'mid' : 'slow';
1825
+ }
1826
+ setSpectrumSpeed(speed, options) {
1827
+ const receiver = options?.receiver ?? 0;
1828
+ const raw = speed === 'fast' ? 0 : speed === 'mid' ? 1 : 2;
1829
+ this.writeScopeSimple(IcomCivSpec_1.CIV.S_SCP_SWP, [receiver, raw]);
1830
+ }
1831
+ async getSpectrumRef(options) {
1832
+ const receiver = options?.receiver ?? 0;
1833
+ const timeoutMs = options?.timeout ?? 3000;
1834
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1835
+ const rigAddr = this.civ.civAddress & 0xff;
1836
+ const req = IcomRigCommands_1.IcomRigCommands.readCommand(ctrAddr, rigAddr, IcomCivSpec_1.CIV.C_CTL_SCP, IcomCivSpec_1.CIV.S_SCP_REF, [receiver]);
1837
+ const resp = await this.waitForCivFrame(`spectrum:ref:${receiver}`, (frame) => IcomControl.matchCommandFrame(frame, IcomCivSpec_1.CIV.C_CTL_SCP, [IcomCivSpec_1.CIV.S_SCP_REF, receiver], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1838
+ if (!resp || resp.length < 10)
1839
+ return null;
1840
+ const value = (0, IcomCivFrame_1.decodeBcdBE)(resp.subarray(7, 9)) / 100;
1841
+ return resp[9] ? -value : value;
1842
+ }
1843
+ setSpectrumRef(db, options) {
1844
+ const receiver = options?.receiver ?? 0;
1845
+ const rounded = Math.round(db * 2) / 2;
1846
+ this.writeScopeSimple(IcomCivSpec_1.CIV.S_SCP_REF, [receiver, ...(0, IcomCivFrame_1.encodeBcdBE)(Math.abs(Math.round(rounded * 100)), 2), rounded < 0 ? 1 : 0]);
1847
+ }
1848
+ async getSpectrumAverage(options) { return this.getLevel('SPECTRUM_AVG', options); }
1849
+ setSpectrumAverage(value) { this.setLevel('SPECTRUM_AVG', value); }
1850
+ async getSpectrumVbw(options) {
1851
+ const receiver = options?.receiver ?? 0;
1852
+ return this.getScopeByte(IcomCivSpec_1.CIV.S_SCP_VBW, [receiver], `spectrum:vbw:${receiver}`, options);
1853
+ }
1854
+ setSpectrumVbw(value, options) {
1855
+ const receiver = options?.receiver ?? 0;
1856
+ this.writeScopeSimple(IcomCivSpec_1.CIV.S_SCP_VBW, [receiver, Math.max(0, Math.min(1, Math.trunc(value)))]);
1857
+ }
1858
+ async getSpectrumRbw(options) {
1859
+ const receiver = options?.receiver ?? 0;
1860
+ return this.getScopeByte(IcomCivSpec_1.CIV.S_SCP_RBW, [receiver], `spectrum:rbw:${receiver}`, options);
1861
+ }
1862
+ setSpectrumRbw(value, options) {
1863
+ const receiver = options?.receiver ?? 0;
1864
+ this.writeScopeSimple(IcomCivSpec_1.CIV.S_SCP_RBW, [receiver, Math.max(0, Math.min(2, Math.trunc(value)))]);
1865
+ }
1866
+ async getSpectrumDuringTx(options) {
1867
+ return this.getScopeBoolean(IcomCivSpec_1.CIV.S_SCP_STX, [], 'spectrum:during-tx', options);
1868
+ }
1869
+ setSpectrumDuringTx(enabled) { this.writeScopeSimple(IcomCivSpec_1.CIV.S_SCP_STX, [enabled ? 1 : 0]); }
1870
+ async getSpectrumCenterType(options) {
1871
+ const raw = await this.getScopeByte(IcomCivSpec_1.CIV.S_SCP_CFQ, [], 'spectrum:center-type', options);
1872
+ if (raw === null)
1873
+ return null;
1874
+ return raw === 1 ? 'carrier-point-center' : raw === 2 ? 'carrier-point-center-abs' : 'filter-center';
1875
+ }
1876
+ setSpectrumCenterType(type) {
1877
+ const raw = type === 'carrier-point-center' ? 1 : type === 'carrier-point-center-abs' ? 2 : 0;
1878
+ this.writeScopeSimple(IcomCivSpec_1.CIV.S_SCP_CFQ, [raw]);
1879
+ }
1880
+ unsupported(commandName, api, reason) {
1881
+ return new errors_1.UnsupportedCommandError({
1882
+ modelId: this.getProfileModelId(),
1883
+ commandName: api,
1884
+ civCommand: commandName,
1885
+ reason,
1886
+ });
1887
+ }
1888
+ async readFunctionRaw(name, spec, options) {
1889
+ const timeoutMs = options?.timeout ?? 3000;
1890
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1891
+ const rigAddr = this.civ.civAddress & 0xff;
1892
+ const prefix = spec.readPrefix ?? [];
1893
+ const req = IcomRigCommands_1.IcomRigCommands.readCommand(ctrAddr, rigAddr, spec.command, spec.subcmd, prefix);
1894
+ const tail = [spec.subcmd, ...prefix];
1895
+ const resp = await this.waitForCivFrame(`func:0x${spec.command.toString(16)}:0x${spec.subcmd.toString(16)}:${prefix.join('.')}:${name}`, (frame) => IcomControl.matchCommandFrame(frame, spec.command, tail, ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1896
+ if (!resp)
1897
+ return null;
1898
+ const index = 5 + tail.length;
1899
+ return index < resp.length - 1 ? resp[index] : null;
1900
+ }
1901
+ writeFunctionRaw(spec, value) {
1902
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1903
+ const rigAddr = this.civ.civAddress & 0xff;
1904
+ const payload = [...(spec.payloadPrefix ?? []), value & 0xff];
1905
+ this.sendCiv(IcomRigCommands_1.IcomRigCommands.writeCommand(ctrAddr, rigAddr, spec.command, spec.subcmd, payload));
1906
+ }
1907
+ async readLevelRaw(name, spec, options) {
1908
+ const timeoutMs = options?.timeout ?? 3000;
1909
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1910
+ const rigAddr = this.civ.civAddress & 0xff;
1911
+ const req = IcomRigCommands_1.IcomRigCommands.readCommand(ctrAddr, rigAddr, spec.command, spec.subcmd);
1912
+ const resp = await this.waitForCivFrame(`level:0x${spec.command.toString(16)}:0x${spec.subcmd.toString(16)}:${name}`, (frame) => IcomControl.matchCommandFrame(frame, spec.command, [spec.subcmd], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1913
+ if (!resp)
1914
+ return null;
1915
+ const data = resp.subarray(6, resp.length - 1);
1916
+ if (data.length < spec.dataBytes)
1917
+ return null;
1918
+ return (0, IcomCivFrame_1.decodeBcdBE)(data.subarray(0, spec.dataBytes));
1919
+ }
1920
+ writeLevelRaw(spec, raw) {
1921
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1922
+ const rigAddr = this.civ.civAddress & 0xff;
1923
+ this.sendCiv(IcomRigCommands_1.IcomRigCommands.writeCommand(ctrAddr, rigAddr, spec.command, spec.subcmd, IcomControl.encodeDataValue(raw, spec.dataType, spec.dataBytes)));
1924
+ }
1925
+ async readExtParamValue(ext, keyPrefix, options) {
1926
+ const timeoutMs = options?.timeout ?? 3000;
1927
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1928
+ const rigAddr = this.civ.civAddress & 0xff;
1929
+ const req = IcomRigCommands_1.IcomRigCommands.readExtParam(ctrAddr, rigAddr, ext.command, ext.subcmd, ext.subext);
1930
+ const tail = [ext.subcmd, ...ext.subext];
1931
+ const resp = await this.waitForCivFrame(`${keyPrefix}:0x${ext.command.toString(16)}:0x${ext.subcmd.toString(16)}:${ext.subext.join('.')}`, (frame) => IcomControl.matchCommandFrame(frame, ext.command, tail, ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1932
+ if (!resp)
1933
+ return null;
1934
+ const start = 5 + tail.length;
1935
+ return IcomControl.decodeDataValue(resp.subarray(start, resp.length - 1), ext.dataType, ext.dataBytes);
1936
+ }
1937
+ writeExtParamValue(ext, value) {
1938
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1939
+ const rigAddr = this.civ.civAddress & 0xff;
1940
+ const raw = ext.dataType === 'level' ? Math.round(Math.max(0, Math.min(1, value)) * 255) : Math.round(value);
1941
+ const payload = IcomControl.encodeDataValue(raw, ext.dataType, ext.dataBytes);
1942
+ this.sendCiv(IcomRigCommands_1.IcomRigCommands.writeExtParam(ctrAddr, rigAddr, ext.command, ext.subcmd, ext.subext, payload));
1943
+ }
1944
+ static encodeDataValue(value, dataType, bytes) {
1945
+ if (dataType === 'time') {
1946
+ const seconds = Math.max(0, Math.round(value));
1947
+ const hhmm = Math.floor(seconds / 3600) * 100 + Math.floor(seconds / 60) % 60;
1948
+ return (0, IcomCivFrame_1.encodeBcdBE)(hhmm, bytes);
1949
+ }
1950
+ return (0, IcomCivFrame_1.encodeBcdBE)(value, bytes);
1951
+ }
1952
+ static decodeDataValue(data, dataType, bytes) {
1953
+ if (data.length < bytes)
1954
+ return null;
1955
+ const value = (0, IcomCivFrame_1.decodeBcdBE)(data.subarray(0, bytes));
1956
+ if (dataType === 'level')
1957
+ return value / 255;
1958
+ if (dataType === 'bool')
1959
+ return value === 0 ? 0 : 1;
1960
+ if (dataType === 'time') {
1961
+ const hours = Math.floor(value / 100);
1962
+ const minutes = value % 100;
1963
+ return hours * 3600 + minutes * 60;
1964
+ }
1965
+ return value;
1966
+ }
1967
+ async readRitOffset(options) {
1968
+ const timeoutMs = options?.timeout ?? 3000;
1969
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1970
+ const rigAddr = this.civ.civAddress & 0xff;
1971
+ const req = IcomRigCommands_1.IcomRigCommands.readRitOffset(ctrAddr, rigAddr);
1972
+ const resp = await this.waitForCivFrame('rit:offset', (frame) => IcomControl.matchCommandFrame(frame, IcomCivSpec_1.CIV.C_CTL_RIT, [IcomCivSpec_1.CIV.S_RIT_FREQ], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1973
+ if (!resp || resp.length < 9)
1974
+ return null;
1975
+ const value = (0, IcomCivFrame_1.decodeFrequencyBcdLE)(resp.subarray(6, 8));
1976
+ return resp[8] === 0 ? value : -value;
1977
+ }
1978
+ writeRitOffset(offsetHz) {
1979
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1980
+ const rigAddr = this.civ.civAddress & 0xff;
1981
+ const payload = [...(0, IcomCivFrame_1.encodeFrequencyBcdLE)(Math.abs(Math.round(offsetHz)), 2), offsetHz < 0 ? 1 : 0];
1982
+ this.sendCiv(IcomRigCommands_1.IcomRigCommands.setRitOffset(ctrAddr, rigAddr, payload));
1983
+ }
1984
+ vfoToSubcmd(vfo) {
1985
+ switch (vfo) {
1986
+ case 'A': return IcomCivSpec_1.CIV.S_VFOA;
1987
+ case 'B': return IcomCivSpec_1.CIV.S_VFOB;
1988
+ case 'MAIN':
1989
+ case 'MAIN_A':
1990
+ case 'MAIN_B': return IcomCivSpec_1.CIV.S_MAIN;
1991
+ case 'SUB':
1992
+ case 'SUB_A':
1993
+ case 'SUB_B': return IcomCivSpec_1.CIV.S_SUB;
1994
+ case 'CURR':
1995
+ case 'TX': return null;
1996
+ case 'MEM': return null;
1997
+ }
1998
+ }
1999
+ async readSplitRaw(options) {
2000
+ const timeoutMs = options?.timeout ?? 3000;
2001
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
2002
+ const rigAddr = this.civ.civAddress & 0xff;
2003
+ const req = IcomRigCommands_1.IcomRigCommands.readSplit(ctrAddr, rigAddr);
2004
+ const resp = await this.waitForCivFrame('split:0x0f', (frame) => IcomControl.matchCommandFrame(frame, IcomCivSpec_1.CIV.C_CTL_SPLT, [], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
2005
+ if (!resp || resp.length < 7)
2006
+ return null;
2007
+ return resp[5];
2008
+ }
2009
+ async readTone(subcmd, options) {
2010
+ if (!this.activeProfile.tone)
2011
+ return null;
2012
+ const timeoutMs = options?.timeout ?? 3000;
2013
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
2014
+ const rigAddr = this.civ.civAddress & 0xff;
2015
+ const req = IcomRigCommands_1.IcomRigCommands.readTone(ctrAddr, rigAddr, subcmd);
2016
+ const resp = await this.waitForCivFrame(`tone:0x${subcmd.toString(16)}`, (frame) => IcomControl.matchCommandFrame(frame, IcomCivSpec_1.CIV.C_SET_TONE, [subcmd], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
2017
+ if (!resp || resp.length < 10)
2018
+ return null;
2019
+ return (0, IcomCivFrame_1.decodeBcdBE)(resp.subarray(6, 9)) / 10;
2020
+ }
2021
+ writeTone(subcmd, hz) {
2022
+ if (!this.activeProfile.tone) {
2023
+ throw this.unsupported(String(subcmd), 'setToneFrequency', 'Tone controls are not enabled for active profile');
2024
+ }
2025
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
2026
+ const rigAddr = this.civ.civAddress & 0xff;
2027
+ this.sendCiv(IcomRigCommands_1.IcomRigCommands.setTone(ctrAddr, rigAddr, subcmd, Math.round(hz * 10)));
2028
+ }
2029
+ audioIfSourceToParameter(source) {
2030
+ switch (source) {
2031
+ case 'wlan': return 'AFIF_WLAN';
2032
+ case 'lan': return 'AFIF_LAN';
2033
+ case 'acc': return 'AFIF_ACC';
2034
+ case 'default': return 'AFIF';
2035
+ }
2036
+ }
2037
+ async getScopeBoolean(subcmd, payload, key, options) {
2038
+ const raw = await this.getScopeByte(subcmd, payload, key, options);
2039
+ return raw === null ? null : raw !== 0;
2040
+ }
2041
+ async getScopeByte(subcmd, payload, key, options) {
2042
+ const timeoutMs = options?.timeout ?? 3000;
2043
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
2044
+ const rigAddr = this.civ.civAddress & 0xff;
2045
+ const req = IcomRigCommands_1.IcomRigCommands.readCommand(ctrAddr, rigAddr, IcomCivSpec_1.CIV.C_CTL_SCP, subcmd, payload);
2046
+ const resp = await this.waitForCivFrame(key, (frame) => IcomControl.matchCommandFrame(frame, IcomCivSpec_1.CIV.C_CTL_SCP, [subcmd, ...payload], ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
2047
+ if (!resp)
2048
+ return null;
2049
+ const index = 5 + 1 + payload.length;
2050
+ return index < resp.length - 1 ? resp[index] : null;
2051
+ }
2052
+ writeScopeSimple(subcmd, payload) {
2053
+ const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
2054
+ const rigAddr = this.civ.civAddress & 0xff;
2055
+ this.sendCiv(IcomRigCommands_1.IcomRigCommands.writeCommand(ctrAddr, rigAddr, IcomCivSpec_1.CIV.C_CTL_SCP, subcmd, payload));
2056
+ }
1394
2057
  static isReplyOf(frame, cmd, ctrAddr, rigAddr) {
1395
2058
  // typical reply FE FE [ctr] [rig] cmd ... FD
1396
2059
  return frame.length >= 7 && frame[0] === 0xfe && frame[1] === 0xfe && frame[4] === (cmd & 0xff);
@@ -1822,26 +2485,14 @@ class IcomControl {
1822
2485
  // Continue loop in case multiple frames are in buffer
1823
2486
  }
1824
2487
  }
1825
- // Wait for single CI-V frame that matches predicate (fed by civFrame event)
1826
- async waitForCivFrame(predicate, timeoutMs, onSend) {
1827
- return new Promise((resolve) => {
1828
- let done = false;
1829
- const onFrame = (frame) => {
1830
- if (!done && predicate(frame)) {
1831
- done = true;
1832
- this.ev.off('civFrame', onFrame);
1833
- resolve(frame);
1834
- }
1835
- };
1836
- this.ev.on('civFrame', onFrame);
1837
- if (onSend)
1838
- onSend();
1839
- setTimeout(() => {
1840
- if (!done) {
1841
- this.ev.off('civFrame', onFrame);
1842
- resolve(null);
1843
- }
1844
- }, timeoutMs);
2488
+ // Wait for a CI-V reply by response key. Same-key queries are deduplicated.
2489
+ async waitForCivFrame(key, predicate, timeoutMs, onSend) {
2490
+ return this.civRequestManager.query({
2491
+ key,
2492
+ predicate,
2493
+ timeoutMs,
2494
+ send: () => { if (onSend)
2495
+ onSend(); },
1845
2496
  });
1846
2497
  }
1847
2498
  // Strict meter reply matcher: FE FE [ctr|00] [rig] 0x15 [sub] ... FD
@@ -1889,7 +2540,7 @@ class IcomControl {
1889
2540
  const ctrAddr = IcomConstants_1.DEFAULT_CONTROLLER_ADDR;
1890
2541
  const rigAddr = this.civ.civAddress & 0xff;
1891
2542
  const req = IcomRigCommands_1.IcomRigCommands.get0x14Level(ctrAddr, rigAddr, subcmd);
1892
- const resp = await this.waitForCivFrame((frame) => IcomControl.is0x14DataReply(frame, subcmd, ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
2543
+ const resp = await this.waitForCivFrame(`level:0x14:0x${subcmd.toString(16)}`, (frame) => IcomControl.is0x14DataReply(frame, subcmd, ctrAddr, rigAddr), timeoutMs, () => this.sendCiv(req));
1893
2544
  if (!resp || resp.length < 9)
1894
2545
  return null;
1895
2546
  const raw = (0, bcd_1.parseTwoByteBcd)(resp.subarray(6, 8));