Add ADS-B Demodulator plugin.

Add GS232 Rotator Controller feature plugin.
Add altitude and station name to My Positon.
Use QtDeploy to ensure all required Qt libraries are included (Should
fix OpenGL issues)
pull/671/head
Jon Beniston 2020-10-27 16:22:10 +00:00
rodzic 8b05670814
commit 1a9b6d1763
92 zmienionych plików z 9158 dodań i 51 usunięć

Wyświetl plik

@ -238,6 +238,9 @@ elseif (WIN32)
set(UHD_LIBRARIES "${EXTERNAL_LIBRARY_FOLDER}/uhd/lib/uhd.lib" CACHE INTERNAL "")
set(UHD_DLL_DIR "${EXTERNAL_LIBRARY_FOLDER}/uhd/bin" CACHE INTERNAL "")
set(OPENSSL_FOUND ON CACHE INTERNAL "")
set(OPENSSL_DLL_DIR "${EXTERNAL_LIBRARY_FOLDER}/openssl" CACHE INTERNAL "")
# ffmpeg
set(FFMPEG_INCLUDE_DIRS "${EXTERNAL_LIBRARY_FOLDER}/ffmpeg/include" CACHE INTERNAL "")
set(FFMPEG_LIBRARIES "${EXTERNAL_LIBRARY_FOLDER}/ffmpeg/bin" CACHE INTERNAL "")
@ -331,11 +334,15 @@ find_package(Qt5 COMPONENTS Widgets REQUIRED)
find_package(Qt5 COMPONENTS WebSockets REQUIRED)
find_package(Qt5 COMPONENTS Multimedia REQUIRED)
find_package(Qt5 COMPONENTS MultimediaWidgets REQUIRED)
find_package(Qt5 COMPONENTS SerialPort)
# for the server we don't need OpenGL components
# for the server we don't need OpenGL/Qt Quick components
if (BUILD_GUI)
find_package(OpenGL REQUIRED)
find_package(Qt5 COMPONENTS OpenGL REQUIRED)
find_package(Qt5 COMPONENTS Quick)
find_package(Qt5 COMPONENTS QuickWidgets)
find_package(Qt5 COMPONENTS Positioning)
endif()
# other requirements
@ -589,6 +596,10 @@ endif()
if (LINUX AND ENABLE_EXTERNAL_LIBRARIES)
install(DIRECTORY ${EXTERNAL_BUILD_LIBRARIES}/lib/ DESTINATION ${INSTALL_LIB_DIR})
endif()
if(WIN32)
include(DeployQt)
windeployqt(${CMAKE_PROJECT_NAME} ${SDRANGEL_BINARY_BIN_DIR} ${PROJECT_SOURCE_DIR}/sdrgui/resources)
endif()
# install documentation
# TODO maybe install readme for every plugins

Wyświetl plik

@ -0,0 +1,49 @@
find_package(Qt5Core REQUIRED)
get_target_property(_qmake_executable Qt5::qmake IMPORTED_LOCATION)
get_filename_component(_qt_bin_dir "${_qmake_executable}" DIRECTORY)
find_program(WINDEPLOYQT_EXECUTABLE windeployqt HINTS "${_qt_bin_dir}")
if(WIN32 AND NOT WINDEPLOYQT_EXECUTABLE)
message(FATAL_ERROR "windeployqt not found")
endif()
# Add commands that copy the required Qt files to ${bindir} as well as including
# them in final installation (by first copying them to a winqt subdir)
# We need to specify ${bindir} as we run this on plugins as well as the main .exe
# Preferably, it would be nicer to skip the extra copy to winqt subdir, but how?
# Also, we should possibly only call install once, after all deployments are made
function(windeployqt target bindir qmldir)
# Run windeployqt after build
# First deploy in to bin directory, so we can run from the build bin directory
add_custom_command(TARGET ${target} POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E
env PATH="${_qt_bin_dir}" "${WINDEPLOYQT_EXECUTABLE}"
--verbose 1
--no-compiler-runtime
--dir "${bindir}"
--qmldir "${qmldir}"
--multimedia
\"$<TARGET_FILE:${target}>\"
COMMENT "Deploying Qt..."
)
# Then, deploy again in to separate directory for install to pick up
add_custom_command(TARGET ${target} POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E
env PATH="${_qt_bin_dir}" "${WINDEPLOYQT_EXECUTABLE}"
--verbose 1
--no-compiler-runtime
--dir "${bindir}/winqt"
--qmldir "${qmldir}"
--multimedia
\"$<TARGET_FILE:${target}>\"
COMMENT "Deploying Qt..."
)
install(DIRECTORY "${bindir}/winqt/" DESTINATION .)
endfunction()
mark_as_advanced(WINDEPLOYQT_EXECUTABLE)

Wyświetl plik

@ -11,6 +11,7 @@ endfunction (QUERY_QMAKE)
query_qmake (QT_INSTALL_PLUGINS QT_PLUGINS_DIR)
query_qmake (QT_INSTALL_IMPORTS QT_IMPORTS_DIR)
query_qmake (QT_INSTALL_QML QT_QML_DIR)
if(APPLE AND BUNDLE AND BUILD_GUI)
@ -172,24 +173,6 @@ elseif(LINUX AND BUNDLE)
elseif(WIN32 OR MINGW)
set(QT_PLUGINS_DIR_SET
"${QT_PLUGINS_DIR}/platforms"
"${QT_PLUGINS_DIR}/audio"
"${QT_PLUGINS_DIR}/imageformats"
"${QT_PLUGINS_DIR}/mediaservice"
"${QT_PLUGINS_DIR}/playlistformats"
"${QT_PLUGINS_DIR}/renderplugins"
"${QT_PLUGINS_DIR}/iconengines"
)
# Copy Qt Plugins; fixup_bundle doesn't do that
foreach(qt_plugin ${QT_PLUGINS_DIR_SET})
get_filename_component(qt_plugin_name "${qt_plugin}" NAME)
add_custom_target(copy_qt_plugin_${qt_plugin_name} ALL
COMMAND ${CMAKE_COMMAND} -E copy_directory "${qt_plugin}" "${SDRANGEL_BINARY_BIN_DIR}/${qt_plugin_name}"
)
endforeach(qt_plugin)
# unfortunately some libraries are dependencies of dll so we copy by hand
# TODO check if we can use fixup_bundle() and have libraries on root path
@ -242,6 +225,14 @@ elseif(WIN32 OR MINGW)
endforeach(uhd_dll)
endif()
file(GLOB OPENSSL_DLLS "${OPENSSL_DLL_DIR}/*${CMAKE_SHARED_LIBRARY_SUFFIX}")
foreach(openssl_dll ${OPENSSL_DLLS})
get_filename_component(openssl_dll_name "${openssl_dll}" NAME)
add_custom_target(copy_openssl_${openssl_dll_name} ALL
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${openssl_dll}" "${SDRANGEL_BINARY_BIN_DIR}/"
)
endforeach(openssl_dll)
# TODO we need a way to fixup_bundle() on the build bin/ directory without call install
if(BUILD_GUI)
install(CODE "
@ -268,23 +259,9 @@ elseif(WIN32 OR MINGW)
" COMPONENT Runtime)
endif(BUILD_GUI)
# Copy Qt Plugins; fixup_bundle doesn't do that
install (
DIRECTORY ${QT_PLUGINS_DIR_SET}
DESTINATION "${INSTALL_BIN_DIR}"
CONFIGURATIONS Release MinSizeRel
COMPONENT runtime
FILES_MATCHING PATTERN "*${CMAKE_SHARED_LIBRARY_SUFFIX}"
PATTERN "*minimal*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
PATTERN "*offscreen*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
PATTERN "*quick*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
PATTERN "*_debug${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
)
# unfortunately some libraries are dependencies of dll so we copy by hand
# TODO check if we can use fixup_bundle() and have libraries on root path
# inputkiwisdr.dll
install(FILES "${Qt5_DIR}/../../../bin/Qt5WebSockets${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION "${INSTALL_LIB_DIR}")
# demoddatv.dll
install(DIRECTORY "${FFMPEG_LIBRARIES}/" DESTINATION "${INSTALL_LIB_DIR}"
FILES_MATCHING PATTERN "*${CMAKE_SHARED_LIBRARY_SUFFIX}")
@ -300,6 +277,9 @@ elseif(WIN32 OR MINGW)
# uhd
install(DIRECTORY "${UHD_DLL_DIR}/" DESTINATION "${INSTALL_LIB_DIR}"
FILES_MATCHING PATTERN "*${CMAKE_SHARED_LIBRARY_SUFFIX}")
# OpenSSL
install(DIRECTORY "${OPENSSL_DLL_DIR}/" DESTINATION "${INSTALL_LIB_DIR}"
FILES_MATCHING PATTERN "*${CMAKE_SHARED_LIBRARY_SUFFIX}")
install(CODE "
# remove *.lib files

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 15 KiB

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 468 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 23 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 17 KiB

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -1,5 +1,8 @@
project(demod)
if (Qt5Quick_FOUND AND Qt5QuickWidgets_FOUND AND Qt5Positioning_FOUND)
add_subdirectory(demodadsb)
endif()
add_subdirectory(demodam)
add_subdirectory(demodbfm)
add_subdirectory(demodnfm)

Wyświetl plik

@ -0,0 +1,70 @@
project(adsb)
set(adsb_SOURCES
adsbdemod.cpp
adsbdemodsettings.cpp
adsbdemodwebapiadapter.cpp
adsbplugin.cpp
adsbdemodsink.cpp
adsbdemodbaseband.cpp
adsbdemodreport.cpp
adsbdemodworker.cpp
)
set(adsb_HEADERS
adsbdemod.h
adsbdemodsettings.h
adsbdemodwebapiadapter.h
adsbplugin.h
adsbdemodsink.h
adsbdemodbaseband.h
adsbdemodreport.h
adsbdemodworker.h
adsb.h
)
include_directories(
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
)
if(NOT SERVER_MODE)
set(adsb_SOURCES
${adsb_SOURCES}
adsbdemodgui.cpp
adsbdemodgui.ui
)
set(adsb_HEADERS
${adsb_HEADERS}
adsbdemodgui.h
)
set(TARGET_NAME demodadsb)
set(TARGET_LIB Qt5::Widgets Qt5::Quick Qt5::QuickWidgets Qt5::Positioning)
set(TARGET_LIB_GUI "sdrgui")
set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR})
else()
set(TARGET_NAME demodadsbsrv)
set(TARGET_LIB "")
set(TARGET_LIB_GUI "")
set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR})
endif()
add_library(${TARGET_NAME} SHARED
${adsb_SOURCES}
)
target_link_libraries(${TARGET_NAME}
Qt5::Core
${TARGET_LIB}
sdrbase
${TARGET_LIB_GUI}
swagger
)
install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER})
if(WIN32)
# Run deployqt for QtQuick etc
include(DeployQt)
windeployqt(${TARGET_NAME} ${SDRANGEL_BINARY_BIN_DIR} ${PROJECT_SOURCE_DIR}/../../../sdrgui/resources)
endif()

Wyświetl plik

@ -0,0 +1,29 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_ADSB_H
#define INCLUDE_ADSB_H
#define ADS_B_CHIPS_PER_BIT 2
#define ADS_B_PREAMBLE_BITS 8
#define ADS_B_PREAMBLE_CHIPS (ADS_B_PREAMBLE_BITS*ADS_B_CHIPS_PER_BIT)
#define ADS_B_ES_BITS 112
#define ADS_B_ES_BYTES (ADS_B_ES_BITS/8)
#define ADS_B_DF_MASK 0x1f
#define ADS_B_BITS_PER_SECOND 1000000
#endif // INCLUDE_ADSB_H

Wyświetl plik

@ -0,0 +1,468 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
// written by Christian Daniel //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <complex.h>
#include <QTime>
#include <QDebug>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QBuffer>
#include <QThread>
#include "SWGChannelSettings.h"
#include "SWGADSBDemodSettings.h"
#include "SWGChannelReport.h"
#include "SWGADSBDemodReport.h"
#include "dsp/dspengine.h"
#include "dsp/dspcommands.h"
#include "dsp/devicesamplemimo.h"
#include "device/deviceapi.h"
#include "util/db.h"
#include "adsbdemod.h"
#include "adsbdemodworker.h"
MESSAGE_CLASS_DEFINITION(ADSBDemod::MsgConfigureADSBDemod, Message)
const QString ADSBDemod::m_channelIdURI = "sdrangel.channel.adsbdemod";
const QString ADSBDemod::m_channelId = "ADSBDemod";
ADSBDemod::ADSBDemod(DeviceAPI *devieAPI) :
ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSink),
m_deviceAPI(devieAPI),
m_basebandSampleRate(0),
m_targetAzElValid(false),
m_targetAzimuth(0.0f),
m_targetElevation(0.0f)
{
qDebug("ADSBDemod::ADSBDemod");
setObjectName(m_channelId);
m_thread = new QThread(this);
m_basebandSink = new ADSBDemodBaseband();
m_basebandSink->moveToThread(m_thread);
m_worker = new ADSBDemodWorker();
m_basebandSink->setMessageQueueToWorker(m_worker->getInputMessageQueue());
applySettings(m_settings, true);
m_deviceAPI->addChannelSink(this);
m_deviceAPI->addChannelSinkAPI(this);
m_networkManager = new QNetworkAccessManager();
connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
}
ADSBDemod::~ADSBDemod()
{
if (m_worker->isRunning()) {
stop();
}
delete m_worker;
disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*)));
delete m_networkManager;
m_deviceAPI->removeChannelSinkAPI(this);
m_deviceAPI->removeChannelSink(this);
delete m_basebandSink;
delete m_thread;
}
uint32_t ADSBDemod::getNumberOfDeviceStreams() const
{
return m_deviceAPI->getNbSourceStreams();
}
void ADSBDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst)
{
(void) firstOfBurst;
m_basebandSink->feed(begin, end);
}
void ADSBDemod::start()
{
qDebug() << "ADSBDemod::start";
if (m_basebandSampleRate != 0) {
m_basebandSink->setBasebandSampleRate(m_basebandSampleRate);
}
m_worker->reset();
m_worker->startWork();
m_basebandSink->reset();
m_thread->start();
ADSBDemodWorker::MsgConfigureADSBDemodWorker *msg = ADSBDemodWorker::MsgConfigureADSBDemodWorker::create(m_settings, true);
m_worker->getInputMessageQueue()->push(msg);
}
void ADSBDemod::stop()
{
qDebug() << "ADSBDemod::stop";
m_worker->stopWork();
m_thread->exit();
m_thread->wait();
}
bool ADSBDemod::handleMessage(const Message& cmd)
{
if (MsgConfigureADSBDemod::match(cmd))
{
MsgConfigureADSBDemod& cfg = (MsgConfigureADSBDemod&) cmd;
qDebug() << "ADSBDemod::handleMessage: MsgConfigureADSBDemod";
applySettings(cfg.getSettings(), cfg.getForce());
return true;
}
else if (DSPSignalNotification::match(cmd))
{
DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
m_basebandSampleRate = notif.getSampleRate();
// Forward to the sink
DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy
qDebug() << "ADSBDemod::handleMessage: DSPSignalNotification";
m_basebandSink->getInputMessageQueue()->push(rep);
return true;
}
else
{
return false;
}
}
void ADSBDemod::applySettings(const ADSBDemodSettings& settings, bool force)
{
qDebug() << "ADSBDemod::applySettings:"
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset
<< " m_rfBandwidth: " << settings.m_rfBandwidth
<< " m_streamIndex: " << settings.m_streamIndex
<< " m_useReverseAPI: " << settings.m_useReverseAPI
<< " m_reverseAPIAddress: " << settings.m_reverseAPIAddress
<< " m_reverseAPIPort: " << settings.m_reverseAPIPort
<< " m_reverseAPIDeviceIndex: " << settings.m_reverseAPIDeviceIndex
<< " m_reverseAPIChannelIndex: " << settings.m_reverseAPIChannelIndex
<< " force: " << force;
QList<QString> reverseAPIKeys;
if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) {
reverseAPIKeys.append("inputFrequencyOffset");
}
if ((settings.m_rgbColor != m_settings.m_rgbColor) || force) {
reverseAPIKeys.append("rgbColor");
}
if ((settings.m_title != m_settings.m_title) || force) {
reverseAPIKeys.append("title");
}
if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force) {
reverseAPIKeys.append("rfBandwidth");
}
if (m_settings.m_streamIndex != settings.m_streamIndex)
{
if (m_deviceAPI->getSampleMIMO()) // change of stream is possible for MIMO devices only
{
m_deviceAPI->removeChannelSinkAPI(this);
m_deviceAPI->removeChannelSink(this, m_settings.m_streamIndex);
m_deviceAPI->addChannelSink(this, settings.m_streamIndex);
m_deviceAPI->addChannelSinkAPI(this);
}
reverseAPIKeys.append("streamIndex");
}
ADSBDemodBaseband::MsgConfigureADSBDemodBaseband *msg = ADSBDemodBaseband::MsgConfigureADSBDemodBaseband::create(settings, force);
m_basebandSink->getInputMessageQueue()->push(msg);
ADSBDemodWorker::MsgConfigureADSBDemodWorker *workerMsg = ADSBDemodWorker::MsgConfigureADSBDemodWorker::create(settings, force);
m_worker->getInputMessageQueue()->push(workerMsg);
if (settings.m_useReverseAPI)
{
bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
(m_settings.m_reverseAPIAddress != settings.m_reverseAPIAddress) ||
(m_settings.m_reverseAPIPort != settings.m_reverseAPIPort) ||
(m_settings.m_reverseAPIDeviceIndex != settings.m_reverseAPIDeviceIndex) ||
(m_settings.m_reverseAPIChannelIndex != settings.m_reverseAPIChannelIndex);
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
m_settings = settings;
}
QByteArray ADSBDemod::serialize() const
{
return m_settings.serialize();
}
bool ADSBDemod::deserialize(const QByteArray& data)
{
bool success = true;
if (!m_settings.deserialize(data))
{
m_settings.resetToDefaults();
success = false;
}
MsgConfigureADSBDemod *msg = MsgConfigureADSBDemod::create(m_settings, true);
m_inputMessageQueue.push(msg);
return success;
}
int ADSBDemod::webapiSettingsGet(
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage)
{
(void) errorMessage;
response.setAdsbDemodSettings(new SWGSDRangel::SWGADSBDemodSettings());
response.getAdsbDemodSettings()->init();
webapiFormatChannelSettings(response, m_settings);
return 200;
}
int ADSBDemod::webapiSettingsPutPatch(
bool force,
const QStringList& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage)
{
(void) errorMessage;
ADSBDemodSettings settings = m_settings;
webapiUpdateChannelSettings(settings, channelSettingsKeys, response);
MsgConfigureADSBDemod *msg = MsgConfigureADSBDemod::create(settings, force);
m_inputMessageQueue.push(msg);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureADSBDemod *msgToGUI = MsgConfigureADSBDemod::create(settings, force);
m_guiMessageQueue->push(msgToGUI);
}
webapiFormatChannelSettings(response, settings);
return 200;
}
void ADSBDemod::webapiUpdateChannelSettings(
ADSBDemodSettings& settings,
const QStringList& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings& response)
{
if (channelSettingsKeys.contains("inputFrequencyOffset")) {
settings.m_inputFrequencyOffset = response.getAdsbDemodSettings()->getInputFrequencyOffset();
}
if (channelSettingsKeys.contains("rfBandwidth")) {
settings.m_rfBandwidth = response.getAdsbDemodSettings()->getRfBandwidth();
}
if (channelSettingsKeys.contains("correlationThreshold")) {
settings.m_correlationThreshold = response.getAdsbDemodSettings()->getCorrelationThreshold();
}
if (channelSettingsKeys.contains("samplesPerBit")) {
settings.m_samplesPerBit = response.getAdsbDemodSettings()->getSamplesPerBit();
}
if (channelSettingsKeys.contains("removeTimeout")) {
settings.m_removeTimeout = response.getAdsbDemodSettings()->getRemoveTimeout();
}
if (channelSettingsKeys.contains("beastEnabled")) {
settings.m_beastEnabled = response.getAdsbDemodSettings()->getBeastEnabled() != 0;
}
if (channelSettingsKeys.contains("beastHost")) {
settings.m_beastHost = *response.getAdsbDemodSettings()->getBeastHost();
}
if (channelSettingsKeys.contains("beastPort")) {
settings.m_beastPort = response.getAdsbDemodSettings()->getBeastPort();
}
if (channelSettingsKeys.contains("rgbColor")) {
settings.m_rgbColor = response.getAdsbDemodSettings()->getRgbColor();
}
if (channelSettingsKeys.contains("title")) {
settings.m_title = *response.getAdsbDemodSettings()->getTitle();
}
if (channelSettingsKeys.contains("streamIndex")) {
settings.m_streamIndex = response.getAdsbDemodSettings()->getStreamIndex();
}
if (channelSettingsKeys.contains("useReverseAPI")) {
settings.m_useReverseAPI = response.getAdsbDemodSettings()->getUseReverseApi() != 0;
}
if (channelSettingsKeys.contains("reverseAPIAddress")) {
settings.m_reverseAPIAddress = *response.getAdsbDemodSettings()->getReverseApiAddress();
}
if (channelSettingsKeys.contains("reverseAPIPort")) {
settings.m_reverseAPIPort = response.getAdsbDemodSettings()->getReverseApiPort();
}
if (channelSettingsKeys.contains("reverseAPIDeviceIndex")) {
settings.m_reverseAPIDeviceIndex = response.getAdsbDemodSettings()->getReverseApiDeviceIndex();
}
if (channelSettingsKeys.contains("reverseAPIChannelIndex")) {
settings.m_reverseAPIChannelIndex = response.getAdsbDemodSettings()->getReverseApiChannelIndex();
}
}
int ADSBDemod::webapiReportGet(
SWGSDRangel::SWGChannelReport& response,
QString& errorMessage)
{
(void) errorMessage;
response.setAdsbDemodReport(new SWGSDRangel::SWGADSBDemodReport());
response.getAdsbDemodReport()->init();
webapiFormatChannelReport(response);
return 200;
}
void ADSBDemod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const ADSBDemodSettings& settings)
{
response.getAdsbDemodSettings()->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
response.getAdsbDemodSettings()->setRfBandwidth(settings.m_rfBandwidth);
response.getAdsbDemodSettings()->setCorrelationThreshold(settings.m_correlationThreshold);
response.getAdsbDemodSettings()->setSamplesPerBit(settings.m_samplesPerBit);
response.getAdsbDemodSettings()->setRemoveTimeout(settings.m_removeTimeout);
response.getAdsbDemodSettings()->setBeastEnabled(settings.m_beastEnabled ? 1 : 0);
response.getAdsbDemodSettings()->setBeastHost(new QString(settings.m_beastHost));
response.getAdsbDemodSettings()->setBeastPort(settings.m_beastPort);
response.getAdsbDemodSettings()->setRgbColor(settings.m_rgbColor);
if (response.getAdsbDemodSettings()->getTitle()) {
*response.getAdsbDemodSettings()->getTitle() = settings.m_title;
} else {
response.getAdsbDemodSettings()->setTitle(new QString(settings.m_title));
}
response.getAdsbDemodSettings()->setStreamIndex(settings.m_streamIndex);
response.getAdsbDemodSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
if (response.getAdsbDemodSettings()->getReverseApiAddress()) {
*response.getAdsbDemodSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
} else {
response.getAdsbDemodSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
}
response.getAdsbDemodSettings()->setReverseApiPort(settings.m_reverseAPIPort);
response.getAdsbDemodSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex);
response.getAdsbDemodSettings()->setReverseApiChannelIndex(settings.m_reverseAPIChannelIndex);
}
void ADSBDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
{
double magsqAvg, magsqPeak;
int nbMagsqSamples;
getMagSqLevels(magsqAvg, magsqPeak, nbMagsqSamples);
response.getAdsbDemodReport()->setChannelPowerDb(CalcDb::dbPower(magsqAvg));
response.getAdsbDemodReport()->setChannelSampleRate(m_basebandSink->getChannelSampleRate());
if (m_targetAzElValid)
{
response.getAdsbDemodReport()->setTargetAzimuth(m_targetAzimuth);
response.getAdsbDemodReport()->setTargetElevation(m_targetElevation);
}
}
void ADSBDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const ADSBDemodSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
swgChannelSettings->setDirection(0); // single sink (Rx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("ADSBDemod"));
swgChannelSettings->setAdsbDemodSettings(new SWGSDRangel::SWGADSBDemodSettings());
SWGSDRangel::SWGADSBDemodSettings *swgADSBDemodSettings = swgChannelSettings->getAdsbDemodSettings();
// transfer data that has been modified. When force is on transfer all data except reverse API data
if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
swgADSBDemodSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
}
if (channelSettingsKeys.contains("rfBandwidth") || force) {
swgADSBDemodSettings->setRfBandwidth(settings.m_rfBandwidth);
}
if (channelSettingsKeys.contains("correlationThreshold") || force) {
swgADSBDemodSettings->setCorrelationThreshold(settings.m_correlationThreshold);
}
if (channelSettingsKeys.contains("samplesPerBit") || force) {
swgADSBDemodSettings->setSamplesPerBit(settings.m_samplesPerBit);
}
if (channelSettingsKeys.contains("removeTimeout") || force) {
swgADSBDemodSettings->setRemoveTimeout(settings.m_removeTimeout);
}
if (channelSettingsKeys.contains("beastEnabled") || force) {
swgADSBDemodSettings->setBeastEnabled(settings.m_beastEnabled ? 1 : 0);
}
if (channelSettingsKeys.contains("beastHost") || force) {
swgADSBDemodSettings->setBeastHost(new QString(settings.m_beastHost));
}
if (channelSettingsKeys.contains("beastPort") || force) {
swgADSBDemodSettings->setBeastPort(settings.m_beastPort);
}
if (channelSettingsKeys.contains("rgbColor") || force) {
swgADSBDemodSettings->setRgbColor(settings.m_rgbColor);
}
if (channelSettingsKeys.contains("title") || force) {
swgADSBDemodSettings->setTitle(new QString(settings.m_title));
}
if (channelSettingsKeys.contains("streamIndex") || force) {
swgADSBDemodSettings->setStreamIndex(settings.m_streamIndex);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void ADSBDemod::networkManagerFinished(QNetworkReply *reply)
{
QNetworkReply::NetworkError replyError = reply->error();
if (replyError)
{
qWarning() << "ADSBDemod::networkManagerFinished:"
<< " error(" << (int) replyError
<< "): " << replyError
<< ": " << reply->errorString();
}
else
{
QString answer = reply->readAll();
answer.chop(1); // remove last \n
qDebug("ADSBDemod::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
}
reply->deleteLater();
}

Wyświetl plik

@ -0,0 +1,155 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
// written by Christian Daniel //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_ADSBDEMOD_H
#define INCLUDE_ADSBDEMOD_H
#include <vector>
#include <QNetworkRequest>
#include "dsp/basebandsamplesink.h"
#include "channel/channelapi.h"
#include "util/message.h"
#include "adsbdemodbaseband.h"
#include "adsbdemodsettings.h"
class QNetworkAccessManager;
class QNetworkReply;
class QThread;
class DeviceAPI;
class ADSBDemodWorker;
class ADSBDemod : public BasebandSampleSink, public ChannelAPI {
Q_OBJECT
public:
class MsgConfigureADSBDemod : public Message {
MESSAGE_CLASS_DECLARATION
public:
const ADSBDemodSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; }
static MsgConfigureADSBDemod* create(const ADSBDemodSettings& settings, bool force)
{
return new MsgConfigureADSBDemod(settings, force);
}
private:
ADSBDemodSettings m_settings;
bool m_force;
MsgConfigureADSBDemod(const ADSBDemodSettings& settings, bool force) :
Message(),
m_settings(settings),
m_force(force)
{ }
};
ADSBDemod(DeviceAPI *deviceAPI);
virtual ~ADSBDemod();
virtual void destroy() { delete this; }
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positive);
virtual void start();
virtual void stop();
virtual bool handleMessage(const Message& cmd);
virtual void getIdentifier(QString& id) { id = m_channelId; }
virtual const QString& getURI() const { return m_channelIdURI; }
virtual void getTitle(QString& title) { title = m_settings.m_title; }
virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; }
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);
virtual int getNbSinkStreams() const { return 1; }
virtual int getNbSourceStreams() const { return 0; }
virtual qint64 getStreamCenterFrequency(int streamIndex, bool sinkElseSource) const
{
(void) streamIndex;
(void) sinkElseSource;
return m_settings.m_inputFrequencyOffset;
}
virtual int webapiSettingsGet(
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage);
virtual int webapiSettingsPutPatch(
bool force,
const QStringList& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage);
virtual int webapiReportGet(
SWGSDRangel::SWGChannelReport& response,
QString& errorMessage);
static void webapiFormatChannelSettings(
SWGSDRangel::SWGChannelSettings& response,
const ADSBDemodSettings& settings);
static void webapiUpdateChannelSettings(
ADSBDemodSettings& settings,
const QStringList& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings& response);
void getMagSqLevels(double& avg, double& peak, int& nbSamples) { m_basebandSink->getMagSqLevels(avg, peak, nbSamples); }
void propagateMessageQueueToGUI() { m_basebandSink->setMessageQueueToGUI(getMessageQueueToGUI()); }
void setTarget(float targetAzimuth, float targetElevation)
{
m_targetAzimuth = targetAzimuth;
m_targetElevation = targetElevation;
m_targetAzElValid = true;
}
void clearTarget() { m_targetAzElValid = false; }
uint32_t getNumberOfDeviceStreams() const;
static const QString m_channelIdURI;
static const QString m_channelId;
private:
DeviceAPI* m_deviceAPI;
QThread *m_thread;
ADSBDemodWorker *m_worker;
ADSBDemodBaseband* m_basebandSink;
ADSBDemodSettings m_settings;
int m_basebandSampleRate; //!< stored from device message used when starting baseband sink
bool m_targetAzElValid;
float m_targetAzimuth;
float m_targetElevation;
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
void applySettings(const ADSBDemodSettings& settings, bool force = false);
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const ADSBDemodSettings& settings, bool force);
private slots:
void networkManagerFinished(QNetworkReply *reply);
};
#endif // INCLUDE_ADSBDEMOD_H

