From c961fa368d28acc6935e3e3808a8259806a40c89 Mon Sep 17 00:00:00 2001 From: f4exb Date: Fri, 25 May 2018 02:02:21 +0200 Subject: [PATCH] Web API: fixes in BFM demod and HackRF input --- plugins/channelrx/demodbfm/bfmdemod.cpp | 6 +- plugins/channelrx/demodbfm/bfmdemod.h | 9 ++ plugins/channelrx/demodbfm/bfmdemodgui.cpp | 2 +- plugins/channelrx/demodbfm/bfmdemodgui.h | 9 -- .../samplesource/hackrfinput/hackrfinput.cpp | 6 + swagger/sdrangel/examples/rx_test.py | 149 ++++++++++++------ swagger/sdrangel/examples/scanner.py | 13 +- 7 files changed, 130 insertions(+), 64 deletions(-) diff --git a/plugins/channelrx/demodbfm/bfmdemod.cpp b/plugins/channelrx/demodbfm/bfmdemod.cpp index 526d885d5..56fe6f37f 100644 --- a/plugins/channelrx/demodbfm/bfmdemod.cpp +++ b/plugins/channelrx/demodbfm/bfmdemod.cpp @@ -447,6 +447,7 @@ void BFMDemod::applySettings(const BFMDemodSettings& settings, bool force) qDebug() << "BFMDemod::applySettings: MsgConfigureBFMDemod:" << " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset << " m_rfBandwidth: " << settings.m_rfBandwidth + << " m_afBandwidth: " << settings.m_afBandwidth << " m_volume: " << settings.m_volume << " m_squelch: " << settings.m_squelch << " m_audioStereo: " << settings.m_audioStereo @@ -480,8 +481,7 @@ void BFMDemod::applySettings(const BFMDemodSettings& settings, bool force) m_settingsMutex.unlock(); } - if((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || - (settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) + if((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force) { m_settingsMutex.lock(); Real lowCut = -(settings.m_rfBandwidth / 2.0) / m_inputSampleRate; @@ -605,7 +605,7 @@ int BFMDemod::webapiSettingsPutPatch( if (frequencyOffsetChanged) { MsgConfigureChannelizer* channelConfigMsg = MsgConfigureChannelizer::create( - m_audioSampleRate, settings.m_inputFrequencyOffset); + requiredBW(settings.m_rfBandwidth), settings.m_inputFrequencyOffset); // FIXME m_inputMessageQueue.push(channelConfigMsg); } diff --git a/plugins/channelrx/demodbfm/bfmdemod.h b/plugins/channelrx/demodbfm/bfmdemod.h index 633d2a615..99c76d07f 100644 --- a/plugins/channelrx/demodbfm/bfmdemod.h +++ b/plugins/channelrx/demodbfm/bfmdemod.h @@ -171,6 +171,15 @@ public: SWGSDRangel::SWGChannelReport& response, QString& errorMessage); + static int requiredBW(int rfBW) + { + if (rfBW <= 48000) { + return 48000; + } else { + return (3*rfBW)/2; + } + } + static const QString m_channelIdURI; static const QString m_channelId; diff --git a/plugins/channelrx/demodbfm/bfmdemodgui.cpp b/plugins/channelrx/demodbfm/bfmdemodgui.cpp index 97cf243ea..5074cad04 100644 --- a/plugins/channelrx/demodbfm/bfmdemodgui.cpp +++ b/plugins/channelrx/demodbfm/bfmdemodgui.cpp @@ -412,7 +412,7 @@ void BFMDemodGUI::applySettings(bool force) if (m_doApplySettings) { BFMDemod::MsgConfigureChannelizer *msgChan = BFMDemod::MsgConfigureChannelizer::create( - requiredBW(m_settings.m_rfBandwidth), + BFMDemod::requiredBW(m_settings.m_rfBandwidth), m_settings.m_inputFrequencyOffset); m_bfmDemod->getInputMessageQueue()->push(msgChan); diff --git a/plugins/channelrx/demodbfm/bfmdemodgui.h b/plugins/channelrx/demodbfm/bfmdemodgui.h index 5850f4ef1..06f0f4842 100644 --- a/plugins/channelrx/demodbfm/bfmdemodgui.h +++ b/plugins/channelrx/demodbfm/bfmdemodgui.h @@ -88,15 +88,6 @@ private: void changeFrequency(qint64 f); - static int requiredBW(int rfBW) - { - if (rfBW <= 48000) { - return 48000; - } else { - return (3*rfBW)/2; - } - } - private slots: void on_deltaFrequency_changed(qint64 value); void on_rfBW_valueChanged(int value); diff --git a/plugins/samplesource/hackrfinput/hackrfinput.cpp b/plugins/samplesource/hackrfinput/hackrfinput.cpp index b287f9b16..744119e0c 100644 --- a/plugins/samplesource/hackrfinput/hackrfinput.cpp +++ b/plugins/samplesource/hackrfinput/hackrfinput.cpp @@ -562,6 +562,12 @@ int HackRFInput::webapiSettingsPutPatch( if (deviceSettingsKeys.contains("log2Decim")) { settings.m_log2Decim = response.getHackRfInputSettings()->getLog2Decim(); } + if (deviceSettingsKeys.contains("fcPos")) + { + int fcPos = response.getHackRfInputSettings()->getFcPos(); + fcPos = fcPos < 0 ? 0 : fcPos > 2 ? 2 : fcPos; + settings.m_fcPos = (HackRFInputSettings::fcPos_t) fcPos; + } if (deviceSettingsKeys.contains("devSampleRate")) { settings.m_devSampleRate = response.getHackRfInputSettings()->getDevSampleRate(); } diff --git a/swagger/sdrangel/examples/rx_test.py b/swagger/sdrangel/examples/rx_test.py index 02528d557..2fe2a9bf5 100644 --- a/swagger/sdrangel/examples/rx_test.py +++ b/swagger/sdrangel/examples/rx_test.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -import requests, json, traceback, sys +import requests, json, traceback, sys, time from optparse import OptionParser base_url = "http://127.0.0.1:8091/sdrangel" @@ -20,12 +20,24 @@ def getInputOptions(): parser.add_option("-a", "--address", dest="address", help="address and port", metavar="ADDRESS", type="string") parser.add_option("-d", "--device-index", dest="device_index", help="device set index", metavar="INDEX", type="int") parser.add_option("-D", "--device-hwid", dest="device_hwid", help="device hardware id", metavar="HWID", type="string") + parser.add_option("-C", "--channel-id", dest="channel_id", help="channel id", metavar="ID", type="string", default="NFMDemod") parser.add_option("-F", "--device-freq", dest="device_freq", help="device center frequency (kHz)", metavar="FREQ", type="int") parser.add_option("-f", "--channel-freq", dest="channel_freq", help="channel center frequency (Hz)", metavar="FREQ", type="int") parser.add_option("-U", "--copy-to-udp", dest="udp_copy", help="UDP audio copy to
[:]", metavar="IP:PORT", type="string") parser.add_option("-A", "--antenna-path", dest="antenna_path", help="antenna path index", metavar="INDEX", type="int") parser.add_option("-s", "--sample-rate", dest="sample_rate", help="device to host sample rate (kS/s)", metavar="RATE", type="int") + parser.add_option("-l", "--log2-decim", dest="log2_decim", help="log2 of the desired software decimation factor", metavar="LOG2", type="int", default=4) + parser.add_option("-b", "--af-bw", dest="af_bw", help="audio babdwidth (kHz)", metavar="FREQUENCY_KHZ", type="int" ,default=3) + parser.add_option("-r", "--rf-bw", dest="rf_bw", help="RF babdwidth (Hz). Sets to nearest available", metavar="FREQUENCY", type="int", default=10000) + parser.add_option("--vol", dest="volume", help="audio volume", metavar="VOLUME", type="float", default=1.0) parser.add_option("-c", "--create", dest="create", help="create a new device set", metavar="CREATE", action="store_true", default=False) + parser.add_option("--ppm", dest="lo_ppm", help="LO correction in PPM", metavar="PPM", type="float", default=0.0) + parser.add_option("--fc-pos", dest="fc_pos", help="Center frequency position 0:inf 1:sup 2:cen", metavar="ENUM", default=2) + parser.add_option("--sq", dest="squelch_db", help="Squelsch threshold in dB", metavar="DECIBEL", type="float", default=-50.0) + parser.add_option("--sq-gate", dest="squelch_gate", help="Squelsch gate in ms", metavar="MILLISECONDS", type="int", default=50) + parser.add_option("--stereo", dest="stereo", help="Broadcast FM stereo", metavar="BOOL", action="store_true", default=False) + parser.add_option("--lsb-stereo", dest="lsb_stereo", help="Broadcast FM LSB stereo", metavar="BOOL", action="store_true", default=False) + parser.add_option("--rds", dest="rds", help="Broadcast FM RDS", metavar="BOOL", action="store_true", default=False) (options, args) = parser.parse_args() @@ -76,20 +88,7 @@ def callAPI(url, method, params, json, text): return None # ====================================================================== -def main(): - try: - options = getInputOptions() - - global base_url - base_url = "http://%s/sdrangel" % options.address - - if options.create: - r = callAPI("/deviceset", "POST", {"tx": 0}, None, "Add Rx device set") - if r is None: - exit(-1) - - deviceset_url = "/deviceset/%d" % options.device_index - +def setupDevice(deviceset_url, options): r = callAPI(deviceset_url + "/device", "PUT", None, {"hwType": "%s" % options.device_hwid, "tx": 0}, "setup device on Rx device set") if r is None: exit(-1) @@ -98,11 +97,20 @@ def main(): if settings is None: exit(-1) - if options.device_hwid == "LimeSDR": + if options.device_hwid == "AirspyHF": + if options.device_freq > 30000: + settings["airspyHFSettings"]["bandIndex"] = 1 + else: + settings["airspyHFSettings"]["bandIndex"] = 0 + settings["airspyHFSettings"]["centerFrequency"] = options.device_freq*1000 + settings["airspyHFSettings"]["devSampleRateIndex"] = 0 + settings['airspyHFSettings']['log2Decim'] = options.log2_decim + settings['airspyHFSettings']['LOppmTenths'] = int(options.lo_ppm * 10) # in tenths of PPM + elif options.device_hwid == "LimeSDR": settings["limeSdrInputSettings"]["antennaPath"] = options.antenna_path settings["limeSdrInputSettings"]["devSampleRate"] = options.sample_rate*1000 settings["limeSdrInputSettings"]["log2HardDecim"] = 4 - settings["limeSdrInputSettings"]["log2SoftDecim"] = 3 + settings["limeSdrInputSettings"]["log2SoftDecim"] = options.log2_decim settings["limeSdrInputSettings"]["centerFrequency"] = options.device_freq*1000 + 500000 settings["limeSdrInputSettings"]["ncoEnable"] = 1 settings["limeSdrInputSettings"]["ncoFrequency"] = -500000 @@ -114,51 +122,98 @@ def main(): settings['rtlSdrSettings']['devSampleRate'] = options.sample_rate*1000 settings['rtlSdrSettings']['centerFrequency'] = options.device_freq*1000 settings['rtlSdrSettings']['gain'] = 496 - settings['rtlSdrSettings']['log2Decim'] = 4 - settings['rtlSdrSettings']['dcBlock'] = 1 + settings['rtlSdrSettings']['log2Decim'] = options.log2_decim + settings['rtlSdrSettings']['fcPos'] = options.fc_pos + settings['rtlSdrSettings']['dcBlock'] = options.fc_pos == 2 + settings['rtlSdrSettings']['iqImbalance'] = options.fc_pos == 2 settings['rtlSdrSettings']['agc'] = 1 + settings['rtlSdrSettings']['loPpmCorrection'] = int(options.lo_ppm) elif options.device_hwid == "HackRF": - settings['hackRFInputSettings']['LOppmTenths'] = -51 + settings['hackRFInputSettings']['LOppmTenths'] = int(options.lo_ppm * 10) # in tenths of PPM settings['hackRFInputSettings']['centerFrequency'] = options.device_freq*1000 - settings['hackRFInputSettings']['dcBlock'] = 1 + settings['hackRFInputSettings']['fcPos'] = options.fc_pos + settings['hackRFInputSettings']['dcBlock'] = options.fc_pos == 2 + settings['hackRFInputSettings']['iqImbalance'] = options.fc_pos == 2 settings['hackRFInputSettings']['devSampleRate'] = options.sample_rate*1000 settings['hackRFInputSettings']['lnaExt'] = 1 settings['hackRFInputSettings']['lnaGain'] = 32 - settings['hackRFInputSettings']['log2Decim'] = 4 + settings['hackRFInputSettings']['log2Decim'] = options.log2_decim settings['hackRFInputSettings']['vgaGain'] = 24 r = callAPI(deviceset_url + "/device/settings", "PATCH", None, settings, "Patch device settings") if r is None: exit(-1) - - r = callAPI(deviceset_url + "/channel", "POST", None, {"channelType": "NFMDemod", "tx": 0}, "Create NFM demod") - if r is None: - exit(-1) - - settings = callAPI(deviceset_url + "/channel/0/settings", "GET", None, None, "Get NFM demod settings") - if settings is None: - exit(-1) - - settings["NFMDemodSettings"]["title"] = "Test NFM" + +# ====================================================================== +def setupChannel(deviceset_url, options): + i = 0 + + settings = callAPI(deviceset_url + "/channel", "POST", None, {"channelType": options.channel_id, "tx": 0}, "Create demod") + if settings is None: + exit(-1) + + settings = callAPI(deviceset_url + "/channel/%d/settings" % i, "GET", None, None, "Get demod settings") + if settings is None: + exit(-1) + + if options.channel_id == "NFMDemod": settings["NFMDemodSettings"]["inputFrequencyOffset"] = options.channel_freq - settings["NFMDemodSettings"]["rfBandwidth"] = 12500 - settings["NFMDemodSettings"]["fmDeviation"] = 3000 - settings["NFMDemodSettings"]["afBandwidth"] = 4000 - settings["NFMDemodSettings"]["squelch"] = -700 - settings["NFMDemodSettings"]["volume"] = 2.0 + settings["NFMDemodSettings"]["afBandwidth"] = options.af_bw * 1000 + settings["NFMDemodSettings"]["rfBandwidth"] = options.rf_bw + settings["NFMDemodSettings"]["volume"] = options.volume + settings["NFMDemodSettings"]["squelch"] = options.squelch_db * 10 # centi-Bels + settings["NFMDemodSettings"]["squelchGate"] = options.squelch_gate / 10 # 10's of ms + settings["NFMDemodSettings"]["title"] = "Channel %d" % i + elif options.channel_id == "BFMDemod": + settings["BFMDemodSettings"]["inputFrequencyOffset"] = options.channel_freq + settings["BFMDemodSettings"]["afBandwidth"] = options.af_bw * 1000 + settings["BFMDemodSettings"]["rfBandwidth"] = options.rf_bw + settings["BFMDemodSettings"]["volume"] = options.volume + settings["BFMDemodSettings"]["squelch"] = options.squelch_db # dB + settings["BFMDemodSettings"]["audioStereo"] = 1 if options.stereo else 0 + settings["BFMDemodSettings"]["lsbStereo"] = 1 if options.lsb_stereo else 0 + settings["BFMDemodSettings"]["rdsActive"] = 1 if options.rds else 0 + settings["BFMDemodSettings"]["title"] = "Channel %d" % i + elif options.channel_id == "AMDemod": + settings["AMDemodSettings"]["inputFrequencyOffset"] = options.channel_freq + settings["AMDemodSettings"]["rfBandwidth"] = options.rf_bw + settings["AMDemodSettings"]["volume"] = options.volume + settings["AMDemodSettings"]["squelch"] = options.squelch_db + settings["AMDemodSettings"]["title"] = "Channel %d" % i + settings["AMDemodSettings"]["bandpassEnable"] = 1 # bandpass filter + elif options.channel_id == "DSDDemod": + settings["DSDDemodSettings"]["inputFrequencyOffset"] = options.channel_freq + settings["DSDDemodSettings"]["rfBandwidth"] = options.rf_bw + settings["DSDDemodSettings"]["volume"] = options.volume + settings["DSDDemodSettings"]["squelch"] = options.squelch_db + settings["DSDDemodSettings"]["baudRate"] = options.baud_rate + settings["DSDDemodSettings"]["fmDeviation"] = options.fm_dev + settings["DSDDemodSettings"]["enableCosineFiltering"] = 1 + settings["DSDDemodSettings"]["pllLock"] = 1 + settings["DSDDemodSettings"]["title"] = "Channel %d" % i + + r = callAPI(deviceset_url + "/channel/%d/settings" % i, "PATCH", None, settings, "Change demod") + if r is None: + exit(-1) + + +# ====================================================================== +def main(): + try: + options = getInputOptions() - if options.udp_copy is not None: - address_port = options.udp_copy.split(':') - if len(address_port) > 1: - settings["NFMDemodSettings"]["udpPort"] = address_port[1] - if len(address_port) > 0: - settings["NFMDemodSettings"]["udpAddress"] = address_port[0] - settings["NFMDemodSettings"]["copyAudioToUDP"] = 1 + global base_url + base_url = "http://%s/sdrangel" % options.address + deviceset_url = "/deviceset/%d" % options.device_index - r = callAPI(deviceset_url + "/channel/0/settings", "PATCH", None, settings, "Change NFM demod") - if r is None: - exit(-1) + if options.create: + r = callAPI("/deviceset", "POST", {"tx": 0}, None, "Add Rx device set") + if r is None: + exit(-1) + setupDevice(deviceset_url, options) + setupChannel(deviceset_url, options) + r = callAPI(deviceset_url + "/device/run", "POST", None, None, "Start running device") if r is None: exit(-1) diff --git a/swagger/sdrangel/examples/scanner.py b/swagger/sdrangel/examples/scanner.py index fb0abcb69..961d8604a 100755 --- a/swagger/sdrangel/examples/scanner.py +++ b/swagger/sdrangel/examples/scanner.py @@ -62,6 +62,7 @@ def getInputOptions(): parser.add_option("-c", "--create", dest="create", help="create a new device set", metavar="BOOLEAN", action="store_true", default=False) parser.add_option("-m", "--mock", dest="mock", help="just print calculated values and exit", metavar="BOOLEAN", action="store_true", default=False) parser.add_option("--ppm", dest="lo_ppm", help="LO correction in PPM", metavar="PPM", type="float", default=0.0) + parser.add_option("--fc-pos", dest="fc_pos", help="Center frequency position 0:inf 1:sup 2:cen", metavar="ENUM", default=2) parser.add_option("-t", "--settling-time", dest="settling_time", help="Scan step settling time in seconds", metavar="SECONDS", type="float", default=1.0) parser.add_option("--sq", dest="squelch_db", help="Squelsch threshold in dB", metavar="DECIBEL", type="float", default=-50.0) parser.add_option("--sq-gate", dest="squelch_gate", help="Squelsch gate in ms", metavar="MILLISECONDS", type="int", default=50) @@ -126,16 +127,18 @@ def setupDevice(scan_control, options): settings['rtlSdrSettings']['centerFrequency'] = scan_control.device_start_freq settings['rtlSdrSettings']['gain'] = 496 settings['rtlSdrSettings']['log2Decim'] = options.log2_decim - settings['rtlSdrSettings']['dcBlock'] = 1 - settings['rtlSdrSettings']['iqImbalance'] = 1 + settings['rtlSdrSettings']['fcPos'] = options.fc_pos + settings['rtlSdrSettings']['dcBlock'] = options.fc_pos == 2 + settings['rtlSdrSettings']['iqImbalance'] = options.fc_pos == 2 settings['rtlSdrSettings']['agc'] = 1 settings['rtlSdrSettings']['loPpmCorrection'] = int(options.lo_ppm) settings['rtlSdrSettings']['rfBandwidth'] = scan_control.device_step_freq + 100000 elif options.device_hwid == "HackRF": settings['hackRFInputSettings']['LOppmTenths'] = int(options.lo_ppm * 10) # in tenths of PPM settings['hackRFInputSettings']['centerFrequency'] = scan_control.device_start_freq - settings['hackRFInputSettings']['dcBlock'] = 1 - settings['hackRFInputSettings']['iqImbalance'] = 1 + settings['hackRFInputSettings']['fcPos'] = options.fc_pos + settings['hackRFInputSettings']['dcBlock'] = options.fc_pos == 2 + settings['hackRFInputSettings']['iqImbalance'] = options.fc_pos == 2 settings['hackRFInputSettings']['devSampleRate'] = scan_control.device_sample_rate settings['hackRFInputSettings']['lnaExt'] = 1 settings['hackRFInputSettings']['lnaGain'] = 32 @@ -199,6 +202,8 @@ def setupChannels(scan_control, options): settings["DSDDemodSettings"]["squelch"] = options.squelch_db settings["DSDDemodSettings"]["baudRate"] = options.baud_rate settings["DSDDemodSettings"]["fmDeviation"] = options.fm_dev + settings["DSDDemodSettings"]["enableCosineFiltering"] = 1 + settings["DSDDemodSettings"]["pllLock"] = 1 settings["DSDDemodSettings"]["title"] = "Channel %d" % i r = callAPI(deviceset_url + "/channel/%d/settings" % i, "PATCH", None, settings, "Change demod")