2021-04-19 16:26:26 +00:00
# include "rigctld.h"
# include "logcategories.h"
2023-05-24 18:50:01 +00:00
2021-08-14 16:20:40 +00:00
static struct
{
quint64 mode ;
2023-05-24 18:50:01 +00:00
rigMode_t mk ;
2021-08-14 16:20:40 +00:00
const char * str ;
2023-05-24 18:50:01 +00:00
uchar data = 0 ;
2021-08-14 16:20:40 +00:00
} mode_str [ ] =
{
2023-05-24 18:50:01 +00:00
{ RIG_MODE_AM , modeAM , " AM " } ,
{ RIG_MODE_CW , modeCW , " CW " } ,
{ RIG_MODE_USB , modeUSB , " USB " } ,
{ RIG_MODE_LSB , modeLSB , " LSB " } ,
{ RIG_MODE_RTTY , modeRTTY , " RTTY " } ,
{ RIG_MODE_FM , modeFM , " FM " } ,
{ RIG_MODE_WFM , modeWFM , " WFM " } ,
{ RIG_MODE_CWR , modeCW_R , " CWR " } ,
{ RIG_MODE_RTTYR , modeRTTY_R , " RTTYR " } ,
{ RIG_MODE_AMS , modeUnknown , " AMS " } ,
{ RIG_MODE_PKTLSB , modeLSB , " PKTLSB " , 1U } ,
{ RIG_MODE_PKTUSB , modeUSB , " PKTUSB " , 1U } ,
{ RIG_MODE_PKTFM , modeFM , " PKTFM " , true } ,
{ RIG_MODE_PKTFMN , modeUnknown , " PKTFMN " , 1U } ,
{ RIG_MODE_ECSSUSB , modeUnknown , " ECSSUSB " } ,
{ RIG_MODE_ECSSLSB , modeUnknown , " ECSSLSB " } ,
{ RIG_MODE_FAX , modeUnknown , " FAX " } ,
{ RIG_MODE_SAM , modeUnknown , " SAM " } ,
{ RIG_MODE_SAL , modeUnknown , " SAL " } ,
{ RIG_MODE_SAH , modeUnknown , " SAH " } ,
{ RIG_MODE_DSB , modeUnknown , " DSB " } ,
{ RIG_MODE_FMN , modeUnknown , " FMN " } ,
{ RIG_MODE_PKTAM , modeUnknown , " PKTAM " } ,
{ RIG_MODE_P25 , modeP25 , " P25 " } ,
{ RIG_MODE_DSTAR , modeDV , " D-STAR " } ,
{ RIG_MODE_DPMR , modedPMR , " DPMR " } ,
{ RIG_MODE_NXDNVN , modeNXDN_VN , " NXDN-VN " } ,
{ RIG_MODE_NXDN_N , modeNXDN_N , " NXDN-N " } ,
{ RIG_MODE_DCR , modeUnknown , " DCR " } ,
{ RIG_MODE_AMN , modeUnknown , " AMN " } ,
{ RIG_MODE_PSK , modePSK , " PSK " } ,
{ RIG_MODE_PSKR , modePSK_R , " PSKR " } ,
{ RIG_MODE_C4FM , modeUnknown , " C4FM " } ,
{ RIG_MODE_SPEC , modeUnknown , " SPEC " } ,
{ RIG_MODE_NONE , modeUnknown , " " } ,
} ;
static const subCommandStruct levels_str [ ] =
{
2024-12-31 20:03:38 +00:00
{ " PREAMP " , funcPreamp , typeUChar } ,
2024-03-05 21:01:13 +00:00
{ " ATT " , funcAttenuator , typeUChar } ,
2024-12-31 20:03:38 +00:00
{ " VOXDELAY " , funcVOXDelay , typeUChar } ,
2024-03-05 21:01:13 +00:00
{ " AF " , funcAfGain , typeFloat } ,
{ " RF " , funcRfGain , typeFloat } ,
{ " SQL " , funcSquelch , typeFloat } ,
2025-01-05 15:39:20 +00:00
{ " IF " , funcFilterWidth , typeFloat } ,
2024-03-05 21:01:13 +00:00
{ " APF " , funcAPFLevel , typeFloat } ,
{ " NR " , funcNRLevel , typeFloat } ,
{ " PBT_IN " , funcPBTInner , typeFloat } ,
{ " PBT_OUT " , funcPBTOuter , typeFloat } ,
{ " CWPITCH " , funcCwPitch , typeFloat } ,
{ " RFPOWER " , funcRFPower , typeFloat } ,
{ " MICGAIN " , funcMicGain , typeFloat } ,
2025-01-03 00:05:50 +00:00
{ " KEYSPD " , funcKeySpeed , typeUShort } ,
2024-03-05 21:01:13 +00:00
{ " NOTCHF " , funcNotchFilter , typeUChar } ,
{ " COMP " , funcCompressorLevel , typeFloat } ,
2025-01-05 15:39:20 +00:00
{ " AGC " , funcAGCTimeConstant , typeUChar } ,
2024-03-05 21:01:13 +00:00
{ " BKINDL " , funcBreakInDelay , typeFloat } ,
{ " BAL " , funcNone , typeFloat } ,
{ " METER " , funcNone , typeFloat } ,
{ " VOXGAIN " , funcVoxGain , typeFloat } ,
{ " ANTIVOX " , funcAntiVoxGain , typeFloat } ,
{ " SLOPE_LOW " , funcNone , typeFloat } ,
{ " SLOPE_HIGH " , funcNone , typeFloat } ,
{ " BKIN_DLYMS " , funcBreakInDelay , typeFloat } ,
{ " RAWSTR " , funcNone , typeFloat } ,
2025-02-03 20:20:40 +00:00
{ " SWR " , funcSWRMeter , typeSWR } ,
2025-02-17 11:57:07 +00:00
{ " ALC " , funcALCMeter , typeDouble } ,
{ " STRENGTH " , funcSMeter , typeDouble } ,
{ " RFPOWER_METER " , funcPowerMeter , typeDouble } ,
{ " COMPMETER " , funcCompMeter , typeDouble } ,
{ " VD_METER " , funcVdMeter , typeDouble } ,
{ " ID_METER " , funcIdMeter , typeDouble } ,
2024-03-05 21:01:13 +00:00
{ " NOTCHF_RAW " , funcNone , typeFloat } ,
{ " MONITOR_GAIN " , funcMonitorGain , typeFloat } ,
{ " NQ " , funcNone , typeFloat } ,
{ " RFPOWER_METER_WATT " , funcNone , typeFloat } ,
{ " SPECTRUM_MDOE " , funcNone , typeFloat } ,
{ " SPECTRUM_SPAN " , funcNone , typeFloat } ,
{ " SPECTRUM_EDGE_LOW " , funcNone , typeFloat } ,
{ " SPECTRUM_EDGE_HIGH " , funcNone , typeFloat } ,
{ " SPECTRUM_SPEED " , funcNone , typeFloat } ,
{ " SPECTRUM_REF " , funcNone , typeFloat } ,
{ " SPECTRUM_AVG " , funcNone , typeFloat } ,
{ " SPECTRUM_ATT " , funcNone , typeFloat } ,
{ " TEMP_METER " , funcNone , typeFloat } ,
{ " BAND_SELECT " , funcNone , typeFloat } ,
{ " USB_AF " , funcNone , typeFloat } ,
2023-05-24 18:50:01 +00:00
{ " " , funcNone , ' \x0 ' }
} ;
static const subCommandStruct functions_str [ ] =
{
2024-04-05 12:01:26 +00:00
{ " FAGC " , funcNone , typeBinary } ,
2024-03-05 21:01:13 +00:00
{ " NB " , funcNoiseBlanker , typeBinary } ,
{ " COMP " , funcCompressor , typeBinary } ,
{ " VOX " , funcVox , typeBinary } ,
{ " TONE " , funcRepeaterTone , typeBinary } ,
{ " TQSL " , funcRepeaterTSQL , typeBinary } ,
{ " SBKIN " , funcBreakIn , typeUChar } ,
{ " FBKIN " , funcBreakIn , typeUChar } ,
{ " ANF " , funcAutoNotch , typeBinary } ,
{ " NR " , funcNoiseReduction , typeBinary } ,
{ " AIP " , funcNone , typeBinary } ,
{ " APF " , funcAPFType , typeBinary } ,
{ " MON " , funcMonitor , typeBinary } ,
{ " MN " , funcManualNotch , typeBinary } ,
{ " RF " , funcNone , typeBinary } ,
{ " ARO " , funcNone , typeBinary } ,
{ " LOCK " , funcLockFunction , typeBinary } ,
{ " MUTE " , funcAFMute , typeBinary } ,
{ " VSC " , funcNone , typeBinary } ,
{ " REV " , funcNone , typeBinary } ,
{ " SQL " , funcSquelch , typeBinary } , // Actually an integer as ICOM doesn't provide on/off for squelch
{ " ABM " , funcNone , typeBinary } ,
{ " VSC " , funcNone , typeBinary } ,
{ " REV " , funcNone , typeBinary } ,
{ " BC " , funcNone , typeBinary } ,
{ " MBC " , funcNone , typeBinary } ,
{ " RIT " , funcRitStatus , typeBinary } ,
{ " AFC " , funcNone , typeBinary } ,
{ " SATMODE " , funcSatelliteMode , typeBinary } ,
{ " SCOPE " , funcScopeOnOff , typeBinary } ,
{ " RESUME " , funcNone , typeBinary } ,
{ " TBURST " , funcNone , typeBinary } ,
{ " TUNER " , funcTunerStatus , typeBinary } ,
{ " XIT " , funcNone , typeBinary } ,
{ " " , funcNone , typeBinary }
2021-08-14 16:20:40 +00:00
} ;
2023-05-24 18:50:01 +00:00
static const subCommandStruct params_str [ ] =
{
2024-03-05 21:01:13 +00:00
{ " ANN " , funcNone , typeUChar } ,
{ " APO " , funcNone , typeUChar } ,
2025-01-05 15:39:20 +00:00
{ " BACKLIGHT " , funcBackLightLevel , typeUChar } ,
2024-03-05 21:01:13 +00:00
{ " BEEP " , funcNone , typeUChar } ,
{ " TIME " , funcTime , typeUChar } ,
{ " BAT " , funcNone , typeUChar } ,
{ " KEYLIGHT " , funcNone , typeUChar } ,
2024-06-03 18:43:00 +00:00
{ " " , funcNone , typeNone }
2023-05-24 18:50:01 +00:00
} ;
# define ARG_IN1 0x01
# define ARG_OUT1 0x02
# define ARG_IN2 0x04
# define ARG_OUT2 0x08
# define ARG_IN3 0x10
# define ARG_OUT3 0x20
# define ARG_IN4 0x40
# define ARG_OUT4 0x80
# define ARG_OUT5 0x100
# define ARG_NONE 0
# define ARG_IN (ARG_IN1|ARG_IN2|ARG_IN3|ARG_IN4)
# define ARG_OUT (ARG_OUT1|ARG_OUT2|ARG_OUT3|ARG_OUT4)
# define ARG_IN_LINE 0x4000
# define ARG_NOVFO 0x8000
# define MAXNAMESIZE 32
2024-03-05 21:01:13 +00:00
2023-05-24 18:50:01 +00:00
static const commandStruct commands_list [ ] =
{
2024-03-05 21:01:13 +00:00
{ ' F ' , " set_freq " , funcFreqSet , typeFreq , ARG_IN , " Frequency " } ,
{ ' f ' , " get_freq " , funcFreqGet , typeFreq , ARG_OUT , " Frequency " } ,
2024-12-29 14:59:52 +00:00
{ ' M ' , " set_mode " , funcModeSet , typeMode , ARG_IN , " Mode " , " Passband " } ,
{ ' m ' , " get_mode " , funcModeGet , typeMode , ARG_OUT , " Mode " , " Passband " } ,
2025-01-03 14:32:38 +00:00
{ ' I ' , " set_split_freq " , funcFreqSet , typeFreq , ARG_IN , " TX Frequency " } ,
{ ' i ' , " get_split_freq " , funcFreqGet , typeFreq , ARG_OUT , " TX Frequency " } ,
2024-12-29 14:59:52 +00:00
{ ' X ' , " set_split_mode " , funcSplitStatus , typeMode , ARG_IN , " TX Mode " , " TX Passband " } ,
{ ' x ' , " get_split_mode " , funcSplitStatus , typeMode , ARG_OUT , " TX Mode " , " TX Passband " } ,
2025-01-03 14:32:38 +00:00
{ ' K ' , " set_split_freq_mode " , funcModeSet , typeFreq , ARG_IN , " TX Frequency " , " TX Mode " , " TX Passband " } ,
{ ' k ' , " get_split_freq_mode " , funcModeGet , typeFreq , ARG_OUT , " TX Frequency " , " TX Mode " , " TX Passband " } ,
2024-12-29 14:59:52 +00:00
{ ' S ' , " set_split_vfo " , funcSplitStatus , typeSplitVFO , ARG_IN , " Split " , " TX VFO " } ,
{ ' s ' , " get_split_vfo " , funcSplitStatus , typeSplitVFO , ARG_OUT , " Split " , " TX VFO " } ,
2024-03-05 21:01:13 +00:00
{ ' N ' , " set_ts " , funcTuningStep , typeUChar , ARG_IN , " Tuning Step " } ,
{ ' n ' , " get_ts " , funcTuningStep , typeUChar , ARG_OUT , " Tuning Step " } ,
{ ' L ' , " set_level " , funcRigctlLevel , typeLevel , ARG_IN , " Level " , " Level Value " } ,
{ ' l ' , " get_level " , funcRigctlLevel , typeLevel , ARG_IN1 | ARG_OUT2 , " Level " , " Level Value " } ,
{ ' U ' , " set_func " , funcRigctlFunction , typeLevel , ARG_IN , " Func " , " Func Status " } ,
{ ' u ' , " get_func " , funcRigctlFunction , typeLevel , ARG_IN1 | ARG_OUT2 , " Func " , " Func Status " } ,
{ ' P ' , " set_parm " , funcRigctlParam , typeLevel , ARG_IN1 | ARG_NOVFO , " Parm " , " Parm Value " } ,
{ ' p ' , " get_parm " , funcRigctlParam , typeLevel , ARG_IN1 | ARG_OUT2 , " Parm " , " Parm Value " } ,
{ ' G ' , " vfo_op " , funcSelectVFO , typeUChar , ARG_IN , " Mem/VFO Op " } ,
{ ' g ' , " scan " , funcScanning , typeUChar , ARG_IN , " Scan Fct " , " Scan Channel " } ,
{ ' A ' , " set_trn " , funcCIVTransceive , typeUChar , ARG_IN | ARG_NOVFO , " Transceive " } ,
{ ' a ' , " get_trn " , funcCIVTransceive , typeUChar , ARG_OUT | ARG_NOVFO , " Transceive " } ,
{ ' R ' , " set_rptr_shift " , funcSendFreqOffset , typeUChar , ARG_IN , " Rptr Shift " } ,
{ ' r ' , " get_rptr_shift " , funcReadFreqOffset , typeUChar , ARG_OUT , " Rptr Shift " } ,
{ ' O ' , " set_rptr_offs " , funcSendFreqOffset , typeUChar , ARG_IN , " Rptr Offset " } ,
{ ' o ' , " get_rptr_offs " , funcReadFreqOffset , typeUChar , ARG_OUT , " Rptr Offset " } ,
{ ' C ' , " set_ctcss_tone " , funcToneFreq , typeUChar , ARG_IN , " CTCSS Tone " } ,
{ ' c ' , " get_ctcss_tone " , funcToneFreq , typeUChar , ARG_OUT , " CTCSS Tone " } ,
{ ' D ' , " set_dcs_code " , funcDTCSCode , typeUChar , ARG_IN , " DCS Code " } ,
{ ' d ' , " get_dcs_code " , funcDTCSCode , typeUChar , ARG_OUT , " DCS Code " } ,
{ 0x90 , " set_ctcss_sql " , funcTSQLFreq , typeUChar , ARG_IN , " CTCSS Sql " } ,
{ 0x91 , " get_ctcss_sql " , funcTSQLFreq , typeUChar , ARG_OUT , " CTCSS Sql " } ,
{ 0x92 , " set_dcs_sql " , funcCSQLCode , typeUChar , ARG_IN , " DCS Sql " } ,
{ 0x93 , " get_dcs_sql " , funcCSQLCode , typeUChar , ARG_OUT , " DCS Sql " } ,
{ ' V ' , " set_vfo " , funcSelectVFO , typeVFO , ARG_IN | ARG_NOVFO , " VFO " } ,
{ ' v ' , " get_vfo " , funcSelectVFO , typeVFO , ARG_NOVFO | ARG_OUT , " VFO " } ,
2025-01-06 20:16:14 +00:00
{ ' T ' , " set_ptt " , funcTransceiverStatus , typeBinary , ARG_IN , " VFO " , " PTT " } ,
{ ' t ' , " get_ptt " , funcTransceiverStatus , typeBinary , ARG_OUT , " VFO " , " PTT " } ,
2024-03-05 21:01:13 +00:00
{ ' E ' , " set_mem " , funcMemoryContents , typeMode , ARG_IN , " Memory# " } ,
{ ' e ' , " get_mem " , funcMemoryContents , typeMode , ARG_OUT , " Memory# " } ,
{ ' H ' , " set_channel " , funcMemoryMode , typeUChar , ARG_IN | ARG_NOVFO , " Channel " } ,
{ ' h ' , " get_channel " , funcMemoryMode , typeUChar , ARG_IN | ARG_NOVFO , " Channel " , " Read Only " } ,
{ ' B ' , " set_bank " , funcMemoryGroup , typeUChar , ARG_IN , " Bank " } ,
{ ' _ ' , " get_info " , funcNone , typeUChar , ARG_OUT | ARG_NOVFO , " Info " } ,
2025-01-18 12:29:34 +00:00
{ ' J ' , " set_rit " , funcRitFreq , typeShort , ARG_IN , " RIT " } ,
{ ' j ' , " get_rit " , funcRitFreq , typeShort , ARG_OUT , " RIT " } ,
{ ' Z ' , " set_xit " , funcXitFreq , typeShort , ARG_IN , " XIT " } ,
{ ' z ' , " get_xit " , funcXitFreq , typeShort , ARG_OUT , " XIT " } ,
2024-03-05 21:01:13 +00:00
{ ' Y ' , " set_ant " , funcAntenna , typeUChar , ARG_IN , " Antenna " , " Option " } ,
{ ' y ' , " get_ant " , funcAntenna , typeUChar , ARG_IN1 | ARG_OUT2 | ARG_NOVFO , " AntCurr " , " Option " , " AntTx " , " AntRx " } ,
{ 0x87 , " set_powerstat " , funcPowerControl , typeBinary , ARG_IN | ARG_NOVFO , " Power Status " } ,
{ 0x88 , " get_powerstat " , funcPowerControl , typeBinary , ARG_OUT | ARG_NOVFO , " Power Status " } ,
{ 0x89 , " send_dtmf " , funcNone , typeUChar , ARG_IN , " Digits " } ,
{ 0x8a , " recv_dtmf " , funcNone , typeUChar , ARG_OUT , " Digits " } ,
{ ' * ' , " reset " , funcNone , typeUChar , ARG_IN , " Reset " } ,
{ ' w ' , " send_cmd " , funcNone , typeUChar , ARG_IN1 | ARG_IN_LINE | ARG_OUT2 | ARG_NOVFO , " Cmd " , " Reply " } ,
{ ' W ' , " send_cmd_rx " , funcNone , typeUChar , ARG_IN | ARG_OUT2 | ARG_NOVFO , " Cmd " , " Reply " } ,
2024-12-29 14:59:52 +00:00
{ ' b ' , " send_morse " , funcSendCW , typeString , ARG_IN | ARG_NOVFO | ARG_IN_LINE , " Morse " } ,
2024-07-12 09:33:49 +00:00
{ 0xbb , " stop_morse " , funcSendCW , typeString , } ,
2024-03-05 21:01:13 +00:00
{ 0xbc , " wait_morse " , funcSendCW , typeUChar , } ,
{ 0x94 , " send_voice_mem " , funcNone , typeUChar , ARG_IN , " Voice Mem# " } ,
{ 0x8b , " get_dcd " , funcNone , typeUChar , ARG_OUT , " DCD " } ,
{ 0x8d , " set_twiddle " , funcNone , typeUChar , ARG_IN | ARG_NOVFO , " Timeout (secs) " } ,
{ 0x8e , " get_twiddle " , funcNone , typeUChar , ARG_OUT | ARG_NOVFO , " Timeout (secs) " } ,
{ 0x97 , " uplink " , funcNone , typeUChar , ARG_IN | ARG_NOVFO , " 1=Sub, 2=Main " } ,
{ 0x95 , " set_cache " , funcNone , typeUChar , ARG_IN | ARG_NOVFO , " Timeout (msecs) " } ,
{ 0x96 , " get_cache " , funcNone , typeUChar , ARG_OUT | ARG_NOVFO , " Timeout (msecs) " } ,
{ ' 2 ' , " power2mW " , funcNone , typeUChar , ARG_IN1 | ARG_IN2 | ARG_IN3 | ARG_OUT1 | ARG_NOVFO , " Power [0.0..1.0] " , " Frequency " , " Mode " , " Power mW " } ,
{ ' 4 ' , " mW2power " , funcNone , typeUChar , ARG_IN1 | ARG_IN2 | ARG_IN3 | ARG_OUT1 | ARG_NOVFO , " Pwr mW " , " Freq " , " Mode " , " Power [0.0..1.0] " } ,
{ ' 1 ' , " dump_caps " , funcNone , typeUChar , ARG_NOVFO } ,
{ ' 3 ' , " dump_conf " , funcNone , typeUChar , ARG_NOVFO } ,
{ 0x8f , " dump_state " , funcNone , typeUChar , ARG_OUT | ARG_NOVFO } ,
2025-01-18 12:29:34 +00:00
{ 0xf0 , " chk_vfo " , funcNone , typeUChar , ARG_NOVFO , " ChkVFO " } , /* rigctld only--check for VFO mode */
2024-03-05 21:01:13 +00:00
{ 0xf2 , " set_vfo_opt " , funcNone , typeUChar , ARG_NOVFO | ARG_IN , " Status " } , /* turn vfo option on/off */
2024-12-29 14:59:52 +00:00
{ 0xf3 , " get_vfo_info " , funcSelectVFO , typeVFOInfo , ARG_IN1 | ARG_NOVFO | ARG_OUT5 , " VFO " , " Freq " , " Mode " , " Width " , " Split " , " SatMode " } , /* get several vfo parameters at once */
2024-03-05 21:01:13 +00:00
{ 0xf5 , " get_rig_info " , funcNone , typeUChar , ARG_NOVFO | ARG_OUT , " RigInfo " } , /* get several vfo parameters at once */
{ 0xf4 , " get_vfo_list " , funcNone , typeUChar , ARG_OUT | ARG_NOVFO , " VFOs " } ,
{ 0xf6 , " get_modes " , funcNone , typeUChar , ARG_OUT | ARG_NOVFO , " Modes " } ,
{ 0xf9 , " get_clock " , funcTime , typeUChar , ARG_NOVFO } ,
{ 0xf8 , " set_clock " , funcTime , typeUChar , ARG_IN | ARG_NOVFO , " YYYYMMDDHHMMSS.sss+ZZ " } ,
{ 0xf1 , " halt " , funcNone , typeUChar , ARG_NOVFO } , /* rigctld only--halt the daemon */
{ 0x8c , " pause " , funcNone , typeUChar , ARG_IN , " Seconds " } ,
{ 0x98 , " password " , funcNone , typeUChar , ARG_IN | ARG_NOVFO , " Password " } ,
{ 0xf7 , " get_mode_bandwidths " , funcNone , typeUChar , ARG_IN | ARG_NOVFO , " Mode " } ,
{ 0xa0 , " set_separator " , funcSeparator , typeUChar , ARG_IN | ARG_NOVFO , " Separator " } ,
{ 0xa1 , " get_separator " , funcSeparator , typeUChar , ARG_NOVFO , " Separator " } ,
{ 0xa2 , " set_lock_mode " , funcLockFunction , typeUChar , ARG_IN | ARG_NOVFO , " Locked " } ,
{ 0xa3 , " get_lock_mode " , funcLockFunction , typeUChar , ARG_NOVFO , " Locked " } ,
{ 0xa4 , " send_raw " , funcNone , typeUChar , ARG_NOVFO | ARG_IN1 | ARG_IN2 | ARG_OUT3 , " Terminator " , " Command " , " Send raw answer " } ,
{ 0xa5 , " client_version " , funcNone , typeUChar , ARG_NOVFO | ARG_IN1 , " Version " , " Client version " } ,
{ 0x00 , " " , funcNone , typeNone } ,
2023-05-24 18:50:01 +00:00
} ;
2024-03-05 21:01:13 +00:00
2021-04-19 16:26:26 +00:00
rigCtlD : : rigCtlD ( QObject * parent ) :
QTcpServer ( parent )
{
}
rigCtlD : : ~ rigCtlD ( )
{
2021-08-04 19:49:32 +00:00
qInfo ( logRigCtlD ( ) ) < < " closing rigctld " ;
2021-04-19 16:26:26 +00:00
}
2021-05-15 09:42:44 +00:00
int rigCtlD : : startServer ( qint16 port )
2021-04-19 16:26:26 +00:00
{
if ( ! this - > listen ( QHostAddress : : Any , port ) ) {
2021-05-15 17:53:16 +00:00
qInfo ( logRigCtlD ( ) ) < < " could not start on port " < < port ;
2021-04-19 16:26:26 +00:00
return - 1 ;
}
else
{
2021-05-15 17:53:16 +00:00
qInfo ( logRigCtlD ( ) ) < < " started on port " < < port ;
2021-04-19 16:26:26 +00:00
}
2021-12-01 10:01:05 +00:00
2021-04-19 16:26:26 +00:00
return 0 ;
}
void rigCtlD : : incomingConnection ( qintptr socket ) {
2024-03-05 21:01:13 +00:00
rigCtlClient * client = new rigCtlClient ( socket , this ) ;
2021-04-19 16:26:26 +00:00
connect ( this , SIGNAL ( onStopped ( ) ) , client , SLOT ( closeSocket ( ) ) ) ;
}
2021-05-15 09:42:44 +00:00
void rigCtlD : : stopServer ( )
2021-04-19 16:26:26 +00:00
{
2021-05-15 17:53:16 +00:00
qInfo ( logRigCtlD ( ) ) < < " stopping server " ;
2021-04-19 16:26:26 +00:00
emit onStopped ( ) ;
}
2024-03-05 21:01:13 +00:00
void rigCtlClient : : receiveRigCaps ( rigCapabilities * caps )
2021-04-19 16:26:26 +00:00
{
2024-03-25 12:42:08 +00:00
if ( caps ! = Q_NULLPTR ) {
qInfo ( logRigCtlD ( ) ) < < " Got rigcaps for: " < < caps - > modelName ;
2024-12-29 14:59:52 +00:00
} else
{
qInfo ( logRigCtlD ( ) ) < < " Rig has gone away, close connection now! " ;
closeSocket ( ) ;
2024-03-25 12:42:08 +00:00
}
2021-04-19 16:26:26 +00:00
this - > rigCaps = caps ;
}
2024-03-05 21:01:13 +00:00
rigCtlClient : : rigCtlClient ( int socketId , rigCtlD * parent ) : QObject ( parent )
2021-04-19 16:26:26 +00:00
{
2021-05-15 09:42:44 +00:00
2023-06-08 07:20:50 +00:00
this - > setObjectName ( " RigCtlD " ) ;
2024-09-30 11:05:51 +00:00
queue = cachingQueue : : getInstance ( ) ;
2024-03-05 21:01:13 +00:00
connect ( queue , SIGNAL ( rigCapsUpdated ( rigCapabilities * ) ) , this , SLOT ( receiveRigCaps ( rigCapabilities * ) ) ) ;
rigCaps = queue - > getRigCaps ( ) ;
2021-04-19 16:26:26 +00:00
commandBuffer . clear ( ) ;
sessionId = socketId ;
socket = new QTcpSocket ( this ) ;
2021-04-20 11:29:10 +00:00
this - > parent = parent ;
2021-04-19 16:26:26 +00:00
if ( ! socket - > setSocketDescriptor ( sessionId ) )
{
2021-05-15 17:53:16 +00:00
qInfo ( logRigCtlD ( ) ) < < " error binding socket: " < < sessionId ;
2021-04-19 16:26:26 +00:00
return ;
}
connect ( socket , SIGNAL ( readyRead ( ) ) , this , SLOT ( socketReadyRead ( ) ) , Qt : : DirectConnection ) ;
connect ( socket , SIGNAL ( disconnected ( ) ) , this , SLOT ( socketDisconnected ( ) ) , Qt : : DirectConnection ) ;
connect ( parent , SIGNAL ( sendData ( QString ) ) , this , SLOT ( sendData ( QString ) ) , Qt : : DirectConnection ) ;
2021-05-15 17:53:16 +00:00
qInfo ( logRigCtlD ( ) ) < < " session connected: " < < sessionId ;
2021-12-01 10:01:05 +00:00
2025-01-03 14:32:38 +00:00
// Find what VFOs we have:
if ( rigCaps - > numVFO > 0 & & rigCaps - > commands . contains ( funcVFOASelect ) )
vfoList | = 1 < < 0 ;
if ( rigCaps - > numVFO > 1 & & rigCaps - > commands . contains ( funcVFOBSelect ) )
vfoList | = 1 < < 1 ;
if ( rigCaps - > numReceiver > 0 & & rigCaps - > commands . contains ( funcVFOMainSelect ) )
vfoList | = 1 < < 26 ;
if ( rigCaps - > numReceiver > 1 & & rigCaps - > commands . contains ( funcVFOSubSelect ) )
vfoList | = 1 < < 25 ;
if ( rigCaps - > commands . contains ( funcMemoryMode ) )
vfoList | = 1 < < 28 ;
2021-04-19 16:26:26 +00:00
}
void rigCtlClient : : socketReadyRead ( )
2023-05-24 18:50:01 +00:00
{
2024-12-29 14:59:52 +00:00
if ( this - > rigCaps = = Q_NULLPTR ) {
qWarning ( logRigCtlD ) < < " Rig has gone away, closing connection " ;
closeSocket ( ) ;
return ;
}
2023-05-24 18:50:01 +00:00
QByteArray data = socket - > readAll ( ) ;
commandBuffer . append ( data ) ;
QStringList commandList ( commandBuffer . split ( ' \n ' ) ) ;
QString sep = " \n " ;
int ret = - RIG_EINVAL ;
2025-01-18 12:29:34 +00:00
bool found = false ;
2023-05-24 18:50:01 +00:00
bool setCommand = false ;
2024-12-29 14:59:52 +00:00
bool longCommand = false ;
2025-01-03 14:32:38 +00:00
bool extended = false ;
2025-01-18 12:29:34 +00:00
bool sendStatus = true ;
2023-05-24 18:50:01 +00:00
QStringList response ;
for ( QString & commands : commandList )
{
restart :
if ( commands . endsWith ( ' \r ' ) )
2023-02-05 21:28:24 +00:00
{
2023-05-24 18:50:01 +00:00
commands . chop ( 1 ) ; // Remove \n character
2023-02-05 21:28:24 +00:00
}
2023-05-24 18:50:01 +00:00
if ( commands . isEmpty ( ) )
2023-02-05 21:28:24 +00:00
{
2023-05-24 18:50:01 +00:00
continue ;
2023-02-05 21:28:24 +00:00
}
2023-05-24 18:50:01 +00:00
// We have a full line so process command.
2024-12-29 14:59:52 +00:00
qDebug ( logRigCtlD ) < < sessionId < < " RX: " < < commands ;
2023-05-24 18:50:01 +00:00
if ( commands [ 0 ] = = ' ; ' | | commands [ 0 ] = = ' | ' | | commands [ 0 ] = = ' , ' )
2023-02-05 21:28:24 +00:00
{
2023-05-24 18:50:01 +00:00
sep = commands [ 0 ] . toLatin1 ( ) ;
commands . remove ( 0 , 1 ) ;
2025-01-03 19:46:27 +00:00
extended = true ;
2023-02-05 21:28:24 +00:00
}
2023-05-24 18:50:01 +00:00
else if ( commands [ 0 ] = = ' + ' )
2023-02-05 21:28:24 +00:00
{
2024-12-29 14:59:52 +00:00
//qDebug(logRigCtlD) << "Extended response requested for this command";
2023-05-24 18:50:01 +00:00
extended = true ;
sep = " \n " ;
commands . remove ( 0 , 1 ) ;
2023-02-05 21:28:24 +00:00
}
2023-05-24 18:50:01 +00:00
else if ( commands [ 0 ] = = ' # ' )
2023-02-05 21:28:24 +00:00
{
2023-05-24 18:50:01 +00:00
continue ;
2023-02-05 21:28:24 +00:00
}
2023-05-24 18:50:01 +00:00
else if ( commands [ 0 ] . toLower ( ) = = ' q ' )
2023-02-05 21:28:24 +00:00
{
2023-05-24 18:50:01 +00:00
closeSocket ( ) ;
return ;
2023-02-05 21:28:24 +00:00
}
2023-02-20 12:43:26 +00:00
2023-05-24 18:50:01 +00:00
if ( commands [ 0 ] = = ' \\ ' )
2023-02-05 21:28:24 +00:00
{
2023-05-24 18:50:01 +00:00
commands . remove ( 0 , 1 ) ;
2024-12-29 14:59:52 +00:00
//qDebug(logRigCtlD) << "This is a long form command";
2023-05-24 18:50:01 +00:00
longCommand = true ;
2021-08-05 12:52:06 +00:00
}
2024-12-29 14:59:52 +00:00
//qDebug(logRigCtlD) << "Got command to parse:" << commands;
2023-05-24 18:50:01 +00:00
QStringList command = commands . split ( " " ) ;
2024-07-14 19:11:05 +00:00
command . removeAll ( { } ) ; // Remove any empty strings (double-whitespace issue)
2025-01-18 12:29:34 +00:00
found = false ;
sendStatus = true ;
2023-05-24 18:50:01 +00:00
for ( int i = 0 ; commands_list [ i ] . sstr ! = 0x00 ; i + + )
2021-11-23 00:39:10 +00:00
{
2023-05-24 18:50:01 +00:00
if ( ( longCommand & & ! strncmp ( command [ 0 ] . toLocal8Bit ( ) , commands_list [ i ] . str , MAXNAMESIZE ) ) | |
( ! longCommand & & ! commands . isNull ( ) & & commands [ 0 ] . toLatin1 ( ) = = commands_list [ i ] . sstr ) )
{
command . removeFirst ( ) ; // Remove the actual command so it only contains params
2025-01-18 12:29:34 +00:00
found = true ;
if ( extended & & commands_list [ i ] . sstr ! = 0xf0 ) {
2025-01-03 14:32:38 +00:00
// First we need to repeat the original command back:
2025-01-03 19:46:27 +00:00
QString repeat = QString ( " %1: " ) . arg ( commands_list [ i ] . str ) ;
2025-01-03 14:32:38 +00:00
for ( const auto & c : command )
{
repeat + = QString ( " %0 " ) . arg ( c ) ;
}
response . append ( repeat ) ;
}
2023-05-24 18:50:01 +00:00
if ( ( ( commands_list [ i ] . flags & ARG_IN ) = = ARG_IN ) )
{
2024-04-28 19:06:32 +00:00
// For debugging only comment next line M0VSE
2024-12-29 14:59:52 +00:00
//qInfo(logRigCtlD()) << "Received set command" << commands;
2023-05-24 18:50:01 +00:00
setCommand = true ;
}
if ( commands_list [ i ] . func = = funcRigctlFunction )
{
ret = getSubCommand ( response , extended , commands_list [ i ] , functions_str , command ) ;
commands . clear ( ) ;
break ;
} else if ( commands_list [ i ] . func = = funcRigctlLevel )
{
ret = getSubCommand ( response , extended , commands_list [ i ] , levels_str , command ) ;
commands . clear ( ) ;
break ;
} else if ( commands_list [ i ] . func = = funcRigctlParam )
{
ret = getSubCommand ( response , extended , commands_list [ i ] , params_str , command ) ;
commands . clear ( ) ;
break ;
} else if ( commands_list [ i ] . sstr = = 0x8f )
{
ret = dumpState ( response , extended ) ;
break ;
} else if ( commands_list [ i ] . sstr = = ' 1 ' )
{
ret = dumpCaps ( response , extended ) ;
setCommand = true ;
break ;
2025-01-03 14:32:38 +00:00
}
else if ( commands_list [ i ] . sstr = = ' 2 ' )
{
// power2mW
ret = power2mW ( response , extended , commands_list [ i ] , command ) ;
setCommand = true ;
break ;
}
else if ( commands_list [ i ] . sstr = = ' 3 ' )
2023-05-24 18:50:01 +00:00
{
2024-06-23 10:59:41 +00:00
response . append ( QString ( " Model: WFVIEW(%0) " ) . arg ( rigCaps - > modelName ) ) ;
2023-05-24 18:50:01 +00:00
ret = RIG_OK ;
break ;
2025-01-03 14:32:38 +00:00
}
else if ( commands_list [ i ] . sstr = = ' 4 ' )
{
// mW2power
ret = mW2power ( response , extended , commands_list [ i ] , command ) ;
setCommand = true ;
break ;
}
else if ( commands_list [ i ] . sstr = = 0xf0 )
2023-05-24 18:50:01 +00:00
{
chkVfoEecuted = true ;
2025-01-18 12:29:34 +00:00
response . append ( QString ( " ChkVFO: %0 " ) . arg ( uchar ( 0 ) ) ) ;
2025-01-03 00:05:50 +00:00
ret = RIG_OK ;
2025-01-18 12:29:34 +00:00
// chk_vfo doesn't output RPRT
sendStatus = false ;
2025-01-03 00:05:50 +00:00
break ;
2023-05-24 18:50:01 +00:00
}
// Special commands are funcNone so will not get called here
if ( commands_list [ i ] . func ! = funcNone ) {
ret = getCommand ( response , extended , commands_list [ i ] , command ) ;
}
break ;
2021-08-05 10:29:20 +00:00
}
2021-08-05 10:06:35 +00:00
}
2023-05-24 18:50:01 +00:00
if ( setCommand )
2021-08-05 10:06:35 +00:00
{
2023-05-24 18:50:01 +00:00
break ; // Cannot be a compound command so just output result.
2021-04-19 16:26:26 +00:00
}
2023-05-24 18:50:01 +00:00
2025-01-18 12:29:34 +00:00
if ( ! longCommand & & ! commands . isEmpty ( ) ) {
2023-05-24 18:50:01 +00:00
commands . remove ( 0 , 1 ) ;
goto restart ; // Need to restart loop without going to next command incase of compound command
2021-08-05 10:29:20 +00:00
}
2021-08-05 10:06:35 +00:00
2021-12-07 12:32:51 +00:00
sep = " \n " ;
2021-11-23 00:39:10 +00:00
2021-04-19 16:26:26 +00:00
}
2023-05-24 18:50:01 +00:00
// We have finished parsing all commands and have a response to send (hopefully)
2021-12-04 19:21:23 +00:00
commandBuffer . clear ( ) ;
2025-01-03 19:46:27 +00:00
for ( int i = 0 ; i < response . size ( ) ; i + + )
2023-05-24 18:50:01 +00:00
{
2025-01-03 19:46:27 +00:00
if ( ! response [ i ] . isEmpty ( ) ) {
2025-01-18 12:29:34 +00:00
sendData ( QString ( " %0%1 " ) . arg ( response [ i ] , sep ) ) ;
2025-01-03 19:46:27 +00:00
}
2023-05-24 18:50:01 +00:00
}
2025-01-18 12:29:34 +00:00
if ( found & & sendStatus & & ( ret < 0 | | setCommand | | extended ) )
sendData ( QString ( " RPRT %1 \n " ) . arg ( QString : : number ( ret ) ) ) ;
2021-04-19 16:26:26 +00:00
}
void rigCtlClient : : socketDisconnected ( )
{
2021-05-15 17:53:16 +00:00
qInfo ( logRigCtlD ( ) ) < < sessionId < < " disconnected " ;
2021-04-19 16:26:26 +00:00
socket - > deleteLater ( ) ;
this - > deleteLater ( ) ;
}
void rigCtlClient : : closeSocket ( )
{
socket - > close ( ) ;
}
void rigCtlClient : : sendData ( QString data )
{
2024-12-29 14:59:52 +00:00
qDebug ( logRigCtlD ( ) ) < < sessionId < < " TX: " < < data ;
2021-04-19 16:26:26 +00:00
if ( socket ! = Q_NULLPTR & & socket - > isValid ( ) & & socket - > isOpen ( ) )
{
socket - > write ( data . toLatin1 ( ) ) ;
}
2021-04-20 11:29:10 +00:00
else
{
2021-05-15 17:53:16 +00:00
qInfo ( logRigCtlD ( ) ) < < " socket not open! " ;
2021-04-20 11:29:10 +00:00
}
2021-04-19 16:26:26 +00:00
}
2022-10-31 12:03:04 +00:00
QString rigCtlClient : : getFilter ( quint8 mode , quint8 filter ) {
2021-04-25 09:58:25 +00:00
if ( mode = = 3 | | mode = = 7 | | mode = = 12 | | mode = = 17 ) {
switch ( filter ) {
case 1 :
return QString ( " 1200 " ) ;
case 2 :
return QString ( " 500 " ) ;
case 3 :
return QString ( " 250 " ) ;
}
}
else if ( mode = = 4 | | mode = = 8 )
{
switch ( filter ) {
case 1 :
return QString ( " 2400 " ) ;
case 2 :
return QString ( " 500 " ) ;
case 3 :
return QString ( " 250 " ) ;
}
}
else if ( mode = = 2 )
{
switch ( filter ) {
case 1 :
return QString ( " 9000 " ) ;
case 2 :
return QString ( " 6000 " ) ;
case 3 :
return QString ( " 3000 " ) ;
}
}
else if ( mode = = 5 )
{
switch ( filter ) {
case 1 :
return QString ( " 15000 " ) ;
case 2 :
return QString ( " 10000 " ) ;
case 3 :
return QString ( " 7000 " ) ;
}
}
else { // SSB or unknown mode
switch ( filter ) {
case 1 :
return QString ( " 3000 " ) ;
case 2 :
return QString ( " 2400 " ) ;
case 3 :
return QString ( " 1800 " ) ;
}
}
return QString ( " " ) ;
}
2023-05-24 18:50:01 +00:00
QString rigCtlClient : : getMode ( modeInfo mode )
{
for ( int i = 0 ; mode_str [ i ] . str [ 0 ] ! = ' \0 ' ; i + + )
{
if ( mode_str [ i ] . mk = = mode . mk & & mode_str [ i ] . data = = mode . data )
{
return ( QString ( mode_str [ i ] . str ) ) ;
}
2021-04-25 09:58:25 +00:00
}
2023-05-24 18:50:01 +00:00
return ( " UNKNOWN " ) ;
2021-04-25 09:58:25 +00:00
}
2023-05-24 18:50:01 +00:00
bool rigCtlClient : : getMode ( QString modeString , modeInfo & mode )
{
2024-12-29 15:19:46 +00:00
//qInfo() << "Looking for mode (set)" << modeString;
2023-05-24 18:50:01 +00:00
for ( int i = 0 ; mode_str [ i ] . str [ 0 ] ! = ' \0 ' ; i + + )
{
if ( QString ( mode_str [ i ] . str ) = = modeString )
{
2024-03-05 21:01:13 +00:00
for ( auto & m : rigCaps - > modes )
2023-05-24 18:50:01 +00:00
{
if ( m . mk = = mode_str [ i ] . mk )
{
mode = modeInfo ( m ) ;
mode . data = mode_str [ i ] . data ;
2023-07-20 15:54:07 +00:00
mode . filter = 1 ;
2023-05-24 18:50:01 +00:00
return true ;
}
}
}
2021-04-25 09:58:25 +00:00
}
2023-05-24 18:50:01 +00:00
return false ;
2021-05-01 05:15:30 +00:00
}
2021-08-05 00:23:15 +00:00
2021-08-07 00:14:41 +00:00
2022-10-31 12:03:04 +00:00
quint8 rigCtlClient : : getAntennas ( )
2021-08-07 12:34:47 +00:00
{
2022-10-31 12:03:04 +00:00
quint8 ant = 0 ;
2024-03-05 21:01:13 +00:00
for ( auto & i : rigCaps - > antennas )
2021-08-07 12:34:47 +00:00
{
2023-05-09 11:11:38 +00:00
ant | = 1 < < i . num ;
2021-08-07 12:34:47 +00:00
}
return ant ;
}
2021-08-07 00:14:41 +00:00
2022-10-31 12:03:04 +00:00
quint64 rigCtlClient : : getRadioModes ( QString md )
2021-08-07 00:14:41 +00:00
{
quint64 modes = 0 ;
2024-03-05 21:01:13 +00:00
for ( auto & & mode : rigCaps - > modes )
2021-08-06 08:25:08 +00:00
{
for ( int i = 0 ; mode_str [ i ] . str [ 0 ] ! = ' \0 ' ; i + + )
{
2022-10-31 12:03:04 +00:00
QString mstr = QString ( mode_str [ i ] . str ) ;
2025-02-10 01:28:22 +00:00
if ( rigCaps - > inputs . size ( ) )
{
2022-10-31 12:03:04 +00:00
if ( mstr . contains ( mode . name ) )
2021-08-06 11:37:03 +00:00
{
2022-10-31 12:03:04 +00:00
// qDebug(logRigCtlD()) << "Found data mode:" << mode.name << mode_str[i].mode;
if ( md . isEmpty ( ) | | mstr . contains ( md ) ) {
2021-12-07 12:32:51 +00:00
modes | = mode_str [ i ] . mode ;
}
2021-08-06 11:37:03 +00:00
}
}
2022-10-31 12:03:04 +00:00
else if ( mode . name = = mstr )
{
//qDebug(logRigCtlD()) << "Found mode:" << mode.name << mode_str[i].mode;
if ( md . isEmpty ( ) | | mstr = = md )
{
modes | = mode_str [ i ] . mode ;
}
}
2021-08-06 08:25:08 +00:00
}
}
2021-08-07 00:14:41 +00:00
return modes ;
2021-08-07 12:34:47 +00:00
}
2022-10-31 12:03:04 +00:00
QString rigCtlClient : : getAntName ( quint8 ant )
2021-08-07 12:34:47 +00:00
{
QString ret ;
switch ( ant )
{
case 0 : ret = " ANT1 " ; break ;
case 1 : ret = " ANT2 " ; break ;
case 2 : ret = " ANT3 " ; break ;
case 3 : ret = " ANT4 " ; break ;
case 4 : ret = " ANT5 " ; break ;
case 30 : ret = " ANT_UNKNOWN " ; break ;
case 31 : ret = " ANT_CURR " ; break ;
default : ret = " ANT_UNK " ; break ;
}
return ret ;
2021-08-08 16:14:48 +00:00
}
2022-10-31 12:03:04 +00:00
quint8 rigCtlClient : : antFromName ( QString name ) {
quint8 ret ;
2021-11-23 00:39:10 +00:00
2022-10-29 14:12:30 +00:00
if ( name . toUpper ( ) = = " ANT1 " )
2021-11-23 00:39:10 +00:00
ret = 0 ;
2022-10-29 14:12:30 +00:00
else if ( name . toUpper ( ) = = " ANT2 " )
2021-11-23 00:39:10 +00:00
ret = 1 ;
2022-10-29 14:12:30 +00:00
else if ( name . toUpper ( ) = = " ANT3 " )
2021-11-23 00:39:10 +00:00
ret = 2 ;
2022-10-29 14:12:30 +00:00
else if ( name . toUpper ( ) = = " ANT4 " )
2021-11-23 00:39:10 +00:00
ret = 3 ;
2022-10-29 14:12:30 +00:00
else if ( name . toUpper ( ) = = " ANT5 " )
2021-11-23 00:39:10 +00:00
ret = 4 ;
2022-10-29 14:12:30 +00:00
else if ( name . toUpper ( ) = = " ANT_UNKNOWN " )
2021-11-23 00:39:10 +00:00
ret = 30 ;
2022-10-29 14:12:30 +00:00
else if ( name . toUpper ( ) = = " ANT_CURR " )
2021-11-23 00:39:10 +00:00
ret = 31 ;
else
ret = 99 ;
return ret ;
}
2024-12-29 14:59:52 +00:00
vfo_t rigCtlClient : : vfoFromName ( QString vfo ) {
2025-01-18 12:29:34 +00:00
rigStateType state = queue - > getState ( ) ;
2024-12-29 14:59:52 +00:00
vfo_t v = vfoUnknown ;
2025-01-18 12:29:34 +00:00
if ( vfo . toUpper ( ) = = " CURRVFO " )
{
v = state . vfo ;
}
else if ( vfo . toUpper ( ) = = " VFOA " )
2025-01-03 00:05:50 +00:00
{
if ( rigCaps - > commands . contains ( funcVFOASelect ) )
v = vfoA ;
else if ( rigCaps - > commands . contains ( funcVFOMainSelect ) )
v = vfoMain ;
else
2025-01-18 12:29:34 +00:00
v = state . vfo ;
2025-01-03 00:05:50 +00:00
}
2024-12-29 14:59:52 +00:00
else if ( vfo . toUpper ( ) = = " VFOB " )
2025-01-03 00:05:50 +00:00
{
if ( rigCaps - > commands . contains ( funcVFOBSelect ) )
v = vfoB ;
else if ( rigCaps - > commands . contains ( funcVFOSubSelect ) )
v = vfoSub ;
else
2025-01-18 12:29:34 +00:00
v = state . vfo ;
2025-01-03 00:05:50 +00:00
}
else if ( vfo . toUpper ( ) = = " MAIN " )
{
if ( rigCaps - > commands . contains ( funcVFOMainSelect ) )
v = vfoMain ;
else if ( rigCaps - > commands . contains ( funcVFOASelect ) )
v = vfoA ;
else
2025-01-18 12:29:34 +00:00
v = state . vfo ;
2025-01-03 00:05:50 +00:00
}
2024-12-29 14:59:52 +00:00
else if ( vfo . toUpper ( ) = = " SUB " )
2025-01-03 00:05:50 +00:00
{
if ( rigCaps - > commands . contains ( funcVFOSubSelect ) )
v = vfoSub ;
else if ( rigCaps - > commands . contains ( funcVFOBSelect ) )
v = vfoB ;
else
2025-01-18 12:29:34 +00:00
v = state . vfo ;
2025-01-03 00:05:50 +00:00
}
2024-12-29 14:59:52 +00:00
else if ( vfo . toUpper ( ) = = " MEM " )
2025-01-03 00:05:50 +00:00
{
2025-01-18 12:29:34 +00:00
if ( rigCaps - > commands . contains ( funcMemoryMode ) )
v = vfoMem ;
else
v = state . vfo ;
2025-01-03 00:05:50 +00:00
}
2025-01-03 16:31:12 +00:00
//qInfo() << "vfoFromName" << vfo << "returns" << v;
2024-12-29 14:59:52 +00:00
return v ;
2023-02-05 21:28:24 +00:00
}
2024-12-29 14:59:52 +00:00
QString rigCtlClient : : getVfoName ( vfo_t vfo )
2023-02-05 21:28:24 +00:00
{
QString ret ;
switch ( vfo ) {
2024-12-29 14:59:52 +00:00
case vfoMain :
ret = " Main " ;
break ;
case vfoSub :
ret = " Sub " ;
break ;
case vfoA :
ret = " VFOA " ;
break ;
case vfoB :
ret = " VFOB " ;
break ;
2025-01-03 00:05:50 +00:00
case vfoCurrent :
ret = " currVFO " ;
2025-01-03 16:11:03 +00:00
break ;
2024-12-29 14:59:52 +00:00
case vfoMem :
ret = " MEM " ;
break ;
default :
2025-01-03 14:32:38 +00:00
ret = " None " ;
2024-12-29 14:59:52 +00:00
break ;
2023-02-05 21:28:24 +00:00
}
2025-01-03 16:31:12 +00:00
//qInfo() << "vfoName" << vfo << "returns" << ret;
2025-01-03 16:11:03 +00:00
2023-02-05 21:28:24 +00:00
return ret ;
}
2024-08-13 12:19:50 +00:00
unsigned long rigCtlClient : : doCrc ( quint8 * p , size_t n )
2023-02-05 21:28:24 +00:00
{
unsigned long crc = 0xfffffffful ;
size_t i ;
if ( crcTable [ 0 ] = = 0 ) { genCrc ( crcTable ) ; }
for ( i = 0 ; i < n ; i + + )
{
crc = crcTable [ * p + + ^ ( crc & 0xff ) ] ^ ( crc > > 8 ) ;
}
return ( ( ~ crc ) & 0xffffffff ) ;
}
void rigCtlClient : : genCrc ( unsigned long crcTable [ ] )
{
unsigned long POLYNOMIAL = 0xEDB88320 ;
2024-08-13 12:19:50 +00:00
quint8 b = 0 ;
2023-02-05 21:28:24 +00:00
while ( 0 ! = + + b )
{
unsigned long remainder = b ;
unsigned long bit ;
for ( bit = 8 ; bit > 0 ; - - bit )
{
if ( remainder & 1 )
{
remainder = ( remainder > > 1 ) ^ POLYNOMIAL ;
}
else
{
remainder = ( remainder > > 1 ) ;
}
}
crcTable [ ( size_t ) b ] = remainder ;
}
2023-02-20 12:43:26 +00:00
}
2023-05-24 18:50:01 +00:00
int rigCtlClient : : getCommand ( QStringList & response , bool extended , const commandStruct cmd , QStringList params )
{
// This is a main command
int ret = - RIG_EINVAL ;
2024-12-29 14:59:52 +00:00
funcs func = cmd . func ;
2025-01-09 21:29:44 +00:00
rigStateType state = queue - > getState ( ) ;
2024-07-14 19:11:05 +00:00
2025-01-18 12:29:34 +00:00
2024-12-29 14:59:52 +00:00
if ( rigCaps = = Q_NULLPTR )
return ret ;
2024-07-14 19:11:05 +00:00
2023-05-24 18:50:01 +00:00
if ( ( ( cmd . flags & ARG_IN ) = = ARG_IN ) & & params . size ( ) )
{
// We are expecting a second argument to the command as it is a set
QVariant val ;
ret = RIG_OK ;
2024-03-05 21:01:13 +00:00
switch ( cmd . type )
{
case typeUChar :
2024-12-29 14:59:52 +00:00
if ( cmd . func = = funcLockFunction )
val . setValue ( modeLock ) ;
else
val . setValue ( static_cast < uchar > ( params [ 0 ] . toInt ( ) ) ) ;
2024-03-05 21:01:13 +00:00
break ;
case typeShort :
2023-05-24 18:50:01 +00:00
val . setValue ( static_cast < short > ( params [ 0 ] . toInt ( ) ) ) ;
2024-03-05 21:01:13 +00:00
break ;
2025-01-03 00:05:50 +00:00
case typeUShort :
val . setValue ( static_cast < ushort > ( params [ 0 ] . toInt ( ) ) ) ;
break ;
2024-03-05 21:01:13 +00:00
case typeFloat :
2023-05-24 18:50:01 +00:00
val . setValue ( static_cast < ushort > ( float ( params [ 0 ] . toFloat ( ) * 255.0 ) ) ) ; // rigctl sends 0.0-1.0, we expect 0-255
2024-03-05 21:01:13 +00:00
break ;
case typeFloatDiv :
2023-05-24 18:50:01 +00:00
val . setValue ( static_cast < uchar > ( float ( params [ 0 ] . toFloat ( ) / 10.0 ) ) ) ;
2024-03-05 21:01:13 +00:00
break ;
case typeFloatDiv5 :
2023-05-24 18:50:01 +00:00
val . setValue ( static_cast < ushort > ( float ( params [ 0 ] . toFloat ( ) * 5.1 ) ) ) ;
2024-03-05 21:01:13 +00:00
break ;
2025-01-06 20:16:14 +00:00
case typeBinary :
2025-01-06 16:25:12 +00:00
if ( params . length ( ) > 1 ) {
2025-01-09 21:29:44 +00:00
queue - > add ( priorityImmediate , queueItem ( funcSelectVFO , QVariant : : fromValue < vfo_t > ( vfoFromName ( params [ 0 ] ) ) , false , state . receiver ) ) ;
2025-01-06 16:25:12 +00:00
val . setValue ( static_cast < bool > ( params [ 1 ] . toInt ( ) ) ) ;
} else {
val . setValue ( static_cast < bool > ( params [ 0 ] . toInt ( ) ) ) ;
}
2025-01-06 16:30:25 +00:00
break ;
2024-03-05 21:01:13 +00:00
case typeFreq :
2025-01-06 20:16:14 +00:00
{
2023-05-24 18:50:01 +00:00
freqt f ;
2025-01-03 16:11:03 +00:00
if ( cmd . sstr = = ' I ' ) {
2025-01-09 21:29:44 +00:00
state . vfo = splitVfo ;
state . receiver = uchar ( ( rigCaps - > numVFO = = 1 & & rigCaps - > numReceiver > 1 ) ) ;
2025-01-06 20:16:14 +00:00
}
2025-01-09 21:29:44 +00:00
if ( params . length ( ) > 1 ) {
state . vfo = vfoFromName ( params [ 0 ] ) ;
2025-02-20 16:48:28 +00:00
f . Hz = static_cast < quint64 > ( params [ 1 ] . toULongLong ( ) ) ;
2025-01-09 21:29:44 +00:00
} else {
2025-02-20 16:48:28 +00:00
f . Hz = static_cast < quint64 > ( params [ 0 ] . toULongLong ( ) ) ;
2025-01-03 16:11:03 +00:00
}
2025-01-09 21:29:44 +00:00
func = queue - > getVfoCommand ( state . vfo , state . receiver , true ) . freqFunc ;
2023-05-24 18:50:01 +00:00
f . VFO = activeVFO ;
f . MHzDouble = f . Hz / 1000000.0 ;
val . setValue ( f ) ;
2025-01-09 21:29:44 +00:00
//qInfo() << "Sending freq command" << funcString[func] << "for freq" << f.Hz;
2024-03-05 21:01:13 +00:00
break ;
2023-05-24 18:50:01 +00:00
}
2024-12-29 14:59:52 +00:00
case typeSplitVFO :
2025-01-03 16:11:03 +00:00
2024-12-29 14:59:52 +00:00
val . setValue ( static_cast < bool > ( params [ 0 ] . toInt ( ) ) ) ;
2025-01-03 14:32:38 +00:00
if ( params . size ( ) > 1 ) { // Just in case we have invalid info
2025-01-03 16:31:12 +00:00
//qInfo() << "Split VFO" << params[0] << "VFO" << params[1];
2024-12-29 14:59:52 +00:00
splitVfo = vfoFromName ( params [ 1 ] ) ;
2025-01-03 14:32:38 +00:00
}
2024-12-29 14:59:52 +00:00
break ;
2024-03-05 21:01:13 +00:00
case typeMode :
{
2025-01-03 16:11:03 +00:00
if ( cmd . sstr = = ' X ' ) {
2025-01-09 21:29:44 +00:00
state . vfo = splitVfo ;
state . receiver = uchar ( ( rigCaps - > numVFO = = 1 & & rigCaps - > numReceiver > 1 ) ) ;
2025-01-03 16:11:03 +00:00
}
2025-01-03 14:32:38 +00:00
2023-05-24 18:50:01 +00:00
modeInfo mi ;
2025-01-06 20:16:14 +00:00
QString mode = " " ;
QString width = " " ;
if ( params . size ( ) = = 3 )
{
2025-01-09 21:29:44 +00:00
state . vfo = vfoFromName ( params [ 0 ] ) ;
2025-01-06 20:16:14 +00:00
mode = params [ 1 ] ;
width = params [ 2 ] ;
}
else if ( params . size ( ) = = 2 )
{
mode = params [ 0 ] ;
width = params [ 1 ] ;
}
// We have VFO, Mode and PB
2025-01-09 21:29:44 +00:00
func = queue - > getVfoCommand ( state . vfo , state . receiver , true ) . modeFunc ;
2025-01-09 00:35:26 +00:00
2025-01-06 20:16:14 +00:00
bool ok ;
int pb = width . toInt ( & ok ) ;
if ( ok & & pb > 0 ) {
2025-01-09 21:29:44 +00:00
queue - > add ( priorityImmediate , queueItem ( funcFilterWidth , QVariant : : fromValue < ushort > ( pb ) , false , state . receiver ) ) ;
2025-01-06 20:16:14 +00:00
}
if ( getMode ( mode , mi ) )
2023-05-24 18:50:01 +00:00
{
val . setValue ( mi ) ;
2023-07-20 15:54:07 +00:00
} else {
qInfo ( logRigCtlD ( ) ) < < " Mode not found: " < < params [ 0 ] ;
return - RIG_EINVAL ;
2023-05-24 18:50:01 +00:00
}
2024-03-05 21:01:13 +00:00
break ;
2023-05-24 18:50:01 +00:00
}
2024-03-05 21:01:13 +00:00
case typeVFO :
// Setting VFO:
2024-12-29 14:59:52 +00:00
if ( params [ 0 ] = = " ? " ) {
// This is a query for a list of values
QString vfo ;
if ( rigCaps - > numVFO > 0 & & rigCaps - > commands . contains ( funcVFOASelect ) )
vfo . append ( " VFOA " ) ;
if ( rigCaps - > numVFO > 1 & & rigCaps - > commands . contains ( funcVFOASelect ) )
vfo . append ( " VFOB " ) ;
if ( rigCaps - > numReceiver > 0 & & rigCaps - > commands . contains ( funcVFOMainSelect ) )
vfo . append ( " Main " ) ;
if ( rigCaps - > numReceiver > 1 & & rigCaps - > commands . contains ( funcVFOSubSelect ) )
vfo . append ( " Sub " ) ;
if ( rigCaps - > commands . contains ( funcMemoryMode ) )
vfo . append ( " MEM " ) ;
vfo . chop ( 1 ) ;
response . append ( vfo ) ;
}
else
2024-07-14 19:11:05 +00:00
{
2025-01-09 21:29:44 +00:00
state . vfo = vfoFromName ( params [ 0 ] ) ;
val . setValue ( state . vfo ) ;
2024-07-14 19:11:05 +00:00
}
2024-03-05 21:01:13 +00:00
break ;
2024-04-05 12:01:26 +00:00
case typeString :
{
// Only used for CW?
2024-07-12 09:08:24 +00:00
QString sendCmd ;
for ( QString & cmd : params ) {
2024-07-12 09:33:49 +00:00
sendCmd = sendCmd + cmd + " " ;
2024-07-12 09:08:24 +00:00
}
2024-07-12 09:29:50 +00:00
sendCmd . chop ( 1 ) ;
2024-07-12 09:08:24 +00:00
val . setValue ( sendCmd ) ;
2024-06-03 18:43:00 +00:00
break ;
2024-04-05 12:01:26 +00:00
}
2024-03-05 21:01:13 +00:00
default :
qInfo ( logRigCtlD ( ) ) < < " Unable to parse value of type " < < cmd . type < < " Command " < < cmd . str ;
2023-05-24 18:50:01 +00:00
return - RIG_EINVAL ;
}
2024-03-05 21:01:13 +00:00
2025-01-09 21:29:44 +00:00
queue - > add ( priorityImmediate , queueItem ( func , val , false , state . receiver ) ) ;
2023-05-24 18:50:01 +00:00
} else {
// Simple get command
2023-07-20 15:54:07 +00:00
cacheItem item ;
2024-07-14 19:11:05 +00:00
2024-12-29 14:59:52 +00:00
// Build QStringList of Prefixes. This is a bit messy, but not sure how else do to it?
2025-01-03 14:32:38 +00:00
QStringList prefixes = buildPrefixes ( cmd , extended ) ;
2025-01-18 12:29:34 +00:00
if ( ! prefixes . length ( ) )
{
qWarning ( logRigCtlD ( ) ) < < " No prefixes found for cmd " < < cmd . str < < " using func " < < funcString [ func ] < < " aborting " ;
}
2025-01-09 00:35:26 +00:00
if ( cmd . sstr = = ' i ' | | cmd . sstr = = ' x ' ) {
if ( splitVfo = = vfoSub & & rigCaps - > numReceiver > 1 ) {
2025-01-09 21:29:44 +00:00
state . receiver = 1 ;
2025-01-09 00:35:26 +00:00
}
2025-01-09 21:29:44 +00:00
state . vfo = splitVfo ;
2024-12-29 14:59:52 +00:00
}
2025-01-09 00:35:26 +00:00
if ( func = = funcFreqGet ) {
2025-01-09 21:29:44 +00:00
func = queue - > getVfoCommand ( state . vfo , state . receiver , true ) . freqFunc ;
2025-01-09 00:35:26 +00:00
} else if ( func = = funcModeGet ) {
2025-01-09 21:29:44 +00:00
func = queue - > getVfoCommand ( state . vfo , state . receiver , true ) . modeFunc ;
2024-12-29 14:59:52 +00:00
}
2025-01-09 21:29:44 +00:00
//qInfo() << "getting Cache Value for func" << funcString[func] << "on rx" << state.receiver;
2024-03-05 21:01:13 +00:00
if ( rigCaps - > commands . contains ( func ) )
2025-01-09 21:29:44 +00:00
item = queue - > getCache ( func , state . receiver ) ;
2024-12-29 14:59:52 +00:00
2025-01-18 12:29:34 +00:00
if ( prefixes . length ( ) & & params . length ( ) )
{
response . append ( QString ( " %0%1 " ) . arg ( prefixes [ 0 ] , params [ 0 ] ) ) ;
}
2023-05-24 18:50:01 +00:00
ret = RIG_OK ;
2024-03-05 21:01:13 +00:00
switch ( cmd . type ) {
2025-01-06 20:16:14 +00:00
case typeBinary :
{
2025-01-06 16:25:12 +00:00
bool b = item . value . toBool ( ) ;
2025-01-18 12:29:34 +00:00
response . append ( QString ( " %0%1 " ) . arg ( prefixes [ prefixes . length ( ) - 1 ] , QString : : number ( b ) ) ) ;
2025-01-06 16:25:12 +00:00
break ;
}
2024-03-05 21:01:13 +00:00
case typeUChar :
2025-01-03 00:05:50 +00:00
case typeUShort :
2024-03-05 21:01:13 +00:00
case typeShort :
{
2023-05-24 18:50:01 +00:00
int i = item . value . toInt ( ) ;
2024-12-29 14:59:52 +00:00
if ( cmd . func = = funcLockFunction )
i = modeLock ;
2025-01-18 12:29:34 +00:00
response . append ( QString ( " %0%1 " ) . arg ( prefixes [ prefixes . length ( ) - 1 ] , QString : : number ( i ) ) ) ;
2024-03-05 21:01:13 +00:00
break ;
2023-05-24 18:50:01 +00:00
}
2024-03-05 21:01:13 +00:00
case typeFloat :
{
2023-05-24 18:50:01 +00:00
float f = item . value . toFloat ( ) / 255.0 ;
2025-01-18 12:29:34 +00:00
response . append ( QString ( " %0%1 " ) . arg ( prefixes [ prefixes . length ( ) - 1 ] , QString : : number ( f , typeFloat , 6 ) ) ) ;
2024-03-05 21:01:13 +00:00
break ;
2023-05-24 18:50:01 +00:00
}
2024-03-05 21:01:13 +00:00
case typeFloatDiv :
{
2023-05-24 18:50:01 +00:00
float f = item . value . toFloat ( ) * 10 ;
2025-01-18 12:29:34 +00:00
response . append ( QString ( " %0%1 " ) . arg ( prefixes [ prefixes . length ( ) - 1 ] , QString : : number ( f , typeFloat , 6 ) ) ) ;
2024-03-05 21:01:13 +00:00
break ;
2023-05-24 18:50:01 +00:00
}
2024-03-05 21:01:13 +00:00
case typeFloatDiv5 :
{
2023-05-24 18:50:01 +00:00
float f = item . value . toFloat ( ) / 5.1 ;
2025-01-18 12:29:34 +00:00
response . append ( QString ( " %0%1 " ) . arg ( prefixes [ prefixes . length ( ) - 1 ] , QString : : number ( f , typeFloat , 6 ) ) ) ;
2024-03-05 21:01:13 +00:00
break ;
2023-05-24 18:50:01 +00:00
}
2024-03-05 21:01:13 +00:00
case typeFreq :
{ // Frequency
2023-05-24 18:50:01 +00:00
freqt f = item . value . value < freqt > ( ) ;
2025-01-18 12:29:34 +00:00
response . append ( QString ( " %0%1 " ) . arg ( prefixes [ prefixes . length ( ) - 1 ] , QString : : number ( f . Hz ) ) ) ;
2024-03-05 21:01:13 +00:00
break ;
2023-05-24 18:50:01 +00:00
}
2024-03-05 21:01:13 +00:00
case typeVFO :
{ // VFO
2024-12-29 14:59:52 +00:00
//uchar v = item.value.value<uchar>();
2025-01-18 12:29:34 +00:00
response . append ( QString ( " %0%1 " ) . arg ( prefixes [ prefixes . length ( ) - 1 ] , getVfoName ( state . vfo ) ) ) ;
2024-12-29 14:59:52 +00:00
break ;
}
case typeSplitVFO :
{ // VFO
bool v = item . value . value < uchar > ( ) ;
if ( prefixes . length ( ) > 0 )
response . append ( QString ( " %0%1 " ) . arg ( prefixes [ 0 ] , QString : : number ( v ) ) ) ;
if ( prefixes . length ( ) > 1 )
response . append ( QString ( " %0%1 " ) . arg ( prefixes [ 1 ] , getVfoName ( splitVfo ) ) ) ;
break ;
}
case typeVFOInfo :
{
2025-01-09 21:29:44 +00:00
funcs freqFunc = queue - > getVfoCommand ( state . vfo , state . receiver , true ) . freqFunc ;
funcs modeFunc = queue - > getVfoCommand ( state . vfo , state . receiver , true ) . modeFunc ;
2024-12-29 14:59:52 +00:00
if ( rigCaps - > numReceiver > 1 & & params . size ( ) & & params [ 0 ] = = " Sub " ) {
2025-01-09 21:29:44 +00:00
state . receiver = 1 ;
2023-05-24 18:50:01 +00:00
}
2024-12-29 14:59:52 +00:00
if ( prefixes . length ( ) > 1 )
2025-01-09 21:29:44 +00:00
response . append ( QString ( " %0%1 " ) . arg ( prefixes [ 1 ] , QString : : number ( queue - > getCache ( freqFunc , state . receiver ) . value . value < freqt > ( ) . Hz ) ) ) ;
2024-12-29 14:59:52 +00:00
if ( prefixes . length ( ) > 2 )
2025-01-09 21:29:44 +00:00
response . append ( QString ( " %0%1 " ) . arg ( prefixes [ 2 ] , getMode ( queue - > getCache ( modeFunc , state . receiver ) . value . value < modeInfo > ( ) ) ) ) ;
2024-12-29 14:59:52 +00:00
if ( prefixes . length ( ) > 3 )
2025-01-09 21:29:44 +00:00
response . append ( QString ( " %0%1 " ) . arg ( prefixes [ 3 ] , QString : : number ( queue - > getCache ( funcFilterWidth , state . receiver ) . value . value < ushort > ( ) ) ) ) ;
2025-01-06 20:16:14 +00:00
if ( prefixes . length ( ) > 4 ) /* Split is only ever on the first rx */
response . append ( QString ( " %0%1 " ) . arg ( prefixes [ 4 ] , QString : : number ( queue - > getCache ( funcSplitStatus , 0 ) . value . value < duplexMode_t > ( ) ) ) ) ;
2024-12-29 14:59:52 +00:00
if ( prefixes . length ( ) > 5 )
2025-01-09 21:29:44 +00:00
response . append ( QString ( " %0%1 " ) . arg ( prefixes [ 5 ] , QString : : number ( queue - > getCache ( funcSatelliteMode , state . receiver ) . value . value < bool > ( ) ) ) ) ;
2024-03-05 21:01:13 +00:00
break ;
2023-05-24 18:50:01 +00:00
}
2024-12-29 14:59:52 +00:00
2024-03-05 21:01:13 +00:00
case typeMode :
{ // Mode
2023-05-24 18:50:01 +00:00
modeInfo m = item . value . value < modeInfo > ( ) ;
2025-01-09 21:29:44 +00:00
cacheItem f = queue - > getCache ( funcFilterWidth , state . receiver ) ;
2024-12-29 14:59:52 +00:00
if ( prefixes . length ( ) > 0 )
response . append ( QString ( " %0%1 " ) . arg ( prefixes [ 0 ] , getMode ( m ) ) ) ;
if ( prefixes . length ( ) > 1 )
2025-01-03 00:05:50 +00:00
response . append ( QString ( " %0%1 " ) . arg ( prefixes [ 1 ] , QString : : number ( f . value . value < ushort > ( ) ) ) ) ;
2024-03-05 21:01:13 +00:00
break ;
}
2024-07-12 09:08:24 +00:00
case typeString :
{
2024-07-12 09:29:50 +00:00
// Stop sending CW if a blank command is received.
2024-07-12 09:08:24 +00:00
queue - > add ( priorityImmediate , queueItem ( func , QString ( QChar ( 0xff ) ) , false , 0 ) ) ;
2024-08-13 07:56:13 +00:00
break ;
2024-07-12 09:08:24 +00:00
}
2024-03-05 21:01:13 +00:00
default :
2023-05-24 18:50:01 +00:00
qInfo ( logRigCtlD ( ) ) < < " Unsupported type (FIXME): " < < item . value . typeName ( ) ;
ret = - RIG_EINVAL ;
return ret ;
}
}
return ret ;
}
int rigCtlClient : : getSubCommand ( QStringList & response , bool extended , const commandStruct cmd , const subCommandStruct sub [ ] , QStringList params )
{
2025-01-03 19:46:27 +00:00
Q_UNUSED ( extended )
2023-05-24 18:50:01 +00:00
int ret = - RIG_EINVAL ;
2024-12-29 14:59:52 +00:00
if ( rigCaps = = Q_NULLPTR )
return ret ;
2025-01-09 21:29:44 +00:00
rigStateType state = queue - > getState ( ) ;
2024-12-29 14:59:52 +00:00
2023-05-24 18:50:01 +00:00
QString resp ;
// Get the required subCommand and process it
if ( params . isEmpty ( ) )
{
return ret ;
}
if ( params [ 0 ] [ 0 ] . toLatin1 ( ) = = ' ? ' )
{
for ( int i = 0 ; sub [ i ] . str [ 0 ] ! = ' \0 ' ; i + + )
{
2024-03-05 21:01:13 +00:00
if ( sub [ i ] . func ! = funcNone & & rigCaps - > commands . contains ( sub [ i ] . func ) ) {
2023-05-24 18:50:01 +00:00
resp . append ( sub [ i ] . str ) ;
resp . append ( " " ) ;
}
}
}
else
{
for ( int i = 0 ; sub [ i ] . str [ 0 ] ! = ' \0 ' ; i + + )
{
if ( ! strncmp ( params [ 0 ] . toLocal8Bit ( ) , sub [ i ] . str , MAXNAMESIZE ) )
{
ret = RIG_OK ;
if ( ( ( cmd . flags & ARG_IN ) = = ARG_IN ) & & params . size ( ) > 1 )
{
// We are expecting a second argument to the command
QVariant val ;
2024-03-05 21:01:13 +00:00
switch ( sub [ i ] . type )
{
2025-01-03 00:05:50 +00:00
case typeUShort :
val . setValue ( static_cast < ushort > ( params [ 1 ] . toInt ( ) ) ) ; // rigctl sends 0.0-1.0, we expect 0-255
break ;
case typeShort :
val . setValue ( static_cast < short > ( params [ 1 ] . toInt ( ) ) ) ; // rigctl sends 0.0-1.0, we expect 0-255
break ;
2024-12-29 14:59:52 +00:00
case typeUChar :
{
2023-12-18 10:47:16 +00:00
uchar v = static_cast < uchar > ( params [ 1 ] . toInt ( ) ) ;
2023-05-24 18:50:01 +00:00
if ( params [ 0 ] = = " FBKIN " )
v = ( v < < 1 ) & 0x02 ; // BREAKIN is not bool!
2024-04-05 12:01:26 +00:00
if ( params [ 0 ] = = " AGC " )
v = ( v < < 1 ) ;
2023-05-24 18:50:01 +00:00
val . setValue ( v ) ;
2024-03-05 21:01:13 +00:00
break ;
2023-05-24 18:50:01 +00:00
}
2024-03-05 21:01:13 +00:00
case typeFloat :
2023-05-24 18:50:01 +00:00
val . setValue ( static_cast < ushort > ( float ( params [ 1 ] . toFloat ( ) * 255.0 ) ) ) ; // rigctl sends 0.0-1.0, we expect 0-255
2024-12-29 14:59:52 +00:00
//qInfo(logRigCtlD()) << "Setting float value" << params[0] << "to" << val << "original" << params[1];
2024-03-05 21:01:13 +00:00
break ;
case typeFloatDiv :
2023-05-24 18:50:01 +00:00
val . setValue ( static_cast < uchar > ( float ( params [ 1 ] . toFloat ( ) / 10.0 ) ) ) ;
2024-03-05 21:01:13 +00:00
break ;
case typeFloatDiv5 :
2023-05-24 18:50:01 +00:00
val . setValue ( static_cast < ushort > ( float ( params [ 1 ] . toFloat ( ) * 5.1 ) ) ) ;
2024-03-05 21:01:13 +00:00
break ;
case typeBinary :
2023-05-24 18:50:01 +00:00
val . setValue ( static_cast < bool > ( params [ 1 ] . toInt ( ) ) ) ;
2024-03-05 21:01:13 +00:00
break ;
default :
2023-05-24 18:50:01 +00:00
qInfo ( logRigCtlD ( ) ) < < " Unable to parse value of type " < < sub [ i ] . type ;
return - RIG_EINVAL ;
}
2024-03-05 21:01:13 +00:00
if ( rigCaps - > commands . contains ( sub [ i ] . func ) )
2025-01-09 21:29:44 +00:00
queue - > add ( priorityImmediate , queueItem ( sub [ i ] . func , val , false , state . receiver ) ) ;
2023-05-24 18:50:01 +00:00
} else if ( params . size ( ) = = 1 ) {
// Not expecting a second argument as it is a get so dump the cache
2023-07-20 15:54:07 +00:00
cacheItem item ;
2024-03-05 21:01:13 +00:00
if ( rigCaps - > commands . contains ( sub [ i ] . func ) )
2025-01-09 21:29:44 +00:00
item = queue - > getCache ( sub [ i ] . func , state . receiver ) ;
2023-05-24 18:50:01 +00:00
int val = 0 ;
2025-02-17 11:57:07 +00:00
switch ( sub [ i ] . type )
{
case typeBinary :
resp . append ( QString ( " %1 " ) . arg ( item . value . toBool ( ) ) ) ;
break ;
case typeUChar :
2023-05-24 18:50:01 +00:00
{
2025-02-17 11:57:07 +00:00
int val = item . value . toInt ( ) ;
if ( params [ 0 ] = = " FBKIN " )
val = ( val > > 1 ) & 0x01 ;
if ( params [ 0 ] = = " AGC " )
val = ( val > > 1 ) ;
resp . append ( QString : : number ( val ) ) ;
break ;
}
2025-02-18 09:53:14 +00:00
case typeDouble :
2025-02-17 11:57:07 +00:00
resp . append ( QString : : number ( item . value . toDouble ( ) , ' f ' , 6 ) ) ;
break ;
case typeUShort :
case typeShort :
resp . append ( QString : : number ( item . value . toInt ( ) ) ) ;
break ;
case typeFloat :
resp . append ( QString : : number ( item . value . toFloat ( ) / 255.0 , ' f ' , 6 ) ) ;
break ;
case typeFloatDiv :
resp . append ( QString : : number ( item . value . toFloat ( ) * 10.0 , ' f ' , 6 ) ) ;
break ;
case typeFloatDiv5 :
resp . append ( QString : : number ( item . value . toFloat ( ) / 5.1 , ' f ' , 6 ) ) ;
break ;
default :
qInfo ( logRigCtlD ( ) ) < < " Unhandled: " < < item . value . toUInt ( ) < < " OUT " < < val ;
ret = - RIG_EINVAL ;
2023-05-24 18:50:01 +00:00
}
2025-02-17 11:57:07 +00:00
qDebug ( logRigCtlD ( ) ) < < " Sending " < < funcString [ sub [ i ] . func ] < < " data: " < < resp ;
2025-01-09 21:29:44 +00:00
response . append ( resp ) ;
}
else
{
2023-05-24 18:50:01 +00:00
qInfo ( logRigCtlD ( ) ) < < " Invalid number of params " < < params . size ( ) ;
ret = - RIG_EINVAL ;
}
break ;
}
}
}
return ret ;
}
int rigCtlClient : : dumpState ( QStringList & response , bool extended )
{
Q_UNUSED ( extended )
quint64 modes = getRadioModes ( ) ;
// rigctld protocol version
response . append ( " 1 " ) ;
// Radio model
2024-03-05 21:01:13 +00:00
response . append ( QString : : number ( rigCaps - > rigctlModel ) ) ;
2023-05-24 18:50:01 +00:00
// Print something (used to be ITU region)
response . append ( " 0 " ) ;
// Supported RX bands (startf,endf,modes,low_power,high_power,vfo,ant)
quint32 lowFreq = 0 ;
quint32 highFreq = 0 ;
2024-06-23 10:59:41 +00:00
for ( const bandType & band : std : : as_const ( rigCaps - > bands ) )
2023-05-24 18:50:01 +00:00
{
if ( lowFreq = = 0 | | band . lowFreq < lowFreq )
lowFreq = band . lowFreq ;
if ( band . highFreq > highFreq )
highFreq = band . highFreq ;
}
response . append ( QString ( " %1.000000 %2.000000 0x%3 %4 %5 0x%6 0x%7 " ) . arg ( lowFreq ) . arg ( highFreq )
2025-01-03 14:32:38 +00:00
. arg ( modes , 0 , 16 ) . arg ( - 1 ) . arg ( - 1 ) . arg ( vfoList , 0 , 16 ) . arg ( getAntennas ( ) , 0 , 16 ) ) ;
2023-05-24 18:50:01 +00:00
response . append ( " 0 0 0 0 0 0 0 " ) ;
2024-03-05 21:01:13 +00:00
if ( rigCaps - > hasTransmit ) {
2023-05-24 18:50:01 +00:00
// Supported TX bands (startf,endf,modes,low_power,high_power,vfo,ant)
2024-06-23 10:59:41 +00:00
for ( const bandType & band : std : : as_const ( rigCaps - > bands ) )
2023-05-24 18:50:01 +00:00
{
response . append ( QString ( " %1.000000 %2.000000 0x%3 %4 %5 0x%6 0x%7 " ) . arg ( band . lowFreq ) . arg ( band . highFreq )
. arg ( modes , 0 , 16 ) . arg ( 2000 ) . arg ( 100000 ) . arg ( 0x16000000 , 0 , 16 ) . arg ( getAntennas ( ) , 0 , 16 ) ) ;
}
}
response . append ( " 0 0 0 0 0 0 0 " ) ;
2024-03-05 21:01:13 +00:00
for ( auto & step : rigCaps - > steps )
2023-05-24 18:50:01 +00:00
{
if ( step . num > 0 )
response . append ( QString ( " 0x%1 %2 " ) . arg ( modes , 0 , 16 ) . arg ( step . hz ) ) ;
}
response . append ( " 0 0 " ) ;
modes = getRadioModes ( " SB " ) ;
if ( modes ) {
response . append ( QString ( " 0x%1 3000 " ) . arg ( modes , 0 , 16 ) ) ;
response . append ( QString ( " 0x%1 2400 " ) . arg ( modes , 0 , 16 ) ) ;
response . append ( QString ( " 0x%1 1800 " ) . arg ( modes , 0 , 16 ) ) ;
}
modes = getRadioModes ( " AM " ) ;
if ( modes ) {
response . append ( QString ( " 0x%1 9000 " ) . arg ( modes , 0 , 16 ) ) ;
response . append ( QString ( " 0x%1 6000 " ) . arg ( modes , 0 , 16 ) ) ;
response . append ( QString ( " 0x%1 3000 " ) . arg ( modes , 0 , 16 ) ) ;
}
modes = getRadioModes ( " CW " ) ;
if ( modes ) {
response . append ( QString ( " 0x%1 1200 " ) . arg ( modes , 0 , 16 ) ) ;
response . append ( QString ( " 0x%1 500 " ) . arg ( modes , 0 , 16 ) ) ;
response . append ( QString ( " 0x%1 200 " ) . arg ( modes , 0 , 16 ) ) ;
}
modes = getRadioModes ( " FM " ) ;
if ( modes ) {
response . append ( QString ( " 0x%1 15000 " ) . arg ( modes , 0 , 16 ) ) ;
response . append ( QString ( " 0x%1 10000 " ) . arg ( modes , 0 , 16 ) ) ;
response . append ( QString ( " 0x%1 7000 " ) . arg ( modes , 0 , 16 ) ) ;
}
modes = getRadioModes ( " RTTY " ) ;
if ( modes ) {
response . append ( QString ( " 0x%1 2400 " ) . arg ( modes , 0 , 16 ) ) ;
response . append ( QString ( " 0x%1 500 " ) . arg ( modes , 0 , 16 ) ) ;
response . append ( QString ( " 0x%1 250 " ) . arg ( modes , 0 , 16 ) ) ;
}
modes = getRadioModes ( " PSK " ) ;
if ( modes ) {
response . append ( QString ( " 0x%1 1200 " ) . arg ( modes , 0 , 16 ) ) ;
response . append ( QString ( " 0x%1 500 " ) . arg ( modes , 0 , 16 ) ) ;
response . append ( QString ( " 0x%1 250 " ) . arg ( modes , 0 , 16 ) ) ;
}
response . append ( " 0 0 " ) ;
response . append ( " 9900 " ) ;
response . append ( " 9900 " ) ;
response . append ( " 10000 " ) ;
response . append ( " 0 " ) ;
QString preamps = " " ;
2024-03-05 21:01:13 +00:00
if ( rigCaps - > commands . contains ( funcPreamp ) ) {
for ( auto & pre : rigCaps - > preamps )
2023-05-24 18:50:01 +00:00
{
if ( pre . num = = 0 )
continue ;
2024-04-05 12:01:26 +00:00
preamps . append ( QString ( " %1 " ) . arg ( pre . num * 10 ) ) ;
2023-05-24 18:50:01 +00:00
}
if ( preamps . endsWith ( " " ) )
preamps . chop ( 1 ) ;
}
else {
preamps = " 0 " ;
}
response . append ( preamps ) ;
QString attens = " " ;
2024-03-05 21:01:13 +00:00
if ( rigCaps - > commands . contains ( funcAttenuator ) ) {
for ( auto att : rigCaps - > attenuators )
2023-05-24 18:50:01 +00:00
{
2025-01-17 00:43:57 +00:00
if ( att . num = = 0 )
2023-05-24 18:50:01 +00:00
continue ;
2025-01-17 00:43:57 +00:00
attens . append ( QString ( " %1 " ) . arg ( att . num ) ) ;
2023-05-24 18:50:01 +00:00
}
if ( attens . endsWith ( " " ) )
attens . chop ( 1 ) ;
}
else {
attens = " 0 " ;
}
response . append ( attens ) ;
qulonglong hasFuncs = 0 ;
qulonglong hasLevels = 0 ;
qulonglong hasParams = 0 ;
for ( int i = 0 ; functions_str [ i ] . str [ 0 ] ! = ' \0 ' ; i + + )
{
2024-03-05 21:01:13 +00:00
if ( functions_str [ i ] . func ! = funcNone & & rigCaps - > commands . contains ( functions_str [ i ] . func ) )
2023-05-24 18:50:01 +00:00
{
hasFuncs | = 1ULL < < i ;
}
}
response . append ( QString ( " 0x%0 " ) . arg ( hasFuncs , 16 , 16 , QChar ( ' 0 ' ) ) ) ;
response . append ( QString ( " 0x%0 " ) . arg ( hasFuncs , 16 , 16 , QChar ( ' 0 ' ) ) ) ;
for ( int i = 0 ; levels_str [ i ] . str [ 0 ] ! = ' \0 ' ; i + + )
{
2024-03-05 21:01:13 +00:00
if ( levels_str [ i ] . func ! = funcNone & & rigCaps - > commands . contains ( levels_str [ i ] . func ) )
2023-05-24 18:50:01 +00:00
{
hasLevels | = 1ULL < < i ;
}
}
response . append ( QString ( " 0x%0 " ) . arg ( hasLevels , 16 , 16 , QChar ( ' 0 ' ) ) ) ;
response . append ( QString ( " 0x%0 " ) . arg ( hasLevels , 16 , 16 , QChar ( ' 0 ' ) ) ) ;
for ( int i = 0 ; params_str [ i ] . str [ 0 ] ! = ' \0 ' ; i + + )
{
2024-03-05 21:01:13 +00:00
if ( params_str [ i ] . func ! = funcNone & & rigCaps - > commands . contains ( params_str [ i ] . func ) )
2023-05-24 18:50:01 +00:00
{
hasParams | = 1ULL < < i ;
}
}
response . append ( QString ( " 0x%0 " ) . arg ( hasParams , 16 , 16 , QChar ( ' 0 ' ) ) ) ;
response . append ( QString ( " 0x%0 " ) . arg ( hasParams , 16 , 16 , QChar ( ' 0 ' ) ) ) ;
if ( chkVfoEecuted ) {
response . append ( QString ( " vfo_ops=0x%1 " ) . arg ( 255 , 0 , 16 ) ) ;
2024-03-05 21:01:13 +00:00
response . append ( QString ( " ptt_type=0x%1 " ) . arg ( rigCaps - > hasTransmit , 0 , 16 ) ) ;
2023-05-24 18:50:01 +00:00
response . append ( QString ( " has_set_vfo=0x%1 " ) . arg ( 1 , 0 , 16 ) ) ;
response . append ( QString ( " has_get_vfo=0x%1 " ) . arg ( 1 , 0 , 16 ) ) ;
response . append ( QString ( " has_set_freq=0x%1 " ) . arg ( 1 , 0 , 16 ) ) ;
response . append ( QString ( " has_get_freq=0x%1 " ) . arg ( 1 , 0 , 16 ) ) ;
response . append ( QString ( " has_set_conf=0x%1 " ) . arg ( 1 , 0 , 16 ) ) ;
response . append ( QString ( " has_get_conf=0x%1 " ) . arg ( 1 , 0 , 16 ) ) ;
response . append ( QString ( " has_power2mW=0x%1 " ) . arg ( 1 , 0 , 16 ) ) ;
response . append ( QString ( " has_mW2power=0x%1 " ) . arg ( 1 , 0 , 16 ) ) ;
response . append ( QString ( " timeout=0x%1 " ) . arg ( 1000 , 0 , 16 ) ) ;
response . append ( " done " ) ;
}
return RIG_OK ;
}
int rigCtlClient : : dumpCaps ( QStringList & response , bool extended )
{
Q_UNUSED ( extended )
2024-03-05 21:01:13 +00:00
response . append ( QString ( " Caps dump for model: %1 " ) . arg ( rigCaps - > modelID ) ) ;
response . append ( QString ( " Model Name: \t %1 " ) . arg ( rigCaps - > modelName ) ) ;
2023-05-24 18:50:01 +00:00
response . append ( QString ( " Mfg Name: \t Icom " ) ) ;
response . append ( QString ( " Backend version: \t 0.1 " ) ) ;
response . append ( QString ( " Backend copyright: \t 2021 " ) ) ;
2024-03-05 21:01:13 +00:00
if ( rigCaps - > hasTransmit ) {
2023-05-24 18:50:01 +00:00
response . append ( QString ( " Rig type: \t Transceiver " ) ) ;
}
else
{
response . append ( QString ( " Rig type: \t Receiver " ) ) ;
}
2024-03-05 21:01:13 +00:00
if ( rigCaps - > commands . contains ( funcTransceiverStatus ) ) {
2023-05-24 18:50:01 +00:00
response . append ( QString ( " PTT type: \t Rig capable " ) ) ;
}
response . append ( QString ( " DCD type: \t Rig capable " ) ) ;
response . append ( QString ( " Port type: \t Network link " ) ) ;
return RIG_OK ;
}
2024-12-29 14:59:52 +00:00
2025-01-03 14:32:38 +00:00
QStringList rigCtlClient : : buildPrefixes ( commandStruct cmd , bool extended )
{
QStringList prefixes ;
if ( extended ) {
if ( cmd . arg1 ! = NULL )
prefixes . append ( QString ( " %0: " ) . arg ( cmd . arg1 ) ) ;
if ( cmd . arg2 ! = NULL )
prefixes . append ( QString ( " %0: " ) . arg ( cmd . arg2 ) ) ;
if ( cmd . arg3 ! = NULL )
prefixes . append ( QString ( " %0: " ) . arg ( cmd . arg3 ) ) ;
if ( cmd . arg4 ! = NULL )
prefixes . append ( QString ( " %0: " ) . arg ( cmd . arg4 ) ) ;
if ( cmd . arg5 ! = NULL )
prefixes . append ( QString ( " %0: " ) . arg ( cmd . arg5 ) ) ;
if ( cmd . arg6 ! = NULL )
prefixes . append ( QString ( " %0: " ) . arg ( cmd . arg6 ) ) ;
} else {
if ( cmd . arg1 ! = NULL )
prefixes . append ( " " ) ;
if ( cmd . arg2 ! = NULL )
prefixes . append ( " " ) ;
if ( cmd . arg3 ! = NULL )
prefixes . append ( " " ) ;
if ( cmd . arg4 ! = NULL )
prefixes . append ( " " ) ;
if ( cmd . arg5 ! = NULL )
prefixes . append ( " " ) ;
if ( cmd . arg6 ! = NULL )
prefixes . append ( " " ) ;
}
return prefixes ;
}
int rigCtlClient : : power2mW ( QStringList & response , bool extended , const commandStruct cmd , QStringList params )
{
int ret = RIG_OK ;
QStringList prefixes = buildPrefixes ( cmd , extended ) ;
2025-01-09 21:29:44 +00:00
rigStateType state = queue - > getState ( ) ;
2025-01-03 14:32:38 +00:00
if ( params . size ( ) > = 2 )
{
bool ok = false ;
float power = params [ 0 ] . toFloat ( & ok ) ;
quint64 freq = params [ 1 ] . toULongLong ( & ok ) ;
if ( ok )
{
if ( freq = = 0 )
{
// Frequency was zero, so get cached freq
2025-01-09 21:29:44 +00:00
freq = queue - > getCache ( queue - > getVfoCommand ( state . vfo , state . receiver , false ) . freqFunc , state . receiver ) . value . value < freqt > ( ) . Hz ;
2025-01-03 14:32:38 +00:00
}
for ( auto & b : rigCaps - > bands )
{
// Highest frequency band is always first!
if ( freq > = b . lowFreq & & freq < = b . highFreq )
{
// This frequency is contained within this band!
int p = int ( ( b . power * power ) * 1000 ) ;
if ( prefixes . length ( ) > 3 )
response . append ( QString ( " %0%1 " ) . arg ( prefixes [ 3 ] , QString : : number ( p ) ) ) ;
break ;
}
}
}
else
{
ret = RIG_EINVAL ;
}
} else {
ret = RIG_EINVAL ;
}
return ret ;
}
int rigCtlClient : : mW2power ( QStringList & response , bool extended , const commandStruct cmd , QStringList params )
{
int ret = RIG_OK ;
QStringList prefixes = buildPrefixes ( cmd , extended ) ;
2025-01-09 21:29:44 +00:00
rigStateType state = queue - > getState ( ) ;
2025-01-03 14:32:38 +00:00
if ( params . size ( ) > 2 )
{
bool ok = false ;
int power = params [ 0 ] . toInt ( & ok ) ;
quint64 freq = params [ 1 ] . toULongLong ( & ok ) ;
if ( ok )
{
if ( freq = = 0 )
{
// Frequency was zero, so get cached freq
2025-01-09 21:29:44 +00:00
freq = queue - > getCache ( queue - > getVfoCommand ( state . vfo , state . receiver , false ) . freqFunc , state . receiver ) . value . value < freqt > ( ) . Hz ;
2025-01-03 14:32:38 +00:00
}
for ( auto & b : rigCaps - > bands )
{
// Highest frequency band is always first!
if ( freq > = b . lowFreq & & freq < = b . highFreq )
{
// This frequency is contained within this band!
float p = float ( power / ( b . power * 1000.0 ) ) ;
if ( prefixes . length ( ) > 3 )
response . append ( QString ( " %0%1 " ) . arg ( prefixes [ 3 ] , QString : : number ( p , ' f ' , 5 ) ) ) ;
break ;
}
}
}
else
{
ret = RIG_EINVAL ;
}
} else {
ret = RIG_EINVAL ;
}
return ret ;
}