From 1a5f643705f0e4059471bc26a40c9131a50881f3 Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 6 May 2019 00:39:53 +0200 Subject: [PATCH] Frequency Tracker: fixed REST API. New Python script to control frequency tracking via API --- scriptsapi/Readme.md | 13 ++ scriptsapi/freqtracking.py | 186 ++++++++++++++++++ scriptsapi/requirements.txt | 2 + sdrbase/resources/res.qrc | 1 + sdrbase/resources/webapi/doc/html2/index.html | 4 +- .../resources/webapi/doc/swagger/swagger.yaml | 2 +- swagger/sdrangel/api/swagger/swagger.yaml | 2 +- swagger/sdrangel/code/html2/index.html | 4 +- .../code/qt5/client/SWGAMDemodReport.cpp | 2 +- .../code/qt5/client/SWGAMDemodReport.h | 2 +- .../code/qt5/client/SWGAMDemodSettings.cpp | 2 +- .../code/qt5/client/SWGAMDemodSettings.h | 2 +- .../code/qt5/client/SWGAMModReport.cpp | 2 +- .../sdrangel/code/qt5/client/SWGAMModReport.h | 2 +- .../code/qt5/client/SWGAMModSettings.cpp | 2 +- .../code/qt5/client/SWGAMModSettings.h | 2 +- .../code/qt5/client/SWGATVModReport.cpp | 2 +- .../code/qt5/client/SWGATVModReport.h | 2 +- .../code/qt5/client/SWGATVModSettings.cpp | 2 +- .../code/qt5/client/SWGATVModSettings.h | 2 +- .../code/qt5/client/SWGAirspyHFReport.cpp | 2 +- .../code/qt5/client/SWGAirspyHFReport.h | 2 +- .../code/qt5/client/SWGAirspyHFSettings.cpp | 2 +- .../code/qt5/client/SWGAirspyHFSettings.h | 2 +- .../code/qt5/client/SWGAirspyReport.cpp | 2 +- .../code/qt5/client/SWGAirspyReport.h | 2 +- .../code/qt5/client/SWGAirspySettings.cpp | 2 +- .../code/qt5/client/SWGAirspySettings.h | 2 +- .../sdrangel/code/qt5/client/SWGArgInfo.cpp | 2 +- swagger/sdrangel/code/qt5/client/SWGArgInfo.h | 2 +- .../sdrangel/code/qt5/client/SWGArgValue.cpp | 2 +- .../sdrangel/code/qt5/client/SWGArgValue.h | 2 +- .../code/qt5/client/SWGAudioDevices.cpp | 2 +- .../code/qt5/client/SWGAudioDevices.h | 2 +- .../code/qt5/client/SWGAudioInputDevice.cpp | 2 +- .../code/qt5/client/SWGAudioInputDevice.h | 2 +- .../code/qt5/client/SWGAudioOutputDevice.cpp | 2 +- .../code/qt5/client/SWGAudioOutputDevice.h | 2 +- .../code/qt5/client/SWGBFMDemodReport.cpp | 2 +- .../code/qt5/client/SWGBFMDemodReport.h | 2 +- .../code/qt5/client/SWGBFMDemodSettings.cpp | 2 +- .../code/qt5/client/SWGBFMDemodSettings.h | 2 +- .../sdrangel/code/qt5/client/SWGBandwidth.cpp | 2 +- .../sdrangel/code/qt5/client/SWGBandwidth.h | 2 +- .../qt5/client/SWGBladeRF1InputSettings.cpp | 2 +- .../qt5/client/SWGBladeRF1InputSettings.h | 2 +- .../qt5/client/SWGBladeRF1OutputSettings.cpp | 2 +- .../qt5/client/SWGBladeRF1OutputSettings.h | 2 +- .../qt5/client/SWGBladeRF2InputReport.cpp | 2 +- .../code/qt5/client/SWGBladeRF2InputReport.h | 2 +- .../qt5/client/SWGBladeRF2InputSettings.cpp | 2 +- .../qt5/client/SWGBladeRF2InputSettings.h | 2 +- .../qt5/client/SWGBladeRF2OutputReport.cpp | 2 +- .../code/qt5/client/SWGBladeRF2OutputReport.h | 2 +- .../qt5/client/SWGBladeRF2OutputSettings.cpp | 2 +- .../qt5/client/SWGBladeRF2OutputSettings.h | 2 +- .../code/qt5/client/SWGCWKeyerSettings.cpp | 2 +- .../code/qt5/client/SWGCWKeyerSettings.h | 2 +- .../sdrangel/code/qt5/client/SWGChannel.cpp | 2 +- swagger/sdrangel/code/qt5/client/SWGChannel.h | 2 +- .../code/qt5/client/SWGChannelListItem.cpp | 2 +- .../code/qt5/client/SWGChannelListItem.h | 2 +- .../code/qt5/client/SWGChannelReport.cpp | 2 +- .../code/qt5/client/SWGChannelReport.h | 2 +- .../code/qt5/client/SWGChannelSettings.cpp | 2 +- .../code/qt5/client/SWGChannelSettings.h | 2 +- .../code/qt5/client/SWGChannelsDetail.cpp | 2 +- .../code/qt5/client/SWGChannelsDetail.h | 2 +- .../sdrangel/code/qt5/client/SWGComplex.cpp | 2 +- swagger/sdrangel/code/qt5/client/SWGComplex.h | 2 +- .../code/qt5/client/SWGDSDDemodReport.cpp | 2 +- .../code/qt5/client/SWGDSDDemodReport.h | 2 +- .../code/qt5/client/SWGDSDDemodSettings.cpp | 2 +- .../code/qt5/client/SWGDSDDemodSettings.h | 2 +- .../code/qt5/client/SWGDVSeralDevices.cpp | 2 +- .../code/qt5/client/SWGDVSeralDevices.h | 2 +- .../code/qt5/client/SWGDVSerialDevice.cpp | 2 +- .../code/qt5/client/SWGDVSerialDevice.h | 2 +- .../code/qt5/client/SWGDeviceListItem.cpp | 2 +- .../code/qt5/client/SWGDeviceListItem.h | 2 +- .../code/qt5/client/SWGDeviceReport.cpp | 2 +- .../code/qt5/client/SWGDeviceReport.h | 2 +- .../sdrangel/code/qt5/client/SWGDeviceSet.cpp | 2 +- .../sdrangel/code/qt5/client/SWGDeviceSet.h | 2 +- .../code/qt5/client/SWGDeviceSetApi.cpp | 2 +- .../code/qt5/client/SWGDeviceSetApi.h | 2 +- .../code/qt5/client/SWGDeviceSetList.cpp | 2 +- .../code/qt5/client/SWGDeviceSetList.h | 2 +- .../code/qt5/client/SWGDeviceSettings.cpp | 2 +- .../code/qt5/client/SWGDeviceSettings.h | 2 +- .../code/qt5/client/SWGDeviceState.cpp | 2 +- .../sdrangel/code/qt5/client/SWGDeviceState.h | 2 +- .../code/qt5/client/SWGErrorResponse.cpp | 2 +- .../code/qt5/client/SWGErrorResponse.h | 2 +- .../code/qt5/client/SWGFCDProPlusSettings.cpp | 2 +- .../code/qt5/client/SWGFCDProPlusSettings.h | 2 +- .../code/qt5/client/SWGFCDProSettings.cpp | 2 +- .../code/qt5/client/SWGFCDProSettings.h | 2 +- .../code/qt5/client/SWGFileSourceReport.cpp | 2 +- .../code/qt5/client/SWGFileSourceReport.h | 2 +- .../code/qt5/client/SWGFileSourceSettings.cpp | 2 +- .../code/qt5/client/SWGFileSourceSettings.h | 2 +- .../code/qt5/client/SWGFreeDVDemodReport.cpp | 2 +- .../code/qt5/client/SWGFreeDVDemodReport.h | 2 +- .../qt5/client/SWGFreeDVDemodSettings.cpp | 2 +- .../code/qt5/client/SWGFreeDVDemodSettings.h | 2 +- .../code/qt5/client/SWGFreeDVModReport.cpp | 2 +- .../code/qt5/client/SWGFreeDVModReport.h | 2 +- .../code/qt5/client/SWGFreeDVModSettings.cpp | 2 +- .../code/qt5/client/SWGFreeDVModSettings.h | 2 +- .../code/qt5/client/SWGFreqTrackerReport.cpp | 2 +- .../code/qt5/client/SWGFreqTrackerReport.h | 2 +- .../qt5/client/SWGFreqTrackerSettings.cpp | 2 +- .../code/qt5/client/SWGFreqTrackerSettings.h | 2 +- .../sdrangel/code/qt5/client/SWGFrequency.cpp | 2 +- .../sdrangel/code/qt5/client/SWGFrequency.h | 2 +- .../code/qt5/client/SWGFrequencyBand.cpp | 2 +- .../code/qt5/client/SWGFrequencyBand.h | 2 +- .../code/qt5/client/SWGFrequencyRange.cpp | 2 +- .../code/qt5/client/SWGFrequencyRange.h | 2 +- swagger/sdrangel/code/qt5/client/SWGGain.cpp | 2 +- swagger/sdrangel/code/qt5/client/SWGGain.h | 2 +- .../qt5/client/SWGHackRFInputSettings.cpp | 2 +- .../code/qt5/client/SWGHackRFInputSettings.h | 2 +- .../qt5/client/SWGHackRFOutputSettings.cpp | 2 +- .../code/qt5/client/SWGHackRFOutputSettings.h | 2 +- .../sdrangel/code/qt5/client/SWGHelpers.cpp | 2 +- swagger/sdrangel/code/qt5/client/SWGHelpers.h | 2 +- .../code/qt5/client/SWGHttpRequest.cpp | 2 +- .../sdrangel/code/qt5/client/SWGHttpRequest.h | 2 +- .../code/qt5/client/SWGInstanceApi.cpp | 2 +- .../sdrangel/code/qt5/client/SWGInstanceApi.h | 2 +- .../client/SWGInstanceChannelsResponse.cpp | 2 +- .../qt5/client/SWGInstanceChannelsResponse.h | 2 +- .../qt5/client/SWGInstanceDevicesResponse.cpp | 2 +- .../qt5/client/SWGInstanceDevicesResponse.h | 2 +- .../qt5/client/SWGInstanceSummaryResponse.cpp | 2 +- .../qt5/client/SWGInstanceSummaryResponse.h | 2 +- .../code/qt5/client/SWGLimeSdrInputReport.cpp | 2 +- .../code/qt5/client/SWGLimeSdrInputReport.h | 2 +- .../qt5/client/SWGLimeSdrInputSettings.cpp | 2 +- .../code/qt5/client/SWGLimeSdrInputSettings.h | 2 +- .../qt5/client/SWGLimeSdrOutputReport.cpp | 2 +- .../code/qt5/client/SWGLimeSdrOutputReport.h | 2 +- .../qt5/client/SWGLimeSdrOutputSettings.cpp | 2 +- .../qt5/client/SWGLimeSdrOutputSettings.h | 2 +- .../code/qt5/client/SWGLocalInputReport.cpp | 2 +- .../code/qt5/client/SWGLocalInputReport.h | 2 +- .../code/qt5/client/SWGLocalInputSettings.cpp | 2 +- .../code/qt5/client/SWGLocalInputSettings.h | 2 +- .../code/qt5/client/SWGLocalSinkSettings.cpp | 2 +- .../code/qt5/client/SWGLocalSinkSettings.h | 2 +- .../qt5/client/SWGLocationInformation.cpp | 2 +- .../code/qt5/client/SWGLocationInformation.h | 2 +- .../code/qt5/client/SWGLoggingInfo.cpp | 2 +- .../sdrangel/code/qt5/client/SWGLoggingInfo.h | 2 +- .../code/qt5/client/SWGModelFactory.h | 2 +- .../code/qt5/client/SWGNFMDemodReport.cpp | 2 +- .../code/qt5/client/SWGNFMDemodReport.h | 2 +- .../code/qt5/client/SWGNFMDemodSettings.cpp | 2 +- .../code/qt5/client/SWGNFMDemodSettings.h | 2 +- .../code/qt5/client/SWGNFMModReport.cpp | 2 +- .../code/qt5/client/SWGNFMModReport.h | 2 +- .../code/qt5/client/SWGNFMModSettings.cpp | 2 +- .../code/qt5/client/SWGNFMModSettings.h | 2 +- .../sdrangel/code/qt5/client/SWGNamedEnum.cpp | 2 +- .../sdrangel/code/qt5/client/SWGNamedEnum.h | 2 +- swagger/sdrangel/code/qt5/client/SWGObject.h | 2 +- .../code/qt5/client/SWGPerseusReport.cpp | 2 +- .../code/qt5/client/SWGPerseusReport.h | 2 +- .../code/qt5/client/SWGPerseusSettings.cpp | 2 +- .../code/qt5/client/SWGPerseusSettings.h | 2 +- .../qt5/client/SWGPlutoSdrInputReport.cpp | 2 +- .../code/qt5/client/SWGPlutoSdrInputReport.h | 2 +- .../qt5/client/SWGPlutoSdrInputSettings.cpp | 2 +- .../qt5/client/SWGPlutoSdrInputSettings.h | 2 +- .../qt5/client/SWGPlutoSdrOutputReport.cpp | 2 +- .../code/qt5/client/SWGPlutoSdrOutputReport.h | 2 +- .../qt5/client/SWGPlutoSdrOutputSettings.cpp | 2 +- .../qt5/client/SWGPlutoSdrOutputSettings.h | 2 +- .../code/qt5/client/SWGPresetExport.cpp | 2 +- .../code/qt5/client/SWGPresetExport.h | 2 +- .../code/qt5/client/SWGPresetGroup.cpp | 2 +- .../sdrangel/code/qt5/client/SWGPresetGroup.h | 2 +- .../code/qt5/client/SWGPresetIdentifier.cpp | 2 +- .../code/qt5/client/SWGPresetIdentifier.h | 2 +- .../code/qt5/client/SWGPresetImport.cpp | 2 +- .../code/qt5/client/SWGPresetImport.h | 2 +- .../code/qt5/client/SWGPresetItem.cpp | 2 +- .../sdrangel/code/qt5/client/SWGPresetItem.h | 2 +- .../code/qt5/client/SWGPresetTransfer.cpp | 2 +- .../code/qt5/client/SWGPresetTransfer.h | 2 +- .../sdrangel/code/qt5/client/SWGPresets.cpp | 2 +- swagger/sdrangel/code/qt5/client/SWGPresets.h | 2 +- .../sdrangel/code/qt5/client/SWGRDSReport.cpp | 2 +- .../sdrangel/code/qt5/client/SWGRDSReport.h | 2 +- .../client/SWGRDSReport_altFrequencies.cpp | 2 +- .../qt5/client/SWGRDSReport_altFrequencies.h | 2 +- swagger/sdrangel/code/qt5/client/SWGRange.cpp | 2 +- swagger/sdrangel/code/qt5/client/SWGRange.h | 2 +- .../code/qt5/client/SWGRangeFloat.cpp | 2 +- .../sdrangel/code/qt5/client/SWGRangeFloat.h | 2 +- .../code/qt5/client/SWGRemoteInputReport.cpp | 2 +- .../code/qt5/client/SWGRemoteInputReport.h | 2 +- .../qt5/client/SWGRemoteInputSettings.cpp | 2 +- .../code/qt5/client/SWGRemoteInputSettings.h | 2 +- .../code/qt5/client/SWGRemoteOutputReport.cpp | 2 +- .../code/qt5/client/SWGRemoteOutputReport.h | 2 +- .../qt5/client/SWGRemoteOutputSettings.cpp | 2 +- .../code/qt5/client/SWGRemoteOutputSettings.h | 2 +- .../code/qt5/client/SWGRemoteSinkSettings.cpp | 2 +- .../code/qt5/client/SWGRemoteSinkSettings.h | 2 +- .../code/qt5/client/SWGRemoteSourceReport.cpp | 2 +- .../code/qt5/client/SWGRemoteSourceReport.h | 2 +- .../qt5/client/SWGRemoteSourceSettings.cpp | 2 +- .../code/qt5/client/SWGRemoteSourceSettings.h | 2 +- .../code/qt5/client/SWGRtlSdrReport.cpp | 2 +- .../code/qt5/client/SWGRtlSdrReport.h | 2 +- .../code/qt5/client/SWGRtlSdrSettings.cpp | 2 +- .../code/qt5/client/SWGRtlSdrSettings.h | 2 +- .../code/qt5/client/SWGSDRPlayReport.cpp | 2 +- .../code/qt5/client/SWGSDRPlayReport.h | 2 +- .../code/qt5/client/SWGSDRPlaySettings.cpp | 2 +- .../code/qt5/client/SWGSDRPlaySettings.h | 2 +- .../code/qt5/client/SWGSSBDemodReport.cpp | 2 +- .../code/qt5/client/SWGSSBDemodReport.h | 2 +- .../code/qt5/client/SWGSSBDemodSettings.cpp | 2 +- .../code/qt5/client/SWGSSBDemodSettings.h | 2 +- .../code/qt5/client/SWGSSBModReport.cpp | 2 +- .../code/qt5/client/SWGSSBModReport.h | 2 +- .../code/qt5/client/SWGSSBModSettings.cpp | 2 +- .../code/qt5/client/SWGSSBModSettings.h | 2 +- .../code/qt5/client/SWGSampleRate.cpp | 2 +- .../sdrangel/code/qt5/client/SWGSampleRate.h | 2 +- .../code/qt5/client/SWGSamplingDevice.cpp | 2 +- .../code/qt5/client/SWGSamplingDevice.h | 2 +- .../client/SWGSoapySDRFrequencySetting.cpp | 2 +- .../qt5/client/SWGSoapySDRFrequencySetting.h | 2 +- .../qt5/client/SWGSoapySDRGainSetting.cpp | 2 +- .../code/qt5/client/SWGSoapySDRGainSetting.h | 2 +- .../qt5/client/SWGSoapySDRInputSettings.cpp | 2 +- .../qt5/client/SWGSoapySDRInputSettings.h | 2 +- .../qt5/client/SWGSoapySDROutputSettings.cpp | 2 +- .../qt5/client/SWGSoapySDROutputSettings.h | 2 +- .../code/qt5/client/SWGSoapySDRReport.cpp | 2 +- .../code/qt5/client/SWGSoapySDRReport.h | 2 +- .../code/qt5/client/SWGSuccessResponse.cpp | 2 +- .../code/qt5/client/SWGSuccessResponse.h | 2 +- .../code/qt5/client/SWGTestSourceSettings.cpp | 2 +- .../code/qt5/client/SWGTestSourceSettings.h | 2 +- .../code/qt5/client/SWGUDPSinkReport.cpp | 2 +- .../code/qt5/client/SWGUDPSinkReport.h | 2 +- .../code/qt5/client/SWGUDPSinkSettings.cpp | 2 +- .../code/qt5/client/SWGUDPSinkSettings.h | 2 +- .../code/qt5/client/SWGUDPSourceReport.cpp | 2 +- .../code/qt5/client/SWGUDPSourceReport.h | 2 +- .../code/qt5/client/SWGUDPSourceSettings.cpp | 2 +- .../code/qt5/client/SWGUDPSourceSettings.h | 2 +- .../code/qt5/client/SWGWFMDemodReport.cpp | 2 +- .../code/qt5/client/SWGWFMDemodReport.h | 2 +- .../code/qt5/client/SWGWFMDemodSettings.cpp | 2 +- .../code/qt5/client/SWGWFMDemodSettings.h | 2 +- .../code/qt5/client/SWGWFMModReport.cpp | 2 +- .../code/qt5/client/SWGWFMModReport.h | 2 +- .../code/qt5/client/SWGWFMModSettings.cpp | 2 +- .../code/qt5/client/SWGWFMModSettings.h | 2 +- .../code/qt5/client/SWGXtrxInputReport.cpp | 2 +- .../code/qt5/client/SWGXtrxInputReport.h | 2 +- .../code/qt5/client/SWGXtrxInputSettings.cpp | 2 +- .../code/qt5/client/SWGXtrxInputSettings.h | 2 +- .../code/qt5/client/SWGXtrxOutputReport.cpp | 2 +- .../code/qt5/client/SWGXtrxOutputReport.h | 2 +- .../code/qt5/client/SWGXtrxOutputSettings.cpp | 2 +- .../code/qt5/client/SWGXtrxOutputSettings.h | 2 +- swagger/sdrangel/examples/Readme.md | 2 +- 275 files changed, 475 insertions(+), 273 deletions(-) create mode 100644 scriptsapi/Readme.md create mode 100644 scriptsapi/freqtracking.py create mode 100644 scriptsapi/requirements.txt diff --git a/scriptsapi/Readme.md b/scriptsapi/Readme.md new file mode 100644 index 000000000..f596f7c5a --- /dev/null +++ b/scriptsapi/Readme.md @@ -0,0 +1,13 @@ +## Python scripts interfacing with the API ## + +These scripts are designed to work in Python 3 preferably with version 3.6 or higher. Dependencies are installed with pip in a virtual environment. The sequence of operations is the following: + +``` +virtualenv -p /usr/bin/python3 venv # Create virtual environment +. ./venv/bin/activate # Activate virtual environment +pip install -r requirements.txt # Install requirements +``` + +

