From 539a03373f894869f14acc072f869394b2463a09 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sat, 21 May 2022 11:20:38 +0200 Subject: [PATCH] LimeRFE feature. Implements #1251 --- plugins/feature/CMakeLists.txt | 4 + plugins/feature/limerfe/CMakeLists.txt | 67 ++ plugins/feature/limerfe/limerfe.cpp | 716 +++++++++++++ plugins/feature/limerfe/limerfe.h | 117 +++ plugins/feature/limerfe/limerfegui.cpp | 1009 +++++++++++++++++++ plugins/feature/limerfe/limerfegui.h | 135 +++ plugins/feature/limerfe/limerfegui.ui | 980 ++++++++++++++++++ plugins/feature/limerfe/limerfeplugin.cpp | 80 ++ plugins/feature/limerfe/limerfeplugin.h | 48 + plugins/feature/limerfe/limerfesettings.cpp | 185 ++++ plugins/feature/limerfe/limerfesettings.h | 122 +++ plugins/feature/limerfe/limerfeusbcalib.cpp | 71 ++ plugins/feature/limerfe/limerfeusbcalib.h | 59 ++ 13 files changed, 3593 insertions(+) create mode 100644 plugins/feature/limerfe/CMakeLists.txt create mode 100644 plugins/feature/limerfe/limerfe.cpp create mode 100644 plugins/feature/limerfe/limerfe.h create mode 100644 plugins/feature/limerfe/limerfegui.cpp create mode 100644 plugins/feature/limerfe/limerfegui.h create mode 100644 plugins/feature/limerfe/limerfegui.ui create mode 100644 plugins/feature/limerfe/limerfeplugin.cpp create mode 100644 plugins/feature/limerfe/limerfeplugin.h create mode 100644 plugins/feature/limerfe/limerfesettings.cpp create mode 100644 plugins/feature/limerfe/limerfesettings.h create mode 100644 plugins/feature/limerfe/limerfeusbcalib.cpp create mode 100644 plugins/feature/limerfe/limerfeusbcalib.h diff --git a/plugins/feature/CMakeLists.txt b/plugins/feature/CMakeLists.txt index 9a00b324d..ac1b031d5 100644 --- a/plugins/feature/CMakeLists.txt +++ b/plugins/feature/CMakeLists.txt @@ -35,3 +35,7 @@ if (Qt5Charts_FOUND) add_subdirectory(radiosonde) add_subdirectory(startracker) endif() + +if (ENABLE_LIMESUITE AND LIMESUITE_FOUND) + add_subdirectory(limerfe) +endif() diff --git a/plugins/feature/limerfe/CMakeLists.txt b/plugins/feature/limerfe/CMakeLists.txt new file mode 100644 index 000000000..bb1555046 --- /dev/null +++ b/plugins/feature/limerfe/CMakeLists.txt @@ -0,0 +1,67 @@ +project(limerfe) + +set(limerfe_SOURCES + limerfe.cpp + limerfesettings.cpp + limerfeusbcalib.cpp + limerfeplugin.cpp + # limerfeworker.cpp + # limerfereport.cpp + # limerfewebapiadapter.cpp +) + +set(limerfe_HEADERS + limerfe.h + limerfesettings.h + limerfeusbcalib.h + limerfeplugin.h + # limerfeworker.h + # limerfereport.h + # limerfewebapiadapter.h +) + +include_directories( + ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client + ${LIMESUITE_INCLUDE_DIR} +) + +if(NOT SERVER_MODE) + set(limerfe_SOURCES + ${limerfe_SOURCES} + limerfegui.cpp + limerfegui.ui + ) + set(limerfe_HEADERS + ${limerfe_HEADERS} + limerfegui.h + ) + + set(TARGET_NAME featurelimerfe) + set(TARGET_LIB "Qt5::Widgets") + set(TARGET_LIB_GUI "sdrgui") + set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR}) +else() + set(TARGET_NAME featurelimerfesrv) + set(TARGET_LIB "") + set(TARGET_LIB_GUI "") + set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR}) +endif() + +add_library(${TARGET_NAME} SHARED + ${limerfe_SOURCES} +) + +target_link_libraries(${TARGET_NAME} + Qt5::Core + ${TARGET_LIB} + sdrbase + ${TARGET_LIB_GUI} + ${LIMESUITE_LIBRARY} +) + +install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER}) + +# Install debug symbols +if (WIN32) + install(FILES $ CONFIGURATIONS Debug RelWithDebInfo DESTINATION ${INSTALL_FOLDER} ) +endif() diff --git a/plugins/feature/limerfe/limerfe.cpp b/plugins/feature/limerfe/limerfe.cpp new file mode 100644 index 000000000..1c108f023 --- /dev/null +++ b/plugins/feature/limerfe/limerfe.cpp @@ -0,0 +1,716 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "SWGDeviceState.h" +#include "SWGErrorResponse.h" + +#include "util/simpleserializer.h" +#include "util/serialutil.h" +#include "webapi/webapiadapterinterface.h" + +#include "limerfe.h" + +MESSAGE_CLASS_DEFINITION(LimeRFE::MsgConfigureLimeRFE, Message) + +const char* const LimeRFE::m_featureIdURI = "sdrangel.feature.limerfe"; +const char* const LimeRFE::m_featureId = "LimeRFE"; + +const std::map LimeRFE::m_errorCodesMap = { + { 0, "OK"}, + {-4, "Error synchronizing communication"}, + {-3, "Non-configurable GPIO pin specified. Only pins 4 and 5 are configurable."}, + {-2, "Problem with .ini configuration file"}, + {-1, "Communication error"}, + { 1, "Wrong TX connector - not possible to route TX of the selecrted channel to the specified port"}, + { 2, "Wrong RX connector - not possible to route RX of the selecrted channel to the specified port"}, + { 3, "Mode TXRX not allowed - when the same port is selected for RX and TX, it is not allowed to use mode RX & TX"}, + { 4, "Wrong mode for cellular channel - Cellular FDD bands (1, 2, 3, and 7) are only allowed mode RX & TX, while TDD band 38 is allowed only RX or TX mode"}, + { 5, "Cellular channels must be the same both for RX and TX"}, + { 6, "Requested channel code is wrong"} +}; + +LimeRFE::LimeRFE(WebAPIAdapterInterface *webAPIAdapterInterface) : + Feature(m_featureIdURI, webAPIAdapterInterface), + m_webAPIAdapterInterface(webAPIAdapterInterface), + m_rfeDevice(nullptr) +{ + setObjectName(m_featureId); + m_state = StIdle; + m_errorMessage = "LimeRFE error"; + m_networkManager = new QNetworkAccessManager(); + QObject::connect( + m_networkManager, + &QNetworkAccessManager::finished, + this, + &LimeRFE::networkManagerFinished + ); + listComPorts(); +} + +LimeRFE::~LimeRFE() +{ + QObject::disconnect( + m_networkManager, + &QNetworkAccessManager::finished, + this, + &LimeRFE::networkManagerFinished + ); + delete m_networkManager; + closeDevice(); +} + +void LimeRFE::start() +{ + qDebug("LimeRFE::start"); + m_state = StRunning; +} + +void LimeRFE::stop() +{ + qDebug("LimeRFE::stop"); + m_state = StIdle; +} + +void LimeRFE::listComPorts() +{ + m_comPorts.clear(); + std::vector comPorts; + SerialUtil::getComPorts(comPorts, "ttyUSB[0-9]+"); // regex is for Linux only + + for (std::vector::const_iterator it = comPorts.begin(); it != comPorts.end(); ++it) { + m_comPorts.push_back(QString(it->c_str())); + } +} + +bool LimeRFE::handleMessage(const Message& cmd) +{ + (void) cmd; + return false; +} + +QByteArray LimeRFE::serialize() const +{ + SimpleSerializer s(1); + + s.writeBlob(1, m_settings.serialize()); + s.writeBlob(2, m_calib.serialize()); + + return s.final(); +} + +bool LimeRFE::deserialize(const QByteArray& data) +{ + SimpleDeserializer d(data); + + if (!d.isValid()) + { + m_settings.resetToDefaults(); + return false; + } + + if (d.getVersion() == 1) + { + QByteArray bytetmp; + bool ret; + + d.readBlob(1, &bytetmp); + + if (m_settings.deserialize(bytetmp)) + { + MsgConfigureLimeRFE *msg = MsgConfigureLimeRFE::create(m_settings, true); + m_inputMessageQueue.push(msg); + ret = true; + } + else + { + m_settings.resetToDefaults(); + MsgConfigureLimeRFE *msg = MsgConfigureLimeRFE::create(m_settings, true); + m_inputMessageQueue.push(msg); + ret = false; + } + + d.readBlob(2, &bytetmp); + + if (!m_calib.deserialize(bytetmp)) { + ret = false; + } + + return ret; + } + else + { + return false; + } +} + +int LimeRFE::openDevice(const std::string& serialDeviceName) +{ + closeDevice(); + + rfe_dev_t *rfeDevice = RFE_Open(serialDeviceName.c_str(), nullptr); + + if (rfeDevice != (void *) -1) + { + m_rfeDevice = rfeDevice; + return 0; + } + else + { + return -1; + } +} + +void LimeRFE::closeDevice() +{ + if (m_rfeDevice) + { + RFE_Close(m_rfeDevice); + m_rfeDevice = nullptr; + } +} + +int LimeRFE::configure() +{ + if (!m_rfeDevice) { + return -1; + } + + qDebug() << "LimeRFE::configure: " + << "attValue: " << (int) m_rfeBoardState.attValue + << "channelIDRX: " << (int) m_rfeBoardState.channelIDRX + << "channelIDTX: " << (int) m_rfeBoardState.channelIDTX + << "mode: " << (int) m_rfeBoardState.mode + << "notchOnOff: " << (int) m_rfeBoardState.notchOnOff + << "selPortRX: " << (int) m_rfeBoardState.selPortRX + << "selPortTX: " << (int) m_rfeBoardState.selPortTX + << "enableSWR: " << (int) m_rfeBoardState.enableSWR + << "sourceSWR: " << (int) m_rfeBoardState.sourceSWR; + + int rc = RFE_ConfigureState(m_rfeDevice, m_rfeBoardState); + + if (rc != 0) { + qInfo("LimeRFE::configure: %s", getError(rc).c_str()); + } else { + qDebug() << "LimeRFE::configure: done"; + } + + return rc; +} + +int LimeRFE::getState() +{ + if (!m_rfeDevice) { + return -1; + } + + int rc = RFE_GetState(m_rfeDevice, &m_rfeBoardState); + + qDebug() << "LimeRFE::getState: " + << "attValue: " << (int) m_rfeBoardState.attValue + << "channelIDRX: " << (int) m_rfeBoardState.channelIDRX + << "channelIDTX: " << (int) m_rfeBoardState.channelIDTX + << "mode: " << (int) m_rfeBoardState.mode + << "notchOnOff: " << (int) m_rfeBoardState.notchOnOff + << "selPortRX: " << (int) m_rfeBoardState.selPortRX + << "selPortTX: " << (int) m_rfeBoardState.selPortTX + << "enableSWR: " << (int) m_rfeBoardState.enableSWR + << "sourceSWR: " << (int) m_rfeBoardState.sourceSWR; + + if (rc != 0) { + qInfo("LimeRFE::getState: %s", getError(rc).c_str()); + } + + return rc; +} + +std::string LimeRFE::getError(int errorCode) +{ + std::map::const_iterator it = m_errorCodesMap.find(errorCode); + + if (it == m_errorCodesMap.end()) { + return "Unknown error"; + } else { + return it->second; + } +} + +int LimeRFE::setRx(LimeRFESettings& settings, bool rxOn) +{ + if (!m_rfeDevice) { + return -1; + } + + int mode = rxOn && settings.m_txOn ? + RFE_MODE_TXRX : rxOn ? + RFE_MODE_RX : settings.m_txOn ? + RFE_MODE_TX : RFE_MODE_NONE; + + int rc = RFE_Mode(m_rfeDevice, mode); + + if (rc == 0) { + settings.m_rxOn = rxOn; + } + + return rc; +} + +int LimeRFE::setTx(LimeRFESettings& settings, bool txOn) +{ + if (!m_rfeDevice) { + return -1; + } + + int mode = txOn && settings.m_rxOn ? + RFE_MODE_TXRX : txOn ? + RFE_MODE_TX : settings.m_rxOn ? + RFE_MODE_RX : RFE_MODE_NONE; + + int rc = RFE_Mode(m_rfeDevice, mode); + + if (rc == 0) { + settings.m_txOn = txOn; + } + + return rc; +} + +bool LimeRFE::turnDevice(int deviceSetIndex, bool on) +{ + qDebug("LimeRFE::turnDevice %d: %s", deviceSetIndex, on ? "on" : "off"); + SWGSDRangel::SWGDeviceState response; + SWGSDRangel::SWGErrorResponse error; + int httpCode; + + if (on) { + httpCode = m_webAPIAdapterInterface->devicesetDeviceRunPost(deviceSetIndex, response, error); + } else { + httpCode = m_webAPIAdapterInterface->devicesetDeviceRunDelete(deviceSetIndex, response, error); + } + + if (httpCode/100 == 2) + { + qDebug("LimeRFE::turnDevice: %s success", on ? "on" : "off"); + return true; + } + else + { + qWarning("LimeRFE::turnDevice: error: %s", qPrintable(*error.getMessage())); + return false; + } +} + +int LimeRFE::getFwdPower(int& powerDB) +{ + if (!m_rfeDevice) { + return -1; + } + + int power; + int rc = RFE_ReadADC(m_rfeDevice, RFE_ADC1, &power); + + if (rc == 0) { + powerDB = power; + } + + return rc; +} + +int LimeRFE::getRefPower(int& powerDB) +{ + if (!m_rfeDevice) { + return -1; + } + + int power; + int rc = RFE_ReadADC(m_rfeDevice, RFE_ADC2, &power); + + if (rc == 0) { + powerDB = power; + } + + return rc; +} + +void LimeRFE::settingsToState(const LimeRFESettings& settings) +{ + if (settings.m_rxChannels == LimeRFESettings::ChannelGroups::ChannelsCellular) + { + if (settings.m_rxCellularChannel == LimeRFESettings::CellularChannel::CellularBand1) + { + m_rfeBoardState.channelIDRX = RFE_CID_CELL_BAND01; + m_rfeBoardState.mode = RFE_MODE_TXRX; + } + else if (settings.m_rxCellularChannel == LimeRFESettings::CellularChannel::CellularBand2) + { + m_rfeBoardState.channelIDRX = RFE_CID_CELL_BAND02; + m_rfeBoardState.mode = RFE_MODE_TXRX; + } + else if (settings.m_rxCellularChannel == LimeRFESettings::CellularChannel::CellularBand3) + { + m_rfeBoardState.channelIDRX = RFE_CID_CELL_BAND03; + m_rfeBoardState.mode = RFE_MODE_TXRX; + } + else if (settings.m_rxCellularChannel == LimeRFESettings::CellularChannel::CellularBand38) + { + m_rfeBoardState.channelIDRX = RFE_CID_CELL_BAND38; + } + else if (settings.m_rxCellularChannel == LimeRFESettings::CellularChannel::CellularBand7) + { + m_rfeBoardState.channelIDRX = RFE_CID_CELL_BAND07; + m_rfeBoardState.mode = RFE_MODE_TXRX; + } + + m_rfeBoardState.selPortRX = RFE_PORT_1; + m_rfeBoardState.selPortTX = RFE_PORT_1; + m_rfeBoardState.channelIDTX = m_rfeBoardState.channelIDRX; + } + else + { + m_rfeBoardState.mode = settings.m_rxOn && settings.m_txOn ? + RFE_MODE_TXRX : + settings.m_rxOn ? + RFE_MODE_RX : + settings.m_txOn ? + RFE_MODE_TX : + RFE_MODE_NONE; + + if (settings.m_rxChannels == LimeRFESettings::ChannelGroups::ChannelsWideband) + { + if (settings.m_rxWidebandChannel == LimeRFESettings::WidebandChannel::WidebandLow) { + m_rfeBoardState.channelIDRX = RFE_CID_WB_1000; + } else if (settings.m_rxWidebandChannel == LimeRFESettings::WidebandChannel::WidebandHigh) { + m_rfeBoardState.channelIDRX = RFE_CID_WB_4000; + } + } + else if (settings.m_rxChannels == LimeRFESettings::ChannelGroups::ChannelsHAM) + { + if (settings.m_rxHAMChannel == LimeRFESettings::HAMChannel::HAM_30M) { + m_rfeBoardState.channelIDRX = RFE_CID_HAM_0030; + } else if (settings.m_rxHAMChannel == LimeRFESettings::HAMChannel::HAM_50_70MHz) { + m_rfeBoardState.channelIDRX = RFE_CID_HAM_0070; + } else if (settings.m_rxHAMChannel == LimeRFESettings::HAMChannel::HAM_144_146MHz) { + m_rfeBoardState.channelIDRX = RFE_CID_HAM_0145; + } else if (settings.m_rxHAMChannel == LimeRFESettings::HAMChannel::HAM_220_225MHz) { + m_rfeBoardState.channelIDRX = RFE_CID_HAM_0220; + } else if (settings.m_rxHAMChannel == LimeRFESettings::HAMChannel::HAM_430_440MHz) { + m_rfeBoardState.channelIDRX = RFE_CID_HAM_0435; + } else if (settings.m_rxHAMChannel == LimeRFESettings::HAMChannel::HAM_902_928MHz) { + m_rfeBoardState.channelIDRX = RFE_CID_HAM_0920; + } else if (settings.m_rxHAMChannel == LimeRFESettings::HAMChannel::HAM_1240_1325MHz) { + m_rfeBoardState.channelIDRX = RFE_CID_HAM_1280; + } else if (settings.m_rxHAMChannel == LimeRFESettings::HAMChannel::HAM_2300_2450MHz) { + m_rfeBoardState.channelIDRX = RFE_CID_HAM_2400; + } else if (settings.m_rxHAMChannel == LimeRFESettings::HAMChannel::HAM_3300_3500MHz) { + m_rfeBoardState.channelIDRX = RFE_CID_HAM_3500; + } + } + + if (settings.m_rxPort == LimeRFESettings::RxPort::RxPortJ3) { + m_rfeBoardState.selPortRX = RFE_PORT_1; + } else if (settings.m_rxPort == LimeRFESettings::RxPort::RxPortJ5) { + m_rfeBoardState.selPortRX = RFE_PORT_3; + } + + if (settings.m_txRxDriven) + { + m_rfeBoardState.channelIDTX = m_rfeBoardState.channelIDRX; + } + else + { + if (settings.m_txChannels == LimeRFESettings::ChannelGroups::ChannelsWideband) + { + if (settings.m_txWidebandChannel == LimeRFESettings::WidebandChannel::WidebandLow) { + m_rfeBoardState.channelIDTX = RFE_CID_WB_1000; + } else if (settings.m_txWidebandChannel == LimeRFESettings::WidebandChannel::WidebandHigh) { + m_rfeBoardState.channelIDTX = RFE_CID_WB_4000; + } + } + else if (settings.m_txChannels == LimeRFESettings::ChannelGroups::ChannelsHAM) + { + if (settings.m_txHAMChannel == LimeRFESettings::HAMChannel::HAM_30M) { + m_rfeBoardState.channelIDTX = RFE_CID_HAM_0030; + } else if (settings.m_txHAMChannel == LimeRFESettings::HAMChannel::HAM_50_70MHz) { + m_rfeBoardState.channelIDTX = RFE_CID_HAM_0070; + } else if (settings.m_txHAMChannel == LimeRFESettings::HAMChannel::HAM_144_146MHz) { + m_rfeBoardState.channelIDTX = RFE_CID_HAM_0145; + } else if (settings.m_txHAMChannel == LimeRFESettings::HAMChannel::HAM_220_225MHz) { + m_rfeBoardState.channelIDTX = RFE_CID_HAM_0220; + } else if (settings.m_txHAMChannel == LimeRFESettings::HAMChannel::HAM_430_440MHz) { + m_rfeBoardState.channelIDTX = RFE_CID_HAM_0435; + } else if (settings.m_txHAMChannel == LimeRFESettings::HAMChannel::HAM_902_928MHz) { + m_rfeBoardState.channelIDTX = RFE_CID_HAM_0920; + } else if (settings.m_txHAMChannel == LimeRFESettings::HAMChannel::HAM_1240_1325MHz) { + m_rfeBoardState.channelIDTX = RFE_CID_HAM_1280; + } else if (settings.m_txHAMChannel == LimeRFESettings::HAMChannel::HAM_2300_2450MHz) { + m_rfeBoardState.channelIDTX = RFE_CID_HAM_2400; + } else if (settings.m_txHAMChannel == LimeRFESettings::HAMChannel::HAM_3300_3500MHz) { + m_rfeBoardState.channelIDTX = RFE_CID_HAM_3500; + } + } + } + + if (settings.m_txPort == LimeRFESettings::TxPort::TxPortJ3) { + m_rfeBoardState.selPortTX = RFE_PORT_1; + } else if (settings.m_txPort == LimeRFESettings::TxPort::TxPortJ4) { + m_rfeBoardState.selPortTX = RFE_PORT_2; + } else if (settings.m_txPort == LimeRFESettings::TxPort::TxPortJ5) { + m_rfeBoardState.selPortTX = RFE_PORT_3; + } + } + + m_rfeBoardState.attValue = settings.m_attenuationFactor > 7 ? 7 : settings.m_attenuationFactor; + m_rfeBoardState.notchOnOff = settings.m_amfmNotch; + m_rfeBoardState.enableSWR = settings.m_swrEnable ? RFE_SWR_ENABLE : RFE_SWR_DISABLE; + + if (settings.m_swrSource == LimeRFESettings::SWRSource::SWRExternal) { + m_rfeBoardState.sourceSWR = RFE_SWR_SRC_EXT; + } else if (settings.m_swrSource == LimeRFESettings::SWRSource::SWRCellular) { + m_rfeBoardState.sourceSWR = RFE_SWR_SRC_CELL; + } +} + +void LimeRFE::stateToSettings(LimeRFESettings& settings) +{ + if (m_rfeBoardState.channelIDRX == RFE_CID_CELL_BAND01) + { + settings.m_rxChannels = LimeRFESettings::ChannelGroups::ChannelsCellular; + settings.m_rxCellularChannel = LimeRFESettings::CellularChannel::CellularBand1; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_CELL_BAND02) + { + settings.m_rxChannels = LimeRFESettings::ChannelGroups::ChannelsCellular; + settings.m_rxCellularChannel = LimeRFESettings::CellularChannel::CellularBand2; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_CELL_BAND03) + { + settings.m_rxChannels = LimeRFESettings::ChannelGroups::ChannelsCellular; + settings.m_rxCellularChannel = LimeRFESettings::CellularChannel::CellularBand3; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_CELL_BAND07) + { + settings.m_rxChannels = LimeRFESettings::ChannelGroups::ChannelsCellular; + settings.m_rxCellularChannel = LimeRFESettings::CellularChannel::CellularBand7; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_CELL_BAND38) + { + settings.m_rxChannels = LimeRFESettings::ChannelGroups::ChannelsCellular; + settings.m_rxCellularChannel = LimeRFESettings::CellularChannel::CellularBand38; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_WB_1000) + { + settings.m_rxChannels = LimeRFESettings::ChannelGroups::ChannelsWideband; + settings.m_rxWidebandChannel = LimeRFESettings::WidebandChannel::WidebandLow; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_WB_4000) + { + settings.m_rxChannels = LimeRFESettings::ChannelGroups::ChannelsWideband; + settings.m_rxWidebandChannel = LimeRFESettings::WidebandChannel::WidebandHigh; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_HAM_0030) + { + settings.m_rxChannels = LimeRFESettings::ChannelGroups::ChannelsHAM; + settings.m_rxHAMChannel = LimeRFESettings::HAMChannel::HAM_30M; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_HAM_0070) + { + settings.m_rxChannels = LimeRFESettings::ChannelGroups::ChannelsHAM; + settings.m_rxHAMChannel = LimeRFESettings::HAMChannel::HAM_50_70MHz; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_HAM_0145) + { + settings.m_rxChannels = LimeRFESettings::ChannelGroups::ChannelsHAM; + settings.m_rxHAMChannel = LimeRFESettings::HAMChannel::HAM_144_146MHz; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_HAM_0220) + { + settings.m_rxChannels = LimeRFESettings::ChannelGroups::ChannelsHAM; + settings.m_rxHAMChannel = LimeRFESettings::HAMChannel::HAM_220_225MHz; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_HAM_0435) + { + settings.m_rxChannels = LimeRFESettings::ChannelGroups::ChannelsHAM; + settings.m_rxHAMChannel = LimeRFESettings::HAMChannel::HAM_430_440MHz; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_HAM_0920) + { + settings.m_rxChannels = LimeRFESettings::ChannelGroups::ChannelsHAM; + settings.m_rxHAMChannel = LimeRFESettings::HAMChannel::HAM_902_928MHz; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_HAM_1280) + { + settings.m_rxChannels = LimeRFESettings::ChannelGroups::ChannelsHAM; + settings.m_rxHAMChannel = LimeRFESettings::HAMChannel::HAM_1240_1325MHz; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_HAM_2400) + { + settings.m_rxChannels = LimeRFESettings::ChannelGroups::ChannelsHAM; + settings.m_rxHAMChannel = LimeRFESettings::HAMChannel::HAM_2300_2450MHz; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_HAM_3500) + { + settings.m_rxChannels = LimeRFESettings::ChannelGroups::ChannelsHAM; + settings.m_rxHAMChannel = LimeRFESettings::HAMChannel::HAM_3300_3500MHz; + } + + if (m_rfeBoardState.selPortRX == RFE_PORT_1) { + settings.m_rxPort = LimeRFESettings::RxPort::RxPortJ3; + } else if (m_rfeBoardState.selPortRX == RFE_PORT_3) { + settings.m_rxPort = LimeRFESettings::RxPort::RxPortJ5; + } + + if (m_rfeBoardState.channelIDTX == RFE_CID_CELL_BAND01) + { + settings.m_txChannels = LimeRFESettings::ChannelGroups::ChannelsCellular; + settings.m_txCellularChannel = LimeRFESettings::CellularChannel::CellularBand1; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_CELL_BAND02) + { + settings.m_txChannels = LimeRFESettings::ChannelGroups::ChannelsCellular; + settings.m_txCellularChannel = LimeRFESettings::CellularChannel::CellularBand2; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_CELL_BAND03) + { + settings.m_txChannels = LimeRFESettings::ChannelGroups::ChannelsCellular; + settings.m_txCellularChannel = LimeRFESettings::CellularChannel::CellularBand3; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_CELL_BAND07) + { + settings.m_txChannels = LimeRFESettings::ChannelGroups::ChannelsCellular; + settings.m_txCellularChannel = LimeRFESettings::CellularChannel::CellularBand7; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_CELL_BAND38) + { + settings.m_txChannels = LimeRFESettings::ChannelGroups::ChannelsCellular; + settings.m_txCellularChannel = LimeRFESettings::CellularChannel::CellularBand38; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_WB_1000) + { + settings.m_txChannels = LimeRFESettings::ChannelGroups::ChannelsWideband; + settings.m_txWidebandChannel = LimeRFESettings::WidebandChannel::WidebandLow; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_WB_4000) + { + settings.m_txChannels = LimeRFESettings::ChannelGroups::ChannelsWideband; + settings.m_txWidebandChannel = LimeRFESettings::WidebandChannel::WidebandHigh; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_HAM_0030) + { + settings.m_txChannels = LimeRFESettings::ChannelGroups::ChannelsHAM; + settings.m_txHAMChannel = LimeRFESettings::HAMChannel::HAM_30M; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_HAM_0070) + { + settings.m_txChannels = LimeRFESettings::ChannelGroups::ChannelsHAM; + settings.m_txHAMChannel = LimeRFESettings::HAMChannel::HAM_50_70MHz; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_HAM_0145) + { + settings.m_txChannels = LimeRFESettings::ChannelGroups::ChannelsHAM; + settings.m_txHAMChannel = LimeRFESettings::HAMChannel::HAM_144_146MHz; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_HAM_0220) + { + settings.m_txChannels = LimeRFESettings::ChannelGroups::ChannelsHAM; + settings.m_txHAMChannel = LimeRFESettings::HAMChannel::HAM_220_225MHz; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_HAM_0435) + { + settings.m_txChannels = LimeRFESettings::ChannelGroups::ChannelsHAM; + settings.m_txHAMChannel = LimeRFESettings::HAMChannel::HAM_430_440MHz; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_HAM_0920) + { + settings.m_txChannels = LimeRFESettings::ChannelGroups::ChannelsHAM; + settings.m_txHAMChannel = LimeRFESettings::HAMChannel::HAM_902_928MHz; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_HAM_1280) + { + settings.m_txChannels = LimeRFESettings::ChannelGroups::ChannelsHAM; + settings.m_txHAMChannel = LimeRFESettings::HAMChannel::HAM_1240_1325MHz; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_HAM_2400) + { + settings.m_txChannels = LimeRFESettings::ChannelGroups::ChannelsHAM; + settings.m_txHAMChannel = LimeRFESettings::HAMChannel::HAM_2300_2450MHz; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_HAM_3500) + { + settings.m_txChannels = LimeRFESettings::ChannelGroups::ChannelsHAM; + settings.m_txHAMChannel = LimeRFESettings::HAMChannel::HAM_3300_3500MHz; + } + + if (m_rfeBoardState.selPortTX == RFE_PORT_1) { + settings.m_txPort = LimeRFESettings::TxPort::TxPortJ3; + } else if (m_rfeBoardState.selPortTX == RFE_PORT_2) { + settings.m_txPort = LimeRFESettings::TxPort::TxPortJ4; + } else if (m_rfeBoardState.selPortTX == RFE_PORT_3) { + settings.m_txPort = LimeRFESettings::TxPort::TxPortJ5; + } + + settings.m_attenuationFactor = m_rfeBoardState.attValue; + settings.m_amfmNotch = m_rfeBoardState.notchOnOff == RFE_NOTCH_ON; + + if (m_rfeBoardState.mode == RFE_MODE_RX) + { + settings.m_rxOn = true; + settings.m_txOn = false; + } + else if (m_rfeBoardState.mode == RFE_MODE_TX) + { + settings.m_rxOn = false; + settings.m_txOn = true; + } + else if (m_rfeBoardState.mode == RFE_MODE_NONE) + { + settings.m_rxOn = false; + settings.m_txOn = false; + } + else if (m_rfeBoardState.mode == RFE_MODE_TXRX) + { + settings.m_rxOn = true; + settings.m_txOn = true; + } + + settings.m_swrEnable = m_rfeBoardState.enableSWR == RFE_SWR_ENABLE; + settings.m_swrSource = m_rfeBoardState.sourceSWR == RFE_SWR_SRC_CELL ? + LimeRFESettings::SWRSource::SWRCellular : + LimeRFESettings::SWRSource::SWRExternal; +} + +void LimeRFE::networkManagerFinished(QNetworkReply *reply) +{ + QNetworkReply::NetworkError replyError = reply->error(); + + if (replyError) + { + qWarning() << "LimeRFE::networkManagerFinished:" + << " error(" << (int) replyError + << "): " << replyError + << ": " << reply->errorString(); + } + else + { + QString answer = reply->readAll(); + answer.chop(1); // remove last \n + qDebug("LimeRFE::networkManagerFinished: reply:\n%s", answer.toStdString().c_str()); + } + + reply->deleteLater(); +} diff --git a/plugins/feature/limerfe/limerfe.h b/plugins/feature/limerfe/limerfe.h new file mode 100644 index 000000000..e55c57956 --- /dev/null +++ b/plugins/feature/limerfe/limerfe.h @@ -0,0 +1,117 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_FEATURE_LIMERFE_H_ +#define INCLUDE_FEATURE_LIMERFE_H_ + +#include + +#include +#include +#include "lime/limeRFE.h" + +#include "feature/feature.h" +#include "util/message.h" + +#include "limerfesettings.h" +#include "limerfeusbcalib.h" + +class QNetworkReply; +class QNetworkAccessManager; + +class LimeRFE : public Feature +{ + Q_OBJECT +public: + class MsgConfigureLimeRFE : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const LimeRFESettings& getSettings() const { return m_settings; } + bool getForce() const { return m_force; } + + static MsgConfigureLimeRFE* create(const LimeRFESettings& settings, bool force) { + return new MsgConfigureLimeRFE(settings, force); + } + + private: + LimeRFESettings m_settings; + bool m_force; + + MsgConfigureLimeRFE(const LimeRFESettings& settings, bool force) : + Message(), + m_settings(settings), + m_force(force) + { } + }; + + LimeRFE(WebAPIAdapterInterface *webAPIAdapterInterface); + virtual ~LimeRFE(); + virtual void destroy() { delete this; } + virtual bool handleMessage(const Message& cmd); + + virtual void getIdentifier(QString& id) const { id = objectName(); } + virtual QString getIdentifier() const { return objectName(); } + virtual void getTitle(QString& title) const { title = m_settings.m_title; } + + virtual QByteArray serialize() const; + virtual bool deserialize(const QByteArray& data); + + LimeRFEUSBCalib *getCalib() { return &m_calib; } + + int openDevice(const std::string& serialDeviceName); + void closeDevice(); + + const QStringList& getComPorts() { return m_comPorts; } + int configure(); + int getState(); + static std::string getError(int errorCode); + int setRx(LimeRFESettings& settings, bool rxOn); + int setTx(LimeRFESettings& settings, bool txOn); + bool turnDevice(int deviceSetIndex, bool on); + int getFwdPower(int& powerDB); + int getRefPower(int& powerDB); + + void settingsToState(const LimeRFESettings& settings); + void stateToSettings(LimeRFESettings& settings); + + static const char* const m_featureIdURI; + static const char* const m_featureId; + +private: + LimeRFESettings m_settings; + LimeRFEUSBCalib m_calib; + + QNetworkAccessManager *m_networkManager; + QNetworkRequest m_networkRequest; + WebAPIAdapterInterface *m_webAPIAdapterInterface; + + rfe_dev_t *m_rfeDevice; + rfe_boardState m_rfeBoardState; + static const std::map m_errorCodesMap; + QStringList m_comPorts; + + void start(); + void stop(); + void listComPorts(); + +private slots: + void networkManagerFinished(QNetworkReply *reply); + +}; + +#endif diff --git a/plugins/feature/limerfe/limerfegui.cpp b/plugins/feature/limerfe/limerfegui.cpp new file mode 100644 index 000000000..496fa88df --- /dev/null +++ b/plugins/feature/limerfe/limerfegui.cpp @@ -0,0 +1,1009 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "feature/featureuiset.h" +#include "gui/basicfeaturesettingsdialog.h" +#include "gui/crightclickenabler.h" +#include "util/db.h" +#include "dsp/dspengine.h" +#include "dsp/dspdevicesourceengine.h" +#include "dsp/dspdevicesinkengine.h" +#include "device/deviceset.h" +#include "maincore.h" + +#include "limerfeusbcalib.h" +#include "ui_limerfegui.h" +#include "limerfe.h" +#include "limerfegui.h" + +LimeRFEGUI* LimeRFEGUI::create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature) +{ + LimeRFEGUI* gui = new LimeRFEGUI(pluginAPI, featureUISet, feature); + return gui; +} + +void LimeRFEGUI::destroy() +{ + delete this; +} + +void LimeRFEGUI::resetToDefaults() +{ + m_settings.resetToDefaults(); + displaySettings(); + applySettings(true); +} + +QByteArray LimeRFEGUI::serialize() const +{ + return m_settings.serialize(); +} + +bool LimeRFEGUI::deserialize(const QByteArray& data) +{ + if (m_settings.deserialize(data)) + { + m_feature->setWorkspaceIndex(m_settings.m_workspaceIndex); + displaySettings(); + return true; + } + else + { + resetToDefaults(); + return false; + } +} + +void LimeRFEGUI::setWorkspaceIndex(int index) +{ + m_settings.m_workspaceIndex = index; + m_feature->setWorkspaceIndex(index); +} + +void LimeRFEGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + +void LimeRFEGUI::onWidgetRolled(QWidget* widget, bool rollDown) +{ + (void) widget; + (void) rollDown; + + getRollupContents()->saveState(m_rollupState); + applySettings(); +} + +void LimeRFEGUI::onMenuDialogCalled(const QPoint &p) +{ + if (m_contextMenuType == ContextMenuChannelSettings) + { + BasicFeatureSettingsDialog dialog(this); + dialog.setTitle(m_settings.m_title); + 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.setDefaultTitle(m_displayedName); + + dialog.move(p); + dialog.exec(); + + 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(); + + setTitle(m_settings.m_title); + setTitleColor(m_settings.m_rgbColor); + + applySettings(); + } + + resetContextMenuType(); +} + +LimeRFEGUI::LimeRFEGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent) : + FeatureGUI(parent), + ui(new Ui::LimeRFEGUI), + m_pluginAPI(pluginAPI), + m_featureUISet(featureUISet), + m_doApplySettings(true), + m_rxTxToggle(false), + m_currentPowerCorrection(0.0), + m_avgPower(false), + m_deviceSetSync(false) +{ + m_feature = feature; + setAttribute(Qt::WA_DeleteOnClose, true); + m_helpURL = "plugins/feature/limerfe/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + + m_limeRFE = reinterpret_cast(feature); + m_limeRFE->setMessageQueueToGUI(&m_inputMessageQueue); + m_limeRFEUSBCalib = m_limeRFE->getCalib(); + + for (const auto& comPortName : m_limeRFE->getComPorts()) { + ui->device->addItem(comPortName); + } + + m_settings.setRollupState(&m_rollupState); + + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); + connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); + + updateDeviceSetList(); + displaySettings(); + highlightApplyButton(false); + m_timer.setInterval(500); + makeUIConnections(); +} + +LimeRFEGUI::~LimeRFEGUI() +{ + delete ui; +} + +void LimeRFEGUI::applySettings(bool force) +{ + if (m_doApplySettings) + { + LimeRFE::MsgConfigureLimeRFE* message = LimeRFE::MsgConfigureLimeRFE::create( m_settings, force); + m_limeRFE->getInputMessageQueue()->push(message); + } +} + +void LimeRFEGUI::displaySettings() +{ + setTitleColor(m_settings.m_rgbColor); + setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); + blockApplySettings(true); + setRxChannels(); + ui->rxPort->setCurrentIndex(m_settings.m_rxPort); + ui->attenuation->setCurrentIndex(m_settings.m_attenuationFactor); + ui->amFmNotchFilter->setChecked(m_settings.m_amfmNotch); + setTxChannels(); + ui->txPort->setCurrentIndex(m_settings.m_txPort); + ui->txFollowsRx->setChecked(m_settings.m_txRxDriven); + ui->rxTxToggle->setChecked(m_rxTxToggle); + displayMode(); + displayPower(); + blockApplySettings(false); +} + +void LimeRFEGUI::displayMode() +{ + QString s; + + if (m_settings.m_rxOn) + { + if (m_settings.m_txOn) { + s = "Rx/Tx"; + } else { + s = "Rx"; + } + } + else + { + if (m_settings.m_txOn) { + s = "Tx"; + } else { + s = "None"; + } + } + + ui->modeText->setText(s); + + ui->modeRx->blockSignals(true); + ui->modeTx->blockSignals(true); + + if (m_settings.m_rxOn) { + ui->modeRx->setStyleSheet("QToolButton { background-color : green; }"); + } else { + ui->modeRx->setStyleSheet("QToolButton { background:rgb(79,79,79); }"); + } + + if (m_settings.m_txOn) { + ui->modeTx->setStyleSheet("QToolButton { background-color : red; }"); + } else { + ui->modeTx->setStyleSheet("QToolButton { background:rgb(79,79,79); }"); + } + + ui->modeRx->setChecked(m_settings.m_rxOn); + ui->modeTx->setChecked(m_settings.m_txOn); + + ui->modeRx->blockSignals(false); + ui->modeTx->blockSignals(false); +} + +void LimeRFEGUI::displayPower() +{ + ui->powerEnable->blockSignals(true); + ui->powerSource->blockSignals(true); + + ui->powerEnable->setChecked(m_settings.m_swrEnable); + ui->powerSource->setCurrentIndex((int) m_settings.m_swrSource); + + ui->powerEnable->blockSignals(false); + ui->powerSource->blockSignals(false); +} + +void LimeRFEGUI::refreshPower() +{ + int fwdPower, refPower; + int rc = m_limeRFE->getFwdPower(fwdPower); + + if (rc != 0) + { + ui->statusText->setText(m_limeRFE->getError(rc).c_str()); + return; + } + + rc = m_limeRFE->getRefPower(refPower); + + if (rc != 0) + { + ui->statusText->setText(m_limeRFE->getError(rc).c_str()); + return; + } + + double fwdPowerDB = fwdPower / 10.0; + double refPowerDB = refPower / 10.0; + double retLossDB = fwdPowerDB - refPowerDB; + + ui->powerFwdText->setText(QString::number(fwdPowerDB, 'f', 1)); + ui->powerRefText->setText(QString::number(refPowerDB, 'f', 1)); + ui->returnLossText->setText(QString::number(retLossDB, 'f', 1)); + + double denom = CalcDb::powerFromdB(retLossDB/2.0) - 1.0; + + if (denom == 0.0) + { + ui->swrText->setText("---"); + } + else + { + double vswr = (CalcDb::powerFromdB(retLossDB/2.0) + 1.0) / denom; + vswr = vswr < 0.0 ? 0.0 : vswr > 99.999 ? 99.999 : vswr; + ui->swrText->setText(QString::number(vswr, 'f', 3)); + } + + updateAbsPower(m_currentPowerCorrection); +} + +void LimeRFEGUI::setRxChannels() +{ + ui->rxChannel->blockSignals(true); + ui->rxPort->blockSignals(true); + ui->rxChannel->clear(); + ui->rxPort->clear(); + + if (m_settings.m_rxChannels == LimeRFESettings::ChannelsWideband) + { + ui->rxChannel->addItem("1-1000MHz"); + ui->rxChannel->addItem("1-4GHz"); + ui->rxChannel->setCurrentIndex((int) m_settings.m_rxWidebandChannel); + ui->rxPort->addItem("TX/RX (J3)"); + ui->rxPort->addItem("TX/RX 30M (J5)"); + ui->rxPort->setCurrentIndex((int) m_settings.m_rxPort); + ui->txFollowsRx->setEnabled(true); + ui->rxPort->setEnabled(true); + } + else if (m_settings.m_rxChannels == LimeRFESettings::ChannelsHAM) + { + ui->rxChannel->addItem("<30MHz"); + ui->rxChannel->addItem("50-70MHz"); + ui->rxChannel->addItem("144-146MHz"); + ui->rxChannel->addItem("220-225MHz"); + ui->rxChannel->addItem("430-440MHz"); + ui->rxChannel->addItem("902-928MHz"); + ui->rxChannel->addItem("1240-1325MHz"); + ui->rxChannel->addItem("2300-2450MHz"); + ui->rxChannel->addItem("3300-3500MHz"); + ui->rxChannel->setCurrentIndex((int) m_settings.m_rxHAMChannel); + ui->txFollowsRx->setEnabled(true); + + switch(m_settings.m_rxHAMChannel) + { + case LimeRFESettings::HAM_30M: + case LimeRFESettings::HAM_50_70MHz: + case LimeRFESettings::HAM_144_146MHz: + case LimeRFESettings::HAM_220_225MHz: + case LimeRFESettings::HAM_430_440MHz: + ui->rxPort->addItem("TX/RX (J3)"); + ui->rxPort->addItem("TX/RX 30M (J5)"); + ui->rxPort->setEnabled(true); + ui->rxPort->setCurrentIndex((int) m_settings.m_rxPort); + break; + case LimeRFESettings::HAM_902_928MHz: + case LimeRFESettings::HAM_1240_1325MHz: + case LimeRFESettings::HAM_2300_2450MHz: + case LimeRFESettings::HAM_3300_3500MHz: + ui->rxPort->addItem("TX/RX (J3)"); + ui->rxPort->setEnabled(false); + m_settings.m_rxPort = LimeRFESettings::RxPortJ3; + ui->rxPort->setCurrentIndex((int) m_settings.m_rxPort); + break; + default: + break; + } + } + else if (m_settings.m_rxChannels == LimeRFESettings::ChannelsCellular) + { + ui->rxChannel->addItem("Band1"); + ui->rxChannel->addItem("Band2"); + ui->rxChannel->addItem("Band3"); + ui->rxChannel->addItem("Band7"); + ui->rxChannel->addItem("Band38"); + ui->rxChannel->setCurrentIndex((int) m_settings.m_rxCellularChannel); + ui->rxPort->addItem("TX/RX (J3)"); + ui->rxPort->setEnabled(false); + m_settings.m_rxPort = LimeRFESettings::RxPortJ3; + ui->rxPort->setCurrentIndex((int) m_settings.m_rxPort); + m_settings.m_txRxDriven = true; + ui->txFollowsRx->setEnabled(false); + ui->txFollowsRx->setChecked(m_settings.m_txRxDriven); + } + + ui->rxChannelGroup->setCurrentIndex((int) m_settings.m_rxChannels); + ui->rxPort->blockSignals(false); + ui->rxChannel->blockSignals(false); +} + +void LimeRFEGUI::setTxChannels() +{ + ui->txChannel->blockSignals(true); + ui->txPort->blockSignals(true); + ui->powerCorrValue->blockSignals(true); + + ui->txChannel->clear(); + ui->txPort->clear(); + + if (m_settings.m_txChannels == LimeRFESettings::ChannelsWideband) + { + ui->txChannel->addItem("1-1000MHz"); + ui->txChannel->addItem("1-4GHz"); + ui->txChannel->setCurrentIndex((int) m_settings.m_txWidebandChannel); + ui->txPort->addItem("TX/RX (J3)"); + ui->txPort->addItem("TX (J4)"); + ui->txPort->setCurrentIndex((int) m_settings.m_txPort); + ui->txPort->setEnabled(true); + } + else if (m_settings.m_txChannels == LimeRFESettings::ChannelsHAM) + { + ui->txChannel->addItem("<30MHz"); + ui->txChannel->addItem("50-70MHz"); + ui->txChannel->addItem("144-146MHz"); + ui->txChannel->addItem("220-225MHz"); + ui->txChannel->addItem("430-440MHz"); + ui->txChannel->addItem("902-928MHz"); + ui->txChannel->addItem("1240-1325MHz"); + ui->txChannel->addItem("2300-2450MHz"); + ui->txChannel->addItem("3300-3500MHz"); + ui->txChannel->setCurrentIndex((int) m_settings.m_txHAMChannel); + + switch(m_settings.m_txHAMChannel) + { + case LimeRFESettings::HAM_30M: + case LimeRFESettings::HAM_50_70MHz: + ui->txPort->addItem("TX/RX (J3)"); + ui->txPort->addItem("TX (J4)"); + ui->txPort->addItem("TX/RX 30M (J5)"); + ui->txPort->setEnabled(false); + m_settings.m_txPort = LimeRFESettings::TxPortJ5; + ui->txPort->setCurrentIndex((int) m_settings.m_txPort); + break; + case LimeRFESettings::HAM_144_146MHz: + case LimeRFESettings::HAM_220_225MHz: + case LimeRFESettings::HAM_430_440MHz: + case LimeRFESettings::HAM_902_928MHz: + case LimeRFESettings::HAM_1240_1325MHz: + case LimeRFESettings::HAM_2300_2450MHz: + case LimeRFESettings::HAM_3300_3500MHz: + ui->txPort->addItem("TX/RX (J3)"); + ui->txPort->addItem("TX (J4)"); + ui->txPort->setCurrentIndex(m_settings.m_txPort < 2 ? m_settings.m_txPort : 1); + ui->txPort->setEnabled(true); + break; + default: + break; + } + } + else if (m_settings.m_txChannels == LimeRFESettings::ChannelsCellular) + { + ui->txChannel->addItem("Band1"); + ui->txChannel->addItem("Band2"); + ui->txChannel->addItem("Band3"); + ui->txChannel->addItem("Band7"); + ui->txChannel->addItem("Band38"); + ui->txChannel->setCurrentIndex((int) m_settings.m_txCellularChannel); + ui->txPort->addItem("TX/RX (J3)"); + m_settings.m_txPort = LimeRFESettings::TxPortJ3; + ui->txPort->setEnabled(false); + ui->txPort->setCurrentIndex((int) m_settings.m_txPort); + } + + ui->txChannelGroup->setCurrentIndex((int) m_settings.m_txChannels); + m_currentPowerCorrection = getPowerCorrection(); + ui->powerCorrValue->setText(QString::number(m_currentPowerCorrection, 'f', 1)); + updateAbsPower(m_currentPowerCorrection); + + ui->powerCorrValue->blockSignals(false); + ui->txPort->blockSignals(false); + ui->txChannel->blockSignals(false); +} + +int LimeRFEGUI::getPowerCorectionIndex() +{ + LimeRFEUSBCalib::ChannelRange range; + + switch (m_settings.m_txChannels) + { + case LimeRFESettings::ChannelsWideband: + { + switch (m_settings.m_txWidebandChannel) + { + case LimeRFESettings::WidebandLow: + range = LimeRFEUSBCalib::WidebandLow; + break; + case LimeRFESettings::WidebandHigh: + range = LimeRFEUSBCalib::WidebandHigh; + break; + default: + return -1; + break; + } + break; + } + case LimeRFESettings::ChannelsHAM: + { + switch (m_settings.m_txHAMChannel) + { + case LimeRFESettings::HAM_30M: + range = LimeRFEUSBCalib::HAM_30MHz; + break; + case LimeRFESettings::HAM_50_70MHz: + range = LimeRFEUSBCalib::HAM_50_70MHz; + break; + case LimeRFESettings::HAM_144_146MHz: + range = LimeRFEUSBCalib::HAM_144_146MHz; + break; + case LimeRFESettings::HAM_220_225MHz: + range = LimeRFEUSBCalib::HAM_220_225MHz; + break; + case LimeRFESettings::HAM_430_440MHz: + range = LimeRFEUSBCalib::HAM_430_440MHz; + break; + case LimeRFESettings::HAM_902_928MHz: + range = LimeRFEUSBCalib::HAM_902_928MHz; + break; + case LimeRFESettings::HAM_1240_1325MHz: + range = LimeRFEUSBCalib::HAM_1240_1325MHz; + break; + case LimeRFESettings::HAM_2300_2450MHz: + range = LimeRFEUSBCalib::HAM_2300_2450MHz; + break; + case LimeRFESettings::HAM_3300_3500MHz: + range = LimeRFEUSBCalib::HAM_3300_3500MHz; + break; + default: + return -1; + break; + } + break; + } + case LimeRFESettings::ChannelsCellular: + { + switch (m_settings.m_txCellularChannel) + { + case LimeRFESettings::CellularBand1: + range = LimeRFEUSBCalib::CellularBand1; + break; + case LimeRFESettings::CellularBand2: + range = LimeRFEUSBCalib::CellularBand2; + break; + case LimeRFESettings::CellularBand3: + range = LimeRFEUSBCalib::CellularBand3; + break; + case LimeRFESettings::CellularBand7: + range = LimeRFEUSBCalib::CellularBand7; + break; + case LimeRFESettings::CellularBand38: + range = LimeRFEUSBCalib::CellularBand38; + break; + default: + return -1; + break; + } + break; + } + default: + return -1; + break; + } + + return (int) range; +} + +double LimeRFEGUI::getPowerCorrection() +{ + int index = getPowerCorectionIndex(); + + QMap::const_iterator it = m_limeRFEUSBCalib->m_calibrations.find(index); + + if (it != m_limeRFEUSBCalib->m_calibrations.end()) { + return it.value(); + } else { + return 0.0; + } +} + +void LimeRFEGUI::setPowerCorrection(double dbValue) +{ + int index = getPowerCorectionIndex(); + + if (index < 0) { + return; + } + + m_limeRFEUSBCalib->m_calibrations[index] = dbValue; +} + +void LimeRFEGUI::updateAbsPower(double powerCorrDB) +{ + bool ok; + double power = ui->powerFwdText->text().toDouble(&ok); + + if (ok) + { + double powerCorrected = power + powerCorrDB; + double powerDisplayed = powerCorrected; + + if (m_avgPower) + { + m_powerMovingAverage(powerCorrected); + powerDisplayed = m_powerMovingAverage.asDouble(); + } + + ui->powerAbsDbText->setText(tr("%1 dBm").arg(QString::number(powerDisplayed, 'f', 1))); + double powerWatts = CalcDb::powerFromdB(powerDisplayed - 30.0); + powerWatts = powerWatts > 8.0 ? 8.0 : powerWatts; + ui->powerAbsWText->setText(tr("%1 W").arg(QString::number(powerWatts, 'f', 3))); + } +} + +void LimeRFEGUI::updateDeviceSetList() +{ + MainCore *mainCore = MainCore::instance(); + std::vector& deviceSets = mainCore->getDeviceSets(); + std::vector::const_iterator it = deviceSets.begin(); + + ui->deviceSetRx->blockSignals(true); + ui->deviceSetTx->blockSignals(true); + + // Save current positions + int rxIndex = ui->deviceSetRx->currentIndex(); + int txIndex = ui->deviceSetTx->currentIndex(); + + ui->deviceSetRx->clear(); + ui->deviceSetTx->clear(); + unsigned int deviceSetIndex = 0; + + for (; it != deviceSets.end(); ++it, deviceSetIndex++) + { + DSPDeviceSourceEngine *deviceSourceEngine = (*it)->m_deviceSourceEngine; + DSPDeviceSinkEngine *deviceSinkEngine = (*it)->m_deviceSinkEngine; + + if (deviceSourceEngine) { + ui->deviceSetRx->addItem(QString("R:%1").arg(deviceSetIndex), deviceSetIndex); + } else if (deviceSinkEngine) { + ui->deviceSetTx->addItem(QString("T:%1").arg(deviceSetIndex), deviceSetIndex); + } + } + + // Restore current positions (if possible) + ui->deviceSetRx->setCurrentIndex(rxIndex < 0 ? 0 : rxIndex); + ui->deviceSetTx->setCurrentIndex(txIndex < 0 ? 0 : txIndex); + + ui->deviceSetRx->blockSignals(false); + ui->deviceSetTx->blockSignals(false); +} + +void LimeRFEGUI::highlightApplyButton(bool highlight) +{ + if (highlight) { + ui->apply->setStyleSheet("QPushButton { background-color : green; }"); + } else { + ui->apply->setStyleSheet("QPushButton { background:rgb(64, 64, 64); }"); + } +} + +void LimeRFEGUI::on_openDevice_clicked() +{ + int rc = m_limeRFE->openDevice(ui->device->currentText().toStdString()); + ui->statusText->append(QString("Open %1: %2").arg(ui->device->currentText()).arg(m_limeRFE->getError(rc).c_str())); + + if (rc != 0) { + return; + } + + rc = m_limeRFE->getState(); + ui->statusText->append(QString("Get state: %1").arg(m_limeRFE->getError(rc).c_str())); +} + +void LimeRFEGUI::on_closeDevice_clicked() +{ + ui->statusText->clear(); + m_limeRFE->closeDevice(); + ui->statusText->setText("Closed"); +} + +void LimeRFEGUI::on_deviceToGUI_clicked() +{ + int rc = m_limeRFE->getState(); + + if (rc != 0) + { + ui->statusText->setText(m_limeRFE->getError(rc).c_str()); + return; + } + + m_limeRFE->stateToSettings(m_settings); + displaySettings(); + highlightApplyButton(false); +} + +void LimeRFEGUI::on_rxChannelGroup_currentIndexChanged(int index) +{ + m_settings.m_rxChannels = (LimeRFESettings::ChannelGroups) index; + setRxChannels(); + + if (m_settings.m_txRxDriven) + { + m_settings.m_txChannels = m_settings.m_rxChannels; + ui->txChannelGroup->setCurrentIndex((int) m_settings.m_txChannels); + } + + highlightApplyButton(true); +} + +void LimeRFEGUI::on_rxChannel_currentIndexChanged(int index) +{ + if (m_settings.m_rxChannels == LimeRFESettings::ChannelsWideband) { + m_settings.m_rxWidebandChannel = (LimeRFESettings::WidebandChannel) index; + } else if (m_settings.m_rxChannels == LimeRFESettings::ChannelsHAM) { + m_settings.m_rxHAMChannel = (LimeRFESettings::HAMChannel) index; + } else if (m_settings.m_rxChannels == LimeRFESettings::ChannelsCellular) { + m_settings.m_rxCellularChannel = (LimeRFESettings::CellularChannel) index; + } + + setRxChannels(); + + if (m_settings.m_txRxDriven) + { + m_settings.m_txWidebandChannel = m_settings.m_rxWidebandChannel; + m_settings.m_txHAMChannel = m_settings.m_rxHAMChannel; + m_settings.m_txCellularChannel = m_settings.m_rxCellularChannel; + setTxChannels(); + } + + highlightApplyButton(true); +} + +void LimeRFEGUI::on_rxPort_currentIndexChanged(int index) +{ + m_settings.m_rxPort = (LimeRFESettings::RxPort) index; + highlightApplyButton(true); +} + +void LimeRFEGUI::on_txFollowsRx_clicked() +{ + bool checked = ui->txFollowsRx->isChecked(); + m_settings.m_txRxDriven = checked; + ui->txChannelGroup->setEnabled(!checked); + ui->txChannel->setEnabled(!checked); + m_settings.m_txChannels = m_settings.m_rxChannels; + m_settings.m_txWidebandChannel = m_settings.m_rxWidebandChannel; + m_settings.m_txHAMChannel = m_settings.m_rxHAMChannel; + m_settings.m_txCellularChannel = m_settings.m_rxCellularChannel; + ui->txChannelGroup->setCurrentIndex((int) m_settings.m_txChannels); + + if (checked) { + highlightApplyButton(true); + } +} + +void LimeRFEGUI::on_txChannelGroup_currentIndexChanged(int index) +{ + m_settings.m_txChannels = (LimeRFESettings::ChannelGroups) index; + setTxChannels(); + highlightApplyButton(true); +} + +void LimeRFEGUI::on_txChannel_currentIndexChanged(int index) +{ + if (m_settings.m_txChannels == LimeRFESettings::ChannelsWideband) { + m_settings.m_txWidebandChannel = (LimeRFESettings::WidebandChannel) index; + } else if (m_settings.m_txChannels == LimeRFESettings::ChannelsHAM) { + m_settings.m_txHAMChannel = (LimeRFESettings::HAMChannel) index; + } else if (m_settings.m_txChannels == LimeRFESettings::ChannelsCellular) { + m_settings.m_txCellularChannel = (LimeRFESettings::CellularChannel) index; + } + + setTxChannels(); + highlightApplyButton(true); +} + +void LimeRFEGUI::on_txPort_currentIndexChanged(int index) +{ + m_settings.m_txPort = (LimeRFESettings::TxPort) index; + highlightApplyButton(true); +} + +void LimeRFEGUI::on_powerEnable_clicked() +{ + m_settings.m_swrEnable = ui->powerEnable->isChecked(); + highlightApplyButton(true); +} + +void LimeRFEGUI::on_powerSource_currentIndexChanged(int index) +{ + m_settings.m_swrSource = (LimeRFESettings::SWRSource) index; + highlightApplyButton(true); +} + +void LimeRFEGUI::on_powerRefresh_clicked() +{ + refreshPower(); +} + +void LimeRFEGUI::on_powerAutoRefresh_toggled(bool checked) +{ + if (checked) + { + connect(&m_timer, SIGNAL(timeout()), this, SLOT(tick())); + m_timer.start(); + } + else + { + m_timer.stop(); + disconnect(&m_timer, SIGNAL(timeout()), this, SLOT(tick())); + } +} + +void LimeRFEGUI::on_powerAbsAvg_clicked() +{ + m_avgPower = ui->powerAbsAvg->isChecked(); +} + +void LimeRFEGUI::on_powerCorrValue_textEdited(const QString &text) +{ + bool ok; + double powerCorrection = text.toDouble(&ok); + + if (ok) + { + setPowerCorrection(powerCorrection); + m_currentPowerCorrection = powerCorrection; + updateAbsPower(powerCorrection); + } +} + +void LimeRFEGUI::on_deviceSetRefresh_clicked() +{ + updateDeviceSetList(); +} + +void LimeRFEGUI::on_deviceSetSync_clicked() +{ + m_deviceSetSync = ui->deviceSetSync->isChecked(); + + if (m_deviceSetSync) { + syncRxTx(); + } +} + +void LimeRFEGUI::syncRxTx() +{ + if (!m_settings.m_txOn) { + stopStartTx(m_settings.m_txOn); + } + + stopStartRx(m_settings.m_rxOn); + + if (m_settings.m_txOn) { + stopStartTx(m_settings.m_txOn); + } +} + +void LimeRFEGUI::stopStartRx(bool start) +{ + if (ui->deviceSetRx->currentIndex() < 0) { + return; + } + + int deviceSetIndex = ui->deviceSetRx->currentData().toInt(); + m_limeRFE->turnDevice(deviceSetIndex, start); +} + +void LimeRFEGUI::stopStartTx(bool start) +{ + if (ui->deviceSetTx->currentIndex() < 0) { + return; + } + + int deviceSetIndex = ui->deviceSetTx->currentData().toInt(); + m_limeRFE->turnDevice(deviceSetIndex, start); +} + +void LimeRFEGUI::on_modeRx_toggled(bool checked) +{ + int rc; + ui->statusText->clear(); + m_settings.m_rxOn = checked; + + if (m_rxTxToggle) + { + m_settings.m_txOn = !checked; + + if (checked) // Rx on + { + rc = m_limeRFE->setTx(m_settings, false); // stop Tx first + ui->statusText->append(QString("Stop TX: %1").arg(m_limeRFE->getError(rc).c_str())); + } + + rc = m_limeRFE->setRx(m_settings, m_settings.m_rxOn); // Rx on or off + ui->statusText->append(QString("RX: %1").arg(m_limeRFE->getError(rc).c_str())); + + if (!checked) // Rx off + { + rc = m_limeRFE->setTx(m_settings, true); // start Tx next + ui->statusText->append(QString("Start TX: %1").arg(m_limeRFE->getError(rc).c_str())); + } + } + else + { + rc = m_limeRFE->setRx(m_settings, m_settings.m_rxOn); + ui->statusText->setText(m_limeRFE->getError(rc).c_str()); + } + + if (m_deviceSetSync) { + syncRxTx(); + } + + displayMode(); +} + +void LimeRFEGUI::on_modeTx_toggled(bool checked) +{ + int rc; + ui->statusText->clear(); + m_settings.m_txOn = checked; + + if (m_rxTxToggle) + { + m_settings.m_rxOn = !checked; + + if (checked) // Tx on + { + rc = m_limeRFE->setRx(m_settings, false); // stop Rx first + ui->statusText->append(QString("Stop RX: %1").arg(m_limeRFE->getError(rc).c_str())); + } + + rc = m_limeRFE->setTx(m_settings, m_settings.m_txOn); // Tx on or off + ui->statusText->append(QString("TX: %1").arg(m_limeRFE->getError(rc).c_str())); + + if (!checked) // Tx off + { + rc = m_limeRFE->setRx(m_settings, true); // start Rx next + ui->statusText->append(QString("Start RX: %1").arg(m_limeRFE->getError(rc).c_str())); + } + } + else + { + rc = m_limeRFE->setTx(m_settings, m_settings.m_txOn); + ui->statusText->setText(m_limeRFE->getError(rc).c_str()); + } + + if (m_deviceSetSync) { + syncRxTx(); + } + + displayMode(); +} + +void LimeRFEGUI::on_rxTxToggle_clicked() +{ + m_rxTxToggle = ui->rxTxToggle->isChecked(); + + if (m_rxTxToggle && m_settings.m_rxOn && m_settings.m_txOn) + { + m_settings.m_txOn = false; + int rc = m_limeRFE->setTx(m_settings, m_settings.m_txOn); + ui->statusText->setText(m_limeRFE->getError(rc).c_str()); + displayMode(); + + if (m_deviceSetSync) { + syncRxTx(); + } + } +} + +void LimeRFEGUI::on_attenuation_currentIndexChanged(int index) +{ + m_settings.m_attenuationFactor = index; + highlightApplyButton(true); +} + +void LimeRFEGUI::on_amFmNotchFilter_clicked() +{ + m_settings.m_amfmNotch = ui->amFmNotchFilter->isChecked(); + highlightApplyButton(true); +} + +void LimeRFEGUI::on_apply_clicked() +{ + ui->statusText->clear(); + m_limeRFE->settingsToState(m_settings); + int rc = m_limeRFE->configure(); + ui->statusText->setText(m_limeRFE->getError(rc).c_str()); + highlightApplyButton(false); +} + +void LimeRFEGUI::tick() +{ + refreshPower(); +} + +void LimeRFEGUI::makeUIConnections() +{ + QObject::connect(ui->openDevice, &QPushButton::clicked, this, &LimeRFEGUI::on_openDevice_clicked); + QObject::connect(ui->closeDevice, &QPushButton::clicked, this, &LimeRFEGUI::on_closeDevice_clicked); + QObject::connect(ui->deviceToGUI, &QPushButton::clicked, this, &LimeRFEGUI::on_deviceToGUI_clicked); + QObject::connect(ui->rxChannelGroup, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeRFEGUI::on_rxChannelGroup_currentIndexChanged); + QObject::connect(ui->rxChannel, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeRFEGUI::on_rxChannel_currentIndexChanged); + QObject::connect(ui->rxPort, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeRFEGUI::on_rxPort_currentIndexChanged); + QObject::connect(ui->attenuation, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeRFEGUI::on_attenuation_currentIndexChanged); + QObject::connect(ui->amFmNotchFilter, &QCheckBox::clicked, this, &LimeRFEGUI::on_amFmNotchFilter_clicked); + QObject::connect(ui->txFollowsRx, &QCheckBox::clicked, this, &LimeRFEGUI::on_txFollowsRx_clicked); + QObject::connect(ui->txChannelGroup, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeRFEGUI::on_txChannelGroup_currentIndexChanged); + QObject::connect(ui->txChannel, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeRFEGUI::on_txChannel_currentIndexChanged); + QObject::connect(ui->txPort, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeRFEGUI::on_txPort_currentIndexChanged); + QObject::connect(ui->powerEnable, &QCheckBox::clicked, this, &LimeRFEGUI::on_powerEnable_clicked); + QObject::connect(ui->powerSource, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeRFEGUI::on_powerSource_currentIndexChanged); + QObject::connect(ui->powerRefresh, &QPushButton::clicked, this, &LimeRFEGUI::on_powerRefresh_clicked); + QObject::connect(ui->powerAutoRefresh, &ButtonSwitch::toggled, this, &LimeRFEGUI::on_powerAutoRefresh_toggled); + QObject::connect(ui->powerAbsAvg, &QCheckBox::clicked, this, &LimeRFEGUI::on_powerAbsAvg_clicked); + QObject::connect(ui->powerCorrValue, &QLineEdit::textEdited, this, &LimeRFEGUI::on_powerCorrValue_textEdited); + QObject::connect(ui->modeRx, &QToolButton::toggled, this, &LimeRFEGUI::on_modeRx_toggled); + QObject::connect(ui->modeTx, &QToolButton::toggled, this, &LimeRFEGUI::on_modeTx_toggled); + QObject::connect(ui->rxTxToggle, &QCheckBox::clicked, this, &LimeRFEGUI::on_rxTxToggle_clicked); + QObject::connect(ui->deviceSetRefresh, &QPushButton::clicked, this, &LimeRFEGUI::on_deviceSetRefresh_clicked); + QObject::connect(ui->deviceSetSync, &QCheckBox::clicked, this, &LimeRFEGUI::on_deviceSetSync_clicked); + QObject::connect(ui->apply, &QPushButton::clicked, this, &LimeRFEGUI::on_apply_clicked); +} diff --git a/plugins/feature/limerfe/limerfegui.h b/plugins/feature/limerfe/limerfegui.h new file mode 100644 index 000000000..6646ce788 --- /dev/null +++ b/plugins/feature/limerfe/limerfegui.h @@ -0,0 +1,135 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_FEATURE_LIMERFEGUI_H_ +#define INCLUDE_FEATURE_LIMERFEGUI_H_ + +#include + +#include "feature/featuregui.h" +#include "util/messagequeue.h" +#include "util/movingaverage.h" +#include "settings/rollupstate.h" + +#include "limerfesettings.h" + +class PluginAPI; +class FeatureUISet; +class Feature; +class LimeRFE; +class LimeRFEUSBCalib; +class DSPDeviceSourceEngine; +class DSPDeviceSinkEngine; + +namespace Ui { + class LimeRFEGUI; +} + +class LimeRFEGUI : public FeatureGUI +{ + Q_OBJECT +public: + static LimeRFEGUI* 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; } + virtual void setWorkspaceIndex(int index); + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; } + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; } + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; } + +protected: + void resizeEvent(QResizeEvent* size); + +private: + Ui::LimeRFEGUI* ui; + PluginAPI* m_pluginAPI; + FeatureUISet* m_featureUISet; + LimeRFESettings m_settings; + LimeRFEUSBCalib* m_limeRFEUSBCalib; + RollupState m_rollupState; + bool m_doApplySettings; + bool m_rxTxToggle; + QTimer m_timer; + double m_currentPowerCorrection; + bool m_avgPower; + MovingAverageUtil m_powerMovingAverage; + bool m_deviceSetSync; + std::vector m_sourceEngines; + std::vector m_rxDeviceSetIndex; + std::vector m_sinkEngines; + std::vector m_txDeviceSetIndex; + + LimeRFE* m_limeRFE; + MessageQueue m_inputMessageQueue; + + explicit LimeRFEGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent = nullptr); + virtual ~LimeRFEGUI(); + + void blockApplySettings(bool block) { m_doApplySettings = !block; } + void applySettings(bool force = false); + void displaySettings(); + void displayMode(); + void displayPower(); + void refreshPower(); + void setRxChannels(); + void setTxChannels(); + int getPowerCorectionIndex(); + double getPowerCorrection(); + void setPowerCorrection(double dbValue); + void updateAbsPower(double powerCorrDB); + void updateDeviceSetList(); + void stopStartRx(bool start); + void stopStartTx(bool start); + void syncRxTx(); + void highlightApplyButton(bool highlight); + void makeUIConnections(); + +private slots: + void onMenuDialogCalled(const QPoint &p); + void onWidgetRolled(QWidget* widget, bool rollDown); + void on_openDevice_clicked(); + void on_closeDevice_clicked(); + void on_deviceToGUI_clicked(); + void on_rxChannelGroup_currentIndexChanged(int index); + void on_rxChannel_currentIndexChanged(int index); + void on_rxPort_currentIndexChanged(int index); + void on_attenuation_currentIndexChanged(int index); + void on_amFmNotchFilter_clicked(); + void on_txFollowsRx_clicked(); + void on_txChannelGroup_currentIndexChanged(int index); + void on_txChannel_currentIndexChanged(int index); + void on_txPort_currentIndexChanged(int index); + void on_powerEnable_clicked(); + void on_powerSource_currentIndexChanged(int index); + void on_powerRefresh_clicked(); + void on_powerAutoRefresh_toggled(bool checked); + void on_powerAbsAvg_clicked(); + void on_powerCorrValue_textEdited(const QString &text); + void on_modeRx_toggled(bool checked); + void on_modeTx_toggled(bool checked); + void on_rxTxToggle_clicked(); + void on_deviceSetRefresh_clicked(); + void on_deviceSetSync_clicked(); + void on_apply_clicked(); + void tick(); +}; + +#endif diff --git a/plugins/feature/limerfe/limerfegui.ui b/plugins/feature/limerfe/limerfegui.ui new file mode 100644 index 000000000..13574f3e3 --- /dev/null +++ b/plugins/feature/limerfe/limerfegui.ui @@ -0,0 +1,980 @@ + + + LimeRFEGUI + + + + 0 + 0 + 392 + 667 + + + + + 0 + 0 + + + + + 390 + 667 + + + + + 560 + 667 + + + + + Liberation Sans + 9 + + + + LimeRFE USB controller + + + + + 0 + 0 + 391 + 372 + + + + Settings + + + + 3 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + + Dev + + + + + + + + 220 + 0 + + + + Device + + + + + + + + 60 + 16777215 + + + + Open device + + + Open + + + + + + + + 60 + 16777215 + + + + Close Device + + + Close + + + + + + + + + + + Transfer data to GUI + + + to GUI + + + + + + + Apply changes + + + Apply + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Horizontal + + + + + + + + + Rx channel + + + + + + + + + + + + 120 + 0 + + + + Rx channel group + + + + Wideband + + + + + HAM + + + + + Cellular + + + + + + + + + 200 + 0 + + + + Rx channel range + + + + + + + + + + + Rx port + + + + + + + + 99 + 16777215 + + + + Rx port + + + + Tx/Rx (J3) + + + + + Tx/Rx HF (J5) + + + + + + + + Att + + + + + + + Rx attenuation + + + + 0 + + + + + 2 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 14 + + + + + + + + dB + + + + + + + AM/FM notch filter + + + Notch + + + + + + + + + Qt::Horizontal + + + + + + + + + Tx channel + + + + + + + Channel same as Rx + + + Same as Rx + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 120 + 0 + + + + Rx channel group + + + + Wideband + + + + + HAM + + + + + Cellular + + + + + + + + + 200 + 0 + + + + Rx channel range + + + + + + + + + + + + 47 + 0 + + + + Tx port + + + + + + + Tx port + + + + Tx/Rx (J3) + + + + + Tx (J4) + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + 0 + 373 + 391 + 121 + + + + Power + + + + 3 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + + Enable power measurements + + + Pwr + + + + + + + Refresh power + + + + + + + :/recycle.png:/recycle.png + + + + + + + Power measurement source (EXTernal, CELlular) + + + + EXT + + + + + CEL + + + + + + + + Auto refresh power + + + + + + + :/play.png:/play.png + + + true + + + + + + + Corr + + + + + + + + 60 + 16777215 + + + + Qt::ClickFocus + + + Power correction in dBm + + + -00.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 10 + + + + + Fwd + + + + + + + Relative forward power in dB + + + 00.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Vertical + + + + + + + Ref + + + + + + + Relative reflected power in dB + + + 00.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Vertical + + + + + + + RL + + + + + + + Return loss in dB + + + 00.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + dB + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Vertical + + + + + + + VSWR + + + + + + + Voltage Standing Wave Ratio + + + 1.000 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Abs power + + + + + + + Corrected forward power in dBm + + + -00.0 dBm + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Corrected forward power in Watts + + + 0.000 W + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Corrected power averaging + + + Avg + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + 0 + 495 + 391 + 171 + + + + Control + + + + 3 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + + Mode + + + + + + + + 110 + 0 + + + + Rx/Tx state + + + None + + + + + + + DeviceSet synchronization + + + Rx/Tx Sync + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Switch Rx + + + RX + + + true + + + + + + + Switch Tx + + + TX + + + true + + + + + + + Rx/Tx toggle + + + Toggle + + + + + + + Rx + + + + + + + Index of Rx DeviceSet + + + + + + + Tx + + + + + + + Index of Tx DeviceSet + + + + + + + Refresh DeviceSet indexes + + + + + + + :/recycle.png:/recycle.png + + + + + + + + + + + Messages + + + + + + + + + + + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
+ + RollupContents + QWidget +
gui/rollupcontents.h
+ 1 +
+
+ + + + +
diff --git a/plugins/feature/limerfe/limerfeplugin.cpp b/plugins/feature/limerfe/limerfeplugin.cpp new file mode 100644 index 000000000..491011da3 --- /dev/null +++ b/plugins/feature/limerfe/limerfeplugin.cpp @@ -0,0 +1,80 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 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 . // +/////////////////////////////////////////////////////////////////////////////////// + + +#include +#include "plugin/pluginapi.h" + +#ifndef SERVER_MODE +#include "limerfegui.h" +#endif +#include "limerfe.h" +#include "limerfeplugin.h" +// #include "simplepttwebapiadapter.h" + +const PluginDescriptor LimeRFEPlugin::m_pluginDescriptor = { + LimeRFE::m_featureId, + QStringLiteral("LimeRFE USB Controller"), + QStringLiteral("7.1.0"), + QStringLiteral("(c) Edouard Griffiths, F4EXB"), + QStringLiteral("https://github.com/f4exb/sdrangel"), + true, + QStringLiteral("https://github.com/f4exb/sdrangel") +}; + +LimeRFEPlugin::LimeRFEPlugin(QObject* parent) : + QObject(parent), + m_pluginAPI(nullptr) +{ +} + +const PluginDescriptor& LimeRFEPlugin::getPluginDescriptor() const +{ + return m_pluginDescriptor; +} + +void LimeRFEPlugin::initPlugin(PluginAPI* pluginAPI) +{ + m_pluginAPI = pluginAPI; + + // register Simple PTT feature + m_pluginAPI->registerFeature(LimeRFE::m_featureIdURI, LimeRFE::m_featureId, this); +} + +#ifdef SERVER_MODE +FeatureGUI* LimeRFEPlugin::createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const +{ + (void) featureUISet; + (void) feature; + return nullptr; +} +#else +FeatureGUI* LimeRFEPlugin::createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const +{ + return LimeRFEGUI::create(m_pluginAPI, featureUISet, feature); +} +#endif + +Feature* LimeRFEPlugin::createFeature(WebAPIAdapterInterface* webAPIAdapterInterface) const +{ + return new LimeRFE(webAPIAdapterInterface); +} + +FeatureWebAPIAdapter* LimeRFEPlugin::createFeatureWebAPIAdapter() const +{ + return nullptr; // TODO new SimplePTTWebAPIAdapter(); +} diff --git a/plugins/feature/limerfe/limerfeplugin.h b/plugins/feature/limerfe/limerfeplugin.h new file mode 100644 index 000000000..53aca7c26 --- /dev/null +++ b/plugins/feature/limerfe/limerfeplugin.h @@ -0,0 +1,48 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_FEATURE_LIMERFEPLUGIN_H +#define INCLUDE_FEATURE_LIMERFEPLUGIN_H + +#include +#include "plugin/plugininterface.h" + +class FeatureGUI; +class WebAPIAdapterInterface; + +class LimeRFEPlugin : public QObject, PluginInterface { + Q_OBJECT + Q_INTERFACES(PluginInterface) + Q_PLUGIN_METADATA(IID "sdrangel.feature.limerfe") + +public: + explicit LimeRFEPlugin(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_SIMPLEPTTPLUGIN_H diff --git a/plugins/feature/limerfe/limerfesettings.cpp b/plugins/feature/limerfe/limerfesettings.cpp new file mode 100644 index 000000000..e164cc96d --- /dev/null +++ b/plugins/feature/limerfe/limerfesettings.cpp @@ -0,0 +1,185 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#include + +#include "util/simpleserializer.h" +#include "settings/serializable.h" + +#include "limerfesettings.h" + +LimeRFESettings::LimeRFESettings() : + m_rollupState(nullptr) +{ + resetToDefaults(); +} + +void LimeRFESettings::resetToDefaults() +{ + m_devicePath = ""; + m_title = "Lime RFE"; + m_rgbColor = QColor(50, 205, 50).rgb(); + m_rxChannels = ChannelsWideband; + m_rxWidebandChannel = WidebandLow; + m_rxHAMChannel = HAM_144_146MHz; + m_rxCellularChannel = CellularBand38; + m_rxPort = RxPortJ3; + m_amfmNotch = false; + m_attenuationFactor = 0; + m_txChannels = ChannelsWideband; + m_txWidebandChannel = WidebandLow; + m_txHAMChannel = HAM_144_146MHz; + m_txCellularChannel = CellularBand38; + m_txPort = TxPortJ3; + m_swrEnable = false; + m_swrSource = SWRExternal; + m_txRxDriven = false; + m_rxOn = false; + m_txOn = false; + m_useReverseAPI = false; + m_reverseAPIAddress = "127.0.0.1"; + m_reverseAPIPort = 8888; + m_reverseAPIFeatureSetIndex = 0; + m_reverseAPIFeatureIndex = 0; + m_workspaceIndex = 0; +} + +QByteArray LimeRFESettings::serialize() const +{ + SimpleSerializer s(1); + + s.writeS32(1, (int) m_rxChannels); + s.writeS32(2, (int) m_rxWidebandChannel); + s.writeS32(3, (int) m_rxHAMChannel); + s.writeS32(4, (int) m_rxCellularChannel); + s.writeS32(5, (int) m_rxPort); + s.writeBool(6, m_amfmNotch); + s.writeU32(7, m_attenuationFactor); + + s.writeS32(10, (int) m_txChannels); + s.writeS32(11, (int) m_txWidebandChannel); + s.writeS32(12, (int) m_txHAMChannel); + s.writeS32(13, (int) m_txCellularChannel); + s.writeS32(14, (int) m_txPort); + s.writeBool(15, m_swrEnable); + s.writeS32(16, (int) m_swrSource); + + s.writeBool(20, m_txRxDriven); + s.writeBool(21, m_rxOn); + s.writeBool(22, m_txOn); + + s.writeString(30, m_title); + s.writeU32(31, m_rgbColor); + s.writeBool(32, m_useReverseAPI); + s.writeString(33, m_reverseAPIAddress); + s.writeU32(34, m_reverseAPIPort); + s.writeU32(35, m_reverseAPIFeatureSetIndex); + s.writeU32(36, m_reverseAPIFeatureIndex); + + if (m_rollupState) { + s.writeBlob(37, m_rollupState->serialize()); + } + + s.writeS32(38, m_workspaceIndex); + s.writeBlob(39, m_geometryBytes); + s.writeString(40, m_devicePath); + + return s.final(); +} + +bool LimeRFESettings::deserialize(const QByteArray& data) +{ + SimpleDeserializer d(data); + + if(!d.isValid()) + { + resetToDefaults(); + return false; + } + + if(d.getVersion() == 1) + { + QByteArray bytetmp; + uint32_t utmp; + int tmp; + + d.readS32(1, &tmp, (int) ChannelsWideband); + m_rxChannels = (ChannelGroups) tmp; + d.readS32(2, &tmp, (int) WidebandLow); + m_rxWidebandChannel = (WidebandChannel) tmp; + d.readS32(3, &tmp, (int) HAM_144_146MHz); + m_rxHAMChannel = (HAMChannel) tmp; + d.readS32(4, &tmp, (int) CellularBand38); + m_rxCellularChannel = (CellularChannel) tmp; + d.readS32(5, &tmp, (int) RxPortJ3); + m_rxPort = (RxPort) tmp; + d.readBool(6, &m_amfmNotch, false); + d.readU32(7, &m_attenuationFactor, 0); + + d.readS32(10, &tmp, (int) ChannelsWideband); + m_txChannels = (ChannelGroups) tmp; + d.readS32(11, &tmp, (int) WidebandLow); + m_txWidebandChannel = (WidebandChannel) tmp; + d.readS32(12, &tmp, (int) HAM_144_146MHz); + m_txHAMChannel = (HAMChannel) tmp; + d.readS32(13, &tmp, (int) CellularBand38); + m_txCellularChannel = (CellularChannel) tmp; + d.readS32(14, &tmp, (int) TxPortJ3); + m_txPort = (TxPort) tmp; + d.readBool(15, &m_swrEnable, false); + d.readS32(16, &tmp, (int) SWRExternal); + m_swrSource = (SWRSource) tmp; + + d.readBool(20, &m_txRxDriven, false); + d.readBool(21, &m_rxOn, false); + d.readBool(22, &m_txOn, false); + + d.readString(30, &m_title, "Lime RFE"); + d.readU32(31, &m_rgbColor, QColor(50, 205, 50).rgb()); + d.readBool(32, &m_useReverseAPI, false); + d.readString(33, &m_reverseAPIAddress, "127.0.0.1"); + d.readU32(34, &utmp, 0); + + if ((utmp > 1023) && (utmp < 65535)) { + m_reverseAPIPort = utmp; + } else { + m_reverseAPIPort = 8888; + } + + d.readU32(35, &utmp, 0); + m_reverseAPIFeatureSetIndex = utmp > 99 ? 99 : utmp; + d.readU32(36, &utmp, 0); + m_reverseAPIFeatureIndex = utmp > 99 ? 99 : utmp; + + if (m_rollupState) + { + d.readBlob(37, &bytetmp); + m_rollupState->deserialize(bytetmp); + } + + d.readS32(38, &m_workspaceIndex, 0); + d.readBlob(39, &m_geometryBytes); + d.readString(40, &m_devicePath, ""); + + return true; + } + else + { + resetToDefaults(); + return false; + } +} diff --git a/plugins/feature/limerfe/limerfesettings.h b/plugins/feature/limerfe/limerfesettings.h new file mode 100644 index 000000000..9e3a98180 --- /dev/null +++ b/plugins/feature/limerfe/limerfesettings.h @@ -0,0 +1,122 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_FEATURE_LIMERFESETTINGS_H_ +#define INCLUDE_FEATURE_LIMERFESETTINGS_H_ + +#include +#include + +class Serializable; + +struct LimeRFESettings +{ + enum ChannelGroups + { + ChannelsWideband, + ChannelsHAM, + ChannelsCellular + }; + + enum WidebandChannel + { + WidebandLow, //!< 1 - 1000 MHz + WidebandHigh //!< 1000 - 4000 MHz + }; + + enum HAMChannel + { + HAM_30M, + HAM_50_70MHz, + HAM_144_146MHz, + HAM_220_225MHz, + HAM_430_440MHz, + HAM_902_928MHz, + HAM_1240_1325MHz, + HAM_2300_2450MHz, + HAM_3300_3500MHz + }; + + enum CellularChannel + { + CellularBand1, + CellularBand2, + CellularBand3, + CellularBand7, + CellularBand38 + }; + + enum RxPort + { + RxPortJ3, //!< Rx/Tx + RxPortJ5 //!< Rx/Tx HF + }; + + enum TxPort + { + TxPortJ3, //!< Rx/Tx + TxPortJ4, //!< Tx + TxPortJ5 //!< Rx/Tx HF + }; + + enum SWRSource + { + SWRExternal, + SWRCellular + }; + + // Rx + ChannelGroups m_rxChannels; + WidebandChannel m_rxWidebandChannel; + HAMChannel m_rxHAMChannel; + CellularChannel m_rxCellularChannel; + RxPort m_rxPort; + unsigned int m_attenuationFactor; //!< Attenuation is 2 times this factor in dB (0..7 => 0..14dB) + bool m_amfmNotch; + // Tx + ChannelGroups m_txChannels; + WidebandChannel m_txWidebandChannel; + HAMChannel m_txHAMChannel; + CellularChannel m_txCellularChannel; + TxPort m_txPort; + bool m_swrEnable; + SWRSource m_swrSource; + // Rx/Tx + bool m_txRxDriven; //!< Tx settings set according to Rx settings + bool m_rxOn; + bool m_txOn; + // Common + QString m_devicePath; + QString m_title; + quint32 m_rgbColor; + bool m_useReverseAPI; + QString m_reverseAPIAddress; + uint16_t m_reverseAPIPort; + uint16_t m_reverseAPIFeatureSetIndex; + uint16_t m_reverseAPIFeatureIndex; + Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; + + LimeRFESettings(); + void resetToDefaults(); + QByteArray serialize() const; + bool deserialize(const QByteArray& data); + void setRollupState(Serializable *rollupState) { m_rollupState = rollupState; } +}; + +#endif diff --git a/plugins/feature/limerfe/limerfeusbcalib.cpp b/plugins/feature/limerfe/limerfeusbcalib.cpp new file mode 100644 index 000000000..1502fe246 --- /dev/null +++ b/plugins/feature/limerfe/limerfeusbcalib.cpp @@ -0,0 +1,71 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +#include "util/simpleserializer.h" + +#include "limerfeusbcalib.h" + +QByteArray LimeRFEUSBCalib::serialize() const +{ + SimpleSerializer s(1); + QByteArray data; + + serializeCalibMap(data); + s.writeBlob(1, data); + + return s.final(); +} + +bool LimeRFEUSBCalib::deserialize(const QByteArray& data) +{ + SimpleDeserializer d(data); + + if (!d.isValid()) { + return false; + } + + if (d.getVersion() == 1) + { + QByteArray data; + + d.readBlob(1, &data); + deserializeCalibMap(data); + + return true; + } + else + { + return false; + } +} + +void LimeRFEUSBCalib::serializeCalibMap(QByteArray& data) const +{ + QDataStream *stream = new QDataStream(&data, QIODevice::WriteOnly); + *stream << m_calibrations; + delete stream; +} + +void LimeRFEUSBCalib::deserializeCalibMap(QByteArray& data) +{ + QDataStream readStream(&data, QIODevice::ReadOnly); + readStream >> m_calibrations; +} diff --git a/plugins/feature/limerfe/limerfeusbcalib.h b/plugins/feature/limerfe/limerfeusbcalib.h new file mode 100644 index 000000000..80f419575 --- /dev/null +++ b/plugins/feature/limerfe/limerfeusbcalib.h @@ -0,0 +1,59 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef SDRBASE_LIMERFE_LIMERFEUSBCALIB_H_ +#define SDRBASE_LIMERFE_LIMERFEUSBCALIB_H_ + +#include +#include "export.h" + +class QByteArray; + +class SDRBASE_API LimeRFEUSBCalib +{ +public: + QByteArray serialize() const; + bool deserialize(const QByteArray& data); + + enum ChannelRange + { + WidebandLow, //!< 1 - 1000 MHz + WidebandHigh, //!< 1000 - 4000 MHz + HAM_30MHz, //!< Up to 30 MHz + HAM_50_70MHz, + HAM_144_146MHz, + HAM_220_225MHz, + HAM_430_440MHz, + HAM_902_928MHz, + HAM_1240_1325MHz, + HAM_2300_2450MHz, + HAM_3300_3500MHz, + CellularBand1, + CellularBand2, + CellularBand3, + CellularBand7, + CellularBand38 + }; + + QMap m_calibrations; //!< Channel range to calibration value in floating point decibels + +private: + void serializeCalibMap(QByteArray& data) const; + void deserializeCalibMap(QByteArray& data); +}; + +#endif // SDRBASE_LIMERFE_LIMERFEUSBCALIB_H_