Web API: AM demod and AirspyHF: many fixes

This commit is contained in:
f4exb 2018-03-22 06:34:51 +01:00
parent 0cf53e1dc9
commit 1204734b58
6 changed files with 129 additions and 26 deletions

View File

@ -390,6 +390,7 @@ int AMDemod::webapiSettingsPutPatch(
MsgConfigureAMDemod *msg = MsgConfigureAMDemod::create(settings, force); MsgConfigureAMDemod *msg = MsgConfigureAMDemod::create(settings, force);
m_inputMessageQueue.push(msg); m_inputMessageQueue.push(msg);
qDebug("AMDemod::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue);
if (m_guiMessageQueue) // forward to GUI if any if (m_guiMessageQueue) // forward to GUI if any
{ {
MsgConfigureAMDemod *msgToGUI = MsgConfigureAMDemod::create(settings, force); MsgConfigureAMDemod *msgToGUI = MsgConfigureAMDemod::create(settings, force);

View File

@ -91,9 +91,33 @@ bool AMDemodGUI::deserialize(const QByteArray& data)
bool AMDemodGUI::handleMessage(const Message& message __attribute__((unused))) bool AMDemodGUI::handleMessage(const Message& message __attribute__((unused)))
{ {
if (AMDemod::MsgConfigureAMDemod::match(message))
{
qDebug("AMDemodGUI::handleMessage: AMDemod::MsgConfigureAMDemod");
const AMDemod::MsgConfigureAMDemod& cfg = (AMDemod::MsgConfigureAMDemod&) message;
m_settings = cfg.getSettings();
blockApplySettings(true);
displaySettings();
blockApplySettings(false);
return true;
}
return false; return false;
} }
void AMDemodGUI::handleInputMessages()
{
Message* message;
while ((message = getInputMessageQueue()->pop()) != 0)
{
if (handleMessage(*message))
{
delete message;
}
}
}
void AMDemodGUI::channelMarkerChangedByCursor() void AMDemodGUI::channelMarkerChangedByCursor()
{ {
ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency());
@ -201,7 +225,8 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandS
connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
m_amDemod = (AMDemod*) rxChannel; //new AMDemod(m_deviceUISet->m_deviceSourceAPI); m_amDemod = reinterpret_cast<AMDemod*>(rxChannel); //new AMDemod(m_deviceUISet->m_deviceSourceAPI);
m_amDemod->setMessageQueueToGUI(getInputMessageQueue());
connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms
@ -233,6 +258,7 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandS
connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor()));
connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor()));
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
displaySettings(); displaySettings();
applySettings(true); applySettings(true);

View File

@ -75,6 +75,7 @@ private slots:
void on_useRTP_toggled(bool checked); void on_useRTP_toggled(bool checked);
void onWidgetRolled(QWidget* widget, bool rollDown); void onWidgetRolled(QWidget* widget, bool rollDown);
void onMenuDialogCalled(const QPoint& p); void onMenuDialogCalled(const QPoint& p);
void handleInputMessages();
void tick(); void tick();
}; };

View File