Wyświetl plik

@ -0,0 +1,157 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QDebug>
#include "dsp/dspengine.h"
#include "dsp/dspcommands.h"
#include "dsp/downchannelizer.h"
#include "adsbdemodbaseband.h"
#include "adsb.h"
MESSAGE_CLASS_DEFINITION(ADSBDemodBaseband::MsgConfigureADSBDemodBaseband, Message)
ADSBDemodBaseband::ADSBDemodBaseband() :
m_mutex(QMutex::Recursive)
{
m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(8000000));
m_channelizer = new DownChannelizer(&m_sink);
qDebug("ADSBDemodBaseband::ADSBDemodBaseband");
QObject::connect(
&m_sampleFifo,
&SampleSinkFifo::dataReady,
this,
&ADSBDemodBaseband::handleData,
Qt::QueuedConnection
);
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
}
ADSBDemodBaseband::~ADSBDemodBaseband()
{
delete m_channelizer;
}
void ADSBDemodBaseband::reset()
{
QMutexLocker mutexLocker(&m_mutex);
m_sampleFifo.reset();
}
void ADSBDemodBaseband::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end)
{
m_sampleFifo.write(begin, end);
}
void ADSBDemodBaseband::handleData()
{
QMutexLocker mutexLocker(&m_mutex);
while ((m_sampleFifo.fill() > 0) && (m_inputMessageQueue.size() == 0))
{
SampleVector::iterator part1begin;
SampleVector::iterator part1end;
SampleVector::iterator part2begin;
SampleVector::iterator part2end;
std::size_t count = m_sampleFifo.readBegin(m_sampleFifo.fill(), &part1begin, &part1end, &part2begin, &part2end);
// first part of FIFO data
if (part1begin != part1end) {
m_channelizer->feed(part1begin, part1end);
}
// second part of FIFO data (used when block wraps around)
if(part2begin != part2end) {
m_channelizer->feed(part2begin, part2end);
}
m_sampleFifo.readCommit((unsigned int) count);
}
}
void ADSBDemodBaseband::handleInputMessages()
{
Message* message;
while ((message = m_inputMessageQueue.pop()) != nullptr)
{
if (handleMessage(*message)) {
delete message;
}
}
}
bool ADSBDemodBaseband::handleMessage(const Message& cmd)
{
if (MsgConfigureADSBDemodBaseband::match(cmd))
{
QMutexLocker mutexLocker(&m_mutex);
MsgConfigureADSBDemodBaseband& cfg = (MsgConfigureADSBDemodBaseband&) cmd;
qDebug() << "ADSBDemodBaseband::handleMessage: MsgConfigureADSBDemodBaseband";
applySettings(cfg.getSettings(), cfg.getForce());
return true;
}
else if (DSPSignalNotification::match(cmd))
{
QMutexLocker mutexLocker(&m_mutex);
DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
qDebug() << "ADSBDemodBaseband::handleMessage: DSPSignalNotification: basebandSampleRate: " << notif.getSampleRate();
m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(8*notif.getSampleRate())); // Need a large FIFO otherwise we get overflows - revist after better upsampling
m_channelizer->setBasebandSampleRate(notif.getSampleRate());
m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset());
return true;
}
else
{
return false;
}
}
void ADSBDemodBaseband::applySettings(const ADSBDemodSettings& settings, bool force)
{
if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset)
|| (settings.m_samplesPerBit != m_settings.m_samplesPerBit) || force)
{
int requestedRate = ADS_B_BITS_PER_SECOND * settings.m_samplesPerBit;
m_channelizer->setChannelization(requestedRate, settings.m_inputFrequencyOffset);
m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset());
}
m_sink.applySettings(settings, force);
m_settings = settings;
}
int ADSBDemodBaseband::getChannelSampleRate() const
{
return m_channelizer->getChannelSampleRate();
}
void ADSBDemodBaseband::setBasebandSampleRate(int sampleRate)
{
m_channelizer->setBasebandSampleRate(sampleRate);
m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset());
}

Wyświetl plik

@ -0,0 +1,87 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_ADSBDEMODBASEBAND_H
#define INCLUDE_ADSBDEMODBASEBAND_H
#include <QObject>
#include <QMutex>
#include "dsp/samplesinkfifo.h"
#include "util/message.h"
#include "util/messagequeue.h"
#include "adsbdemodsink.h"
class DownChannelizer;
class ADSBDemodBaseband : public QObject
{
Q_OBJECT
public:
class MsgConfigureADSBDemodBaseband : public Message {
MESSAGE_CLASS_DECLARATION
public:
const ADSBDemodSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; }
static MsgConfigureADSBDemodBaseband* create(const ADSBDemodSettings& settings, bool force)
{
return new MsgConfigureADSBDemodBaseband(settings, force);
}
private:
ADSBDemodSettings m_settings;
bool m_force;
MsgConfigureADSBDemodBaseband(const ADSBDemodSettings& settings, bool force) :
Message(),
m_settings(settings),
m_force(force)
{ }
};
ADSBDemodBaseband();
~ADSBDemodBaseband();
void reset();
void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end);
MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication
int getChannelSampleRate() const;
void getMagSqLevels(double& avg, double& peak, int& nbSamples) { m_sink.getMagSqLevels(avg, peak, nbSamples); }
void setMessageQueueToGUI(MessageQueue *messageQueue) { m_sink.setMessageQueueToGUI(messageQueue); }
void setMessageQueueToWorker(MessageQueue *messageQueue) { m_sink.setMessageQueueToWorker(messageQueue); }
void setBasebandSampleRate(int sampleRate);
private:
SampleSinkFifo m_sampleFifo;
DownChannelizer *m_channelizer;
ADSBDemodSink m_sink;
MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication
ADSBDemodSettings m_settings;
QMutex m_mutex;
bool handleMessage(const Message& cmd);
void applySettings(const ADSBDemodSettings& settings, bool force = false);
private slots:
void handleInputMessages();
void handleData(); //!< Handle data when samples have to be processed
};
#endif // INCLUDE_ADSBDEMODBASEBAND_H

Wyświetl plik

@ -0,0 +1,272 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_ADSBDEMODGUI_H
#define INCLUDE_ADSBDEMODGUI_H
#include <QTableWidgetItem>
#include <QGeoCoordinate>
#include <QDateTime>
#include <QAbstractListModel>
#include "channel/channelgui.h"
#include "dsp/dsptypes.h"
#include "dsp/channelmarker.h"
#include "dsp/movingaverage.h"
#include "util/messagequeue.h"
#include "util/azel.h"
#include "adsbdemodsettings.h"
class PluginAPI;
class DeviceUISet;
class BasebandSampleSink;
class ADSBDemod;
namespace Ui {
class ADSBDemodGUI;
}
// Data about an aircraft extracted from an ADS-B frames
struct Aircraft {
int m_icao; // 24-bit ICAO aircraft address
QString m_flight; // Flight callsign
Real m_latitude; // Latitude in decimal degrees
Real m_longitude; // Longitude in decimal degrees
int m_altitude; // Altitude in feet
int m_speed; // Speed in knots
enum SpeedType {
GS, // Ground speed
TAS, // True air speed
IAS // Indicated air speed
} m_speedType;
static const char *m_speedTypeNames[];
int m_heading; // Heading in degrees
int m_verticalRate; // Vertical climb rate in ft/min
QString m_emitterCategory; // Aircraft type
QString m_status; // Aircraft status
Real m_range; // Distance from station to aircraft
Real m_azimuth; // Azimuth from station to aircraft
Real m_elevation; // Elevation from station to aicraft;
QDateTime m_time; // When last updated
bool m_positionValid; // Indicates if we have valid data for the above fields
bool m_altitudeValid;
bool m_speedValid;
bool m_headingValid;
bool m_verticalRateValid;
// State for calculating position using two CPR frames
bool m_cprValid[2];
Real m_cprLat[2];
Real m_cprLong[2];
int m_adsbFrameCount; // Number of ADS-B frames for this aircraft
float m_minCorrelation;
float m_maxCorrelation;
float m_sumCorrelation;
bool m_isBeingTracked; // Are we tracking this aircraft
// GUI table items for above data
QTableWidgetItem *m_icaoItem;
QTableWidgetItem *m_flightItem;
QTableWidgetItem *m_latitudeItem;
QTableWidgetItem *m_longitudeItem;
QTableWidgetItem *m_altitudeItem;
QTableWidgetItem *m_speedItem;
QTableWidgetItem *m_headingItem;
QTableWidgetItem *m_verticalRateItem;
QTableWidgetItem *m_emitterCategoryItem;
QTableWidgetItem *m_statusItem;
QTableWidgetItem *m_rangeItem;
QTableWidgetItem *m_azElItem;
QTableWidgetItem *m_timeItem;
QTableWidgetItem *m_adsbFrameCountItem;
QTableWidgetItem *m_correlationItem;
Aircraft() :
m_icao(0),
m_latitude(0),
m_longitude(0),
m_altitude(0),
m_speed(0),
m_heading(0),
m_verticalRate(0),
m_azimuth(0),
m_elevation(0),
m_positionValid(false),
m_altitudeValid(false),
m_speedValid(false),
m_headingValid(false),
m_verticalRateValid(false),
m_adsbFrameCount(0),
m_minCorrelation(INFINITY),
m_maxCorrelation(-INFINITY),
m_sumCorrelation(0.0f),
m_isBeingTracked(false)
{
for (int i = 0; i < 2; i++)
{
m_cprValid[i] = false;
}
// These are deleted by QTableWidget
m_icaoItem = new QTableWidgetItem();
m_flightItem = new QTableWidgetItem();
m_latitudeItem = new QTableWidgetItem();
m_longitudeItem = new QTableWidgetItem();
m_altitudeItem = new QTableWidgetItem();
m_speedItem = new QTableWidgetItem();
m_headingItem = new QTableWidgetItem();
m_verticalRateItem = new QTableWidgetItem();
m_emitterCategoryItem = new QTableWidgetItem();
m_statusItem = new QTableWidgetItem();
m_rangeItem = new QTableWidgetItem();
m_azElItem = new QTableWidgetItem();
m_timeItem = new QTableWidgetItem();
m_adsbFrameCountItem = new QTableWidgetItem();
m_correlationItem = new QTableWidgetItem();
}
};
// Aircraft data model used by QML map item
class AircraftModel : public QAbstractListModel {
Q_OBJECT
public:
using QAbstractListModel::QAbstractListModel;
enum MarkerRoles{
positionRole = Qt::UserRole + 1,
headingRole = Qt::UserRole + 2,
adsbDataRole = Qt::UserRole + 3,
aircraftImageRole = Qt::UserRole + 4,
bubbleColourRole = Qt::UserRole + 5
};
Q_INVOKABLE void addAircraft(Aircraft *aircraft) {
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_aircrafts.append(aircraft);
endInsertRows();
}
int rowCount(const QModelIndex &parent = QModelIndex()) const override {
Q_UNUSED(parent)
return m_aircrafts.count();
}
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
void aircraftUpdated(Aircraft *aircraft) {
int row = m_aircrafts.indexOf(aircraft);
if (row >= 0)
{
QModelIndex idx = index(row);
emit dataChanged(idx, idx);
}
}
void removeAircraft(Aircraft *aircraft) {
int row = m_aircrafts.indexOf(aircraft);
if (row >= 0)
{
beginRemoveRows(QModelIndex(), row, row);
m_aircrafts.removeAt(row);
endRemoveRows();
}
}
QHash<int, QByteArray> roleNames() const {
QHash<int, QByteArray> roles;
roles[positionRole] = "position";
roles[headingRole] = "heading";
roles[adsbDataRole] = "adsbData";
roles[aircraftImageRole] = "aircraftImage";
roles[bubbleColourRole] = "bubbleColour";
return roles;
}
private:
QList<Aircraft *> m_aircrafts;
};
class ADSBDemodGUI : public ChannelGUI {
Q_OBJECT
public:
static ADSBDemodGUI* create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel);
virtual void destroy();
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
public slots:
void channelMarkerChangedByCursor();
void channelMarkerHighlightedByCursor();
private:
Ui::ADSBDemodGUI* ui;
PluginAPI* m_pluginAPI;
DeviceUISet* m_deviceUISet;
ChannelMarker m_channelMarker;
ADSBDemodSettings m_settings;
bool m_basicSettingsShown;
bool m_doApplySettings;
ADSBDemod* m_adsbDemod;
uint32_t m_tickCount;
MessageQueue m_inputMessageQueue;
QHash<int,Aircraft *> m_aircraft; // Hashed on ICAO
AircraftModel m_aircraftModel;
AzEl m_azEl; // Position of station
Aircraft *m_trackAircraft; // Aircraft we want to track in Channel Report
explicit ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent = 0);
virtual ~ADSBDemodGUI();
void blockApplySettings(bool block);
void applySettings(bool force = false);
void displaySettings();
void displayStreamIndex();
bool handleMessage(const Message& message);
void updatePosition(Aircraft *aircraft);
void handleADSB(const QByteArray data, const QDateTime dateTime, float correlation);
void leaveEvent(QEvent*);
void enterEvent(QEvent*);
private slots:
void on_deltaFrequency_changed(qint64 value);
void on_rfBW_valueChanged(int value);
void on_threshold_valueChanged(int value);
void on_adsbData_cellDoubleClicked(int row, int column);
void on_spb_currentIndexChanged(int value);
void on_beastEnabled_stateChanged(int state);
void on_host_editingFinished(QString value);
void on_port_valueChanged(int value);
void onWidgetRolled(QWidget* widget, bool rollDown);
void onMenuDialogCalled(const QPoint& p);
void handleInputMessages();
void tick();
signals:
void homePositionChanged();
};
#endif // INCLUDE_ADSBDEMODGUI_H

Wyświetl plik

@ -0,0 +1,667 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ADSBDemodGUI</class>
<widget class="RollupWidget" name="ADSBDemodGUI">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>350</width>
<height>1019</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>350</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Sans</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="windowTitle">
<string>ADS-B Demodulator</string>
</property>
<widget class="QWidget" name="settingsContainer" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>340</width>
<height>101</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>Settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayoutSettings">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<layout class="QHBoxLayout" name="deltaFreqPowerLayout">
<property name="topMargin">
<number>2</number>
</property>
<item>
<layout class="QHBoxLayout" name="DeltaFrequencyLayout">
<item>
<widget class="QLabel" name="deltaFrequencyLabel">
<property name="minimumSize">
<size>
<width>16</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Df</string>
</property>
</widget>
</item>
<item>
<widget class="ValueDialZ" name="deltaFrequency" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>32</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>12</pointsize>
</font>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>Demod shift frequency from center in Hz</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="deltaUnits">
<property name="text">
<string>Hz </string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="channelPower">
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Channel power</string>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>-100.0 dB</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="levelMeterLayout">
<item>
<widget class="QLabel" name="channelPowerMeterUnits">
<property name="text">
<string>dB</string>
</property>
</widget>
</item>
<item>
<widget class="LevelMeterSignalDB" name="channelPowerMeter" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>24</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>8</pointsize>
</font>
</property>
<property name="toolTip">
<string>Level meter (dB) top trace: average, bottom trace: instantaneous peak, tip: peak hold</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="rfBWLayout">
<item>
<widget class="QLabel" name="rfBWLabel">
<property name="text">
<string>RFBW</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="rfBW">
<property name="toolTip">
<string>RF bandwidth</string>
</property>
<property name="minimum">
<number>1000000</number>
</property>
<property name="maximum">
<number>3000000</number>
</property>
<property name="singleStep">
<number>100000</number>
</property>
<property name="pageStep">
<number>1000000</number>
</property>
<property name="value">
<number>2300000</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="rfBWText">
<property name="text">
<string>2.3M</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="spbrLabel">
<property name="text">
<string>SR</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="spb">
<property name="minimumSize">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Demodulator sample rate. This should ideally be matched to baseband sample rate</string>
</property>
<item>
<property name="text">
<string>4</string>
</property>
</item>
<item>
<property name="text">
<string>6</string>
</property>
</item>
<item>
<property name="text">
<string>8</string>
</property>
</item>
<item>
<property name="text">
<string>10</string>
</property>
</item>
<item>
<property name="text">
<string>12</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="spbUnit">
<property name="text">
<string>M</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="thresholdLabel">
<property name="text">
<string>Threshold</string>
</property>
</widget>
</item>
<item>
<widget class="QDial" name="threshold">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Correlation threshold. Lower values will increase the number of frames that can be received, but require more processing.</string>
</property>
<property name="minimum">
<number>-100</number>
</property>
<property name="maximum">
<number>20</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="thresholdText">
<property name="minimumSize">
<size>
<width>30</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>-15.0</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QCheckBox" name="beastEnabled">
<property name="toolTip">
<string>Enable feeding of received ADS-B messages in Beast binary format to the specifed server</string>
</property>
<property name="text">
<string>Feed</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="hostLabel">
<property name="text">
<string>Server</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="host">
<property name="toolTip">
<string>Hostname of the server to feed</string>
</property>
<property name="text">
<string>feed.adsbexchange.com</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="portLabel">
<property name="text">
<string>Port</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="port">
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Port the server is listening on</string>
</property>
<property name="minimum">
<number>1024</number>
</property>
<property name="maximum">
<number>65535</number>
</property>
<property name="value">
<number>30005</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="dataContainer" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>114</y>
<width>341</width>
<height>291</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>ADS-B Data</string>
</property>
<layout class="QVBoxLayout" name="verticalLayoutTable">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>3</number>
</property>
<property name="topMargin">
<number>3</number>
</property>
<property name="rightMargin">
<number>3</number>
</property>
<property name="bottomMargin">
<number>3</number>
</property>
<item>
<widget class="QTableWidget" name="adsbData">
<property name="font">
<font>
<family>Segoe UI</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<column>
<property name="text">
<string>ICAO ID</string>
</property>
<property name="toolTip">
<string extracomment="Double click to search for the aircraft on www.planespotters.net"/>
</property>
</column>
<column>
<property name="text">
<string>Flight No.</string>
</property>
</column>
<column>
<property name="text">
<string>Latitude (°)</string>
</property>
<property name="toolTip">
<string extracomment="Double click to centre the map on this aircraft"/>
</property>
</column>
<column>
<property name="text">
<string>Longitude (°)</string>
</property>
<property name="toolTip">
<string extracomment="Double click to centre the map on this aircraft"/>
</property>
</column>
<column>
<property name="text">
<string>Altitude (ft)</string>
</property>
</column>
<column>
<property name="text">
<string>Speed (kn)</string>
</property>
</column>
<column>
<property name="text">
<string>Heading (°)</string>
</property>
</column>
<column>
<property name="text">
<string>Climb (ft/min)</string>
</property>
</column>
<column>
<property name="text">
<string>Category</string>
</property>
</column>
<column>
<property name="text">
<string>Status</string>
</property>
</column>
<column>
<property name="text">
<string>Range (km)</string>
</property>
</column>
<column>
<property name="text">
<string>Az/El (°)</string>
</property>
</column>
<column>
<property name="text">
<string>Updated</string>
</property>
</column>
<column>
<property name="text">
<string>RX Frames</string>
</property>
</column>
<column>
<property name="text">
<string>Correlation</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="mapContainer" native="true">
<property name="geometry">
<rect>
<x>10</x>
<y>420</y>
<width>331</width>
<height>581</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Map</string>
</property>
<layout class="QVBoxLayout" name="verticalLayoutMap" stretch="0">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>3</number>
</property>
<property name="topMargin">
<number>3</number>
</property>
<property name="rightMargin">
<number>3</number>
</property>
<property name="bottomMargin">
<number>3</number>
</property>
<item>
<widget class="QQuickWidget" name="map">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>400</height>
</size>
</property>
<property name="toolTip">
<string>Aircraft location map</string>
</property>
<property name="resizeMode">
<enum>QQuickWidget::SizeRootObjectToView</enum>
</property>
<property name="source">
<url>
<string>qrc:/map.qml</string>
</url>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>QQuickWidget</class>
<extends>QWidget</extends>
<header location="global">QtQuickWidgets/QQuickWidget</header>
</customwidget>
<customwidget>
<class>RollupWidget</class>
<extends>QWidget</extends>
<header>gui/rollupwidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>LevelMeterSignalDB</class>
<extends>QWidget</extends>
<header>gui/levelmeter.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ValueDialZ</class>
<extends>QWidget</extends>
<header>gui/valuedialz.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>deltaFrequency</tabstop>
<tabstop>rfBW</tabstop>
<tabstop>spb</tabstop>
<tabstop>threshold</tabstop>
<tabstop>beastEnabled</tabstop>
<tabstop>host</tabstop>
<tabstop>port</tabstop>
<tabstop>adsbData</tabstop>
<tabstop>map</tabstop>
</tabstops>
<resources>
<include location="../../../sdrgui/resources/res.qrc"/>
</resources>
<connections/>
</ui>

Wyświetl plik

@ -0,0 +1,21 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "adsbdemodreport.h"
MESSAGE_CLASS_DEFINITION(ADSBDemodReport::MsgReportADSB, Message)

Wyświetl plik

@ -0,0 +1,65 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_CHANNELRX_DEMOADSB_ADSBDEMODREPORT_H_
#define PLUGINS_CHANNELRX_DEMOADSB_ADSBDEMODREPORT_H_
#include <QObject>
#include <QByteArray>
#include <QDateTime>
#include "dsp/dsptypes.h"
#include "util/message.h"
class ADSBDemodReport : public QObject
{
Q_OBJECT
public:
class MsgReportADSB : public Message {
MESSAGE_CLASS_DECLARATION
public:
QByteArray getData() const { return m_data; }
QDateTime getDateTime() const { return m_dateTime; }
float getPreambleCorrelation() const { return m_premableCorrelation; }
static MsgReportADSB* create(QByteArray data, float premableCorrelation)
{
return new MsgReportADSB(data, premableCorrelation);
}
private:
QByteArray m_data;
QDateTime m_dateTime;
float m_premableCorrelation;
MsgReportADSB(QByteArray data, float premableCorrelation) :
Message(),
m_data(data),
m_premableCorrelation(premableCorrelation)
{
m_dateTime = QDateTime::currentDateTime();
}
};
public:
ADSBDemodReport() {}
~ADSBDemodReport() {}
};
#endif // PLUGINS_CHANNELRX_DEMOADSB_ADSBDEMODREPORT_H_

Wyświetl plik

@ -0,0 +1,142 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QColor>
#include "dsp/dspengine.h"
#include "util/simpleserializer.h"
#include "settings/serializable.h"
#include "adsbdemodsettings.h"
ADSBDemodSettings::ADSBDemodSettings() :
m_channelMarker(0)
{
resetToDefaults();
}
void ADSBDemodSettings::resetToDefaults()
{
m_inputFrequencyOffset = 0;
m_rfBandwidth = 2*1300000;
m_correlationThreshold = 0.0f;
m_samplesPerBit = 6;
m_removeTimeout = 60;
m_beastEnabled = false;
m_beastHost = "feed.adsbexchange.com";
m_beastPort = 30005;
m_rgbColor = QColor(255, 0, 0).rgb();
m_title = "ADS-B Demodulator";
m_streamIndex = 0;
m_useReverseAPI = false;
m_reverseAPIAddress = "127.0.0.1";
m_reverseAPIPort = 8888;
m_reverseAPIDeviceIndex = 0;
m_reverseAPIChannelIndex = 0;
}
QByteArray ADSBDemodSettings::serialize() const
{
SimpleSerializer s(1);
s.writeS32(1, m_inputFrequencyOffset);
s.writeReal(2, m_rfBandwidth);
s.writeReal(3, m_correlationThreshold);
s.writeS32(4, m_samplesPerBit);
s.writeS32(5, m_removeTimeout);
s.writeBool(6, m_beastEnabled);
s.writeString(7, m_beastHost);
s.writeU32(8, m_beastPort);
s.writeU32(9, m_rgbColor);
if (m_channelMarker) {
s.writeBlob(10, m_channelMarker->serialize());
}
s.writeString(11, m_title);
s.writeBool(12, m_useReverseAPI);
s.writeString(13, m_reverseAPIAddress);
s.writeU32(14, m_reverseAPIPort);
s.writeU32(15, m_reverseAPIDeviceIndex);
s.writeU32(16, m_reverseAPIChannelIndex);
s.writeS32(17, m_streamIndex);
return s.final();
}
bool ADSBDemodSettings::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if (!d.isValid())
{
resetToDefaults();
return false;
}
if (d.getVersion() == 1)
{
QByteArray bytetmp;
qint32 tmp;
uint32_t utmp;
if (m_channelMarker)
{
d.readBlob(10, &bytetmp);
m_channelMarker->deserialize(bytetmp);
}
d.readS32(1, &tmp, 0);
m_inputFrequencyOffset = tmp;
d.readReal(2, &m_rfBandwidth, 2*1300000);
d.readReal(3, &m_correlationThreshold, 1.0f);
d.readS32(4, &m_samplesPerBit, 6);
d.readS32(5, &m_removeTimeout, 60);
d.readBool(6, &m_beastEnabled, false);
d.readString(7, &m_beastHost, "feed.adsbexchange.com");
d.readU32(8, &utmp, 0);
if ((utmp > 1023) && (utmp < 65535)) {
m_beastPort = utmp;
} else {
m_beastPort = 30005;
}
d.readU32(9, &m_rgbColor, QColor(255, 0, 0).rgb());
d.readString(11, &m_title, "ADS-B Demodulator");
d.readBool(12, &m_useReverseAPI, false);
d.readString(13, &m_reverseAPIAddress, "127.0.0.1");
d.readU32(14, &utmp, 0);
if ((utmp > 1023) && (utmp < 65535)) {
m_reverseAPIPort = utmp;
} else {
m_reverseAPIPort = 8888;
}
d.readU32(15, &utmp, 0);
m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp;
d.readU32(16, &utmp, 0);
m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp;
d.readS32(17, &m_streamIndex, 0);
return true;
}
else
{
resetToDefaults();
return false;
}
}

Wyświetl plik

@ -0,0 +1,58 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_CHANNELRX_DEMODADSB_ADSBDEMODSETTINGS_H_
#define PLUGINS_CHANNELRX_DEMODADSB_ADSBDEMODSETTINGS_H_
#include <QtGlobal>
#include <QString>
#include <stdint.h>
#include "dsp/dsptypes.h"
class Serializable;
struct ADSBDemodSettings
{
int32_t m_inputFrequencyOffset;
Real m_rfBandwidth;
Real m_correlationThreshold;
int m_samplesPerBit;
int m_removeTimeout; // Time in seconds before removing an aircraft, unless a new frame is received
bool m_beastEnabled;
QString m_beastHost;
uint16_t m_beastPort;
quint32 m_rgbColor;
QString m_title;
int m_streamIndex; //!< MIMO channel. Not relevant when connected to SI (single Rx).
bool m_useReverseAPI;
QString m_reverseAPIAddress;
uint16_t m_reverseAPIPort;
uint16_t m_reverseAPIDeviceIndex;
uint16_t m_reverseAPIChannelIndex;
Serializable *m_channelMarker;
ADSBDemodSettings();
void resetToDefaults();
void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; }
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
};
#endif /* PLUGINS_CHANNELRX_DEMODADSB_ADSBDEMODSETTINGS_H_ */

Wyświetl plik