freqtracking.py

+ +This script is used to achieve frequency tracking with the FreqTracker plugin. \ No newline at end of file diff --git a/scriptsapi/freqtracking.py b/scriptsapi/freqtracking.py new file mode 100644 index 000000000..e0baabf90 --- /dev/null +++ b/scriptsapi/freqtracking.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python3 +''' +Frequency tracker: + +Listens on a TCP port for SDRangel reverse API requests. + - When the request comes from a FreqTracker channel it gets the FreqTracker channel frequency shift + - When the request comes from another channel it records the difference between the FreqTracker frequency shift and +this channel frequency shift. Then it will periodically send a center frequency change request to this channel with +the FreqTracker channel frequency shift plus the difference thus achieving the locking of this channel to the FreqTracker +channel frequency. + - If the reply from the channel returns an error it will un-register the channel. + +In the SDRangel instance you must activate the reverse API of the FreqTracker channel and the controlled channel(s) +reverse API giving the address and port of this instance of the script. You have to click on the small grey box at the +top left of the plugin GUI to open the channel details dialog where the reverse API can be configured. +''' + +import requests +import time +import argparse +from flask import Flask +from flask import request, jsonify + +SDRANGEL_API_ADDR = None +SDRANGEL_API_PORT = 8091 +TRACKER_OFFSET = 0 +TRACKER_DEVICE = 0 +TRACKING_DICT = {} + +app = Flask(__name__) + +# ====================================================================== +def getInputOptions(): + """ This is the argument line parser """ +# ---------------------------------------------------------------------- + parser = argparse.ArgumentParser(description="Manages PTT from an SDRangel instance automatically") + parser.add_argument("-A", "--address", dest="addr", help="listening address (default 0.0.0.0)", metavar="IP", type=str) + parser.add_argument("-P", "--port", dest="port", help="listening port (default 8000)", metavar="PORT", type=int) + parser.add_argument("-a", "--address-sdr", dest="sdrangel_address", help="SDRangel REST API address (defaults to calling address)", metavar="ADDRESS", type=str) + parser.add_argument("-p", "--port-sdr", dest="sdrangel_port", help="SDRangel REST API port (default 8091)", metavar="PORT", type=int) + + options = parser.parse_args() + + if options.addr == None: + options.addr = "0.0.0.0" + if options.port == None: + options.port = 8000 + if options.sdrangel_port == None: + options.sdrangel_port = 8091 + + return options.addr, options.port, options.sdrangel_address, options.sdrangel_port + +# ====================================================================== +def get_sdrangel_ip(request): + """ Extract originator address from request """ +# ---------------------------------------------------------------------- + if SDRANGEL_API_ADDR is not None: + return SDRANGEL_API_ADDR + if request.environ.get('HTTP_X_FORWARDED_FOR') is None: + return request.environ['REMOTE_ADDR'] + else: + return request.environ['HTTP_X_FORWARDED_FOR'] + +# ====================================================================== +def gen_dict_extract(key, var): + """ Gets a key value in a dictionnary or sub-dictionnary structure """ +# ---------------------------------------------------------------------- + if hasattr(var,'items'): + for k, v in var.items(): + if k == key: + yield v + if isinstance(v, dict): + for result in gen_dict_extract(key, v): + yield result + elif isinstance(v, list): + for d in v: + for result in gen_dict_extract(key, d): + yield result + +# ====================================================================== +def update_frequency_setting(request_content, frequency): + """ Finds the channel settings key that contains the inputFrequencyOffset key + and replace it with a single inputFrequencyOffset key with new frequency + """ +# ---------------------------------------------------------------------- + for k in request_content: + setting_item = request_content[k] + if isinstance(setting_item, dict): + if 'inputFrequencyOffset' in setting_item: + setting_item.update({ + 'inputFrequencyOffset': frequency + }) + + +# ====================================================================== +def adjust_channels(sdrangel_ip, sdrangel_port): + """ Adjust registered channels center frequencies + Remove keys for channels returning error + """ +# ---------------------------------------------------------------------- + global TRACKING_DICT + base_url = f'http://{sdrangel_ip}:{sdrangel_port}/sdrangel' + remove_keys = [] + for k in TRACKING_DICT: + device_index = k[0] + channel_index = k[1] + tracking_item = TRACKING_DICT[k] + frequency_correction = TRACKER_OFFSET - tracking_item['trackerFrequency'] + frequency = tracking_item['channelFrequency'] + frequency_correction + update_frequency_setting(tracking_item['requestContent'], frequency) + r = requests.patch(url=base_url + f'/deviceset/{device_index}/channel/{channel_index}/settings', json=tracking_item['requestContent']) + if r.status_code / 100 != 2: + remove_keys.append(k) + for k in remove_keys: + TRACKING_DICT.pop(k, None) + + +# ====================================================================== +def register_channel(device_index, channel_index, channel_frequency, request_content): + """ Register a channel or change its center frequency reference """ +# ---------------------------------------------------------------------- + global TRACKING_DICT + TRACKING_DICT.update({ + (device_index, channel_index) : { + 'channelFrequency': channel_frequency, + 'trackerFrequency': TRACKER_OFFSET, + 'requestContent': request_content + } + }) + +# ====================================================================== +@app.route('/sdrangel') +def hello_sdrangel(): + """ Just to test if it works """ +# ---------------------------------------------------------------------- + sdrangel_ip = get_sdrangel_ip(request) + print(f'SDRangel IP: {sdrangel_ip}') + return 'Hello, SDRangel!' + + +# ====================================================================== +@app.route('/sdrangel/deviceset//channel//settings', methods=['GET', 'PATCH', 'PUT']) +def channel_settings(deviceset_index, channel_index): + """ Receiving channel settings from reverse API """ +# ---------------------------------------------------------------------- + global TRACKER_OFFSET + global TRACKER_DEVICE + orig_device_index = None + orig_channel_index = None + content = request.get_json(silent=True) + if content: + orig_device_index = content.get('originatorDeviceSetIndex') + orig_channel_index = content.get('originatorChannelIndex') + if orig_device_index is None or orig_channel_index is None: + print('device_settings: SDRangel reverse API v4.5.2 or higher required. No or invalid originator information') + return "SDRangel reverse API v4.5.2 or higher required " + sdrangel_ip = get_sdrangel_ip(request) + channel_type = content.get('channelType') + for freq_offset in gen_dict_extract('inputFrequencyOffset', content): + if channel_type == "FreqTracker": + print(f'SDRangel: {sdrangel_ip}:{SDRANGEL_API_PORT} Tracker: {freq_offset} Hz') + TRACKER_OFFSET = freq_offset + TRACKER_DEVICE = orig_device_index + adjust_channels(sdrangel_ip, SDRANGEL_API_PORT) + else: + register_channel(orig_device_index, orig_channel_index, freq_offset, content) + print(f'SDRangel: {sdrangel_ip}:{SDRANGEL_API_PORT} {channel_type} [{orig_device_index}:{orig_channel_index}] at {freq_offset} Hz') + return "OK processed " + + +# ====================================================================== +def main(): + """ This is the main routine """ +# ---------------------------------------------------------------------- + global SDRANGEL_API_ADDR + global SDRANGEL_API_PORT + addr, port, SDRANGEL_API_ADDR, SDRANGEL_API_PORT = getInputOptions() + print(f'main: starting at: {addr}:{port}') + app.run(debug=True, host=addr, port=port) + + +# ====================================================================== +if __name__ == "__main__": + """ When called from command line... """ +# ---------------------------------------------------------------------- + main() diff --git a/scriptsapi/requirements.txt b/scriptsapi/requirements.txt new file mode 100644 index 000000000..b914feac2 --- /dev/null +++ b/scriptsapi/requirements.txt @@ -0,0 +1,2 @@ +requests +Flask \ No newline at end of file diff --git a/sdrbase/resources/res.qrc b/sdrbase/resources/res.qrc index 4b7d46ea0..903d46282 100644 --- a/sdrbase/resources/res.qrc +++ b/sdrbase/resources/res.qrc @@ -17,6 +17,7 @@ webapi/doc/swagger/include/FileSource.yaml webapi/doc/swagger/include/FreeDVDemod.yaml webapi/doc/swagger/include/FreeDVMod.yaml + webapi/doc/swagger/include/FreqTracker.yaml webapi/doc/swagger/include/HackRF.yaml webapi/doc/swagger/include/LimeSdr.yaml webapi/doc/swagger/include/LocalInput.yaml diff --git a/sdrbase/resources/webapi/doc/html2/index.html b/sdrbase/resources/webapi/doc/html2/index.html index 8e2cde445..e4d320a93 100644 --- a/sdrbase/resources/webapi/doc/html2/index.html +++ b/sdrbase/resources/webapi/doc/html2/index.html @@ -5950,7 +5950,7 @@ margin-bottom: 20px;