@ -1508,6 +1508,21 @@ bool WebAPIRequestMapper::validateDeviceSettings(
return false; return false;
} }
} }
else if ((*deviceHwType == "AirspyHF") && (deviceSettings.getTx() == 0))
{
if (jsonObject.contains("airspyHFSettings") && jsonObject["airspyHFSettings"].isObject())
{
QJsonObject airspyHFSettingsJsonObject = jsonObject["airspyHFSettings"].toObject();
deviceSettingsKeys = airspyHFSettingsJsonObject.keys();
deviceSettings.setAirspyHfSettings(new SWGSDRangel::SWGAirspyHFSettings());
deviceSettings.getAirspyHfSettings()->fromJsonObject(airspyHFSettingsJsonObject);
return true;
}
else
{
return false;
}
}
else if ((*deviceHwType == "HackRF") && (deviceSettings.getTx() == 0)) else if ((*deviceHwType == "HackRF") && (deviceSettings.getTx() == 0))
{ {
if (jsonObject.contains("hackRFInputSettings") && jsonObject["hackRFInputSettings"].isObject()) if (jsonObject.contains("hackRFInputSettings") && jsonObject["hackRFInputSettings"].isObject())
@ -1608,7 +1623,21 @@ bool WebAPIRequestMapper::validateChannelSettings(
QString *channelType = channelSettings.getChannelType(); QString *channelType = channelSettings.getChannelType();
if (*channelType == "NFMDemod") if (*channelType == "AMDemod")
{
if (channelSettings.getTx() == 0)
{
QJsonObject amDemodSettingsJsonObject = jsonObject["AMDemodSettings"].toObject();
channelSettingsKeys = amDemodSettingsJsonObject.keys();
channelSettings.setAmDemodSettings(new SWGSDRangel::SWGAMDemodSettings());
channelSettings.getAmDemodSettings()->fromJsonObject(amDemodSettingsJsonObject);
return true;
}
else {
return false;
}
}
else if (*channelType == "NFMDemod")
{ {
if (channelSettings.getTx() == 0) if (channelSettings.getTx() == 0)
{ {
@ -1668,7 +1697,21 @@ bool WebAPIRequestMapper::validateChannelReport(
QString *channelType = channelReport.getChannelType(); QString *channelType = channelReport.getChannelType();
if (*channelType == "NFMDemod") if (*channelType == "AMDemod")
{
if (channelReport.getTx() == 0)
{
QJsonObject amDemodReportJsonObject = jsonObject["AMDemodReport"].toObject();
channelReportKeys = amDemodReportJsonObject.keys();
channelReport.setAmDemodReport(new SWGSDRangel::SWGAMDemodReport());
channelReport.getAmDemodReport()->fromJsonObject(amDemodReportJsonObject);
return true;
}
else {
return false;
}
}
else if (*channelType == "NFMDemod")
{ {
if (channelReport.getTx() == 0) if (channelReport.getTx() == 0)
{ {

View File

@ -64,12 +64,6 @@ It uses the following APIs:
- URI: `/sdrangel/deviceset/{deviceSetIndex}/device/run` - URI: `/sdrangel/deviceset/{deviceSetIndex}/device/run`
- HTTP method: `POST` - HTTP method: `POST`
<h2>nfm_scanner.py</h2>
Simple NFM scanner with multiple equally spaced NFM channels. Stops whenever any of the channels squelch opens.
Requires numpy
<h2>nfm_test.py</h2> <h2>nfm_test.py</h2>
Example of creating NFM channels (demodulator and modulator) and changing the settings Example of creating NFM channels (demodulator and modulator) and changing the settings
@ -178,6 +172,24 @@ It uses the following APIs:
Combines `rx_test` and `tx_test` to create a pair of source and sink device sets. The APIs used are the same as in `rx_test` or `tx_test`. Combines `rx_test` and `tx_test` to create a pair of source and sink device sets. The APIs used are the same as in `rx_test` or `tx_test`.
<h2>scanner.py</h2>
Simple AM and NFM scanner with multiple equally spaced channels. Stops whenever any of the channels squelch opens. At the moment the following sampling devices can be used:
- AirspyHF
- HackRF
- LimeSDR
- RTLSDR
Requires numpy
In addition to some APIs being used in other script it uses:
- Get channels reports:
- Operation ID: `devicesetChannelsReportGet`
- URI: `/sdrangel/deviceset/{deviceSetIndex}/channels/report`
- HTTP method: `GET`
<h2>start_stop.py</h2> <h2>start_stop.py</h2>
Starts or stops a device in the specified device set Starts or stops a device in the specified device set

View File

@ -3,7 +3,7 @@
""" """
SDRangel REST API client script SDRangel REST API client script
Simple scanner for NFM channels. Builds an array of equally spaced channels. Moves device center frequency Simple scanner for AM and NFM channels. Builds an array of equally spaced channels. Moves device center frequency
so that adjacent parts of the spectrum are scanned by the array of channels. Stops when any of the channels so that adjacent parts of the spectrum are scanned by the array of channels. Stops when any of the channels
is active. Resumes when none of the channels is active. is active. Resumes when none of the channels is active.
@ -48,10 +48,11 @@ def getInputOptions():
parser = OptionParser(usage="usage: %%prog [-t]\n") parser = OptionParser(usage="usage: %%prog [-t]\n")
parser.add_option("-a", "--address", dest="address", help="address and port", metavar="ADDRESS", type="string") 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", default=0) parser.add_option("-d", "--device-index", dest="device_index", help="device set index", metavar="INDEX", type="int", default=0)
parser.add_option("-D", "--device-hwid", dest="device_hwid", help="device hardware id", metavar="HWID", type="string", default="RTLSDR") parser.add_option("-D", "--device-hwid", dest="device_hwid", help="device hardware id", metavar="ID", type="string", default="RTLSDR")
parser.add_option("-C", "--channel-id", dest="channel_id", help="channel id", metavar="ID", type="string", default="NFMDemod")
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("-l", "--log2-decim", dest="log2_decim", help="log2 of the desired software decimation factor", metavar="LOG2", type="int", default=4)
parser.add_option("-n", "--num-channels", dest="num_channels", help="number of parallel channels", metavar="NUMBER", type="int", default=8) parser.add_option("-n", "--num-channels", dest="num_channels", help="number of parallel channels", metavar="NUMBER", type="int", default=8)
parser.add_option("-s", "--freq-step", dest="freq_step", help="frequency step (Hz)", metavar="FREQUENCY", type="int", default=12500) parser.add_option("-s", "--freq-step", dest="freq_step", help="frequency step (Hz)", metavar="FREQUENCY", type="float", default=12500)
parser.add_option("-S", "--freq-start", dest="freq_start", help="frequency start (Hz)", metavar="FREQUENCY", type="int", default=446006250) parser.add_option("-S", "--freq-start", dest="freq_start", help="frequency start (Hz)", metavar="FREQUENCY", type="int", default=446006250)
parser.add_option("-T", "--freq-stop", dest="freq_stop", help="frequency stop (Hz)", metavar="FREQUENCY", type="int", default=446193750) parser.add_option("-T", "--freq-stop", dest="freq_stop", help="frequency stop (Hz)", metavar="FREQUENCY", type="int", default=446193750)
parser.add_option("-b", "--af-bw", dest="af_bw", help="audio babdwidth (kHz)", metavar="FREQUENCY_KHZ", type="int" ,default=3) parser.add_option("-b", "--af-bw", dest="af_bw", help="audio babdwidth (kHz)", metavar="FREQUENCY_KHZ", type="int" ,default=3)
@ -88,7 +89,16 @@ def setupDevice(scan_control, options):
if settings is None: if settings is None:
exit(-1) exit(-1)
if options.device_hwid == "LimeSDR": if options.device_hwid == "AirspyHF":
if scan_control.device_start_freq > 30000000:
settings["airspyHFSettings"]["bandIndex"] = 1
else:
settings["airspyHFSettings"]["bandIndex"] = 0
settings["airspyHFSettings"]["centerFrequency"] = scan_control.device_start_freq
settings["airspyHFSettings"]["devSampleRateIndex"] = 0
settings['airspyHFSettings']['log2Decim'] = options.log2_decim
settings['airspyHFSettings']['loPpmCorrection'] = int(options.lo_ppm * 10) # in tenths of PPM
elif options.device_hwid == "LimeSDR":
settings["limeSdrInputSettings"]["antennaPath"] = 0 settings["limeSdrInputSettings"]["antennaPath"] = 0
settings["limeSdrInputSettings"]["devSampleRate"] = scan_control.device_sample_rate settings["limeSdrInputSettings"]["devSampleRate"] = scan_control.device_sample_rate
settings["limeSdrInputSettings"]["log2HardDecim"] = 4 settings["limeSdrInputSettings"]["log2HardDecim"] = 4
@ -111,7 +121,7 @@ def setupDevice(scan_control, options):
settings['rtlSdrSettings']['loPpmCorrection'] = int(options.lo_ppm) settings['rtlSdrSettings']['loPpmCorrection'] = int(options.lo_ppm)
settings['rtlSdrSettings']['rfBandwidth'] = scan_control.device_step_freq + 100000 settings['rtlSdrSettings']['rfBandwidth'] = scan_control.device_step_freq + 100000
elif options.device_hwid == "HackRF": elif options.device_hwid == "HackRF":
settings['hackRFInputSettings']['LOppmTenths'] = options.lo_ppm * 10 # in tenths of PPM settings['hackRFInputSettings']['LOppmTenths'] = int(options.lo_ppm * 10) # in tenths of PPM
settings['hackRFInputSettings']['centerFrequency'] = scan_control.device_start_freq settings['hackRFInputSettings']['centerFrequency'] = scan_control.device_start_freq
settings['hackRFInputSettings']['dcBlock'] = 1 settings['hackRFInputSettings']['dcBlock'] = 1
settings['hackRFInputSettings']['iqImbalance'] = 1 settings['hackRFInputSettings']['iqImbalance'] = 1
@ -131,7 +141,9 @@ def changeDeviceFrequency(fc, options):
if settings is None: if settings is None:
exit(-1) exit(-1)
if options.device_hwid == "LimeSDR": if options.device_hwid == "AirspyHF":
settings["airspyHFSettings"]["centerFrequency"] = fc
elif options.device_hwid == "LimeSDR":
settings["limeSdrInputSettings"]["centerFrequency"] = fc + 500000 settings["limeSdrInputSettings"]["centerFrequency"] = fc + 500000
elif options.device_hwid == "RTLSDR": elif options.device_hwid == "RTLSDR":
settings['rtlSdrSettings']['centerFrequency'] = fc settings['rtlSdrSettings']['centerFrequency'] = fc
@ -146,7 +158,7 @@ def changeDeviceFrequency(fc, options):
def setupChannels(scan_control, options): def setupChannels(scan_control, options):
i = 0 i = 0
for shift in scan_control.channel_shifts: for shift in scan_control.channel_shifts:
settings = callAPI(deviceset_url + "/channel", "POST", None, {"channelType": "NFMDemod", "tx": 0}, "Create NFM demod") settings = callAPI(deviceset_url + "/channel", "POST", None, {"channelType": options.channel_id, "tx": 0}, "Create NFM demod")
if settings is None: if settings is None:
exit(-1) exit(-1)
@ -154,14 +166,21 @@ def setupChannels(scan_control, options):
if settings is None: if settings is None:
exit(-1) exit(-1)
settings["NFMDemodSettings"]["inputFrequencyOffset"] = int(shift) if options.channel_id == "NFMDemod":
settings["NFMDemodSettings"]["afBandwidth"] = options.af_bw * 1000 settings["NFMDemodSettings"]["inputFrequencyOffset"] = int(shift)
settings["NFMDemodSettings"]["rfBandwidth"] = options.rf_bw settings["NFMDemodSettings"]["afBandwidth"] = options.af_bw * 1000
settings["NFMDemodSettings"]["squelch"] = options.squelch_db * 10 # centi-Bels settings["NFMDemodSettings"]["rfBandwidth"] = options.rf_bw
settings["NFMDemodSettings"]["squelchGate"] = options.squelch_gate / 10 # 10's of ms settings["NFMDemodSettings"]["squelch"] = options.squelch_db * 10 # centi-Bels
settings["NFMDemodSettings"]["title"] = "Channel %d" % i settings["NFMDemodSettings"]["squelchGate"] = options.squelch_gate / 10 # 10's of ms
settings["NFMDemodSettings"]["title"] = "Channel %d" % i
elif options.channel_id == "AMDemod":
settings["AMDemodSettings"]["inputFrequencyOffset"] = int(shift)
settings["AMDemodSettings"]["rfBandwidth"] = options.rf_bw
settings["AMDemodSettings"]["squelch"] = options.squelch_db
settings["AMDemodSettings"]["title"] = "Channel %d" % i
settings["AMDemodSettings"]["bandpassEnable"] = 1 # bandpass filter
r = callAPI(deviceset_url + "/channel/%d/settings" % i, "PATCH", None, settings, "Change NFM demod") r = callAPI(deviceset_url + "/channel/%d/settings" % i, "PATCH", None, settings, "Change demod")
if r is None: if r is None:
exit(-1) exit(-1)
@ -172,11 +191,12 @@ def checkScanning(fc, options):
reports = callAPI(deviceset_url + "/channels/report", "GET", None, None, "Get channels report") reports = callAPI(deviceset_url + "/channels/report", "GET", None, None, "Get channels report")
if reports is None: if reports is None:
exit(-1) exit(-1)
reportKey = "%sReport" % options.channel_id
for i in range(reports["channelcount"]): for i in range(reports["channelcount"]):
channel = reports["channels"][i] channel = reports["channels"][i]
if "report" in channel: if "report" in channel:
if "NFMDemodReport" in channel["report"]: if reportKey in channel["report"]:
if channel["report"]["NFMDemodReport"]["squelch"] == 1: if channel["report"][reportKey]["squelch"] == 1:
f_channel = channel["deltaFrequency"]+fc f_channel = channel["deltaFrequency"]+fc
if f_channel not in options.excl_flist: if f_channel not in options.excl_flist:
print("Stopped at %d Hz" % f_channel) print("Stopped at %d Hz" % f_channel)
@ -256,7 +276,7 @@ def main():
if r is None: if r is None:
exit(-1) exit(-1)
r = callAPI(deviceset_url + "/device", "PUT", None, {"hwType": "%s" % options.device_hwid, "tx": 0}, "setup device on Rx device set") r = callAPI(deviceset_url + "/device", "PUT", None, {"hwType": options.device_hwid, "tx": 0}, "setup device on Rx device set")
if r is None: if r is None:
exit(-1) exit(-1)