@ -0,0 +1,278 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <complex.h>
#include <QTime>
#include <QDebug>
#include "util/stepfunctions.h"
#include "util/db.h"
#include "util/crc.h"
#include "audio/audiooutput.h"
#include "dsp/dspengine.h"
#include "dsp/dspcommands.h"
#include "dsp/devicesamplemimo.h"
#include "device/deviceapi.h"
#include "adsbdemodreport.h"
#include "adsbdemodsink.h"
#include "adsb.h"
ADSBDemodSink::ADSBDemodSink() :
m_channelSampleRate(6000000),
m_channelFrequencyOffset(0),
m_sampleIdx(0),
m_sampleCount(0),
m_skipCount(0),
m_magsq(0.0f),
m_magsqSum(0.0f),
m_magsqPeak(0.0f),
m_magsqCount(0),
m_messageQueueToGUI(nullptr),
m_sampleBuffer(nullptr),
m_preamble(nullptr)
{
applySettings(m_settings, true);
applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true);
}
ADSBDemodSink::~ADSBDemodSink()
{
delete m_sampleBuffer;
delete m_preamble;
}
void ADSBDemodSink::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end)
{
Complex ci;
for (SampleVector::const_iterator it = begin; it != end; ++it)
{
Complex c(it->real(), it->imag());
c *= m_nco.nextIQ();
if (m_interpolatorDistance == 1.0f)
{
processOneSample(c);
}
else if (m_interpolatorDistance < 1.0f) // interpolate
{
while (!m_interpolator.interpolate(&m_interpolatorDistanceRemain, c, &ci))
{
processOneSample(ci);
m_interpolatorDistanceRemain += m_interpolatorDistance;
}
}
else // decimate
{
if (m_interpolator.decimate(&m_interpolatorDistanceRemain, c, &ci))
{
processOneSample(ci);
m_interpolatorDistanceRemain += m_interpolatorDistance;
}
}
}
}
void ADSBDemodSink::processOneSample(Complex &ci)
{
Real sample;
double magsqRaw = ci.real()*ci.real() + ci.imag()*ci.imag();
Real magsq = magsqRaw / (SDR_RX_SCALED*SDR_RX_SCALED);
m_movingAverage(magsq);
m_magsqSum += magsq;
if (magsq > m_magsqPeak)
{
m_magsqPeak = magsq;
}
m_magsqCount++;
sample = std::sqrtf(magsq);
m_sampleBuffer[m_sampleCount] = sample;
m_sampleCount++;
// Do we have enough data for a frame
if ((m_sampleCount >= m_totalSamples) && (m_skipCount == 0))
{
int startIdx = m_sampleCount - m_totalSamples;
// Correlate received signal with expected preamble
Real preambleCorrelation = 0.0f;
for (int i = 0; i < ADS_B_PREAMBLE_CHIPS*m_samplesPerChip; i++)
preambleCorrelation += m_preamble[i] * m_sampleBuffer[startIdx+i];
// If the correlation is exactly 0, it's probably no signal
if ((preambleCorrelation > m_settings.m_correlationThreshold) && (preambleCorrelation != 0.0f))
{
// Skip over preamble
startIdx += m_settings.m_samplesPerBit*ADS_B_PREAMBLE_BITS;
// Demodulate waveform to bytes
unsigned char data[ADS_B_ES_BYTES];
int byteIdx = 0;
int currentBit;
unsigned char currentByte = 0;
bool adsbOnly = true;
int df;
for (int bit = 0; bit < ADS_B_ES_BITS; bit++)
{
// PPM (Pulse position modulation) - Each bit spreads to two chips, 1->10, 0->01
// Determine if bit is 1 or 0, by seeing which chip has largest combined energy over the sampling period
Real oneSum = 0.0f;
Real zeroSum = 0.0f;
for (int i = 0; i < m_samplesPerChip; i++)
{
oneSum += m_sampleBuffer[startIdx+i];
zeroSum += m_sampleBuffer[startIdx+m_samplesPerChip+i];
}
currentBit = oneSum > zeroSum;
startIdx += m_settings.m_samplesPerBit;
// Convert bit to bytes - MSB first
currentByte |= currentBit << (7-(bit & 0x7));
if ((bit & 0x7) == 0x7)
{
data[byteIdx++] = currentByte;
currentByte = 0;
// Don't try to demodulate any further, if this isn't an ADS-B frame
// to help reduce processing overhead
if (adsbOnly && (bit == 7))
{
df = ((data[0] >> 3) & ADS_B_DF_MASK);
if ((df != 17) && (df != 18))
break;
}
}
}
// Is ADS-B?
df = ((data[0] >> 3) & ADS_B_DF_MASK);
if ((df == 17) || (df == 18))
{
crcadsb crc;
//int icao = (data[1] << 16) | (data[2] << 8) | data[3]; // ICAO aircraft address
int parity = (data[11] << 16) | (data[12] << 8) | data[13]; // Parity / CRC
crc.calculate(data, ADS_B_ES_BYTES-3);
if (parity == crc.get())
{
// Got a valid frame
// Don't try to re-demodulate the same frame
m_skipCount = (ADS_B_ES_BITS+ADS_B_PREAMBLE_BITS)*ADS_B_CHIPS_PER_BIT*m_samplesPerChip;
// Pass to GUI
if (getMessageQueueToGUI())
{
ADSBDemodReport::MsgReportADSB *msg = ADSBDemodReport::MsgReportADSB::create(QByteArray((char*)data, sizeof(data)), preambleCorrelation);
getMessageQueueToGUI()->push(msg);
}
// Pass to worker
if (getMessageQueueToWorker())
{
ADSBDemodReport::MsgReportADSB *msg = ADSBDemodReport::MsgReportADSB::create(QByteArray((char*)data, sizeof(data)), preambleCorrelation);
getMessageQueueToWorker()->push(msg);
}
}
}
}
}
if (m_skipCount > 0)
m_skipCount--;
if (m_sampleCount >= 2*m_totalSamples)
{
// Copy second half of buffer to first
memcpy(&m_sampleBuffer[0], &m_sampleBuffer[m_totalSamples], m_totalSamples*sizeof(Real));
m_sampleCount = m_totalSamples;
}
m_sampleIdx++;
}
void ADSBDemodSink::init(int samplesPerBit)
{
if (m_sampleBuffer)
delete m_sampleBuffer;
if (m_preamble)
delete m_preamble;
m_totalSamples = samplesPerBit*(ADS_B_PREAMBLE_BITS+ADS_B_ES_BITS);
m_samplesPerChip = samplesPerBit/ADS_B_CHIPS_PER_BIT;
m_sampleBuffer = new Real[2*m_totalSamples];
m_preamble = new Real[ADS_B_PREAMBLE_CHIPS*m_samplesPerChip];
// Possibly don't look for first chip
const int preambleChips[] = {1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1};
for (int i = 0; i < ADS_B_PREAMBLE_CHIPS; i++)
{
for (int j = 0; j < m_samplesPerChip; j++)
{
m_preamble[i*m_samplesPerChip+j] = preambleChips[i];
}
}
}
void ADSBDemodSink::applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force)
{
qDebug() << "ADSBDemodSink::applyChannelSettings:"
<< " channelSampleRate: " << channelSampleRate
<< " channelFrequencyOffset: " << channelFrequencyOffset;
if ((channelFrequencyOffset != m_channelFrequencyOffset) ||
(channelSampleRate != m_channelSampleRate) || force)
{
m_nco.setFreq(-channelFrequencyOffset, channelSampleRate);
}
if ((channelSampleRate != m_channelSampleRate) || force)
{
m_interpolator.create(16, channelSampleRate, m_settings.m_rfBandwidth / 2.2);
m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) channelSampleRate / (Real) (ADS_B_BITS_PER_SECOND * m_settings.m_samplesPerBit);
}
m_channelSampleRate = channelSampleRate;
m_channelFrequencyOffset = channelFrequencyOffset;
}
void ADSBDemodSink::applySettings(const ADSBDemodSettings& settings, bool force)
{
qDebug() << "ADSBDemodSink::applySettings:"
<< " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset
<< " m_rfBandwidth: " << settings.m_rfBandwidth
<< " m_correlationThreshold: " << settings.m_correlationThreshold
<< " m_samplesPerBit: " << settings.m_samplesPerBit
<< " force: " << force;
if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth)
|| (settings.m_samplesPerBit != m_settings.m_samplesPerBit) || force)
{
m_interpolator.create(16, m_channelSampleRate, settings.m_rfBandwidth / 2.2);
m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) m_channelSampleRate / (Real) (ADS_B_BITS_PER_SECOND * settings.m_samplesPerBit);
}
if ((settings.m_samplesPerBit != m_settings.m_samplesPerBit) || force)
{
init(settings.m_samplesPerBit);
}
m_settings = settings;
}

Wyświetl plik

@ -0,0 +1,106 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_ADSBDEMODSINK_H
#define INCLUDE_ADSBDEMODSINK_H
#include <vector>
#include "dsp/channelsamplesink.h"
#include "dsp/nco.h"
#include "dsp/interpolator.h"
#include "util/movingaverage.h"
#include "adsbdemodsettings.h"
class ADSBDemodSink : public ChannelSampleSink {
public:
ADSBDemodSink();
~ADSBDemodSink();
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end);
void getMagSqLevels(double& avg, double& peak, int& nbSamples)
{
if (m_magsqCount > 0)
{
m_magsq = m_magsqSum / m_magsqCount;
m_magSqLevelStore.m_magsq = m_magsq;
m_magSqLevelStore.m_magsqPeak = m_magsqPeak;
}
avg = m_magSqLevelStore.m_magsq;
peak = m_magSqLevelStore.m_magsqPeak;
nbSamples = m_magsqCount == 0 ? 1 : m_magsqCount;
m_magsqSum = 0.0f;
m_magsqPeak = 0.0f;
m_magsqCount = 0;
}
void init(int samplesPerBit);
void applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force = false);
void applySettings(const ADSBDemodSettings& settings, bool force = false);
void setMessageQueueToGUI(MessageQueue *messageQueue) { m_messageQueueToGUI = messageQueue; }
void setMessageQueueToWorker(MessageQueue *messageQueue) { m_messageQueueToWorker = messageQueue; }
private:
struct MagSqLevelsStore
{
MagSqLevelsStore() :
m_magsq(1e-12),
m_magsqPeak(1e-12)
{}
double m_magsq;
double m_magsqPeak;
};
int m_channelSampleRate;
int m_channelFrequencyOffset;
ADSBDemodSettings m_settings;
NCO m_nco;
Interpolator m_interpolator;
Real m_interpolatorDistance;
Real m_interpolatorDistanceRemain;
int m_sampleIdx;
int m_sampleCount;
int m_skipCount; // Samples to skip, because we've already received a frame
Real *m_sampleBuffer;
Real *m_preamble;
int m_totalSamples; // These two values are derived from samplesPerBit
int m_samplesPerChip;
double m_magsq; //!< displayed averaged value
double m_magsqSum;
double m_magsqPeak;
int m_magsqCount;
MagSqLevelsStore m_magSqLevelStore;
MovingAverageUtil<Real, double, 32> m_movingAverage;
MessageQueue *m_messageQueueToGUI;
MessageQueue *m_messageQueueToWorker;
void processOneSample(Complex &ci);
MessageQueue *getMessageQueueToGUI() { return m_messageQueueToGUI; }
MessageQueue *getMessageQueueToWorker() { return m_messageQueueToWorker; }
};
#endif // INCLUDE_ADSBDEMODSINK_H

Wyświetl plik

@ -0,0 +1,51 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 Edouard Griffiths, F4EXB. //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "SWGChannelSettings.h"
#include "adsbdemod.h"
#include "adsbdemodwebapiadapter.h"
ADSBDemodWebAPIAdapter::ADSBDemodWebAPIAdapter()
{}
ADSBDemodWebAPIAdapter::~ADSBDemodWebAPIAdapter()
{}
int ADSBDemodWebAPIAdapter::webapiSettingsGet(
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage)
{
(void) errorMessage;
response.setAdsbDemodSettings(new SWGSDRangel::SWGADSBDemodSettings());
response.getAdsbDemodSettings()->init();
ADSBDemod::webapiFormatChannelSettings(response, m_settings);
return 200;
}
int ADSBDemodWebAPIAdapter::webapiSettingsPutPatch(
bool force,
const QStringList& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage)
{
(void) errorMessage;
ADSBDemod::webapiUpdateChannelSettings(m_settings, channelSettingsKeys, response);
return 200;
}

Wyświetl plik

@ -0,0 +1,50 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 Edouard Griffiths, F4EXB. //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_ADSBDEMOD_WEBAPIADAPTER_H
#define INCLUDE_ADSBDEMOD_WEBAPIADAPTER_H
#include "channel/channelwebapiadapter.h"
#include "adsbdemodsettings.h"
/**
* Standalone API adapter only for the settings
*/
class ADSBDemodWebAPIAdapter : public ChannelWebAPIAdapter {
public:
ADSBDemodWebAPIAdapter();
virtual ~ADSBDemodWebAPIAdapter();
virtual QByteArray serialize() const { return m_settings.serialize(); }
virtual bool deserialize(const QByteArray& data) { return m_settings.deserialize(data); }
virtual int webapiSettingsGet(
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage);
virtual int webapiSettingsPutPatch(
bool force,
const QStringList& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage);
private:
ADSBDemodSettings m_settings;
};
#endif // INCLUDE_ADSBDEMOD_WEBAPIADAPTER_H

Wyświetl plik

@ -0,0 +1,197 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Jon Beniston, M7RCE //
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QDebug>
#include <QTcpServer>
#include <QTcpSocket>
#include <QEventLoop>
#include <QTimer>
#include "adsbdemodworker.h"
#include "adsbdemodreport.h"
MESSAGE_CLASS_DEFINITION(ADSBDemodWorker::MsgConfigureADSBDemodWorker, Message)
ADSBDemodWorker::ADSBDemodWorker() :
m_running(false),
m_mutex(QMutex::Recursive)
{
connect(&m_heartbeatTimer, SIGNAL(timeout()), this, SLOT(heartbeat()));
connect(&m_socket, SIGNAL(readyRead()),this, SLOT(recv()));
}
ADSBDemodWorker::~ADSBDemodWorker()
{
m_inputMessageQueue.clear();
}
void ADSBDemodWorker::reset()
{
QMutexLocker mutexLocker(&m_mutex);
m_inputMessageQueue.clear();
}
bool ADSBDemodWorker::startWork()
{
QMutexLocker mutexLocker(&m_mutex);
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
m_heartbeatTimer.start(60*1000);
m_running = true;
return m_running;
}
void ADSBDemodWorker::stopWork()
{
QMutexLocker mutexLocker(&m_mutex);
m_heartbeatTimer.stop();
disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
m_running = false;
}
void ADSBDemodWorker::handleInputMessages()
{
Message* message;
while ((message = m_inputMessageQueue.pop()) != nullptr)
{
if (handleMessage(*message)) {
delete message;
}
}
}
bool ADSBDemodWorker::handleMessage(const Message& message)
{
if (MsgConfigureADSBDemodWorker::match(message))
{
QMutexLocker mutexLocker(&m_mutex);
MsgConfigureADSBDemodWorker& cfg = (MsgConfigureADSBDemodWorker&) message;
applySettings(cfg.getSettings(), cfg.getForce());
return true;
}
else if (ADSBDemodReport::MsgReportADSB::match(message))
{
ADSBDemodReport::MsgReportADSB& report = (ADSBDemodReport::MsgReportADSB&) message;
handleADSB(report.getData(), report.getDateTime(), report.getPreambleCorrelation());
return true;
}
else
{
return false;
}
}
void ADSBDemodWorker::applySettings(const ADSBDemodSettings& settings, bool force)
{
qDebug() << "ADSBDemodWorker::applySettings:"
<< " m_beastEnabled: " << settings.m_beastEnabled
<< " m_beastHost: " << settings.m_beastHost
<< " m_beastPort: " << settings.m_beastPort
<< " force: " << force;
if ((settings.m_beastEnabled != m_settings.m_beastEnabled)
|| (settings.m_beastHost != m_settings.m_beastHost)
|| (settings.m_beastPort != m_settings.m_beastPort) || force)
{
// Close any existing connection
if (m_socket.isOpen())
m_socket.close();
// Open connection
if (settings.m_beastEnabled)
m_socket.connectToHost(settings.m_beastHost, settings.m_beastPort);
}
m_settings = settings;
}
void ADSBDemodWorker::recv()
{
// Not expecting to receving anything from server
qDebug() << "ADSBDemodWorker::recv";
qDebug() << m_socket.readAll();
}
void ADSBDemodWorker::send(const char *data, int length)
{
if (m_settings.m_beastEnabled)
{
// Reopen connection if it was lost
if (!m_socket.isOpen())
m_socket.connectToHost(m_settings.m_beastHost, m_settings.m_beastPort);
// Send data
m_socket.write(data, length);
}
}
#define BEAST_ESC 0x1a
char *ADSBDemodWorker::escape(char *p, char c)
{
*p++ = c;
if (c == BEAST_ESC)
*p++ = BEAST_ESC;
return p;
}
// Forward ADS-B data in Beast binary format to specified server
// See: https://wiki.jetvision.de/wiki/Mode-S_Beast:Data_Output_Formats
void ADSBDemodWorker::handleADSB(QByteArray data, const QDateTime dateTime, float correlation)
{
char beastBinary[2+6*2+1*2+14*2];
int length;
char *p = beastBinary;
qint64 timestamp;
unsigned char signalStrength;
timestamp = dateTime.toMSecsSinceEpoch();
if (correlation > 255)
signalStrength = 255;
if (correlation < 1)
signalStrength = 1;
else
signalStrength = (unsigned char)correlation;
*p++ = BEAST_ESC;
*p++ = '3'; // Mode-S long
p = escape(p, timestamp >> 56); // Big-endian timestamp
p = escape(p, timestamp >> 48);
p = escape(p, timestamp >> 32);
p = escape(p, timestamp >> 24);
p = escape(p, timestamp >> 16);
p = escape(p, timestamp >> 8);
p = escape(p, timestamp);
p = escape(p, signalStrength); // Signal strength
for (int i = 0; i < data.length(); i++) // ADS-B data
p = escape(p, data[i]);
length = p - beastBinary;
send(beastBinary, length);
}
// Periodically send heartbeat to keep connection alive
void ADSBDemodWorker::heartbeat()
{
const char heartbeat[] = {BEAST_ESC, '1', 0, 0, 0, 0, 0, 0, 0, 0, 0}; // Mode AC packet
send(heartbeat, sizeof(heartbeat));
}

Wyświetl plik

@ -0,0 +1,87 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Jon Beniston, M7RCE //
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_ADSBDEMODWORKER_H
#define INCLUDE_ADSBDEMODWORKER_H
#include <QObject>
#include <QTimer>
#include <QTcpSocket>
#include "util/message.h"
#include "util/messagequeue.h"
#include "adsbdemodsettings.h"
class ADSBDemodWorker : public QObject
{
Q_OBJECT
public:
class MsgConfigureADSBDemodWorker : public Message {
MESSAGE_CLASS_DECLARATION
public:
const ADSBDemodSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; }
static MsgConfigureADSBDemodWorker* create(const ADSBDemodSettings& settings, bool force)
{
return new MsgConfigureADSBDemodWorker(settings, force);
}
private:
ADSBDemodSettings m_settings;
bool m_force;
MsgConfigureADSBDemodWorker(const ADSBDemodSettings& settings, bool force) :
Message(),
m_settings(settings),
m_force(force)
{ }
};
ADSBDemodWorker();
~ADSBDemodWorker();
void reset();
bool startWork();
void stopWork();
bool isRunning() const { return m_running; }
MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
private:
MessageQueue m_inputMessageQueue;
ADSBDemodSettings m_settings;
bool m_running;
QMutex m_mutex;
QTimer m_heartbeatTimer;
QTcpSocket m_socket;
bool handleMessage(const Message& cmd);
void applySettings(const ADSBDemodSettings& settings, bool force = false);
void send(const char *data, int length);
char *escape(char *p, char c);
void handleADSB(QByteArray data, const QDateTime dateTime, float correlation);
private slots:
void handleInputMessages();
void recv();
void heartbeat();
};
#endif // INCLUDE_ADSBDEMODWORKER_H

Wyświetl plik

@ -0,0 +1,92 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QtPlugin>
#include "plugin/pluginapi.h"
#include "adsbplugin.h"
#ifndef SERVER_MODE
#include "adsbdemodgui.h"
#endif
#include "adsbdemod.h"
#include "adsbdemodwebapiadapter.h"
#include "adsbplugin.h"
const PluginDescriptor ADSBPlugin::m_pluginDescriptor = {
ADSBDemod::m_channelId,
QString("ADS-B Demodulator"),
QString("4.20.0"),
QString("(c) Jon Beniston, M7RCE"),
QString("https://github.com/f4exb/sdrangel"),
true,
QString("https://github.com/f4exb/sdrangel")
};
ADSBPlugin::ADSBPlugin(QObject* parent) :
QObject(parent),
m_pluginAPI(0)
{
}
const PluginDescriptor& ADSBPlugin::getPluginDescriptor() const
{
return m_pluginDescriptor;
}
void ADSBPlugin::initPlugin(PluginAPI* pluginAPI)
{
m_pluginAPI = pluginAPI;
// register demodulator
m_pluginAPI->registerRxChannel(ADSBDemod::m_channelIdURI, ADSBDemod::m_channelId, this);
}
void ADSBPlugin::createRxChannel(DeviceAPI *deviceAPI, BasebandSampleSink **bs, ChannelAPI **cs) const
{
if (bs || cs)
{
ADSBDemod *instance = new ADSBDemod(deviceAPI);
if (bs) {
*bs = instance;
}
if (cs) {
*cs = instance;
}
}
}
#ifdef SERVER_MODE
ChannelGUI* ADSBPlugin::createRxChannelGUI(
DeviceUISet *deviceUISet,
BasebandSampleSink *rxChannel) const
{
return 0;
}
#else
ChannelGUI* ADSBPlugin::createRxChannelGUI(DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel) const
{
return ADSBDemodGUI::create(m_pluginAPI, deviceUISet, rxChannel);
}
#endif
ChannelWebAPIAdapter* ADSBPlugin::createChannelWebAPIAdapter() const
{
return new ADSBDemodWebAPIAdapter();
}

Wyświetl plik

@ -0,0 +1,49 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_ADSBPLUGIN_H
#define INCLUDE_ADSBPLUGIN_H
#include <QObject>
#include "plugin/plugininterface.h"
class DeviceUISet;
class BasebandSampleSink;
class ADSBPlugin : public QObject, PluginInterface {
Q_OBJECT
Q_INTERFACES(PluginInterface)
Q_PLUGIN_METADATA(IID "sdrangel.channel.adsbdemod")
public:
explicit ADSBPlugin(QObject* parent = NULL);
const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI);
virtual void createRxChannel(DeviceAPI *deviceAPI, BasebandSampleSink **bs, ChannelAPI **cs) const;
virtual ChannelGUI* createRxChannelGUI(DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel) const;
virtual ChannelWebAPIAdapter* createChannelWebAPIAdapter() const;
private:
static const PluginDescriptor m_pluginDescriptor;
PluginAPI* m_pluginAPI;
};
#endif // INCLUDE_ADSBPLUGIN_H

Wyświetl plik

@ -0,0 +1,86 @@
<h1>ADS-B demodulator plugin</h1>
<h2>Introduction</h2>
This plugin can be used to receive and display ADS-B aircraft information. This is information about an aircraft, such as position, altitude, heading and speed, broadcast by aircraft on 1090MHz, in the 1090ES (Extended Squitter) format. 1090ES frames have a chip rate of 2Mchip/s, so the baseband sample rate should be set to be greater than 2MSa/s.
<h2>Interface</h2>
![ADS-B Demodulator plugin GUI](../../../doc/img/ADSBdemod_plugin.png)
<h3>1: Frequency shift from center frequency of reception value</h3>
Use the wheels to adjust the frequency shift in Hz from the center frequency of reception. Right click on a digit sets all digits on the right to zero. This effectively floors value at the digit position. Wheels are moved with the mousewheel while pointing at the wheel or by selecting the wheel with the left mouse click and using the keyboard arrows. Pressing shift simultaneously moves digit by 5 and pressing control moves it by 2. Left click on a digit sets the cursor position at this digit.
<h3>2: Channel power</h3>
Average total power in dB relative to a +/- 1.0 amplitude signal received in the pass band.
<h3>3: Level meter in dB</h3>
- top bar (green): average value
- bottom bar (blue green): instantaneous peak value
- tip vertical bar (bright green): peak hold value
<h3>4: RF bandwidth</h3>
This is the bandwidth in MHz of the channel signal before demodulation.
<h3>5: SR - Channel Sample Rate</h3>
This specifies the channel sample rate the demodulator uses. Values of 4M-12MSa/s are supported, 2MSa/s steps. Ideally, this should be set to the same value as the baseband sample rate (the sample rate received from the radio). If it is different from the baseband sample rate, interpolation or decimation will be performed as needed to match the rates. However, interpolation currently requires a significant amount of processing power and may result in dropped samples.
Higher channel sample rates may help decode more frames, but will require more processing power.
<h3>6: Threshold</h3>
This sets the correlation threshold between the received signal and expected 1090ES preamble, that is required to be exceeded before the demodulator will try to decode a frame. Lower values should decode more frames, but will require more processing power.
<h3>7: Feed</h3>
Checking Feed enables feeding received ADS-B frames to aggregators such as ADS-B Exchange: https://www.adsbexchange.com The server name and port to send the frames to should be entered in the Server and Port fields. For ADS-B Exchange, set Server to feed.adsbexchange.com and Port to 30005. You can check if you are feeding data to ADS-B Exchange (after about 30 seconds) at: https://www.adsbexchange.com/myip/ Frames are forwarded in the Beast binary format as described here: https://wiki.jetvision.de/wiki/Mode-S_Beast:Data_Output_Formats
<h3>ADS-B Data</h3>
The table displays the decoded ADS-B data for each aircraft. The data is not all able to be transmitted in a single ADS-B frame, so the table displays an amalgamation of the latest received data of each type.
![ADS-B Demodulator Data](../../../doc/img/ADSBdemod_plugin_table.png)
* ICAO ID - 24-bit hexidecimal ICAO aircraft address. This is unique for each aircraft.
* Flight No. - Airline flight number or callsign.
* Latitude - Vertical position coordinate, in decimal degrees.
* Longitude - Horizontal position coordinate, in decimal degrees.
* Altitude - Altitude in feet.
* Speed - Speed (either ground speed, indicated airspeed, or true airspeed) in knots.
* Heading - The direction the aircraft is heading, in degrees.
* Climb - The vertical climb rate (or descent rate if negative) in feet/minute.
* Categoty - The vehicle category, such as Light, Large, Heavy or Rotorcraft.
* Range - The range (distance) to the aircraft from the receiving antenna in kilometres. The location of the receiving antenna is set under the Preferences > My Position menu.
* Az/El - The azimuth and elevation angles to the aircraft from the receiving antenna in degrees. These values can be sent to a rotator controller to track the aircraft.
* Updated - The local time at which the last ADS-B message was received.
* RX Frames - A count of the number of ADS-B frames received from this aircraft.
* Correlation - Displays the minimum, average and maximum of the preamable correlation for each recevied frame. These values can be used to help select a threshold setting.
A suffix of L in the latitude and longitude columns, indicates the position is based on a local decode, using a single received frame and the position of the radio station. No suffix will be added for a global decode, which is based upon receving and odd and even frame.
If an ADS-B frame has not been received from an aircraft for 60 seconds, the aircraft is removed from the table and map.
Double clicking in an ICAO ID cell will open a Web browser and search for the corresponding aircraft on https://www.planespotters.net/
Double clicking in an Flight No cell will open a Web browser and search for the corresponding flight on https://www.flightradar24.com/
Double clicking in an Az/El cell will set the aircraft as the active target. The azimuth and elevation to the aicraft will be sent to a rotator controller plugin. The aircraft text will be coloured green, rather than blue, on the map.
Double clicking on any other cell in the table will centre the map on the corresponding aircraft.
<h3>Map</h3>
The map displays aircraft locations and data geographically.
![ADS-B Demodulator Map](../../../doc/img/ADSBdemod_plugin_map.png)
The initial antenna location is placed according to My Position set under the Preferences > My Position menu. The position is only updated when the ADS-B demodulator plugin is first opened.
Aircraft are only placed upon the map when a position can be calculated, which can require several frames to be received.
To pan around the map, click the left mouse button and drag. To zoom in or out, use the mouse scroll wheel.
<h3>Attribution</h3>
Icons are by Alice Design, Alex Ahineev, Verry Obito, Sean Maldjia, Tinashe Mugayi, Andreas Vögele and Angriawan Ditya Zulkarnain from the Noun Project https://thenounproject.com/

Wyświetl plik

@ -1,4 +1,7 @@
project(feature)
if (Qt5SerialPort_FOUND)
add_subdirectory(gs232controller)
endif()
add_subdirectory(rigctlserver)
add_subdirectory(simpleptt)

Wyświetl plik

@ -0,0 +1,64 @@
project(gs232controller)
set(gs232controller_SOURCES
gs232controller.cpp
gs232controllersettings.cpp
gs232controllerplugin.cpp
gs232controllerworker.cpp
gs232controllerwebapiadapter.cpp
)
set(gs232controller_HEADERS
gs232controller.h
gs232controllersettings.h
gs232controllerplugin.h
gs232controllerreport.h
gs232controllerworker.h
gs232controllerwebapiadapter.h
)
include_directories(
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
)
if(NOT SERVER_MODE)
set(gs232controller_SOURCES
${gs232controller_SOURCES}
gs232controllergui.cpp
gs232controllergui.ui
)
set(gs232controller_HEADERS
${gs232controller_HEADERS}
gs232controllergui.h
)
set(TARGET_NAME featuregs232controller)
set(TARGET_LIB Qt5::Widgets)
set(TARGET_LIB_GUI "sdrgui")
set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR})
else()
set(TARGET_NAME featuregs232controllersrv)
set(TARGET_LIB "")
set(TARGET_LIB_GUI "")
set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR})
endif()
add_library(${TARGET_NAME} SHARED
${gs232controller_SOURCES}
)
target_link_libraries(${TARGET_NAME}
Qt5::Core
Qt5::SerialPort
${TARGET_LIB}
sdrbase
${TARGET_LIB_GUI}
)
install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER})
if(WIN32)
# Run deployqt for serial libraries
include(DeployQt)
windeployqt(${TARGET_NAME} ${SDRANGEL_BINARY_BIN_DIR} ${PROJECT_SOURCE_DIR}/../../../sdrgui/resources)
endif()

Wyświetl plik

@ -0,0 +1,425 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Jon Beniston, M7RCE //
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QDebug>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QBuffer>
#include "SWGFeatureSettings.h"
#include "SWGFeatureReport.h"
#include "SWGFeatureActions.h"
#include "SWGSimplePTTReport.h"
#include "SWGDeviceState.h"
#include "dsp/dspengine.h"
#include "gs232controllerworker.h"
#include "gs232controller.h"
MESSAGE_CLASS_DEFINITION(GS232Controller::MsgConfigureGS232Controller, Message)
MESSAGE_CLASS_DEFINITION(GS232Controller::MsgStartStop, Message)
const QString GS232Controller::m_featureIdURI = "sdrangel.feature.gs232controller";
const QString GS232Controller::m_featureId = "GS232Controller";
GS232Controller::GS232Controller(WebAPIAdapterInterface *webAPIAdapterInterface) :
Feature(m_featureIdURI, webAPIAdapterInterface),
m_ptt(false)
{
qDebug("GS232Controller::GS232Controller: webAPIAdapterInterface: %p", webAPIAdapterInterface);
setObjectName(m_featureId);
m_worker = new GS232ControllerWorker(webAPIAdapterInterface);
m_state = StIdle;
m_errorMessage = "GS232Controller error";
}
GS232Controller::~GS232Controller()
{
if (m_worker->isRunning()) {
stop();
}
delete m_worker;
}
void GS232Controller::start()
{
qDebug("GS232Controller::start");
m_worker->reset();
m_worker->setMessageQueueToFeature(getInputMessageQueue());
m_worker->setMessageQueueToGUI(getMessageQueueToGUI());
bool ok = m_worker->startWork();
m_state = ok ? StRunning : StError;
m_thread.start();
GS232ControllerWorker::MsgConfigureGS232ControllerWorker *msg = GS232ControllerWorker::MsgConfigureGS232ControllerWorker::create(m_settings, true);
m_worker->getInputMessageQueue()->push(msg);
}
void GS232Controller::stop()
{
qDebug("GS232Controller::stop");
m_worker->stopWork();
m_state = StIdle;
m_thread.quit();
m_thread.wait();
}
bool GS232Controller::handleMessage(const Message& cmd)
{
if (MsgConfigureGS232Controller::match(cmd))
{
MsgConfigureGS232Controller& cfg = (MsgConfigureGS232Controller&) cmd;
qDebug() << "GS232Controller::handleMessage: MsgConfigureGS232Controller";
applySettings(cfg.getSettings(), cfg.getForce());
return true;
}
else if (MsgStartStop::match(cmd))
{
MsgStartStop& cfg = (MsgStartStop&) cmd;
qDebug() << "GS232Controller::handleMessage: MsgStartStop: start:" << cfg.getStartStop();
if (cfg.getStartStop()) {
start();
} else {
stop();
}
return true;
}
else if (GS232ControllerSettings::MsgChannelIndexChange::match(cmd))
{
GS232ControllerSettings::MsgChannelIndexChange& cfg = (GS232ControllerSettings::MsgChannelIndexChange&) cmd;
int newChannelIndex = cfg.getIndex();
qDebug() << "GS232Controller::handleMessage: MsgChannelIndexChange: " << newChannelIndex;
GS232ControllerSettings settings = m_settings;
settings.m_channelIndex = newChannelIndex;
applySettings(settings, false);
if (getMessageQueueToGUI())
{
GS232ControllerSettings::MsgChannelIndexChange *msg = new GS232ControllerSettings::MsgChannelIndexChange(cfg);
getMessageQueueToGUI()->push(msg);
}
return true;
}
else
{
return false;
}
}
QByteArray GS232Controller::serialize() const
{
return m_settings.serialize();
}
bool GS232Controller::deserialize(const QByteArray& data)
{
if (m_settings.deserialize(data))
{
MsgConfigureGS232Controller *msg = MsgConfigureGS232Controller::create(m_settings, true);
m_inputMessageQueue.push(msg);
return true;
}
else
{
m_settings.resetToDefaults();
MsgConfigureGS232Controller *msg = MsgConfigureGS232Controller::create(m_settings, true);
m_inputMessageQueue.push(msg);
return false;
}
}
void GS232Controller::applySettings(const GS232ControllerSettings& settings, bool force)
{
qDebug() << "GS232Controller::applySettings:"
<< " m_azimuth: " << settings.m_azimuth
<< " m_elevation: " << settings.m_elevation
<< " m_serialPort: " << settings.m_serialPort
<< " m_baudRate: " << settings.m_baudRate
<< " m_track: " << settings.m_track
<< " m_deviceIndex: " << settings.m_deviceIndex
<< " m_channelIndex: " << settings.m_channelIndex
<< " m_title: " << settings.m_title
<< " m_rgbColor: " << settings.m_rgbColor
<< " m_useReverseAPI: " << settings.m_useReverseAPI
<< " m_reverseAPIAddress: " << settings.m_reverseAPIAddress
<< " m_reverseAPIPort: " << settings.m_reverseAPIPort
<< " m_reverseAPIFeatureSetIndex: " << settings.m_reverseAPIFeatureSetIndex
<< " m_reverseAPIFeatureIndex: " << settings.m_reverseAPIFeatureIndex
<< " force: " << force;
QList<QString> reverseAPIKeys;
if ((m_settings.m_azimuth != settings.m_azimuth) || force) {
reverseAPIKeys.append("azimuth");
}
if ((m_settings.m_elevation != settings.m_elevation) || force) {
reverseAPIKeys.append("elevation");
}
if ((m_settings.m_serialPort != settings.m_serialPort) || force) {
reverseAPIKeys.append("serialPort");
}
if ((m_settings.m_baudRate != settings.m_baudRate) || force) {
reverseAPIKeys.append("baudRate");
}
if ((m_settings.m_track != settings.m_track) || force) {
reverseAPIKeys.append("track");
}
if ((m_settings.m_deviceIndex != settings.m_deviceIndex) || force) {
reverseAPIKeys.append("deviceIndex");
}
if ((m_settings.m_channelIndex != settings.m_channelIndex) || force) {
reverseAPIKeys.append("channelIndex");
}
if ((m_settings.m_title != settings.m_title) || force) {
reverseAPIKeys.append("title");
}
if ((m_settings.m_rgbColor != settings.m_rgbColor) || force) {
reverseAPIKeys.append("rgbColor");
}
GS232ControllerWorker::MsgConfigureGS232ControllerWorker *msg = GS232ControllerWorker::MsgConfigureGS232ControllerWorker::create(
settings, force
);
m_worker->getInputMessageQueue()->push(msg);
if (settings.m_useReverseAPI)
{
bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
(m_settings.m_reverseAPIAddress != settings.m_reverseAPIAddress) ||
(m_settings.m_reverseAPIPort != settings.m_reverseAPIPort) ||
(m_settings.m_reverseAPIFeatureSetIndex != settings.m_reverseAPIFeatureSetIndex) ||
(m_settings.m_reverseAPIFeatureIndex != settings.m_reverseAPIFeatureIndex);
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
m_settings = settings;
}
int GS232Controller::webapiRun(bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage)
{
getFeatureStateStr(*response.getState());
MsgStartStop *msg = MsgStartStop::create(run);
getInputMessageQueue()->push(msg);
return 202;
}
int GS232Controller::webapiSettingsGet(
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage)
{
(void) errorMessage;
response.setGs232ControllerSettings(new SWGSDRangel::SWGGS232ControllerSettings());
response.getGs232ControllerSettings()->init();
webapiFormatFeatureSettings(response, m_settings);
return 200;
}
int GS232Controller::webapiSettingsPutPatch(
bool force,
const QStringList& featureSettingsKeys,
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage)
{
(void) errorMessage;
GS232ControllerSettings settings = m_settings;
webapiUpdateFeatureSettings(settings, featureSettingsKeys, response);
MsgConfigureGS232Controller *msg = MsgConfigureGS232Controller::create(settings, force);
m_inputMessageQueue.push(msg);
qDebug("GS232Controller::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureGS232Controller *msgToGUI = MsgConfigureGS232Controller::create(settings, force);
m_guiMessageQueue->push(msgToGUI);
}
webapiFormatFeatureSettings(response, settings);
return 200;
}
void GS232Controller::webapiFormatFeatureSettings(
SWGSDRangel::SWGFeatureSettings& response,
const GS232ControllerSettings& settings)
{
response.getGs232ControllerSettings()->setAzimuth(settings.m_azimuth);
response.getGs232ControllerSettings()->setElevation(settings.m_elevation);
response.getGs232ControllerSettings()->setSerialPort(new QString(settings.m_serialPort));
response.getGs232ControllerSettings()->setBaudRate(settings.m_baudRate);
response.getGs232ControllerSettings()->setTrack(settings.m_track);
response.getGs232ControllerSettings()->setDeviceIndex(settings.m_deviceIndex);
response.getGs232ControllerSettings()->setChannelIndex(settings.m_channelIndex);
if (response.getGs232ControllerSettings()->getTitle()) {
*response.getGs232ControllerSettings()->getTitle() = settings.m_title;
} else {
response.getGs232ControllerSettings()->setTitle(new QString(settings.m_title));
}
response.getGs232ControllerSettings()->setRgbColor(settings.m_rgbColor);
response.getGs232ControllerSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
if (response.getGs232ControllerSettings()->getReverseApiAddress()) {
*response.getGs232ControllerSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
} else {
response.getGs232ControllerSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
}
response.getGs232ControllerSettings()->setReverseApiPort(settings.m_reverseAPIPort);
response.getGs232ControllerSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIFeatureSetIndex);
response.getGs232ControllerSettings()->setReverseApiChannelIndex(settings.m_reverseAPIFeatureIndex);
}
void GS232Controller::webapiUpdateFeatureSettings(
GS232ControllerSettings& settings,
const QStringList& featureSettingsKeys,
SWGSDRangel::SWGFeatureSettings& response)
{
if (featureSettingsKeys.contains("azimuth")) {
settings.m_azimuth = response.getGs232ControllerSettings()->getAzimuth();
}
if (featureSettingsKeys.contains("elevation")) {
settings.m_elevation = response.getGs232ControllerSettings()->getElevation();
}
if (featureSettingsKeys.contains("serialPort")) {
settings.m_serialPort = *response.getGs232ControllerSettings()->getSerialPort();
}
if (featureSettingsKeys.contains("baudRate")) {
settings.m_serialPort = response.getGs232ControllerSettings()->getBaudRate();
}
if (featureSettingsKeys.contains("track")) {
settings.m_track = response.getGs232ControllerSettings()->getTrack() != 0;
}
if (featureSettingsKeys.contains("deviceIndex")) {
settings.m_deviceIndex = response.getGs232ControllerSettings()->getDeviceIndex();
}
if (featureSettingsKeys.contains("channelIndex")) {
settings.m_channelIndex = response.getGs232ControllerSettings()->getChannelIndex();
}
if (featureSettingsKeys.contains("title")) {
settings.m_title = *response.getGs232ControllerSettings()->getTitle();
}
if (featureSettingsKeys.contains("rgbColor")) {
settings.m_rgbColor = response.getGs232ControllerSettings()->getRgbColor();
}
if (featureSettingsKeys.contains("useReverseAPI")) {
settings.m_useReverseAPI = response.getGs232ControllerSettings()->getUseReverseApi() != 0;
}
if (featureSettingsKeys.contains("reverseAPIAddress")) {
settings.m_reverseAPIAddress = *response.getGs232ControllerSettings()->getReverseApiAddress();
}
if (featureSettingsKeys.contains("reverseAPIPort")) {
settings.m_reverseAPIPort = response.getGs232ControllerSettings()->getReverseApiPort();
}
if (featureSettingsKeys.contains("reverseAPIDeviceIndex")) {
settings.m_reverseAPIFeatureSetIndex = response.getGs232ControllerSettings()->getReverseApiDeviceIndex();
}
if (featureSettingsKeys.contains("reverseAPIChannelIndex")) {
settings.m_reverseAPIFeatureIndex = response.getGs232ControllerSettings()->getReverseApiChannelIndex();
}
}
void GS232Controller::webapiReverseSendSettings(QList<QString>& featureSettingsKeys, const GS232ControllerSettings& settings, bool force)
{
SWGSDRangel::SWGFeatureSettings *swgFeatureSettings = new SWGSDRangel::SWGFeatureSettings();
// swgFeatureSettings->setOriginatorFeatureIndex(getIndexInDeviceSet());
// swgFeatureSettings->setOriginatorFeatureSetIndex(getDeviceSetIndex());
swgFeatureSettings->setFeatureType(new QString("GS232Controller"));
swgFeatureSettings->setGs232ControllerSettings(new SWGSDRangel::SWGGS232ControllerSettings());
SWGSDRangel::SWGGS232ControllerSettings *swgGS232ControllerSettings = swgFeatureSettings->getGs232ControllerSettings();
// transfer data that has been modified. When force is on transfer all data except reverse API data
if (featureSettingsKeys.contains("azimuth") || force) {
swgGS232ControllerSettings->setAzimuth(settings.m_azimuth);
}
if (featureSettingsKeys.contains("elevation") || force) {
swgGS232ControllerSettings->setElevation(settings.m_elevation);
}
if (featureSettingsKeys.contains("serialPort") || force) {
swgGS232ControllerSettings->setSerialPort(new QString(settings.m_serialPort));
}
if (featureSettingsKeys.contains("baudRate") || force) {
swgGS232ControllerSettings->setBaudRate(settings.m_baudRate);
}
if (featureSettingsKeys.contains("track") || force) {
swgGS232ControllerSettings->setTrack(settings.m_track);
}
if (featureSettingsKeys.contains("deviceIndex") || force) {
swgGS232ControllerSettings->setDeviceIndex(settings.m_deviceIndex);
}
if (featureSettingsKeys.contains("channelIndex") || force) {
swgGS232ControllerSettings->setChannelIndex(settings.m_channelIndex);
}
if (featureSettingsKeys.contains("title") || force) {
swgGS232ControllerSettings->setTitle(new QString(settings.m_title));
}
if (featureSettingsKeys.contains("rgbColor") || force) {
swgGS232ControllerSettings->setRgbColor(settings.m_rgbColor);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/featureset/%3/feature/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIFeatureSetIndex)
.arg(settings.m_reverseAPIFeatureIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgFeatureSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgFeatureSettings;
}
void GS232Controller::networkManagerFinished(QNetworkReply *reply)
{
QNetworkReply::NetworkError replyError = reply->error();
if (replyError)
{
qWarning() << "GS232Controller::networkManagerFinished:"
<< " error(" << (int) replyError
<< "): " << replyError
<< ": " << reply->errorString();
}
else
{
QString answer = reply->readAll();
answer.chop(1); // remove last \n
qDebug("GS232Controller::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
}
reply->deleteLater();
}

Wyświetl plik

@ -0,0 +1,140 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Jon Beniston, M7RCE //
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_FEATURE_GS232CONTROLLER_H_
#define INCLUDE_FEATURE_GS232CONTROLLER_H_
#include <QThread>
#include <QNetworkRequest>
#include "feature/feature.h"
#include "util/message.h"
#include "gs232controllersettings.h"
class WebAPIAdapterInterface;
class GS232ControllerWorker;
class QNetworkAccessManager;
class QNetworkReply;
namespace SWGSDRangel {
class SWGDeviceState;
}
class GS232Controller : public Feature
{
Q_OBJECT
public:
class MsgConfigureGS232Controller : public Message {
MESSAGE_CLASS_DECLARATION
public:
const GS232ControllerSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; }
static MsgConfigureGS232Controller* create(const GS232ControllerSettings& settings, bool force) {
return new MsgConfigureGS232Controller(settings, force);
}
private:
GS232ControllerSettings m_settings;
bool m_force;
MsgConfigureGS232Controller(const GS232ControllerSettings& settings, bool force) :
Message(),
m_settings(settings),
m_force(force)
{ }
};
class MsgStartStop : public Message {
MESSAGE_CLASS_DECLARATION
public:
bool getStartStop() const { return m_startStop; }
static MsgStartStop* create(bool startStop) {
return new MsgStartStop(startStop);
}
protected:
bool m_startStop;
MsgStartStop(bool startStop) :
Message(),
m_startStop(startStop)
{ }
};
GS232Controller(WebAPIAdapterInterface *webAPIAdapterInterface);
virtual ~GS232Controller();
virtual void destroy() { delete this; }
virtual bool handleMessage(const Message& cmd);
virtual const QString& getURI() const { return m_featureIdURI; }
virtual void getIdentifier(QString& id) const { id = m_featureId; }
virtual void getTitle(QString& title) const { title = m_settings.m_title; }
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);
virtual int webapiRun(bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage);
virtual int webapiSettingsGet(
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage);
virtual int webapiSettingsPutPatch(
bool force,
const QStringList& featureSettingsKeys,
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage);
static void webapiFormatFeatureSettings(
SWGSDRangel::SWGFeatureSettings& response,
const GS232ControllerSettings& settings);
static void webapiUpdateFeatureSettings(
GS232ControllerSettings& settings,
const QStringList& featureSettingsKeys,
SWGSDRangel::SWGFeatureSettings& response);
static const QString m_featureIdURI;
static const QString m_featureId;
private:
QThread m_thread;
GS232ControllerWorker *m_worker;
GS232ControllerSettings m_settings;
bool m_ptt;
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
void start();
void stop();
void applySettings(const GS232ControllerSettings& settings, bool force = false);
void webapiReverseSendSettings(QList<QString>& featureSettingsKeys, const GS232ControllerSettings& settings, bool force);
private slots:
void networkManagerFinished(QNetworkReply *reply);
};
#endif // INCLUDE_FEATURE_GS232CONTROLLER_H_

Wyświetl plik

@ -0,0 +1,447 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Jon Beniston, M7RCE //
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QMessageBox>
#include <QLineEdit>
#include <QSerialPortInfo>
#include "feature/featureuiset.h"
#include "gui/basicfeaturesettingsdialog.h"
#include "mainwindow.h"
#include "device/deviceuiset.h"
#include "ui_gs232controllergui.h"
#include "gs232controller.h"
#include "gs232controllergui.h"
#include "gs232controllerreport.h"
GS232ControllerGUI* GS232ControllerGUI::create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature)
{
GS232ControllerGUI* gui = new GS232ControllerGUI(pluginAPI, featureUISet, feature);
return gui;
}
void GS232ControllerGUI::destroy()
{
delete this;
}
void GS232ControllerGUI::resetToDefaults()
{
m_settings.resetToDefaults();
displaySettings();
applySettings(true);
}
QByteArray GS232ControllerGUI::serialize() const
{
qDebug("GS232ControllerGUI::serialize: %d", m_settings.m_channelIndex);
return m_settings.serialize();
}
bool GS232ControllerGUI::deserialize(const QByteArray& data)
{
if (m_settings.deserialize(data))
{
qDebug("GS232ControllerGUI::deserialize: %d", m_settings.m_channelIndex);
updateDeviceSetList();
displaySettings();
applySettings(true);
return true;
}
else
{
resetToDefaults();
return false;
}
}
bool GS232ControllerGUI::handleMessage(const Message& message)
{
if (GS232Controller::MsgConfigureGS232Controller::match(message))
{
qDebug("GS232ControllerGUI::handleMessage: GS232Controller::MsgConfigureGS232Controller");
const GS232Controller::MsgConfigureGS232Controller& cfg = (GS232Controller::MsgConfigureGS232Controller&) message;
m_settings = cfg.getSettings();
blockApplySettings(true);
displaySettings();
blockApplySettings(false);
return true;
}
else if (GS232ControllerSettings::MsgChannelIndexChange::match(message))
{
const GS232ControllerSettings::MsgChannelIndexChange& cfg = (GS232ControllerSettings::MsgChannelIndexChange&) message;
int newChannelIndex = cfg.getIndex();
qDebug("GS232ControllerGUI::handleMessage: GS232ControllerSettings::MsgChannelIndexChange: %d", newChannelIndex);
ui->channel->blockSignals(true);
ui->channel->setCurrentIndex(newChannelIndex);
m_settings.m_channelIndex = newChannelIndex;
ui->channel->blockSignals(false);
return true;
} else if (GS232ControllerReport::MsgReportAzAl::match(message))
{
GS232ControllerReport::MsgReportAzAl& azAl = (GS232ControllerReport::MsgReportAzAl&) message;
if (azAl.getType() == GS232ControllerReport::AzAlType::TARGET)
{
ui->azimuth->setValue(std::round(azAl.getAzimuth()));
ui->elevation->setValue(std::round(azAl.getElevation()));
}
else
{
ui->azimuthCurrentText->setText(QString("%1").arg(std::round(azAl.getAzimuth())));
ui->elevationCurrentText->setText(QString("%1").arg(std::round(azAl.getElevation())));
}
return true;
}
return false;
}
void GS232ControllerGUI::handleInputMessages()
{
Message* message;
while ((message = getInputMessageQueue()->pop()))
{
if (handleMessage(*message)) {
delete message;
}
}
}
void GS232ControllerGUI::onWidgetRolled(QWidget* widget, bool rollDown)
{
(void) widget;
(void) rollDown;
}
GS232ControllerGUI::GS232ControllerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent) :
FeatureGUI(parent),
ui(new Ui::GS232ControllerGUI),
m_pluginAPI(pluginAPI),
m_featureUISet(featureUISet),
m_doApplySettings(true),
m_lastFeatureState(0)
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose, true);
setChannelWidget(false);
connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
m_gs232Controller = reinterpret_cast<GS232Controller*>(feature);
m_gs232Controller->setMessageQueueToGUI(&m_inputMessageQueue);
m_featureUISet->addRollupWidget(this);
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
m_statusTimer.start(1000);
updateSerialPortList();
updateDeviceSetList();
displaySettings();
applySettings(true);
}
GS232ControllerGUI::~GS232ControllerGUI()
{
delete ui;
}
void GS232ControllerGUI::blockApplySettings(bool block)
{
m_doApplySettings = !block;
}
void GS232ControllerGUI::displaySettings()
{
setTitleColor(m_settings.m_rgbColor);
setWindowTitle(m_settings.m_title);
blockApplySettings(true);
ui->azimuth->setValue(m_settings.m_azimuth);
ui->elevation->setValue(m_settings.m_elevation);
if (m_settings.m_serialPort.length() > 0)
ui->serialPort->lineEdit()->setText(m_settings.m_serialPort);
ui->baudRate->setCurrentText(QString("%1").arg(m_settings.m_baudRate));
ui->track->setChecked(m_settings.m_track);
blockApplySettings(false);
}
void GS232ControllerGUI::updateSerialPortList()
{
ui->serialPort->clear();
QList<QSerialPortInfo> serialPorts = QSerialPortInfo::availablePorts();
QListIterator<QSerialPortInfo> i(serialPorts);
while (i.hasNext())
{
QSerialPortInfo info = i.next();
ui->serialPort->addItem(info.portName());
}
}
void GS232ControllerGUI::updateDeviceSetList()
{
MainWindow *mainWindow = MainWindow::getInstance();
std::vector<DeviceUISet*>& deviceUISets = mainWindow->getDeviceUISets();
std::vector<DeviceUISet*>::const_iterator it = deviceUISets.begin();
ui->device->blockSignals(true);
ui->device->clear();
unsigned int deviceIndex = 0;
for (; it != deviceUISets.end(); ++it, deviceIndex++)
{
DSPDeviceSourceEngine *deviceSourceEngine = (*it)->m_deviceSourceEngine;
DSPDeviceSinkEngine *deviceSinkEngine = (*it)->m_deviceSinkEngine;
DSPDeviceMIMOEngine *deviceMIMOEngine = (*it)->m_deviceMIMOEngine;
if (deviceSourceEngine) {
ui->device->addItem(QString("R%1").arg(deviceIndex), deviceIndex);
}
}
int newDeviceIndex;
if (it != deviceUISets.begin())
{
if (m_settings.m_deviceIndex < 0) {
ui->device->setCurrentIndex(0);
} else {
ui->device->setCurrentIndex(m_settings.m_deviceIndex);
}
newDeviceIndex = ui->device->currentData().toInt();
}
else
{
newDeviceIndex = -1;
}
if (newDeviceIndex != m_settings.m_deviceIndex)
{
qDebug("GS232ControllerGUI::updateDeviceSetLists: device index changed: %d", newDeviceIndex);
m_settings.m_deviceIndex = newDeviceIndex;
}
updateChannelList();
ui->device->blockSignals(false);
}
bool GS232ControllerGUI::updateChannelList()
{
int newChannelIndex;
ui->channel->blockSignals(true);
ui->channel->clear();
if (m_settings.m_deviceIndex < 0)
{
newChannelIndex = -1;
}
else
{
MainWindow *mainWindow = MainWindow::getInstance();
std::vector<DeviceUISet*>& deviceUISets = mainWindow->getDeviceUISets();
DeviceUISet *deviceUISet = deviceUISets[m_settings.m_deviceIndex];
int nbChannels = deviceUISet->getNumberOfChannels();
for (int ch = 0; ch < nbChannels; ch++) {
ui->channel->addItem(QString("%1").arg(ch), ch);
}
if (nbChannels > 0)
{
if (m_settings.m_channelIndex < 0) {
ui->channel->setCurrentIndex(0);
} else {
ui->channel->setCurrentIndex(m_settings.m_channelIndex);
}
newChannelIndex = ui->channel->currentIndex();
}
else
{
newChannelIndex = -1;
}
}
ui->channel->blockSignals(false);
if (newChannelIndex != m_settings.m_channelIndex)
{
qDebug("GS232ControllerGUI::updateChannelList: channel index changed: %d", newChannelIndex);
m_settings.m_channelIndex = newChannelIndex;
return true;
}
return false;
}
void GS232ControllerGUI::leaveEvent(QEvent*)
{
}
void GS232ControllerGUI::enterEvent(QEvent*)
{
}
void GS232ControllerGUI::onMenuDialogCalled(const QPoint &p)
{
if (m_contextMenuType == ContextMenuChannelSettings)
{
BasicFeatureSettingsDialog dialog(this);
dialog.setTitle(m_settings.m_title);
dialog.setColor(m_settings.m_rgbColor);
dialog.setUseReverseAPI(m_settings.m_useReverseAPI);
dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress);
dialog.setReverseAPIPort(m_settings.m_reverseAPIPort);
dialog.setReverseAPIFeatureSetIndex(m_settings.m_reverseAPIFeatureSetIndex);
dialog.setReverseAPIFeatureIndex(m_settings.m_reverseAPIFeatureIndex);
dialog.move(p);
dialog.exec();
m_settings.m_rgbColor = dialog.getColor().rgb();
m_settings.m_title = dialog.getTitle();
m_settings.m_useReverseAPI = dialog.useReverseAPI();
m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress();
m_settings.m_reverseAPIPort = dialog.getReverseAPIPort();
m_settings.m_reverseAPIFeatureSetIndex = dialog.getReverseAPIFeatureSetIndex();
m_settings.m_reverseAPIFeatureIndex = dialog.getReverseAPIFeatureIndex();
setWindowTitle(m_settings.m_title);
setTitleColor(m_settings.m_rgbColor);
applySettings();
}
resetContextMenuType();
}
void GS232ControllerGUI::on_startStop_toggled(bool checked)
{
if (m_doApplySettings)
{
GS232Controller::MsgStartStop *message = GS232Controller::MsgStartStop::create(checked);
m_gs232Controller->getInputMessageQueue()->push(message);
}
}
void GS232ControllerGUI::on_devicesRefresh_clicked()
{
updateDeviceSetList();
displaySettings();
applySettings();
}
void GS232ControllerGUI::on_device_currentIndexChanged(int index)
{
if (index >= 0)
{
m_settings.m_deviceIndex = ui->device->currentData().toInt();
updateChannelList();
applySettings();
}
}
void GS232ControllerGUI::on_channel_currentIndexChanged(int index)
{
if (index >= 0)
{
m_settings.m_channelIndex = index;
applySettings();
}
}
void GS232ControllerGUI::on_serialPort_currentIndexChanged(int index)
{
m_settings.m_serialPort = ui->serialPort->currentText();
applySettings();
}
void GS232ControllerGUI::on_baudRate_currentIndexChanged(int index)
{
m_settings.m_baudRate = ui->baudRate->currentText().toInt();
applySettings();
}
void GS232ControllerGUI::on_azimuth_valueChanged(int value)
{
m_settings.m_azimuth = value;
applySettings();
}
void GS232ControllerGUI::on_elevation_valueChanged(int value)
{
m_settings.m_elevation = value;
applySettings();
}
void GS232ControllerGUI::on_track_stateChanged(int state)
{
m_settings.m_track = state == Qt::Checked;
ui->devicesRefresh->setEnabled(m_settings.m_track);
ui->deviceLabel->setEnabled(m_settings.m_track);
ui->device->setEnabled(m_settings.m_track);
ui->channelLabel->setEnabled(m_settings.m_track);
ui->channel->setEnabled(m_settings.m_track);
applySettings();
}
void GS232ControllerGUI::updateStatus()
{
int state = m_gs232Controller->getState();
if (m_lastFeatureState != state)
{
switch (state)
{
case Feature::StNotStarted:
ui->startStop->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
break;
case Feature::StIdle:
ui->startStop->setStyleSheet("QToolButton { background-color : blue; }");
break;
case Feature::StRunning:
ui->startStop->setStyleSheet("QToolButton { background-color : green; }");
break;
case Feature::StError:
ui->startStop->setStyleSheet("QToolButton { background-color : red; }");
QMessageBox::information(this, tr("Message"), m_gs232Controller->getErrorMessage());
break;
default:
break;
}
m_lastFeatureState = state;
}
}
void GS232ControllerGUI::applySettings(bool force)
{
if (m_doApplySettings)
{
GS232Controller::MsgConfigureGS232Controller* message = GS232Controller::MsgConfigureGS232Controller::create(m_settings, force);
m_gs232Controller->getInputMessageQueue()->push(message);
}
}

Wyświetl plik

@ -0,0 +1,90 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Jon Beniston, M7RCE //
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_FEATURE_GS232CONTROLLERGUI_H_
#define INCLUDE_FEATURE_GS232CONTROLLERGUI_H_
#include <QTimer>
#include "feature/featuregui.h"
#include "util/messagequeue.h"
#include "gs232controllersettings.h"
class PluginAPI;
class FeatureUISet;
class GS232Controller;
namespace Ui {
class GS232ControllerGUI;
}
class GS232ControllerGUI : public FeatureGUI {
Q_OBJECT
public:
static GS232ControllerGUI* create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature);
virtual void destroy();
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
private:
Ui::GS232ControllerGUI* ui;
PluginAPI* m_pluginAPI;
FeatureUISet* m_featureUISet;
GS232ControllerSettings m_settings;
bool m_doApplySettings;
GS232Controller* m_gs232Controller;
MessageQueue m_inputMessageQueue;
QTimer m_statusTimer;
int m_lastFeatureState;
explicit GS232ControllerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent = nullptr);
virtual ~GS232ControllerGUI();
void blockApplySettings(bool block);
void applySettings(bool force = false);
void displaySettings();
void updateSerialPortList();
void updateDeviceSetList();
bool updateChannelList(); //!< true if channel index has changed
bool handleMessage(const Message& message);
void leaveEvent(QEvent*);
void enterEvent(QEvent*);
private slots:
void onMenuDialogCalled(const QPoint &p);
void onWidgetRolled(QWidget* widget, bool rollDown);
void handleInputMessages();
void on_startStop_toggled(bool checked);
void on_devicesRefresh_clicked();
void on_device_currentIndexChanged(int index);
void on_channel_currentIndexChanged(int index);
void on_serialPort_currentIndexChanged(int index);
void on_baudRate_currentIndexChanged(int index);
void on_track_stateChanged(int state);
void on_azimuth_valueChanged(int value);
void on_elevation_valueChanged(int value);
void updateStatus();
};
#endif // INCLUDE_FEATURE_GS232CONTROLLERGUI_H_

Wyświetl plik

@ -0,0 +1,397 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>GS232ControllerGUI</class>
<widget class="RollupWidget" name="GS232ControllerGUI">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>320</width>
<height>187</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>320</width>
<height>100</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>320</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Sans</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="windowTitle">
<string>GS-232 Rotator Controller</string>
</property>
<widget class="QWidget" name="settingsContainer" native="true">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>301</width>
<height>171</height>
</rect>
</property>
<property name="windowTitle">
<string>Settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<layout class="QHBoxLayout" name="controlLayout">
<item>
<widget class="ButtonSwitch" name="startStop">
<property name="toolTip">
<string>start/stop acquisition</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/play.png</normaloff>
<normalon>:/stop.png</normalon>:/play.png</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="azimuthtLabel">
<property name="text">
<string>Azimuth</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="azimuth">
<property name="toolTip">
<string>Target azimuth in degrees</string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>450</number>
</property>
<property name="value">
<number>359</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="azimuthCurrentText">
<property name="minimumSize">
<size>
<width>23</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Current azimuth in degrees</string>
</property>
<property name="text">
<string>-</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="elevationLabel">
<property name="text">
<string>Elevation</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="elevation">
<property name="toolTip">
<string>Target elevation in degrees</string>
</property>
<property name="maximum">
<number>180</number>
</property>
<property name="value">
<number>180</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="elevationCurrentText">
<property name="minimumSize">
<size>
<width>22</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Current elevation in degrees</string>
</property>
<property name="text">
<string>-</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="serverLayout">
<item>
<widget class="QLabel" name="serialLabel">
<property name="text">
<string>Serial Port</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="serialPort">
<property name="toolTip">
<string>Name of serial port to use to connect to the GS-232 controller</string>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="baudRateLabel">
<property name="text">
<string>Baud rate</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="baudRate">
<property name="toolTip">
<string>Serial port baud rate for the GS-232 controller</string>
</property>
<property name="currentIndex">
<number>3</number>
</property>
<item>
<property name="text">
<string>1200</string>
</property>
</item>
<item>
<property name="text">
<string>2400</string>
</property>
</item>
<item>
<property name="text">
<string>4800</string>
</property>
</item>
<item>
<property name="text">
<string>9600</string>
</property>
</item>
<item>
<property name="text">
<string>19200</string>
</property>
</item>
<item>
<property name="text">
<string>38400</string>
</property>
</item>
<item>
<property name="text">
<string>57600</string>
</property>
</item>
<item>
<property name="text">
<string>115200</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="localDeviceLayout">
<item>
<widget class="QCheckBox" name="track">
<property name="toolTip">
<string>Check to enable automatic tracking of azimuth and elevation from the specified channel</string>
</property>
<property name="text">
<string>Track</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="devicesRefresh">
<property name="maximumSize">
<size>
<width>24</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Refresh indexes of available device sets</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/recycle.png</normaloff>:/recycle.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="deviceLabel">
<property name="text">
<string>Device</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="device">
<property name="minimumSize">
<size>
<width>55</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Receiver deviceset index</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="channelLabel">
<property name="text">
<string>Channel</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="channel">
<property name="minimumSize">
<size>
<width>55</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Channel index</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="channelLayout">
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>RollupWidget</class>
<extends>QWidget</extends>
<header>gui/rollupwidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ButtonSwitch</class>
<extends>QToolButton</extends>
<header>gui/buttonswitch.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../../../sdrgui/resources/res.qrc"/>
</resources>
<connections/>
</ui>

Wyświetl plik

@ -0,0 +1,80 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Jon Beniston, M7RCE //
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QtPlugin>
#include "plugin/pluginapi.h"
#ifndef SERVER_MODE
#include "gs232controllergui.h"
#endif
#include "gs232controller.h"
#include "gs232controllerplugin.h"
#include "gs232controllerwebapiadapter.h"
const PluginDescriptor GS232ControllerPlugin::m_pluginDescriptor = {
GS232Controller::m_featureId,
QString("GS-232 Rotator Controller"),
QString("4.20.0"),
QString("(c) Jon Beniston, M7RCE"),
QString("https://github.com/f4exb/sdrangel"),
true,
QString("https://github.com/f4exb/sdrangel")
};
GS232ControllerPlugin::GS232ControllerPlugin(QObject* parent) :
QObject(parent),
m_pluginAPI(nullptr)
{
}
const PluginDescriptor& GS232ControllerPlugin::getPluginDescriptor() const
{
return m_pluginDescriptor;
}
void GS232ControllerPlugin::initPlugin(PluginAPI* pluginAPI)
{
m_pluginAPI = pluginAPI;
m_pluginAPI->registerFeature(GS232Controller::m_featureIdURI, GS232Controller::m_featureId, this);
}
#ifdef SERVER_MODE
FeatureGUI* GS232ControllerPlugin::createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const
{
(void) featureUISet;
(void) feature;
return nullptr;
}
#else
FeatureGUI* GS232ControllerPlugin::createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const
{
return GS232ControllerGUI::create(m_pluginAPI, featureUISet, feature);
}
#endif
Feature* GS232ControllerPlugin::createFeature(WebAPIAdapterInterface* webAPIAdapterInterface) const
{
return new GS232Controller(webAPIAdapterInterface);
}
FeatureWebAPIAdapter* GS232ControllerPlugin::createFeatureWebAPIAdapter() const
{
return new GS232ControllerWebAPIAdapter();
}

Wyświetl plik

@ -0,0 +1,49 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Jon Beniston, M7RCE //
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_FEATURE_GS232CONTROLLERPLUGIN_H
#define INCLUDE_FEATURE_GS232CONTROLLERPLUGIN_H
#include <QObject>
#include "plugin/plugininterface.h"
class FeatureGUI;
class WebAPIAdapterInterface;
class GS232ControllerPlugin : public QObject, PluginInterface {
Q_OBJECT
Q_INTERFACES(PluginInterface)
Q_PLUGIN_METADATA(IID "sdrangel.feature.gs232controller")
public:
explicit GS232ControllerPlugin(QObject* parent = nullptr);
const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI);
virtual FeatureGUI* createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const;
virtual Feature* createFeature(WebAPIAdapterInterface *webAPIAdapterInterface) const;
virtual FeatureWebAPIAdapter* createFeatureWebAPIAdapter() const;
private:
static const PluginDescriptor m_pluginDescriptor;
PluginAPI* m_pluginAPI;
};
#endif // INCLUDE_FEATURE_GS232CONTROLLERPLUGIN_H

Wyświetl plik

@ -0,0 +1,64 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_FEATURE_GS232CONTROLLERREPORT_H_
#define INCLUDE_FEATURE_GS232CONTROLLERREPORT_H_
#include <QObject>
#include "util/message.h"
class GS232ControllerReport : public QObject
{
Q_OBJECT
public:
enum AzAlType {TARGET, ACTUAL};
class MsgReportAzAl : public Message {
MESSAGE_CLASS_DECLARATION
public:
float getAzimuth() const { return m_azimuth; }
float getElevation() const { return m_elevation; }
AzAlType getType() const { return m_type; }
static MsgReportAzAl* create(float azimuth, float elevation, AzAlType type)
{
return new MsgReportAzAl(azimuth, elevation, type);
}
private:
float m_azimuth;
float m_elevation;
AzAlType m_type;
MsgReportAzAl(float azimuth, float elevation, AzAlType type) :
Message(),
m_azimuth(azimuth),
m_elevation(elevation),
m_type(type)
{
}
};
public:
GS232ControllerReport() {}
~GS232ControllerReport() {}
};
#endif // INCLUDE_FEATURE_GS232CONTROLLERREPORT_H_

Wyświetl plik

@ -0,0 +1,121 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Jon Beniston, M7RCE //
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QColor>
#include "util/simpleserializer.h"
#include "settings/serializable.h"
#include "gs232controllersettings.h"
MESSAGE_CLASS_DEFINITION(GS232ControllerSettings::MsgChannelIndexChange, Message)
GS232ControllerSettings::GS232ControllerSettings()
{
resetToDefaults();
}
void GS232ControllerSettings::resetToDefaults()
{
m_azimuth = 0;
m_elevation = 0;
m_serialPort = "";
m_baudRate = 9600;
m_track = false;
m_deviceIndex = -1;
m_channelIndex = -1;
m_title = "GS-232 Rotator Controller";
m_rgbColor = QColor(225, 25, 99).rgb();
m_useReverseAPI = false;
m_reverseAPIAddress = "127.0.0.1";
m_reverseAPIPort = 8888;
m_reverseAPIFeatureSetIndex = 0;
m_reverseAPIFeatureIndex = 0;
}
QByteArray GS232ControllerSettings::serialize() const
{
SimpleSerializer s(1);
s.writeS32(1, m_azimuth);
s.writeS32(2, m_elevation);
s.writeString(3, m_serialPort);
s.writeS32(4, m_baudRate);
s.writeBool(5, m_track);
s.writeS32(6, m_deviceIndex);
s.writeS32(7, m_channelIndex);
s.writeString(8, m_title);
s.writeU32(9, m_rgbColor);
s.writeBool(10, m_useReverseAPI);
s.writeString(11, m_reverseAPIAddress);
s.writeU32(12, m_reverseAPIPort);
s.writeU32(13, m_reverseAPIFeatureSetIndex);
s.writeU32(14, m_reverseAPIFeatureIndex);
return s.final();
}
bool GS232ControllerSettings::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if (!d.isValid())
{
resetToDefaults();
return false;
}
if (d.getVersion() == 1)
{
QByteArray bytetmp;
qint32 tmp;
uint32_t utmp;
QString strtmp;
d.readS32(1, &m_azimuth, 0);
d.readS32(2, &m_elevation, 0);
d.readString(3, &m_serialPort, "");
d.readS32(4, &m_baudRate, 9600);
d.readBool(5, &m_track, false);
d.readS32(6, &m_deviceIndex, -1);
d.readS32(7, &m_channelIndex, -1);
d.readString(8, &m_title, "GS-232 Rotator Controller");
d.readU32(9, &m_rgbColor, QColor(225, 25, 99).rgb());
d.readBool(10, &m_useReverseAPI, false);
d.readString(11, &m_reverseAPIAddress, "127.0.0.1");
d.readU32(12, &utmp, 0);
if ((utmp > 1023) && (utmp < 65535)) {
m_reverseAPIPort = utmp;
} else {
m_reverseAPIPort = 8888;
}
d.readU32(13, &utmp, 0);
m_reverseAPIFeatureSetIndex = utmp > 99 ? 99 : utmp;
d.readU32(14, &utmp, 0);
m_reverseAPIFeatureIndex = utmp > 99 ? 99 : utmp;
return true;
}
else
{
resetToDefaults();
return false;
}
}

Wyświetl plik

@ -0,0 +1,71 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Jon Beniston, M7RCE //
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_FEATURE_GS232CONTROLLERSETTINGS_H_
#define INCLUDE_FEATURE_GS232CONTROLLERSETTINGS_H_
#include <QByteArray>
#include <QString>
#include "util/message.h"
class Serializable;
struct GS232ControllerSettings
{
class MsgChannelIndexChange : public Message {
MESSAGE_CLASS_DECLARATION
public:
bool getIndex() const { return m_index; }
static MsgChannelIndexChange* create(int index) {
return new MsgChannelIndexChange(index);
}
protected:
int m_index;
MsgChannelIndexChange(int index) :
Message(),
m_index(index)
{ }
};
int m_azimuth;
int m_elevation;
QString m_serialPort;
int m_baudRate;
int m_deviceIndex;
bool m_track;
int m_channelIndex;
QString m_title;
quint32 m_rgbColor;
bool m_useReverseAPI;
QString m_reverseAPIAddress;
uint16_t m_reverseAPIPort;
uint16_t m_reverseAPIFeatureSetIndex;
uint16_t m_reverseAPIFeatureIndex;
GS232ControllerSettings();
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
};
#endif // INCLUDE_FEATURE_GS232CONTROLLERSETTINGS_H_

Wyświetl plik

@ -0,0 +1,51 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Jon Beniston, M7RCE //
// Copyright (C) 2020 Edouard Griffiths, F4EXB. //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "SWGFeatureSettings.h"
#include "gs232controller.h"
#include "gs232controllerwebapiadapter.h"
GS232ControllerWebAPIAdapter::GS232ControllerWebAPIAdapter()
{}
GS232ControllerWebAPIAdapter::~GS232ControllerWebAPIAdapter()
{}
int GS232ControllerWebAPIAdapter::webapiSettingsGet(
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage)
{
(void) errorMessage;
response.setSimplePttSettings(new SWGSDRangel::SWGSimplePTTSettings());
response.getSimplePttSettings()->init();
GS232Controller::webapiFormatFeatureSettings(response, m_settings);
return 200;
}
int GS232ControllerWebAPIAdapter::webapiSettingsPutPatch(
bool force,
const QStringList& featureSettingsKeys,
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage)
{
(void) errorMessage;
GS232Controller::webapiUpdateFeatureSettings(m_settings, featureSettingsKeys, response);
return 200;
}

Wyświetl plik

@ -0,0 +1,50 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Jon Beniston, M7RCE //
// Copyright (C) 2020 Edouard Griffiths, F4EXB. //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_GS232CONTROLLER_WEBAPIADAPTER_H
#define INCLUDE_GS232CONTROLLER_WEBAPIADAPTER_H
#include "feature/featurewebapiadapter.h"
#include "gs232controllersettings.h"
/**
* Standalone API adapter only for the settings
*/
class GS232ControllerWebAPIAdapter : public FeatureWebAPIAdapter {
public:
GS232ControllerWebAPIAdapter();
virtual ~GS232ControllerWebAPIAdapter();
virtual QByteArray serialize() const { return m_settings.serialize(); }
virtual bool deserialize(const QByteArray& data) { return m_settings.deserialize(data); }
virtual int webapiSettingsGet(
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage);
virtual int webapiSettingsPutPatch(
bool force,
const QStringList& featureSettingsKeys,
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage);
private:
GS232ControllerSettings m_settings;
};
#endif // INCLUDE_GS232CONTROLLER_WEBAPIADAPTER_H

Wyświetl plik

@ -0,0 +1,248 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Jon Beniston, M7RCE //
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QDebug>
#include <QTcpServer>
#include <QTcpSocket>
#include <QEventLoop>
#include <QTimer>
#include <QSerialPort>
#include <QRegularExpression>
#include "SWGDeviceState.h"
#include "SWGSuccessResponse.h"
#include "SWGErrorResponse.h"
#include "SWGDeviceSettings.h"
#include "SWGChannelSettings.h"
#include "SWGDeviceSet.h"
#include "SWGChannelReport.h"
#include "webapi/webapiadapterinterface.h"
#include "webapi/webapiutils.h"
#include "gs232controllerworker.h"
#include "gs232controllerreport.h"
MESSAGE_CLASS_DEFINITION(GS232ControllerWorker::MsgConfigureGS232ControllerWorker, Message)
MESSAGE_CLASS_DEFINITION(GS232ControllerReport::MsgReportAzAl, Message)
GS232ControllerWorker::GS232ControllerWorker(WebAPIAdapterInterface *webAPIAdapterInterface) :
m_webAPIAdapterInterface(webAPIAdapterInterface),
m_msgQueueToFeature(nullptr),
m_msgQueueToGUI(nullptr),
m_running(false),
m_mutex(QMutex::Recursive)
{
connect(&m_pollTimer, SIGNAL(timeout()), this, SLOT(update()));
m_pollTimer.start(1000);
}
GS232ControllerWorker::~GS232ControllerWorker()
{
m_inputMessageQueue.clear();
}
void GS232ControllerWorker::reset()
{
QMutexLocker mutexLocker(&m_mutex);
m_inputMessageQueue.clear();
}
bool GS232ControllerWorker::startWork()
{
QMutexLocker mutexLocker(&m_mutex);
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
connect(&m_serialPort, &QSerialPort::readyRead, this, &GS232ControllerWorker::readSerialData);
m_running = true;
return m_running;
}
void GS232ControllerWorker::stopWork()
{
QMutexLocker mutexLocker(&m_mutex);
disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
disconnect(&m_serialPort, &QSerialPort::readyRead, this, &GS232ControllerWorker::readSerialData);
m_running = false;
}
void GS232ControllerWorker::handleInputMessages()
{
Message* message;
while ((message = m_inputMessageQueue.pop()) != nullptr)
{
if (handleMessage(*message)) {
delete message;
}
}
}
bool GS232ControllerWorker::handleMessage(const Message& cmd)
{
if (MsgConfigureGS232ControllerWorker::match(cmd))
{
QMutexLocker mutexLocker(&m_mutex);
MsgConfigureGS232ControllerWorker& cfg = (MsgConfigureGS232ControllerWorker&) cmd;
applySettings(cfg.getSettings(), cfg.getForce());
return true;
}
else
{
return false;
}
}
void GS232ControllerWorker::applySettings(const GS232ControllerSettings& settings, bool force)
{
qDebug() << "GS232ControllerWorker::applySettings:"
<< " m_azimuth: " << settings.m_azimuth
<< " m_elevation: " << settings.m_elevation
<< " m_serialPort: " << settings.m_serialPort
<< " m_baudRate: " << settings.m_baudRate
<< " m_deviceIndex: " << settings.m_deviceIndex
<< " m_channelIndex: " << settings.m_channelIndex
<< " force: " << force;
if ((settings.m_serialPort != m_settings.m_serialPort) || force)
{
if (m_serialPort.isOpen())
m_serialPort.close();
m_serialPort.setPortName(settings.m_serialPort);
m_serialPort.setBaudRate(settings.m_baudRate);
if (!m_serialPort.open(QIODevice::ReadWrite))
qCritical() << "GS232ControllerWorker::applySettings: Failed to open serial port " << settings.m_serialPort << ". Error: " << m_serialPort.error();
}
else if ((settings.m_baudRate != m_settings.m_baudRate) || force)
{
m_serialPort.setBaudRate(settings.m_baudRate);
}
if ((settings.m_elevation != m_settings.m_elevation) || force)
{
setAzimuthElevation(settings.m_azimuth, settings.m_elevation);
}
else if ((settings.m_azimuth != m_settings.m_azimuth) || force)
{
setAzimuth(settings.m_azimuth);
}
m_settings = settings;
}
void GS232ControllerWorker::setAzimuth(int azimuth)
{
QString cmd = QString("M%1\r\n").arg(azimuth, 3, 10, QLatin1Char('0'));
QByteArray data = cmd.toLatin1();
m_serialPort.write(data);
}
void GS232ControllerWorker::setAzimuthElevation(int azimuth, int elevation)
{
QString cmd = QString("W%1 %2\r\n").arg(azimuth, 3, 10, QLatin1Char('0')).arg(elevation, 3, 10, QLatin1Char('0'));
QByteArray data = cmd.toLatin1();
m_serialPort.write(data);
}
void GS232ControllerWorker::readSerialData()
{
char buf[1024];
qint64 len;
while (m_serialPort.canReadLine())
{
len = m_serialPort.readLine(buf, sizeof(buf));
if (len != -1)
{
QString response = QString::fromUtf8(buf, len);
QRegularExpression re("AZ=(\\d\\d\\d)EL=(\\d\\d\\d)");
QRegularExpressionMatch match = re.match(response);
if (match.hasMatch())
{
QString az = match.captured(1);
QString el = match.captured(2);
//qDebug() << "GS232ControllerWorker::readSerialData read az " << az << " el " << el;
if (getMessageQueueToGUI())
{
GS232ControllerReport::MsgReportAzAl *msg = GS232ControllerReport::MsgReportAzAl::create(
az.toFloat(), el.toFloat(), GS232ControllerReport::ACTUAL);
getMessageQueueToGUI()->push(msg);
}
}
else
{
qDebug() << "GS232ControllerWorker::readSerialData unknown response " << response;
}
}
}
}
void GS232ControllerWorker::update()
{
// Request current Az/El from GS-232 controller
if (m_serialPort.isOpen())
{
QByteArray cmd("C2\r\n");
m_serialPort.write(cmd);
}
// Request target Az/EL from channel
if (m_settings.m_track)
{
SWGSDRangel::SWGChannelReport response;
SWGSDRangel::SWGErrorResponse errorResponse;
int httpRC = m_webAPIAdapterInterface->devicesetChannelReportGet(
m_settings.m_deviceIndex,
m_settings.m_channelIndex,
response,
errorResponse
);
if (httpRC/100 != 2)
{
qWarning("GS232ControllerWorker::update: get channel report error %d: %s",
httpRC, qPrintable(*errorResponse.getMessage()));
}
else
{
QJsonObject *jsonObj = response.asJsonObject();
double targetAzimuth;
double targetElevation;
bool gotElevation = false;
bool gotAzimuth = false;
if (WebAPIUtils::getSubObjectDouble(*jsonObj, "targetAzimuth", targetAzimuth))
gotAzimuth = true;
if (WebAPIUtils::getSubObjectDouble(*jsonObj, "targetElevation", targetElevation))
gotElevation = true;
if (gotAzimuth && gotElevation)
{
if (getMessageQueueToGUI())
{
GS232ControllerReport::MsgReportAzAl *msg = GS232ControllerReport::MsgReportAzAl::create(
targetAzimuth, targetElevation, GS232ControllerReport::TARGET);
getMessageQueueToGUI()->push(msg);
}
}
}
}
}

Wyświetl plik

@ -0,0 +1,94 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Jon Beniston, M7RCE //
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_FEATURE_GS232CONTROLLERWORKER_H_
#define INCLUDE_FEATURE_GS232CONTROLLERWORKER_H_
#include <QObject>
#include <QTimer>
#include <QSerialPort>
#include "util/message.h"
#include "util/messagequeue.h"
#include "gs232controllersettings.h"
class WebAPIAdapterInterface;
class GS232ControllerWorker : public QObject
{
Q_OBJECT
public:
class MsgConfigureGS232ControllerWorker : public Message {
MESSAGE_CLASS_DECLARATION
public:
const GS232ControllerSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; }
static MsgConfigureGS232ControllerWorker* create(const GS232ControllerSettings& settings, bool force)
{
return new MsgConfigureGS232ControllerWorker(settings, force);
}
private:
GS232ControllerSettings m_settings;
bool m_force;
MsgConfigureGS232ControllerWorker(const GS232ControllerSettings& settings, bool force) :
Message(),
m_settings(settings),
m_force(force)
{ }
};
GS232ControllerWorker(WebAPIAdapterInterface *webAPIAdapterInterface);
~GS232ControllerWorker();
void reset();
bool startWork();
void stopWork();
bool isRunning() const { return m_running; }
MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
void setMessageQueueToFeature(MessageQueue *messageQueue) { m_msgQueueToFeature = messageQueue; }
void setMessageQueueToGUI(MessageQueue *messageQueue) { m_msgQueueToGUI = messageQueue; }
private:
WebAPIAdapterInterface *m_webAPIAdapterInterface;
MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication
MessageQueue *m_msgQueueToFeature; //!< Queue to report channel change to main feature object
MessageQueue *m_msgQueueToGUI;
GS232ControllerSettings m_settings;
bool m_running;
QMutex m_mutex;
QSerialPort m_serialPort;
QTimer m_pollTimer;
bool handleMessage(const Message& cmd);
void applySettings(const GS232ControllerSettings& settings, bool force = false);
MessageQueue *getMessageQueueToGUI() { return m_msgQueueToGUI; }
void setAzimuth(int azimuth);
void setAzimuthElevation(int azimuth, int elevation);
private slots:
void handleInputMessages();
void readSerialData();
void update();
};
#endif // INCLUDE_FEATURE_GS232CONTROLLERWORKER_H_

Wyświetl plik

@ -0,0 +1,52 @@
<h1>GS-232 Rotator Controller Feature Plugin</h1>
<h2>Introduction</h2>
The GS-232 Rotator Controller feature plugin allows SDRangel to send commands to GS-232 rotators. This allows SDRangel to point antennas mounted on a rotator to a specified azimuth and elevation.
Azimuth and elevation can be set manually by a user in the GUI, via the REST API, or via another plugin, such as the ADS-B Demodulator, which can track a selected aircraft.
<h2>Interface</h2>
![File source channel plugin GUI](../../../doc/img/GS232Controller_plugin.png)
<h3>1: Start/Stop plugin</h3>
This button starts or stops the plugin. When the plugin is stopped, azimuth and elevation commands will not be sent to the GS-232 rotator.
<h3>2: Azimuth</h3>
Specifies the target azimuth (angle in degrees, clockwise from North) to point the antenna towards. Valid values range from 0 to 450 degrees. The value to the right of the target azimuth, is the current azimuth read from the GS-232 rotator.
<h3>3: Elevation</h3>
Specifies the target elevation (angle in degrees) to point the antenna towards. Valid values range from 0 to 180 degrees, where 0 and 180 point towards the horizon and 90 degrees to zenith. The value to the right of the target elevation, is the current elevation read from the GS-232 rotator.
<h3>4: Serial Port</h3>
Specifies the serial port (E.g. COM3 on Windows or /dev/ttyS0 on Linux) that will be used to send commands to the GS-232 rotator.
<h3>5: Baud rate</h3>
Specifies the baud rate that will be used to send commands to the GS-232 rotator. Typically this is 9600.
<h3>6: Track</h3>
When checked, the GS-232 Rotator Controller plugin will query the channel specified by the Device (8) and Channel (9) combo boxes for the target azimuth and elevation. For example, this allows an aircraft to be tracked, by setting the Device and Channel to correspond to the ADS-B Demodulator plugin.
<h3>7: Refresh list of devices and channels</h3>
Use this button to refresh the list of devices (8) and channels (9)
<h3>8: Select device set</h3>
Specify the SDRangel device set containing the channel plugin that will be asked for aziumth and elevation values. Defaults to R0.
<h3>9: Select channel</h3>
The channel index specifies the SDRangel channel that will be asked for azimuth and elevation values. Defaults to 0.
<h2>Developer Information</h2>
For a channel plugin to be able to set the azimuth and elevation, its channel report should contain targetAzimuth and targetElevation. See the ADS-B plugin as an example.

Wyświetl plik

@ -149,6 +149,7 @@ set(sdrbase_SOURCES
settings/preset.cpp
settings/mainsettings.cpp
util/azel.cpp
util/crc.cpp
util/CRC64.cpp
util/db.cpp
@ -314,6 +315,7 @@ set(sdrbase_HEADERS
settings/preset.h
settings/mainsettings.h
util/azel.h
util/CRC64.h
util/db.h
util/doublebuffer.h

Wyświetl plik

@ -696,6 +696,87 @@ margin-bottom: 20px;
<script>
// Script section to load models into a JS Var
var defs = {}
defs.ADSBDemodReport = {
"properties" : {
"channelPowerDB" : {
"type" : "number",
"format" : "float",
"description" : "power received in channel (dB)"
},
"channelSampleRate" : {
"type" : "integer"
},
"targetAzimuth" : {
"type" : "number",
"format" : "float"
},
"targetElevation" : {
"type" : "number",
"format" : "float"
}
},
"description" : "ADSBDemod"
};
defs.ADSBDemodSettings = {
"properties" : {
"inputFrequencyOffset" : {
"type" : "integer",
"format" : "int64",
"description" : "channel center frequency shift from baseband center in Hz"
},
"rfBandwidth" : {
"type" : "number",
"format" : "float",
"description" : "channel RF bandwidth in Hz"
},
"correlationThreshold" : {
"type" : "number",
"format" : "float"
},
"samplesPerBit" : {
"type" : "integer"
},
"removeTimeout" : {
"type" : "integer"
},
"beastEnabled" : {
"type" : "integer"
},
"beastHost" : {
"type" : "string"
},
"beastPort" : {
"type" : "integer"
},
"rgbColor" : {
"type" : "integer"
},
"title" : {
"type" : "string"
},
"streamIndex" : {
"type" : "integer",
"description" : "MIMO channel. Not relevant when connected to SI (single Rx)."
},
"useReverseAPI" : {
"type" : "integer",
"description" : "Synchronize with reverse API (1 for yes, 0 for no)"
},
"reverseAPIAddress" : {
"type" : "string"
},
"reverseAPIPort" : {
"type" : "integer"
},
"reverseAPIDeviceIndex" : {
"type" : "integer"
},
"reverseAPIChannelIndex" : {
"type" : "integer"
}
},
"description" : "ADSBDemod"
};
defs.AMBEDevice = {
"properties" : {
"deviceRef" : {
@ -2163,6 +2244,9 @@ margin-bottom: 20px;
"type" : "integer",
"description" : "0 for Rx only, 1 for Tx only or 2 for any number and direction (default 0)"
},
"ADSBDemodReport" : {
"$ref" : "#/definitions/ADSBDemodReport"
},
"AMDemodReport" : {
"$ref" : "#/definitions/AMDemodReport"
},
@ -2249,6 +2333,9 @@ margin-bottom: 20px;
"type" : "integer",
"description" : "Optional for reverse API. This is the channel index from where the message comes from."
},
"ADSBDemodSettings" : {
"$ref" : "#/definitions/ADSBDemodSettings"
},
"AMDemodSettings" : {
"$ref" : "#/definitions/AMDemodSettings"
},
@ -3300,6 +3387,9 @@ margin-bottom: 20px;
"type" : "integer",
"description" : "Optional for reverse API. This is the feature index from where the message comes from."
},
"GS232ControllerSettings" : {
"$ref" : "#/definitions/GS232ControllerSettings"
},
"SimplePTTSettings" : {
"$ref" : "#/definitions/SimplePTTSettings"
},
@ -4001,6 +4091,58 @@ margin-bottom: 20px;
}
},
"description" : "GLSpectrumGUI settings"
};
defs.GS232ControllerSettings = {
"properties" : {
"azimuth" : {
"type" : "integer",
"description" : "Target azimuth in degrees (0-450)"
},
"elevation" : {
"type" : "integer",
"description" : "Target elevation in degrees (0-180)"
},
"serialPort" : {
"type" : "string",
"description" : "The serial port the GS-232 controller is connected to"
},
"baudRate" : {
"type" : "integer",
"description" : "The baud rate to use for the serial connection to the GS-232 controller"
},
"track" : {
"type" : "integer"
},
"title" : {
"type" : "string"
},
"rgbColor" : {
"type" : "integer"
},
"deviceIndex" : {
"type" : "integer"
},
"channelIndex" : {
"type" : "integer"
},
"useReverseAPI" : {
"type" : "integer",
"description" : "Synchronize with reverse API (1 for yes, 0 for no)"
},
"reverseAPIAddress" : {
"type" : "string"
},
"reverseAPIPort" : {
"type" : "integer"
},
"reverseAPIDeviceIndex" : {
"type" : "integer"
},
"reverseAPIChannelIndex" : {
"type" : "integer"
}
},
"description" : "GS-232 Controller settings"
};
defs.Gain = {
"properties" : {
@ -39969,7 +40111,7 @@ except ApiException as e:
</div>
<div id="generator">
<div class="content">
Generated 2020-10-11T08:49:12.690+02:00
Generated 2020-10-27T16:45:08.746+01:00
</div>
</div>
</div>

Wyświetl plik

@ -73,10 +73,14 @@ public:
const QString& getSourceDeviceId() const { return m_preferences.getSourceDevice(); }
void setSourceDeviceId(const QString& deviceId) { m_preferences.setSourceDevice(deviceId); }
void setLatitude(float latitude) { m_preferences.setLatitude(latitude); }
void setStationName(const QString& name) { m_preferences.setStationName(name); }
void setLatitude(float latitude) { m_preferences.setLatitude(latitude); }
void setLongitude(float longitude) { m_preferences.setLongitude(longitude); }
void setAltitude(float altitude) { m_preferences.setAltitude(altitude); }
QString getStationName() const { return m_preferences.getStationName(); }
float getLatitude() const { return m_preferences.getLatitude(); }
float getLongitude() const { return m_preferences.getLongitude(); }
float getAltitude() const { return m_preferences.getAltitude(); }
void setConsoleMinLogLevel(const QtMsgType& minLogLevel) { m_preferences.setConsoleMinLogLevel(minLogLevel); }
void setFileMinLogLevel(const QtMsgType& minLogLevel) { m_preferences.setFileMinLogLevel(minLogLevel); }

Wyświetl plik

@ -12,8 +12,10 @@ void Preferences::resetToDefaults()
m_audioType.clear();
m_audioDevice.clear();
m_sourceIndex = 0;
m_latitude = 0.0;
m_longitude = 0.0;
m_stationName = "Home";
m_latitude = 49.012423; // Set an interesting location so map doesn't open up in the middle of the ocean
m_longitude = 8.418125;
m_altitude = 0.0f;
m_useLogFile = false;
m_logFileName = "sdrangel.log";
m_consoleMinLogLevel = QtDebugMsg;
@ -33,6 +35,8 @@ QByteArray Preferences::serialize() const
s.writeBool(9, m_useLogFile);
s.writeString(10, m_logFileName);
s.writeS32(11, (int) m_fileMinLogLevel);
s.writeString(12, m_stationName);
s.writeFloat(13, m_altitude);
return s.final();
}
@ -53,8 +57,8 @@ bool Preferences::deserialize(const QByteArray& data)
d.readString(3, &m_audioType);
d.readString(4, &m_audioDevice);
d.readS32(5, &m_sourceIndex, 0);
d.readFloat(6, &m_latitude, 0.0);
d.readFloat(7, &m_longitude, 0.0);
d.readFloat(6, &m_latitude, 0.0f);
d.readFloat(7, &m_longitude, 0.0f);
d.readS32(8, &tmpInt, (int) QtDebugMsg);
@ -72,6 +76,8 @@ bool Preferences::deserialize(const QByteArray& data)
d.readString(10, &m_logFileName, "sdrangel.log");
d.readS32(11, &tmpInt, (int) QtDebugMsg);
d.readString(12, &m_stationName, "Home");
d.readFloat(13, &m_altitude, 0.0f);
if ((tmpInt == (int) QtDebugMsg) ||
(tmpInt == (int) QtInfoMsg) ||

Wyświetl plik

@ -23,10 +23,14 @@ public:
void setAudioDevice(const QString& value) { m_audioDevice = value; }
const QString& getAudioDevice() const { return m_audioDevice; }
void setLatitude(float latitude) { m_latitude = latitude; }
void setStationName(const QString& name) { m_stationName = name; }
void setLatitude(float latitude) { m_latitude = latitude; }
void setLongitude(float longitude) { m_longitude = longitude; }
void setAltitude(float altitude) { m_altitude = altitude; }
QString getStationName() const { return m_stationName; }
float getLatitude() const { return m_latitude; }
float getLongitude() const { return m_longitude; }
float getAltitude() const { return m_altitude; }
void setConsoleMinLogLevel(const QtMsgType& minLogLevel) { m_consoleMinLogLevel = minLogLevel; }
void setFileMinLogLevel(const QtMsgType& minLogLevel) { m_fileMinLogLevel = minLogLevel; }
@ -44,8 +48,10 @@ protected:
QString m_audioType;
QString m_audioDevice;
float m_latitude;
QString m_stationName; //!< Name of the station (for drawing on the map)
float m_latitude; //!< Position of the station
float m_longitude;
float m_altitude; //!< Altitude in metres
QtMsgType m_consoleMinLogLevel;
QtMsgType m_fileMinLogLevel;

Wyświetl plik

@ -0,0 +1,151 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "azel.h"
#define _USE_MATH_DEFINES
#include <cmath>
// Calculate cartesian distance between two points
double AzEl::cartDistance(const AzElPoint& a, const AzElPoint& b)
{
double dx = b.m_cart.m_x - a.m_cart.m_x;
double dy = b.m_cart.m_y - a.m_cart.m_y;
double dz = b.m_cart.m_z - a.m_cart.m_z;
return std::sqrt(dx*dx + dy*dy + dz*dz);
}
// Calculate vector difference then normalise the result
bool AzEl::normVectorDiff(const AzElCartesian& a, const AzElCartesian& b, AzElCartesian& n)
{
n.m_x = b.m_x - a.m_x;
n.m_y = b.m_y - a.m_y;
n.m_z = b.m_z - a.m_z;
double distance = std::sqrt(n.m_x*n.m_x + n.m_y*n.m_y + n.m_z*n.m_z);
if (distance > 0.0f)
{
n.m_x = n.m_x / distance;
n.m_y = n.m_y / distance;
n.m_z = n.m_z / distance;
return true;
}
else
{
return false;
}
}
// Convert geodetic latitude (as given by GPS) to geocentric latitude (angle from centre of Earth between the point and equator)
// Both in radians.
// https://en.wikipedia.org/wiki/Latitude#Geocentric_latitude
double AzEl::geocentricLatitude(double latRad) const
{
double e2 = 0.00669437999014;
return std::atan((1.0 - e2) * std::tan(latRad));
}
// Earth radius for a given latitude, as it's not quite spherical
// http://en.wikipedia.org/wiki/Earth_radius
double AzEl::earthRadiusInMetres(double geodeticLatRad) const
{
double equatorialRadius = 6378137.0;
double polarRadius = 6356752.3;
double cosLat = std::cos(geodeticLatRad);
double sinLat = std::sin(geodeticLatRad);
double t1 = equatorialRadius * equatorialRadius * cosLat;
double t2 = polarRadius * polarRadius * sinLat;
double t3 = equatorialRadius * cosLat;
double t4 = polarRadius * sinLat;
return std::sqrt((t1*t1 + t2*t2)/(t3*t3 + t4*t4));
}
// Convert spherical coordinate to cartesian. Also calculates radius and a normal vector
void AzEl::sphericalToCartesian(AzElPoint& point)
{
// First calculate cartesian coords for point on Earth's surface
double latRad = point.m_spherical.m_latitude * M_PI/180.0;
double longRad = point.m_spherical.m_longitude * M_PI/180.0;
point.m_radius = earthRadiusInMetres(latRad);
double clat = geocentricLatitude(latRad);
double cosLong = cos(longRad);
double sinLong = sin(longRad);
double cosLat = cos(clat);
double sinLat = sin(clat);
point.m_cart.m_x = point.m_radius * cosLong * cosLat;
point.m_cart.m_y = point.m_radius * sinLong * cosLat;
point.m_cart.m_z = point.m_radius * sinLat;
// Calculate normal vector at surface
double cosGLat = std::cos(latRad);
double sinGLat = std::sin(latRad);
point.m_norm.m_x = cosGLat * cosLong;
point.m_norm.m_y = cosGLat * sinLong;
point.m_norm.m_z = sinGLat;
// Add altitude along normal vector
point.m_cart.m_x += point.m_spherical.m_altitude * point.m_norm.m_x;
point.m_cart.m_y += point.m_spherical.m_altitude * point.m_norm.m_y;
point.m_cart.m_z += point.m_spherical.m_altitude * point.m_norm.m_z;
}
// Calculate azimuth of target from location
void AzEl::calcAzimuth()
{
AzElPoint bRot;
// Rotate so location is at lat=0, long=0
bRot.m_spherical.m_latitude = m_target.m_spherical.m_latitude;
bRot.m_spherical.m_longitude = m_target.m_spherical.m_longitude - m_location.m_spherical.m_longitude;
bRot.m_spherical.m_altitude = m_target.m_spherical.m_altitude;
sphericalToCartesian(bRot);
double aLat = geocentricLatitude(-m_location.m_spherical.m_latitude * M_PI / 180.0);
double aCos = std::cos(aLat);
double aSin = std::sin(aLat);
double bx = (bRot.m_cart.m_x * aCos) - (bRot.m_cart.m_z * aSin);
double by = bRot.m_cart.m_y;
double bz = (bRot.m_cart.m_x * aSin) + (bRot.m_cart.m_z * aCos);
if (bz*bz + by*by > 1e-6)
{
double theta = std::atan2(bz, by) * 180.0 / M_PI;
m_azimuth = 90.0 - theta;
if (m_azimuth < 0.0)
m_azimuth += 360.0;
else if (m_azimuth > 360.0)
m_azimuth -= 360.0;
}
else
m_azimuth = 0.0;
}
// Calculate elevation of target from location
void AzEl::calcElevation()
{
AzElCartesian bma;
if (normVectorDiff(m_location.m_cart, m_target.m_cart, bma))
{
m_elevation = 90.0 - (180.0/M_PI) * std::acos(bma.m_x * m_location.m_norm.m_x
+ bma.m_y * m_location.m_norm.m_y
+ bma.m_z * m_location.m_norm.m_z);
}
else
m_elevation = 0.0;
}

133
sdrbase/util/azel.h 100644
Wyświetl plik

@ -0,0 +1,133 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_AZ_EL_H
#define INCLUDE_AZ_EL_H
#include "export.h"
// Spherical coordinate
struct SDRBASE_API AzElSpherical
{
double m_latitude; // Degrees
double m_longitude; // Degrees
double m_altitude; // Metres
};
// Cartesian coordinate
struct SDRBASE_API AzElCartesian
{
double m_x; // Metres
double m_y; // Metres
double m_z; // Metres
};
struct SDRBASE_API AzElPoint
{
AzElSpherical m_spherical; // Spherical coordinates
AzElCartesian m_cart; // Cartesian coordinates
AzElCartesian m_norm; // Normal vector on surface of sphere
double m_radius; // Radius from centre of sphere to the point
};
// Class to calculate azimuth, elevation and distance between two points specified
// by latitude, longitude and altitude
// See: https://doncross.net/geocalc
class SDRBASE_API AzEl
{
public:
// Location is the point we are looking from
void setLocation(double latitude, double longitude, double altitude)
{
m_location.m_spherical.m_latitude = latitude;
m_location.m_spherical.m_longitude = longitude;
m_location.m_spherical.m_altitude = altitude;
sphericalToCartesian(m_location);
}
// Target is the point we are looking at
void setTarget(double latiude, double longitude, double altitude)
{
m_target.m_spherical.m_latitude = latiude;
m_target.m_spherical.m_longitude = longitude;
m_target.m_spherical.m_altitude = altitude;
sphericalToCartesian(m_target);
}
AzElSpherical getLocationSpherical()
{
return m_location.m_spherical;
}
AzElCartesian getLocationCartesian()
{
return m_location.m_cart;
}
AzElSpherical getTargetSpherical()
{
return m_target.m_spherical;
}
AzElCartesian getTargetCartesian()
{
return m_target.m_cart;
}
void calculate()
{
m_distance = cartDistance(m_location, m_target);
calcAzimuth();
calcElevation();
}
double getDistance()
{
return m_distance;
}
double getAzimuth()
{
return m_azimuth;
}
double getElevation()
{
return m_elevation;
}
private:
double cartDistance(const AzElPoint& a, const AzElPoint& b);
bool normVectorDiff(const AzElCartesian& a, const AzElCartesian& b, AzElCartesian& n);
double geocentricLatitude(double latRad) const;
double earthRadiusInMetres(double geodeticLatRad) const;
void sphericalToCartesian(AzElPoint& point);
void calcAzimuth();
void calcElevation();
AzElPoint m_location;
AzElPoint m_target;
double m_azimuth;
double m_elevation;
double m_distance;
};
#endif

Wyświetl plik

@ -111,4 +111,11 @@ public:
crc32c() : crc(32, 0x1EDC6F41, false, 0xffffffff, 0) {}
};
// ADS-B - https://mode-s.org/decode/adsb/introduction.html
class SDRBASE_API crcadsb : public crc
{
public:
crcadsb() : crc(24, 0xfff409, true, 0, 0) {}
};
#endif

Wyświetl plik

@ -57,6 +57,7 @@
#include "SWGFeatureActions.h"
const QMap<QString, QString> WebAPIRequestMapper::m_channelURIToSettingsKey = {
{"sdrangel.channel.adsbdemod", "ADSBDemodSettings"},
{"sdrangel.channel.amdemod", "AMDemodSettings"},
{"de.maintech.sdrangelove.channel.am", "AMDemodSettings"}, // remap
{"sdrangel.channeltx.modam", "AMModSettings"},
@ -136,6 +137,7 @@ const QMap<QString, QString> WebAPIRequestMapper::m_deviceIdToSettingsKey = {
};
const QMap<QString, QString> WebAPIRequestMapper::m_channelTypeToSettingsKey = {
{"ADSBDemod", "ADSBDemodSettings"},
{"AMDemod", "AMDemodSettings"},
{"AMMod", "AMModSettings"},
{"ATVDemod", "ATVDemodSettings"},
@ -242,6 +244,7 @@ const QMap<QString, QString> WebAPIRequestMapper::m_mimoDeviceHwIdToActionsKey=
};
const QMap<QString, QString> WebAPIRequestMapper::m_featureTypeToSettingsKey = {
{"GS232Controller", "GS232ControllerSettings"},
{"SimplePTT", "SimplePTTSettings"},
{"RigCtlServer", "RigCtlServerSettings"}
};
@ -251,6 +254,7 @@ const QMap<QString, QString> WebAPIRequestMapper::m_featureTypeToActionsKey = {
};
const QMap<QString, QString> WebAPIRequestMapper::m_featureURIToSettingsKey = {
{"sdrangel.feature.gs232controller", "GS232ControllerSettings"},
{"sdrangel.feature.simpleptt", "SimplePTTSettings"},
{"sdrangel.feature.rigctlserver", "RigCtlServerSettings"}
};
@ -3715,7 +3719,12 @@ bool WebAPIRequestMapper::getChannelSettings(
appendSettingsSubKeys(settingsJsonObject, cwJson, "cwKeyer", channelSettingsKeys);
}
if (channelSettingsKey == "AMDemodSettings")
if (channelSettingsKey == "ADSBDemodSettings")
{
channelSettings->setAdsbDemodSettings(new SWGSDRangel::SWGADSBDemodSettings());
channelSettings->getAdsbDemodSettings()->fromJsonObject(settingsJsonObject);
}
else if (channelSettingsKey == "AMDemodSettings")
{
channelSettings->setAmDemodSettings(new SWGSDRangel::SWGAMDemodSettings());
channelSettings->getAmDemodSettings()->fromJsonObject(settingsJsonObject);
@ -4179,11 +4188,17 @@ bool WebAPIRequestMapper::getFeatureSettings(
QJsonObject settingsJsonObject = featureSettingsJson[featureSettingsKey].toObject();
featureSettingsKeys = settingsJsonObject.keys();
if (featureSettingsKey == "SimplePTTSettings")
if (featureSettingsKey == "GS232ControllerSettings")
{
featureSettings->setGs232ControllerSettings(new SWGSDRangel::SWGGS232ControllerSettings());
featureSettings->getGs232ControllerSettings()->fromJsonObject(settingsJsonObject);
}
else if (featureSettingsKey == "SimplePTTSettings")
{
featureSettings->setSimplePttSettings(new SWGSDRangel::SWGSimplePTTSettings());
featureSettings->getSimplePttSettings()->fromJsonObject(settingsJsonObject);
} else if (featureSettingsKey == "RigCtlServerSettings")
}
else if (featureSettingsKey == "RigCtlServerSettings")
{
featureSettings->setRigCtlServerSettings(new SWGSDRangel::SWGRigCtlServerSettings());
featureSettings->getRigCtlServerSettings()->fromJsonObject(settingsJsonObject);
@ -4328,6 +4343,7 @@ void WebAPIRequestMapper::resetChannelSettings(SWGSDRangel::SWGChannelSettings&
{
channelSettings.cleanup();
channelSettings.setChannelType(nullptr);
channelSettings.setAdsbDemodSettings(nullptr);
channelSettings.setAmDemodSettings(nullptr);
channelSettings.setAmModSettings(nullptr);
channelSettings.setAtvModSettings(nullptr);
@ -4351,6 +4367,7 @@ void WebAPIRequestMapper::resetChannelReport(SWGSDRangel::SWGChannelReport& chan
{
channelReport.cleanup();
channelReport.setChannelType(nullptr);
channelReport.setAdsbDemodReport(nullptr);
channelReport.setAmDemodReport(nullptr);
channelReport.setAmModReport(nullptr);
channelReport.setAtvModReport(nullptr);

Wyświetl plik

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>324</width>
<height>147</height>
<height>190</height>
</rect>
</property>
<property name="font">
@ -26,22 +26,25 @@
<string>My Station Position</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<item row="2" column="0">
<widget class="QLabel" name="latitudeLabel">
<property name="text">
<string>Latitude</string>
</property>
</widget>
</item>
<item row="1" column="0">
<item row="3" column="0">
<widget class="QLabel" name="longitudeLabel">
<property name="text">
<string>Longitude</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="3" column="1">
<widget class="QDoubleSpinBox" name="longitudeSpinBox">
<property name="toolTip">
<string>Longitude in decimal degrees</string>
</property>
<property name="decimals">
<number>6</number>
</property>
@ -53,8 +56,11 @@
</property>
</widget>
</item>
<item row="0" column="1">
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="latitudeSpinBox">
<property name="toolTip">
<string>Latitude in decimal degrees</string>
</property>
<property name="decimals">
<number>6</number>
</property>
@ -66,6 +72,37 @@
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="altitudeSpinBox">
<property name="toolTip">
<string>Altitude in metres</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="altitudeLabel">
<property name="text">
<string>Altitude (m)</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="name">
<property name="toolTip">
<string>Enter the name of your station</string>
</property>
<property name="text">
<string>Home</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="nameLabel">
<property name="text">
<string>Station name</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -82,7 +119,10 @@
</layout>
</widget>
<tabstops>
<tabstop>buttonBox</tabstop>
<tabstop>name</tabstop>
<tabstop>latitudeSpinBox</tabstop>
<tabstop>longitudeSpinBox</tabstop>
<tabstop>altitudeSpinBox</tabstop>
</tabstops>
<resources/>
<connections>

Wyświetl plik

@ -29,8 +29,10 @@ MyPositionDialog::MyPositionDialog(MainSettings& mainSettings, QWidget* parent)
m_mainSettings(mainSettings)
{
ui->setupUi(this);
ui->name->setText(m_mainSettings.getStationName());
ui->latitudeSpinBox->setValue(m_mainSettings.getLatitude());
ui->longitudeSpinBox->setValue(m_mainSettings.getLongitude());
ui->altitudeSpinBox->setValue(m_mainSettings.getAltitude());
}
MyPositionDialog::~MyPositionDialog()
@ -40,7 +42,9 @@ MyPositionDialog::~MyPositionDialog()
void MyPositionDialog::accept()
{
m_mainSettings.setStationName(ui->name->text());
m_mainSettings.setLatitude(ui->latitudeSpinBox->value());
m_mainSettings.setLongitude(ui->longitudeSpinBox->value());
m_mainSettings.setAltitude(ui->altitudeSpinBox->value());
QDialog::accept();
}

Wyświetl plik

@ -0,0 +1,38 @@
import QtQuick 2.4
import QtLocation 5.6
import QtPositioning 5.6
MapQuickItem {
id: station
property string stationName // Name of the station, E.g. Home
coordinate: QtPositioning.coordinate(51.5, 0.125) // Location of the antenna (QTH) - London
zoomLevel: 11
anchorPoint.x: image.width/2
anchorPoint.y: image.height/2
sourceItem: Grid {
columns: 1
Grid {
horizontalItemAlignment: Grid.AlignHCenter
Image {
id: image
source: "map_antenna.png"
}
Rectangle {
id: bubble
color: "lightblue"
border.width: 1
width: text.width * 1.3
height: text.height * 1.3
radius: 5
Text {
id: text
anchors.centerIn: parent
text: stationName
}
}
}
}
}

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 782 B

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 657 B

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 772 B

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 1.3 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 647 B

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 779 B

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 541 B

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 735 B

Wyświetl plik

@ -0,0 +1,85 @@
import QtQuick 2.4
import QtQuick.Window 2.4
import QtLocation 5.6
import QtPositioning 5.6
Item {
id: qmlMap
property int aircraftZoomLevel: 11
Plugin {
id: mapPlugin
name: "osm"
}
Map {
id: map
objectName: "map"
anchors.fill: parent
plugin: mapPlugin
center: QtPositioning.coordinate(51.5, 0.125) // London
zoomLevel: 10
MapStation {
id: station
objectName: "station"
stationName: "Home"
coordinate: QtPositioning.coordinate(51.5, 0.125)
}
MapItemView{
model: aircraftModel
delegate: aircraftComponent
}
onZoomLevelChanged: {
if (zoomLevel > 11) {
station.zoomLevel = zoomLevel
aircraftZoomLevel = zoomLevel
} else {
station.zoomLevel = 11
aircraftZoomLevel = 11
}
}
}
Component {
id: aircraftComponent
MapQuickItem {
id: aircraft
anchorPoint.x: image.width/2
anchorPoint.y: image.height/2
coordinate: position
zoomLevel: aircraftZoomLevel
sourceItem: Grid {
columns: 1
Grid {
horizontalItemAlignment: Grid.AlignHCenter
Image {
id: image
rotation: heading
source: aircraftImage
}
Rectangle {
id: bubble
color: bubbleColour
border.width: 1
width: text.width * 1.1
height: text.height * 1.1
radius: 5
Text {
id: text
anchors.centerIn: parent
text: adsbData
}
}
}
}
}
}
}

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 1.3 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 619 B

Wyświetl plik

@ -1,5 +1,16 @@
<RCC>
<qresource prefix="/">
<file>map.qml</file>
<file>MapStation.qml</file>
<file>aircraft_2engine.png</file>
<file>aircraft_2enginesmall.png</file>
<file>aircraft_4engine.png</file>
<file>aircraft_helicopter.png</file>
<file>aircraft_light.png</file>
<file>aircraft_space.png</file>
<file>aircraft_drone.png</file>
<file>map_antenna.png</file>
<file>map_truck.png</file>
<file>star.png</file>
<file>swap.png</file>
<file>gridpolar.png</file>

Wyświetl plik

@ -0,0 +1,58 @@
ADSBDemodSettings:
description: ADSBDemod
properties:
inputFrequencyOffset:
description: channel center frequency shift from baseband center in Hz
type: integer
format: int64
rfBandwidth:
description: channel RF bandwidth in Hz
type: number
format: float
correlationThreshold:
type: number
format: float
samplesPerBit:
type: integer
removeTimeout:
type: integer
beastEnabled:
type: integer
beastHost:
type: string
beastPort:
type: integer
rgbColor:
type: integer
title:
type: string
streamIndex:
description: MIMO channel. Not relevant when connected to SI (single Rx).
type: integer
useReverseAPI:
description: Synchronize with reverse API (1 for yes, 0 for no)
type: integer
reverseAPIAddress:
type: string
reverseAPIPort:
type: integer
reverseAPIDeviceIndex:
type: integer
reverseAPIChannelIndex:
type: integer
ADSBDemodReport:
description: ADSBDemod
properties:
channelPowerDB:
description: power received in channel (dB)
type: number
format: float
channelSampleRate:
type: integer
targetAzimuth:
type: number
format: float
targetElevation:
type: number
format: float

Wyświetl plik

@ -11,6 +11,8 @@ ChannelReport:
direction:
description: 0 for Rx only, 1 for Tx only or 2 for any number and direction (default 0)
type: integer
ADSBDemodReport:
$ref: "http://swgserver:8081/api/swagger/include/ADSBDemod.yaml#/ADSBDemodReport"
AMDemodReport:
$ref: "http://swgserver:8081/api/swagger/include/AMDemod.yaml#/AMDemodReport"
AMModReport:

Wyświetl plik

@ -17,6 +17,8 @@ ChannelSettings:
originatorChannelIndex:
description: Optional for reverse API. This is the channel index from where the message comes from.
type: integer
ADSBDemodSettings:
$ref: "http://swgserver:8081/api/swagger/include/ADSBDemod.yaml#/ADSBDemodSettings"
AMDemodSettings:
$ref: "http://swgserver:8081/api/swagger/include/AMDemod.yaml#/AMDemodSettings"
AMModSettings:

Wyświetl plik

@ -13,6 +13,8 @@ FeatureSettings:
originatorFeatureIndex:
description: Optional for reverse API. This is the feature index from where the message comes from.
type: integer
GS232ControllerSettings:
$ref: "http://swgserver:8081/api/swagger/include/GS232Controller.yaml#/GS232ControllerSettings"
SimplePTTSettings:
$ref: "http://swgserver:8081/api/swagger/include/SimplePTT.yaml#/SimplePTTSettings"
RigCtlServerSettings:

Wyświetl plik

@ -0,0 +1,36 @@
GS232ControllerSettings:
description: "GS-232 Controller settings"
properties:
azimuth:
description: Target azimuth in degrees (0-450)
type: integer
elevation:
description: Target elevation in degrees (0-180)
type: integer
serialPort:
description: The serial port the GS-232 controller is connected to
type: string
baudRate:
description: The baud rate to use for the serial connection to the GS-232 controller
type: integer
track:
type: integer
title:
type: string
rgbColor:
type: integer
deviceIndex:
type: integer
channelIndex:
type: integer
useReverseAPI:
description: Synchronize with reverse API (1 for yes, 0 for no)
type: integer
reverseAPIAddress:
type: string
reverseAPIPort:
type: integer
reverseAPIDeviceIndex:
type: integer
reverseAPIChannelIndex:
type: integer

Wyświetl plik

@ -696,6 +696,87 @@ margin-bottom: 20px;
<script>
// Script section to load models into a JS Var
var defs = {}
defs.ADSBDemodReport = {
"properties" : {
"channelPowerDB" : {
"type" : "number",
"format" : "float",
"description" : "power received in channel (dB)"
},
"channelSampleRate" : {
"type" : "integer"
},
"targetAzimuth" : {
"type" : "number",
"format" : "float"
},
"targetElevation" : {
"type" : "number",
"format" : "float"
}
},
"description" : "ADSBDemod"
};
defs.ADSBDemodSettings = {
"properties" : {
"inputFrequencyOffset" : {
"type" : "integer",
"format" : "int64",
"description" : "channel center frequency shift from baseband center in Hz"
},
"rfBandwidth" : {
"type" : "number",
"format" : "float",
"description" : "channel RF bandwidth in Hz"
},
"correlationThreshold" : {
"type" : "number",
"format" : "float"
},
"samplesPerBit" : {
"type" : "integer"
},
"removeTimeout" : {
"type" : "integer"
},
"beastEnabled" : {
"type" : "integer"
},
"beastHost" : {
"type" : "string"
},
"beastPort" : {
"type" : "integer"
},
"rgbColor" : {
"type" : "integer"
},
"title" : {
"type" : "string"
},
"streamIndex" : {
"type" : "integer",
"description" : "MIMO channel. Not relevant when connected to SI (single Rx)."
},
"useReverseAPI" : {
"type" : "integer",
"description" : "Synchronize with reverse API (1 for yes, 0 for no)"
},
"reverseAPIAddress" : {
"type" : "string"
},
"reverseAPIPort" : {
"type" : "integer"
},
"reverseAPIDeviceIndex" : {
"type" : "integer"
},
"reverseAPIChannelIndex" : {
"type" : "integer"
}
},
"description" : "ADSBDemod"
};
defs.AMBEDevice = {
"properties" : {
"deviceRef" : {
@ -2163,6 +2244,9 @@ margin-bottom: 20px;
"type" : "integer",
"description" : "0 for Rx only, 1 for Tx only or 2 for any number and direction (default 0)"
},
"ADSBDemodReport" : {
"$ref" : "#/definitions/ADSBDemodReport"
},
"AMDemodReport" : {
"$ref" : "#/definitions/AMDemodReport"
},
@ -2249,6 +2333,9 @@ margin-bottom: 20px;
"type" : "integer",
"description" : "Optional for reverse API. This is the channel index from where the message comes from."
},
"ADSBDemodSettings" : {
"$ref" : "#/definitions/ADSBDemodSettings"
},
"AMDemodSettings" : {
"$ref" : "#/definitions/AMDemodSettings"
},
@ -3300,6 +3387,9 @@ margin-bottom: 20px;
"type" : "integer",
"description" : "Optional for reverse API. This is the feature index from where the message comes from."
},
"GS232ControllerSettings" : {
"$ref" : "#/definitions/GS232ControllerSettings"
},
"SimplePTTSettings" : {
"$ref" : "#/definitions/SimplePTTSettings"
},
@ -4001,6 +4091,58 @@ margin-bottom: 20px;
}
},
"description" : "GLSpectrumGUI settings"
};
defs.GS232ControllerSettings = {
"properties" : {
"azimuth" : {
"type" : "integer",
"description" : "Target azimuth in degrees (0-450)"
},
"elevation" : {
"type" : "integer",
"description" : "Target elevation in degrees (0-180)"
},
"serialPort" : {
"type" : "string",
"description" : "The serial port the GS-232 controller is connected to"
},
"baudRate" : {
"type" : "integer",
"description" : "The baud rate to use for the serial connection to the GS-232 controller"
},
"track" : {
"type" : "integer"
},
"title" : {
"type" : "string"
},
"rgbColor" : {
"type" : "integer"
},
"deviceIndex" : {
"type" : "integer"
},
"channelIndex" : {
"type" : "integer"
},
"useReverseAPI" : {
"type" : "integer",
"description" : "Synchronize with reverse API (1 for yes, 0 for no)"
},
"reverseAPIAddress" : {
"type" : "string"
},
"reverseAPIPort" : {
"type" : "integer"
},
"reverseAPIDeviceIndex" : {
"type" : "integer"
},
"reverseAPIChannelIndex" : {
"type" : "integer"
}
},
"description" : "GS-232 Controller settings"
};
defs.Gain = {
"properties" : {
@ -39969,7 +40111,7 @@ except ApiException as e:
</div>
<div id="generator">
<div class="content">
Generated 2020-10-11T08:49:12.690+02:00
Generated 2020-10-27T16:45:08.746+01:00
</div>
</div>
</div>

Wyświetl plik

@ -0,0 +1,177 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.15.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
#include "SWGADSBDemodReport.h"
#include "SWGHelpers.h"
#include <QJsonDocument>
#include <QJsonArray>
#include <QObject>
#include <QDebug>
namespace SWGSDRangel {
SWGADSBDemodReport::SWGADSBDemodReport(QString* json) {
init();
this->fromJson(*json);
}
SWGADSBDemodReport::SWGADSBDemodReport() {
channel_power_db = 0.0f;
m_channel_power_db_isSet = false;
channel_sample_rate = 0;
m_channel_sample_rate_isSet = false;
target_azimuth = 0.0f;
m_target_azimuth_isSet = false;
target_elevation = 0.0f;
m_target_elevation_isSet = false;
}
SWGADSBDemodReport::~SWGADSBDemodReport() {
this->cleanup();
}
void
SWGADSBDemodReport::init() {
channel_power_db = 0.0f;
m_channel_power_db_isSet = false;
channel_sample_rate = 0;
m_channel_sample_rate_isSet = false;
target_azimuth = 0.0f;
m_target_azimuth_isSet = false;
target_elevation = 0.0f;
m_target_elevation_isSet = false;
}
void
SWGADSBDemodReport::cleanup() {
}
SWGADSBDemodReport*
SWGADSBDemodReport::fromJson(QString &json) {
QByteArray array (json.toStdString().c_str());
QJsonDocument doc = QJsonDocument::fromJson(array);
QJsonObject jsonObject = doc.object();
this->fromJsonObject(jsonObject);
return this;
}
void
SWGADSBDemodReport::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&channel_power_db, pJson["channelPowerDB"], "float", "");
::SWGSDRangel::setValue(&channel_sample_rate, pJson["channelSampleRate"], "qint32", "");
::SWGSDRangel::setValue(&target_azimuth, pJson["targetAzimuth"], "float", "");
::SWGSDRangel::setValue(&target_elevation, pJson["targetElevation"], "float", "");
}
QString
SWGADSBDemodReport::asJson ()
{
QJsonObject* obj = this->asJsonObject();
QJsonDocument doc(*obj);
QByteArray bytes = doc.toJson();
delete obj;
return QString(bytes);
}
QJsonObject*
SWGADSBDemodReport::asJsonObject() {
QJsonObject* obj = new QJsonObject();
if(m_channel_power_db_isSet){
obj->insert("channelPowerDB", QJsonValue(channel_power_db));
}
if(m_channel_sample_rate_isSet){
obj->insert("channelSampleRate", QJsonValue(channel_sample_rate));
}
if(m_target_azimuth_isSet){
obj->insert("targetAzimuth", QJsonValue(target_azimuth));
}
if(m_target_elevation_isSet){
obj->insert("targetElevation", QJsonValue(target_elevation));
}
return obj;
}
float
SWGADSBDemodReport::getChannelPowerDb() {
return channel_power_db;
}
void
SWGADSBDemodReport::setChannelPowerDb(float channel_power_db) {
this->channel_power_db = channel_power_db;
this->m_channel_power_db_isSet = true;
}
qint32
SWGADSBDemodReport::getChannelSampleRate() {
return channel_sample_rate;
}
void
SWGADSBDemodReport::setChannelSampleRate(qint32 channel_sample_rate) {
this->channel_sample_rate = channel_sample_rate;
this->m_channel_sample_rate_isSet = true;
}
float
SWGADSBDemodReport::getTargetAzimuth() {
return target_azimuth;
}
void
SWGADSBDemodReport::setTargetAzimuth(float target_azimuth) {
this->target_azimuth = target_azimuth;
this->m_target_azimuth_isSet = true;
}
float
SWGADSBDemodReport::getTargetElevation() {
return target_elevation;
}
void
SWGADSBDemodReport::setTargetElevation(float target_elevation) {
this->target_elevation = target_elevation;
this->m_target_elevation_isSet = true;
}
bool
SWGADSBDemodReport::isSet(){
bool isObjectUpdated = false;
do{
if(m_channel_power_db_isSet){
isObjectUpdated = true; break;
}
if(m_channel_sample_rate_isSet){
isObjectUpdated = true; break;
}
if(m_target_azimuth_isSet){
isObjectUpdated = true; break;
}
if(m_target_elevation_isSet){
isObjectUpdated = true; break;
}
}while(false);
return isObjectUpdated;
}
}

Wyświetl plik

@ -0,0 +1,76 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.15.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
/*
* SWGADSBDemodReport.h
*
* ADSBDemod
*/
#ifndef SWGADSBDemodReport_H_
#define SWGADSBDemodReport_H_
#include <QJsonObject>
#include "SWGObject.h"
#include "export.h"
namespace SWGSDRangel {
class SWG_API SWGADSBDemodReport: public SWGObject {
public:
SWGADSBDemodReport();
SWGADSBDemodReport(QString* json);
virtual ~SWGADSBDemodReport();
void init();
void cleanup();
virtual QString asJson () override;
virtual QJsonObject* asJsonObject() override;
virtual void fromJsonObject(QJsonObject &json) override;
virtual SWGADSBDemodReport* fromJson(QString &jsonString) override;
float getChannelPowerDb();
void setChannelPowerDb(float channel_power_db);
qint32 getChannelSampleRate();
void setChannelSampleRate(qint32 channel_sample_rate);
float getTargetAzimuth();
void setTargetAzimuth(float target_azimuth);
float getTargetElevation();
void setTargetElevation(float target_elevation);
virtual bool isSet() override;
private:
float channel_power_db;
bool m_channel_power_db_isSet;
qint32 channel_sample_rate;
bool m_channel_sample_rate_isSet;
float target_azimuth;
bool m_target_azimuth_isSet;
float target_elevation;
bool m_target_elevation_isSet;
};
}
#endif /* SWGADSBDemodReport_H_ */

Wyświetl plik

@ -0,0 +1,459 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.15.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
#include "SWGADSBDemodSettings.h"
#include "SWGHelpers.h"
#include <QJsonDocument>
#include <QJsonArray>
#include <QObject>
#include <QDebug>
namespace SWGSDRangel {
SWGADSBDemodSettings::SWGADSBDemodSettings(QString* json) {
init();
this->fromJson(*json);
}
SWGADSBDemodSettings::SWGADSBDemodSettings() {
input_frequency_offset = 0L;
m_input_frequency_offset_isSet = false;
rf_bandwidth = 0.0f;
m_rf_bandwidth_isSet = false;
correlation_threshold = 0.0f;
m_correlation_threshold_isSet = false;
samples_per_bit = 0;
m_samples_per_bit_isSet = false;
remove_timeout = 0;
m_remove_timeout_isSet = false;
beast_enabled = 0;
m_beast_enabled_isSet = false;
beast_host = nullptr;
m_beast_host_isSet = false;
beast_port = 0;
m_beast_port_isSet = false;
rgb_color = 0;
m_rgb_color_isSet = false;
title = nullptr;
m_title_isSet = false;
stream_index = 0;
m_stream_index_isSet = false;
use_reverse_api = 0;
m_use_reverse_api_isSet = false;
reverse_api_address = nullptr;
m_reverse_api_address_isSet = false;
reverse_api_port = 0;
m_reverse_api_port_isSet = false;
reverse_api_device_index = 0;
m_reverse_api_device_index_isSet = false;
reverse_api_channel_index = 0;
m_reverse_api_channel_index_isSet = false;
}
SWGADSBDemodSettings::~SWGADSBDemodSettings() {
this->cleanup();
}
void
SWGADSBDemodSettings::init() {
input_frequency_offset = 0L;
m_input_frequency_offset_isSet = false;
rf_bandwidth = 0.0f;
m_rf_bandwidth_isSet = false;
correlation_threshold = 0.0f;
m_correlation_threshold_isSet = false;
samples_per_bit = 0;
m_samples_per_bit_isSet = false;
remove_timeout = 0;
m_remove_timeout_isSet = false;
beast_enabled = 0;
m_beast_enabled_isSet = false;
beast_host = new QString("");
m_beast_host_isSet = false;
beast_port = 0;
m_beast_port_isSet = false;
rgb_color = 0;
m_rgb_color_isSet = false;
title = new QString("");
m_title_isSet = false;
stream_index = 0;
m_stream_index_isSet = false;
use_reverse_api = 0;
m_use_reverse_api_isSet = false;
reverse_api_address = new QString("");
m_reverse_api_address_isSet = false;
reverse_api_port = 0;
m_reverse_api_port_isSet = false;
reverse_api_device_index = 0;
m_reverse_api_device_index_isSet = false;
reverse_api_channel_index = 0;
m_reverse_api_channel_index_isSet = false;
}
void
SWGADSBDemodSettings::cleanup() {
if(beast_host != nullptr) {
delete beast_host;
}
if(title != nullptr) {
delete title;
}
if(reverse_api_address != nullptr) {
delete reverse_api_address;
}
}
SWGADSBDemodSettings*
SWGADSBDemodSettings::fromJson(QString &json) {
QByteArray array (json.toStdString().c_str());
QJsonDocument doc = QJsonDocument::fromJson(array);
QJsonObject jsonObject = doc.object();
this->fromJsonObject(jsonObject);
return this;
}
void
SWGADSBDemodSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&input_frequency_offset, pJson["inputFrequencyOffset"], "qint64", "");
::SWGSDRangel::setValue(&rf_bandwidth, pJson["rfBandwidth"], "float", "");
::SWGSDRangel::setValue(&correlation_threshold, pJson["correlationThreshold"], "float", "");
::SWGSDRangel::setValue(&samples_per_bit, pJson["samplesPerBit"], "qint32", "");
::SWGSDRangel::setValue(&remove_timeout, pJson["removeTimeout"], "qint32", "");
::SWGSDRangel::setValue(&beast_enabled, pJson["beastEnabled"], "qint32", "");
::SWGSDRangel::setValue(&beast_host, pJson["beastHost"], "QString", "QString");
::SWGSDRangel::setValue(&beast_port, pJson["beastPort"], "qint32", "");
::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", "");
::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString");
::SWGSDRangel::setValue(&stream_index, pJson["streamIndex"], "qint32", "");
::SWGSDRangel::setValue(&use_reverse_api, pJson["useReverseAPI"], "qint32", "");
::SWGSDRangel::setValue(&reverse_api_address, pJson["reverseAPIAddress"], "QString", "QString");
::SWGSDRangel::setValue(&reverse_api_port, pJson["reverseAPIPort"], "qint32", "");
::SWGSDRangel::setValue(&reverse_api_device_index, pJson["reverseAPIDeviceIndex"], "qint32", "");
::SWGSDRangel::setValue(&reverse_api_channel_index, pJson["reverseAPIChannelIndex"], "qint32", "");
}
QString
SWGADSBDemodSettings::asJson ()
{
QJsonObject* obj = this->asJsonObject();
QJsonDocument doc(*obj);
QByteArray bytes = doc.toJson();
delete obj;
return QString(bytes);
}
QJsonObject*
SWGADSBDemodSettings::asJsonObject() {
QJsonObject* obj = new QJsonObject();
if(m_input_frequency_offset_isSet){
obj->insert("inputFrequencyOffset", QJsonValue(input_frequency_offset));
}
if(m_rf_bandwidth_isSet){
obj->insert("rfBandwidth", QJsonValue(rf_bandwidth));
}
if(m_correlation_threshold_isSet){
obj->insert("correlationThreshold", QJsonValue(correlation_threshold));
}
if(m_samples_per_bit_isSet){
obj->insert("samplesPerBit", QJsonValue(samples_per_bit));
}
if(m_remove_timeout_isSet){
obj->insert("removeTimeout", QJsonValue(remove_timeout));
}
if(m_beast_enabled_isSet){
obj->insert("beastEnabled", QJsonValue(beast_enabled));
}
if(beast_host != nullptr && *beast_host != QString("")){
toJsonValue(QString("beastHost"), beast_host, obj, QString("QString"));
}
if(m_beast_port_isSet){
obj->insert("beastPort", QJsonValue(beast_port));
}
if(m_rgb_color_isSet){
obj->insert("rgbColor", QJsonValue(rgb_color));
}
if(title != nullptr && *title != QString("")){
toJsonValue(QString("title"), title, obj, QString("QString"));
}
if(m_stream_index_isSet){
obj->insert("streamIndex", QJsonValue(stream_index));
}
if(m_use_reverse_api_isSet){
obj->insert("useReverseAPI", QJsonValue(use_reverse_api));
}
if(reverse_api_address != nullptr && *reverse_api_address != QString("")){
toJsonValue(QString("reverseAPIAddress"), reverse_api_address, obj, QString("QString"));
}
if(m_reverse_api_port_isSet){
obj->insert("reverseAPIPort", QJsonValue(reverse_api_port));
}
if(m_reverse_api_device_index_isSet){
obj->insert("reverseAPIDeviceIndex", QJsonValue(reverse_api_device_index));
}
if(m_reverse_api_channel_index_isSet){
obj->insert("reverseAPIChannelIndex", QJsonValue(reverse_api_channel_index));
}
return obj;
}
qint64
SWGADSBDemodSettings::getInputFrequencyOffset() {
return input_frequency_offset;
}
void
SWGADSBDemodSettings::setInputFrequencyOffset(qint64 input_frequency_offset) {
this->input_frequency_offset = input_frequency_offset;
this->m_input_frequency_offset_isSet = true;
}
float
SWGADSBDemodSettings::getRfBandwidth() {
return rf_bandwidth;
}
void
SWGADSBDemodSettings::setRfBandwidth(float rf_bandwidth) {
this->rf_bandwidth = rf_bandwidth;
this->m_rf_bandwidth_isSet = true;
}
float
SWGADSBDemodSettings::getCorrelationThreshold() {
return correlation_threshold;
}
void
SWGADSBDemodSettings::setCorrelationThreshold(float correlation_threshold) {
this->correlation_threshold = correlation_threshold;
this->m_correlation_threshold_isSet = true;
}
qint32
SWGADSBDemodSettings::getSamplesPerBit() {
return samples_per_bit;
}
void
SWGADSBDemodSettings::setSamplesPerBit(qint32 samples_per_bit) {
this->samples_per_bit = samples_per_bit;
this->m_samples_per_bit_isSet = true;
}
qint32
SWGADSBDemodSettings::getRemoveTimeout() {
return remove_timeout;
}
void
SWGADSBDemodSettings::setRemoveTimeout(qint32 remove_timeout) {
this->remove_timeout = remove_timeout;
this->m_remove_timeout_isSet = true;
}
qint32
SWGADSBDemodSettings::getBeastEnabled() {
return beast_enabled;
}
void
SWGADSBDemodSettings::setBeastEnabled(qint32 beast_enabled) {
this->beast_enabled = beast_enabled;
this->m_beast_enabled_isSet = true;
}
QString*
SWGADSBDemodSettings::getBeastHost() {
return beast_host;
}
void
SWGADSBDemodSettings::setBeastHost(QString* beast_host) {
this->beast_host = beast_host;
this->m_beast_host_isSet = true;
}
qint32
SWGADSBDemodSettings::getBeastPort() {
return beast_port;
}
void
SWGADSBDemodSettings::setBeastPort(qint32 beast_port) {
this->beast_port = beast_port;
this->m_beast_port_isSet = true;
}
qint32
SWGADSBDemodSettings::getRgbColor() {
return rgb_color;
}
void
SWGADSBDemodSettings::setRgbColor(qint32 rgb_color) {
this->rgb_color = rgb_color;
this->m_rgb_color_isSet = true;
}
QString*
SWGADSBDemodSettings::getTitle() {
return title;
}
void
SWGADSBDemodSettings::setTitle(QString* title) {
this->title = title;
this->m_title_isSet = true;
}
qint32
SWGADSBDemodSettings::getStreamIndex() {
return stream_index;
}
void
SWGADSBDemodSettings::setStreamIndex(qint32 stream_index) {
this->stream_index = stream_index;
this->m_stream_index_isSet = true;
}
qint32
SWGADSBDemodSettings::getUseReverseApi() {
return use_reverse_api;
}
void
SWGADSBDemodSettings::setUseReverseApi(qint32 use_reverse_api) {
this->use_reverse_api = use_reverse_api;
this->m_use_reverse_api_isSet = true;
}
QString*
SWGADSBDemodSettings::getReverseApiAddress() {
return reverse_api_address;
}
void
SWGADSBDemodSettings::setReverseApiAddress(QString* reverse_api_address) {
this->reverse_api_address = reverse_api_address;
this->m_reverse_api_address_isSet = true;
}
qint32
SWGADSBDemodSettings::getReverseApiPort() {
return reverse_api_port;
}
void
SWGADSBDemodSettings::setReverseApiPort(qint32 reverse_api_port) {
this->reverse_api_port = reverse_api_port;
this->m_reverse_api_port_isSet = true;
}
qint32
SWGADSBDemodSettings::getReverseApiDeviceIndex() {
return reverse_api_device_index;
}
void
SWGADSBDemodSettings::setReverseApiDeviceIndex(qint32 reverse_api_device_index) {
this->reverse_api_device_index = reverse_api_device_index;
this->m_reverse_api_device_index_isSet = true;
}
qint32
SWGADSBDemodSettings::getReverseApiChannelIndex() {
return reverse_api_channel_index;
}
void
SWGADSBDemodSettings::setReverseApiChannelIndex(qint32 reverse_api_channel_index) {
this->reverse_api_channel_index = reverse_api_channel_index;
this->m_reverse_api_channel_index_isSet = true;
}
bool
SWGADSBDemodSettings::isSet(){
bool isObjectUpdated = false;
do{
if(m_input_frequency_offset_isSet){
isObjectUpdated = true; break;
}
if(m_rf_bandwidth_isSet){
isObjectUpdated = true; break;
}
if(m_correlation_threshold_isSet){
isObjectUpdated = true; break;
}
if(m_samples_per_bit_isSet){
isObjectUpdated = true; break;
}
if(m_remove_timeout_isSet){
isObjectUpdated = true; break;
}
if(m_beast_enabled_isSet){
isObjectUpdated = true; break;
}
if(beast_host && *beast_host != QString("")){
isObjectUpdated = true; break;
}
if(m_beast_port_isSet){
isObjectUpdated = true; break;
}
if(m_rgb_color_isSet){
isObjectUpdated = true; break;
}
if(title && *title != QString("")){
isObjectUpdated = true; break;
}
if(m_stream_index_isSet){
isObjectUpdated = true; break;
}
if(m_use_reverse_api_isSet){
isObjectUpdated = true; break;
}
if(reverse_api_address && *reverse_api_address != QString("")){
isObjectUpdated = true; break;
}
if(m_reverse_api_port_isSet){
isObjectUpdated = true; break;
}
if(m_reverse_api_device_index_isSet){
isObjectUpdated = true; break;
}
if(m_reverse_api_channel_index_isSet){
isObjectUpdated = true; break;
}
}while(false);
return isObjectUpdated;
}
}

Wyświetl plik

@ -0,0 +1,149 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.15.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
/*
* SWGADSBDemodSettings.h
*
* ADSBDemod
*/
#ifndef SWGADSBDemodSettings_H_
#define SWGADSBDemodSettings_H_
#include <QJsonObject>
#include <QString>
#include "SWGObject.h"
#include "export.h"
namespace SWGSDRangel {
class SWG_API SWGADSBDemodSettings: public SWGObject {
public:
SWGADSBDemodSettings();
SWGADSBDemodSettings(QString* json);
virtual ~SWGADSBDemodSettings();
void init();
void cleanup();
virtual QString asJson () override;
virtual QJsonObject* asJsonObject() override;
virtual void fromJsonObject(QJsonObject &json) override;
virtual SWGADSBDemodSettings* fromJson(QString &jsonString) override;
qint64 getInputFrequencyOffset();
void setInputFrequencyOffset(qint64 input_frequency_offset);
float getRfBandwidth();
void setRfBandwidth(float rf_bandwidth);
float getCorrelationThreshold();
void setCorrelationThreshold(float correlation_threshold);
qint32 getSamplesPerBit();
void setSamplesPerBit(qint32 samples_per_bit);
qint32 getRemoveTimeout();
void setRemoveTimeout(qint32 remove_timeout);
qint32 getBeastEnabled();
void setBeastEnabled(qint32 beast_enabled);
QString* getBeastHost();
void setBeastHost(QString* beast_host);
qint32 getBeastPort();
void setBeastPort(qint32 beast_port);
qint32 getRgbColor();
void setRgbColor(qint32 rgb_color);
QString* getTitle();
void setTitle(QString* title);
qint32 getStreamIndex();
void setStreamIndex(qint32 stream_index);
qint32 getUseReverseApi();
void setUseReverseApi(qint32 use_reverse_api);
QString* getReverseApiAddress();
void setReverseApiAddress(QString* reverse_api_address);
qint32 getReverseApiPort();
void setReverseApiPort(qint32 reverse_api_port);
qint32 getReverseApiDeviceIndex();
void setReverseApiDeviceIndex(qint32 reverse_api_device_index);
qint32 getReverseApiChannelIndex();
void setReverseApiChannelIndex(qint32 reverse_api_channel_index);
virtual bool isSet() override;
private:
qint64 input_frequency_offset;
bool m_input_frequency_offset_isSet;
float rf_bandwidth;
bool m_rf_bandwidth_isSet;
float correlation_threshold;
bool m_correlation_threshold_isSet;
qint32 samples_per_bit;
bool m_samples_per_bit_isSet;
qint32 remove_timeout;
bool m_remove_timeout_isSet;
qint32 beast_enabled;
bool m_beast_enabled_isSet;
QString* beast_host;
bool m_beast_host_isSet;
qint32 beast_port;
bool m_beast_port_isSet;
qint32 rgb_color;
bool m_rgb_color_isSet;
QString* title;
bool m_title_isSet;
qint32 stream_index;
bool m_stream_index_isSet;
qint32 use_reverse_api;
bool m_use_reverse_api_isSet;
QString* reverse_api_address;
bool m_reverse_api_address_isSet;
qint32 reverse_api_port;
bool m_reverse_api_port_isSet;
qint32 reverse_api_device_index;
bool m_reverse_api_device_index_isSet;
qint32 reverse_api_channel_index;
bool m_reverse_api_channel_index_isSet;
};
}
#endif /* SWGADSBDemodSettings_H_ */

Wyświetl plik

@ -32,6 +32,8 @@ SWGChannelReport::SWGChannelReport() {
m_channel_type_isSet = false;
direction = 0;
m_direction_isSet = false;
adsb_demod_report = nullptr;
m_adsb_demod_report_isSet = false;
am_demod_report = nullptr;
m_am_demod_report_isSet = false;
am_mod_report = nullptr;
@ -86,6 +88,8 @@ SWGChannelReport::init() {
m_channel_type_isSet = false;
direction = 0;
m_direction_isSet = false;
adsb_demod_report = new SWGADSBDemodReport();
m_adsb_demod_report_isSet = false;
am_demod_report = new SWGAMDemodReport();
m_am_demod_report_isSet = false;
am_mod_report = new SWGAMModReport();
@ -136,6 +140,9 @@ SWGChannelReport::cleanup() {
delete channel_type;
}
if(adsb_demod_report != nullptr) {
delete adsb_demod_report;
}
if(am_demod_report != nullptr) {
delete am_demod_report;
}
@ -216,6 +223,8 @@ SWGChannelReport::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&direction, pJson["direction"], "qint32", "");
::SWGSDRangel::setValue(&adsb_demod_report, pJson["ADSBDemodReport"], "SWGADSBDemodReport", "SWGADSBDemodReport");
::SWGSDRangel::setValue(&am_demod_report, pJson["AMDemodReport"], "SWGAMDemodReport", "SWGAMDemodReport");
::SWGSDRangel::setValue(&am_mod_report, pJson["AMModReport"], "SWGAMModReport", "SWGAMModReport");
@ -280,6 +289,9 @@ SWGChannelReport::asJsonObject() {
if(m_direction_isSet){
obj->insert("direction", QJsonValue(direction));
}
if((adsb_demod_report != nullptr) && (adsb_demod_report->isSet())){
toJsonValue(QString("ADSBDemodReport"), adsb_demod_report, obj, QString("SWGADSBDemodReport"));
}
if((am_demod_report != nullptr) && (am_demod_report->isSet())){
toJsonValue(QString("AMDemodReport"), am_demod_report, obj, QString("SWGAMDemodReport"));
}
@ -367,6 +379,16 @@ SWGChannelReport::setDirection(qint32 direction) {
this->m_direction_isSet = true;
}
SWGADSBDemodReport*
SWGChannelReport::getAdsbDemodReport() {
return adsb_demod_report;
}
void
SWGChannelReport::setAdsbDemodReport(SWGADSBDemodReport* adsb_demod_report) {
this->adsb_demod_report = adsb_demod_report;
this->m_adsb_demod_report_isSet = true;
}
SWGAMDemodReport*
SWGChannelReport::getAmDemodReport() {
return am_demod_report;
@ -588,6 +610,9 @@ SWGChannelReport::isSet(){
if(m_direction_isSet){
isObjectUpdated = true; break;
}
if(adsb_demod_report && adsb_demod_report->isSet()){
isObjectUpdated = true; break;
}
if(am_demod_report && am_demod_report->isSet()){
isObjectUpdated = true; break;
}

Wyświetl plik

@ -22,6 +22,7 @@
#include <QJsonObject>
#include "SWGADSBDemodReport.h"
#include "SWGAMDemodReport.h"
#include "SWGAMModReport.h"
#include "SWGATVModReport.h"
@ -69,6 +70,9 @@ public:
qint32 getDirection();
void setDirection(qint32 direction);
SWGADSBDemodReport* getAdsbDemodReport();
void setAdsbDemodReport(SWGADSBDemodReport* adsb_demod_report);
SWGAMDemodReport* getAmDemodReport();
void setAmDemodReport(SWGAMDemodReport* am_demod_report);
@ -142,6 +146,9 @@ private:
qint32 direction;
bool m_direction_isSet;
SWGADSBDemodReport* adsb_demod_report;
bool m_adsb_demod_report_isSet;
SWGAMDemodReport* am_demod_report;
bool m_am_demod_report_isSet;

Wyświetl plik

@ -36,6 +36,8 @@ SWGChannelSettings::SWGChannelSettings() {
m_originator_device_set_index_isSet = false;
originator_channel_index = 0;
m_originator_channel_index_isSet = false;
adsb_demod_settings = nullptr;
m_adsb_demod_settings_isSet = false;
am_demod_settings = nullptr;
m_am_demod_settings_isSet = false;
am_mod_settings = nullptr;
@ -106,6 +108,8 @@ SWGChannelSettings::init() {
m_originator_device_set_index_isSet = false;
originator_channel_index = 0;
m_originator_channel_index_isSet = false;
adsb_demod_settings = new SWGADSBDemodSettings();
m_adsb_demod_settings_isSet = false;
am_demod_settings = new SWGAMDemodSettings();
m_am_demod_settings_isSet = false;
am_mod_settings = new SWGAMModSettings();
@ -170,6 +174,9 @@ SWGChannelSettings::cleanup() {
if(adsb_demod_settings != nullptr) {
delete adsb_demod_settings;
}
if(am_demod_settings != nullptr) {
delete am_demod_settings;
}
@ -272,6 +279,8 @@ SWGChannelSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&originator_channel_index, pJson["originatorChannelIndex"], "qint32", "");
::SWGSDRangel::setValue(&adsb_demod_settings, pJson["ADSBDemodSettings"], "SWGADSBDemodSettings", "SWGADSBDemodSettings");
::SWGSDRangel::setValue(&am_demod_settings, pJson["AMDemodSettings"], "SWGAMDemodSettings", "SWGAMDemodSettings");
::SWGSDRangel::setValue(&am_mod_settings, pJson["AMModSettings"], "SWGAMModSettings", "SWGAMModSettings");
@ -354,6 +363,9 @@ SWGChannelSettings::asJsonObject() {
if(m_originator_channel_index_isSet){
obj->insert("originatorChannelIndex", QJsonValue(originator_channel_index));
}
if((adsb_demod_settings != nullptr) && (adsb_demod_settings->isSet())){
toJsonValue(QString("ADSBDemodSettings"), adsb_demod_settings, obj, QString("SWGADSBDemodSettings"));
}
if((am_demod_settings != nullptr) && (am_demod_settings->isSet())){
toJsonValue(QString("AMDemodSettings"), am_demod_settings, obj, QString("SWGAMDemodSettings"));
}
@ -479,6 +491,16 @@ SWGChannelSettings::setOriginatorChannelIndex(qint32 originator_channel_index) {
this->m_originator_channel_index_isSet = true;
}
SWGADSBDemodSettings*
SWGChannelSettings::getAdsbDemodSettings() {
return adsb_demod_settings;
}
void
SWGChannelSettings::setAdsbDemodSettings(SWGADSBDemodSettings* adsb_demod_settings) {
this->adsb_demod_settings = adsb_demod_settings;
this->m_adsb_demod_settings_isSet = true;
}
SWGAMDemodSettings*
SWGChannelSettings::getAmDemodSettings() {
return am_demod_settings;
@ -766,6 +788,9 @@ SWGChannelSettings::isSet(){
if(m_originator_channel_index_isSet){
isObjectUpdated = true; break;
}
if(adsb_demod_settings && adsb_demod_settings->isSet()){
isObjectUpdated = true; break;
}
if(am_demod_settings && am_demod_settings->isSet()){
isObjectUpdated = true; break;
}

Wyświetl plik

@ -22,6 +22,7 @@
#include <QJsonObject>
#include "SWGADSBDemodSettings.h"
#include "SWGAMDemodSettings.h"
#include "SWGAMModSettings.h"
#include "SWGATVDemodSettings.h"
@ -81,6 +82,9 @@ public:
qint32 getOriginatorChannelIndex();
void setOriginatorChannelIndex(qint32 originator_channel_index);
SWGADSBDemodSettings* getAdsbDemodSettings();
void setAdsbDemodSettings(SWGADSBDemodSettings* adsb_demod_settings);
SWGAMDemodSettings* getAmDemodSettings();
void setAmDemodSettings(SWGAMDemodSettings* am_demod_settings);
@ -178,6 +182,9 @@ private:
qint32 originator_channel_index;
bool m_originator_channel_index_isSet;
SWGADSBDemodSettings* adsb_demod_settings;
bool m_adsb_demod_settings_isSet;
SWGAMDemodSettings* am_demod_settings;
bool m_am_demod_settings_isSet;

Wyświetl plik

@ -34,6 +34,8 @@ SWGFeatureSettings::SWGFeatureSettings() {
m_originator_feature_set_index_isSet = false;
originator_feature_index = 0;
m_originator_feature_index_isSet = false;
gs232_controller_settings = nullptr;
m_gs232_controller_settings_isSet = false;
simple_ptt_settings = nullptr;
m_simple_ptt_settings_isSet = false;
rig_ctl_server_settings = nullptr;
@ -52,6 +54,8 @@ SWGFeatureSettings::init() {
m_originator_feature_set_index_isSet = false;
originator_feature_index = 0;
m_originator_feature_index_isSet = false;
gs232_controller_settings = new SWGGS232ControllerSettings();
m_gs232_controller_settings_isSet = false;
simple_ptt_settings = new SWGSimplePTTSettings();
m_simple_ptt_settings_isSet = false;
rig_ctl_server_settings = new SWGRigCtlServerSettings();
@ -65,6 +69,9 @@ SWGFeatureSettings::cleanup() {
}
if(gs232_controller_settings != nullptr) {
delete gs232_controller_settings;
}
if(simple_ptt_settings != nullptr) {
delete simple_ptt_settings;
}
@ -90,6 +97,8 @@ SWGFeatureSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&originator_feature_index, pJson["originatorFeatureIndex"], "qint32", "");
::SWGSDRangel::setValue(&gs232_controller_settings, pJson["GS232ControllerSettings"], "SWGGS232ControllerSettings", "SWGGS232ControllerSettings");
::SWGSDRangel::setValue(&simple_ptt_settings, pJson["SimplePTTSettings"], "SWGSimplePTTSettings", "SWGSimplePTTSettings");
::SWGSDRangel::setValue(&rig_ctl_server_settings, pJson["RigCtlServerSettings"], "SWGRigCtlServerSettings", "SWGRigCtlServerSettings");
@ -119,6 +128,9 @@ SWGFeatureSettings::asJsonObject() {
if(m_originator_feature_index_isSet){
obj->insert("originatorFeatureIndex", QJsonValue(originator_feature_index));
}
if((gs232_controller_settings != nullptr) && (gs232_controller_settings->isSet())){
toJsonValue(QString("GS232ControllerSettings"), gs232_controller_settings, obj, QString("SWGGS232ControllerSettings"));
}
if((simple_ptt_settings != nullptr) && (simple_ptt_settings->isSet())){
toJsonValue(QString("SimplePTTSettings"), simple_ptt_settings, obj, QString("SWGSimplePTTSettings"));
}
@ -159,6 +171,16 @@ SWGFeatureSettings::setOriginatorFeatureIndex(qint32 originator_feature_index) {
this->m_originator_feature_index_isSet = true;
}
SWGGS232ControllerSettings*
SWGFeatureSettings::getGs232ControllerSettings() {
return gs232_controller_settings;
}
void
SWGFeatureSettings::setGs232ControllerSettings(SWGGS232ControllerSettings* gs232_controller_settings) {
this->gs232_controller_settings = gs232_controller_settings;
this->m_gs232_controller_settings_isSet = true;
}
SWGSimplePTTSettings*
SWGFeatureSettings::getSimplePttSettings() {
return simple_ptt_settings;
@ -193,6 +215,9 @@ SWGFeatureSettings::isSet(){
if(m_originator_feature_index_isSet){
isObjectUpdated = true; break;
}
if(gs232_controller_settings && gs232_controller_settings->isSet()){
isObjectUpdated = true; break;
}
if(simple_ptt_settings && simple_ptt_settings->isSet()){
isObjectUpdated = true; break;
}

Wyświetl plik

@ -22,6 +22,7 @@
#include <QJsonObject>
#include "SWGGS232ControllerSettings.h"
#include "SWGRigCtlServerSettings.h"
#include "SWGSimplePTTSettings.h"
#include <QString>
@ -53,6 +54,9 @@ public:
qint32 getOriginatorFeatureIndex();
void setOriginatorFeatureIndex(qint32 originator_feature_index);
SWGGS232ControllerSettings* getGs232ControllerSettings();
void setGs232ControllerSettings(SWGGS232ControllerSettings* gs232_controller_settings);
SWGSimplePTTSettings* getSimplePttSettings();
void setSimplePttSettings(SWGSimplePTTSettings* simple_ptt_settings);
@ -72,6 +76,9 @@ private:
qint32 originator_feature_index;
bool m_originator_feature_index_isSet;
SWGGS232ControllerSettings* gs232_controller_settings;
bool m_gs232_controller_settings_isSet;
SWGSimplePTTSettings* simple_ptt_settings;
bool m_simple_ptt_settings_isSet;

Wyświetl plik

@ -0,0 +1,413 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.15.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
#include "SWGGS232ControllerSettings.h"
#include "SWGHelpers.h"
#include <QJsonDocument>
#include <QJsonArray>
#include <QObject>
#include <QDebug>
namespace SWGSDRangel {
SWGGS232ControllerSettings::SWGGS232ControllerSettings(QString* json) {
init();
this->fromJson(*json);
}
SWGGS232ControllerSettings::SWGGS232ControllerSettings() {
azimuth = 0;
m_azimuth_isSet = false;
elevation = 0;
m_elevation_isSet = false;
serial_port = nullptr;
m_serial_port_isSet = false;
baud_rate = 0;
m_baud_rate_isSet = false;
track = 0;
m_track_isSet = false;
title = nullptr;
m_title_isSet = false;
rgb_color = 0;
m_rgb_color_isSet = false;
device_index = 0;
m_device_index_isSet = false;
channel_index = 0;
m_channel_index_isSet = false;
use_reverse_api = 0;
m_use_reverse_api_isSet = false;
reverse_api_address = nullptr;
m_reverse_api_address_isSet = false;
reverse_api_port = 0;
m_reverse_api_port_isSet = false;
reverse_api_device_index = 0;
m_reverse_api_device_index_isSet = false;
reverse_api_channel_index = 0;
m_reverse_api_channel_index_isSet = false;
}
SWGGS232ControllerSettings::~SWGGS232ControllerSettings() {
this->cleanup();
}
void
SWGGS232ControllerSettings::init() {
azimuth = 0;
m_azimuth_isSet = false;
elevation = 0;
m_elevation_isSet = false;
serial_port = new QString("");
m_serial_port_isSet = false;
baud_rate = 0;
m_baud_rate_isSet = false;
track = 0;
m_track_isSet = false;
title = new QString("");
m_title_isSet = false;
rgb_color = 0;
m_rgb_color_isSet = false;
device_index = 0;
m_device_index_isSet = false;
channel_index = 0;
m_channel_index_isSet = false;
use_reverse_api = 0;
m_use_reverse_api_isSet = false;
reverse_api_address = new QString("");
m_reverse_api_address_isSet = false;
reverse_api_port = 0;
m_reverse_api_port_isSet = false;
reverse_api_device_index = 0;
m_reverse_api_device_index_isSet = false;
reverse_api_channel_index = 0;
m_reverse_api_channel_index_isSet = false;
}
void
SWGGS232ControllerSettings::cleanup() {
if(serial_port != nullptr) {
delete serial_port;
}
if(title != nullptr) {
delete title;
}
if(reverse_api_address != nullptr) {
delete reverse_api_address;
}
}
SWGGS232ControllerSettings*
SWGGS232ControllerSettings::fromJson(QString &json) {
QByteArray array (json.toStdString().c_str());
QJsonDocument doc = QJsonDocument::fromJson(array);
QJsonObject jsonObject = doc.object();
this->fromJsonObject(jsonObject);
return this;
}
void
SWGGS232ControllerSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&azimuth, pJson["azimuth"], "qint32", "");
::SWGSDRangel::setValue(&elevation, pJson["elevation"], "qint32", "");
::SWGSDRangel::setValue(&serial_port, pJson["serialPort"], "QString", "QString");
::SWGSDRangel::setValue(&baud_rate, pJson["baudRate"], "qint32", "");
::SWGSDRangel::setValue(&track, pJson["track"], "qint32", "");
::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString");
::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", "");
::SWGSDRangel::setValue(&device_index, pJson["deviceIndex"], "qint32", "");
::SWGSDRangel::setValue(&channel_index, pJson["channelIndex"], "qint32", "");
::SWGSDRangel::setValue(&use_reverse_api, pJson["useReverseAPI"], "qint32", "");
::SWGSDRangel::setValue(&reverse_api_address, pJson["reverseAPIAddress"], "QString", "QString");
::SWGSDRangel::setValue(&reverse_api_port, pJson["reverseAPIPort"], "qint32", "");
::SWGSDRangel::setValue(&reverse_api_device_index, pJson["reverseAPIDeviceIndex"], "qint32", "");
::SWGSDRangel::setValue(&reverse_api_channel_index, pJson["reverseAPIChannelIndex"], "qint32", "");
}
QString
SWGGS232ControllerSettings::asJson ()
{
QJsonObject* obj = this->asJsonObject();
QJsonDocument doc(*obj);
QByteArray bytes = doc.toJson();
delete obj;
return QString(bytes);
}
QJsonObject*
SWGGS232ControllerSettings::asJsonObject() {
QJsonObject* obj = new QJsonObject();
if(m_azimuth_isSet){
obj->insert("azimuth", QJsonValue(azimuth));
}
if(m_elevation_isSet){
obj->insert("elevation", QJsonValue(elevation));
}
if(serial_port != nullptr && *serial_port != QString("")){
toJsonValue(QString("serialPort"), serial_port, obj, QString("QString"));
}
if(m_baud_rate_isSet){
obj->insert("baudRate", QJsonValue(baud_rate));
}
if(m_track_isSet){
obj->insert("track", QJsonValue(track));
}
if(title != nullptr && *title != QString("")){
toJsonValue(QString("title"), title, obj, QString("QString"));
}
if(m_rgb_color_isSet){
obj->insert("rgbColor", QJsonValue(rgb_color));
}
if(m_device_index_isSet){
obj->insert("deviceIndex", QJsonValue(device_index));
}
if(m_channel_index_isSet){
obj->insert("channelIndex", QJsonValue(channel_index));
}
if(m_use_reverse_api_isSet){
obj->insert("useReverseAPI", QJsonValue(use_reverse_api));
}
if(reverse_api_address != nullptr && *reverse_api_address != QString("")){
toJsonValue(QString("reverseAPIAddress"), reverse_api_address, obj, QString("QString"));
}
if(m_reverse_api_port_isSet){
obj->insert("reverseAPIPort", QJsonValue(reverse_api_port));
}
if(m_reverse_api_device_index_isSet){
obj->insert("reverseAPIDeviceIndex", QJsonValue(reverse_api_device_index));
}
if(m_reverse_api_channel_index_isSet){
obj->insert("reverseAPIChannelIndex", QJsonValue(reverse_api_channel_index));
}
return obj;
}
qint32
SWGGS232ControllerSettings::getAzimuth() {
return azimuth;
}
void
SWGGS232ControllerSettings::setAzimuth(qint32 azimuth) {
this->azimuth = azimuth;
this->m_azimuth_isSet = true;
}
qint32
SWGGS232ControllerSettings::getElevation() {
return elevation;
}
void
SWGGS232ControllerSettings::setElevation(qint32 elevation) {
this->elevation = elevation;
this->m_elevation_isSet = true;
}
QString*
SWGGS232ControllerSettings::getSerialPort() {
return serial_port;
}
void
SWGGS232ControllerSettings::setSerialPort(QString* serial_port) {
this->serial_port = serial_port;
this->m_serial_port_isSet = true;
}
qint32
SWGGS232ControllerSettings::getBaudRate() {
return baud_rate;
}
void
SWGGS232ControllerSettings::setBaudRate(qint32 baud_rate) {
this->baud_rate = baud_rate;
this->m_baud_rate_isSet = true;
}
qint32
SWGGS232ControllerSettings::getTrack() {
return track;
}
void
SWGGS232ControllerSettings::setTrack(qint32 track) {
this->track = track;
this->m_track_isSet = true;
}
QString*
SWGGS232ControllerSettings::getTitle() {
return title;
}
void
SWGGS232ControllerSettings::setTitle(QString* title) {
this->title = title;
this->m_title_isSet = true;
}
qint32
SWGGS232ControllerSettings::getRgbColor() {
return rgb_color;
}
void
SWGGS232ControllerSettings::setRgbColor(qint32 rgb_color) {
this->rgb_color = rgb_color;
this->m_rgb_color_isSet = true;
}
qint32
SWGGS232ControllerSettings::getDeviceIndex() {
return device_index;
}
void
SWGGS232ControllerSettings::setDeviceIndex(qint32 device_index) {
this->device_index = device_index;
this->m_device_index_isSet = true;
}
qint32
SWGGS232ControllerSettings::getChannelIndex() {
return channel_index;
}
void
SWGGS232ControllerSettings::setChannelIndex(qint32 channel_index) {
this->channel_index = channel_index;
this->m_channel_index_isSet = true;
}
qint32
SWGGS232ControllerSettings::getUseReverseApi() {
return use_reverse_api;
}
void
SWGGS232ControllerSettings::setUseReverseApi(qint32 use_reverse_api) {
this->use_reverse_api = use_reverse_api;
this->m_use_reverse_api_isSet = true;
}
QString*
SWGGS232ControllerSettings::getReverseApiAddress() {
return reverse_api_address;
}
void
SWGGS232ControllerSettings::setReverseApiAddress(QString* reverse_api_address) {
this->reverse_api_address = reverse_api_address;
this->m_reverse_api_address_isSet = true;
}
qint32
SWGGS232ControllerSettings::getReverseApiPort() {
return reverse_api_port;
}
void
SWGGS232ControllerSettings::setReverseApiPort(qint32 reverse_api_port) {
this->reverse_api_port = reverse_api_port;
this->m_reverse_api_port_isSet = true;
}
qint32
SWGGS232ControllerSettings::getReverseApiDeviceIndex() {
return reverse_api_device_index;
}
void
SWGGS232ControllerSettings::setReverseApiDeviceIndex(qint32 reverse_api_device_index) {
this->reverse_api_device_index = reverse_api_device_index;
this->m_reverse_api_device_index_isSet = true;
}
qint32
SWGGS232ControllerSettings::getReverseApiChannelIndex() {
return reverse_api_channel_index;
}
void
SWGGS232ControllerSettings::setReverseApiChannelIndex(qint32 reverse_api_channel_index) {
this->reverse_api_channel_index = reverse_api_channel_index;
this->m_reverse_api_channel_index_isSet = true;
}
bool
SWGGS232ControllerSettings::isSet(){
bool isObjectUpdated = false;
do{
if(m_azimuth_isSet){
isObjectUpdated = true; break;
}
if(m_elevation_isSet){
isObjectUpdated = true; break;
}
if(serial_port && *serial_port != QString("")){
isObjectUpdated = true; break;
}
if(m_baud_rate_isSet){
isObjectUpdated = true; break;
}
if(m_track_isSet){
isObjectUpdated = true; break;
}
if(title && *title != QString("")){
isObjectUpdated = true; break;
}
if(m_rgb_color_isSet){
isObjectUpdated = true; break;
}
if(m_device_index_isSet){
isObjectUpdated = true; break;
}
if(m_channel_index_isSet){
isObjectUpdated = true; break;
}
if(m_use_reverse_api_isSet){
isObjectUpdated = true; break;
}
if(reverse_api_address && *reverse_api_address != QString("")){
isObjectUpdated = true; break;
}
if(m_reverse_api_port_isSet){
isObjectUpdated = true; break;
}
if(m_reverse_api_device_index_isSet){
isObjectUpdated = true; break;
}
if(m_reverse_api_channel_index_isSet){
isObjectUpdated = true; break;
}
}while(false);
return isObjectUpdated;
}
}

Wyświetl plik

@ -0,0 +1,137 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 4.15.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
/*
* SWGGS232ControllerSettings.h
*
* GS-232 Controller settings
*/
#ifndef SWGGS232ControllerSettings_H_
#define SWGGS232ControllerSettings_H_
#include <QJsonObject>
#include <QString>
#include "SWGObject.h"
#include "export.h"
namespace SWGSDRangel {
class SWG_API SWGGS232ControllerSettings: public SWGObject {
public:
SWGGS232ControllerSettings();
SWGGS232ControllerSettings(QString* json);
virtual ~SWGGS232ControllerSettings();
void init();
void cleanup();
virtual QString asJson () override;
virtual QJsonObject* asJsonObject() override;
virtual void fromJsonObject(QJsonObject &json) override;
virtual SWGGS232ControllerSettings* fromJson(QString &jsonString) override;
qint32 getAzimuth();
void setAzimuth(qint32 azimuth);
qint32 getElevation();
void setElevation(qint32 elevation);
QString* getSerialPort();
void setSerialPort(QString* serial_port);
qint32 getBaudRate();
void setBaudRate(qint32 baud_rate);
qint32 getTrack();
void setTrack(qint32 track);
QString* getTitle();
void setTitle(QString* title);
qint32 getRgbColor();
void setRgbColor(qint32 rgb_color);
qint32 getDeviceIndex();
void setDeviceIndex(qint32 device_index);
qint32 getChannelIndex();
void setChannelIndex(qint32 channel_index);
qint32 getUseReverseApi();
void setUseReverseApi(qint32 use_reverse_api);
QString* getReverseApiAddress();
void setReverseApiAddress(QString* reverse_api_address);
qint32 getReverseApiPort();
void setReverseApiPort(qint32 reverse_api_port);
qint32 getReverseApiDeviceIndex();
void setReverseApiDeviceIndex(qint32 reverse_api_device_index);
qint32 getReverseApiChannelIndex();
void setReverseApiChannelIndex(qint32 reverse_api_channel_index);
virtual bool isSet() override;
private:
qint32 azimuth;
bool m_azimuth_isSet;
qint32 elevation;
bool m_elevation_isSet;
QString* serial_port;
bool m_serial_port_isSet;
qint32 baud_rate;
bool m_baud_rate_isSet;
qint32 track;
bool m_track_isSet;
QString* title;
bool m_title_isSet;
qint32 rgb_color;
bool m_rgb_color_isSet;
qint32 device_index;
bool m_device_index_isSet;
qint32 channel_index;
bool m_channel_index_isSet;
qint32 use_reverse_api;
bool m_use_reverse_api_isSet;
QString* reverse_api_address;
bool m_reverse_api_address_isSet;
qint32 reverse_api_port;
bool m_reverse_api_port_isSet;
qint32 reverse_api_device_index;
bool m_reverse_api_device_index_isSet;
qint32 reverse_api_channel_index;
bool m_reverse_api_channel_index_isSet;
};
}
#endif /* SWGGS232ControllerSettings_H_ */

Wyświetl plik

@ -14,6 +14,8 @@
#define ModelFactory_H_
#include "SWGADSBDemodReport.h"
#include "SWGADSBDemodSettings.h"
#include "SWGAMBEDevice.h"
#include "SWGAMBEDevices.h"
#include "SWGAMDemodReport.h"
@ -96,6 +98,7 @@
#include "SWGFrequencyRange.h"
#include "SWGGLScope.h"
#include "SWGGLSpectrum.h"
#include "SWGGS232ControllerSettings.h"
#include "SWGGain.h"
#include "SWGHackRFInputSettings.h"
#include "SWGHackRFOutputSettings.h"
@ -203,6 +206,12 @@
namespace SWGSDRangel {
inline void* create(QString type) {
if(QString("SWGADSBDemodReport").compare(type) == 0) {
return new SWGADSBDemodReport();
}
if(QString("SWGADSBDemodSettings").compare(type) == 0) {
return new SWGADSBDemodSettings();
}
if(QString("SWGAMBEDevice").compare(type) == 0) {
return new SWGAMBEDevice();
}
@ -449,6 +458,9 @@ namespace SWGSDRangel {
if(QString("SWGGLSpectrum").compare(type) == 0) {
return new SWGGLSpectrum();
}
if(QString("SWGGS232ControllerSettings").compare(type) == 0) {
return new SWGGS232ControllerSettings();
}
if(QString("SWGGain").compare(type) == 0) {
return new SWGGain();
}