diff --git a/CMakeLists.txt b/CMakeLists.txt index 2de515ce0..772b8c2cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -383,6 +383,9 @@ if(ENABLE_HACKRF) endif() if(ENABLE_LIMESUITE) find_package(LimeSuite) + if (LIMERFE_FOUND) + add_definitions(-DHAS_LIMERFE) + endif() endif() if(ENABLE_IIO) # PlutoSDR find_package(LibIIO) diff --git a/cmake/Modules/FindLimeSuite.cmake b/cmake/Modules/FindLimeSuite.cmake index d7ea7f41e..a06335d4d 100644 --- a/cmake/Modules/FindLimeSuite.cmake +++ b/cmake/Modules/FindLimeSuite.cmake @@ -28,8 +28,19 @@ endif (LIMESUITE_INCLUDE_DIR AND LIMESUITE_LIBRARY) if (LIMESUITE_FOUND) message (STATUS "Found Lime Suite: ${LIMESUITE_INCLUDE_DIR}, ${LIMESUITE_LIBRARY}") + find_file(LIMERFE_INCLUDE_FILE + name lime/limeRFE.h + HINTS ${LIMESUITE_INCLUDE_DIR} + ) else (LIMESUITE_FOUND) message (STATUS "Could not find Lime Suite") endif (LIMESUITE_FOUND) +if (LIMERFE_INCLUDE_FILE) + set(LIMERFE_FOUND TRUE) + message (STATUS "Lime Suite has LimeRFE support: ${LIMERFE_INCLUDE_FILE}") +else() + message (STATUS "Lime Suite has not LimeRFE support") +endif() + mark_as_advanced(LIMESUITE_INCLUDE_DIR LIMESUITE_LIBRARY) diff --git a/sdrbase/CMakeLists.txt b/sdrbase/CMakeLists.txt index c8c5eb02c..f61f87a54 100644 --- a/sdrbase/CMakeLists.txt +++ b/sdrbase/CMakeLists.txt @@ -31,6 +31,19 @@ else(FFTW3F_FOUND) add_definitions(-DUSE_KISSFFT) endif(FFTW3F_FOUND) +if (LIMERFE_FOUND) + set(sdrbase_SOURCES + ${sdrbase_SOURCES} + limerfe/limerfecontroller.cpp + ) + set(sdrbase_HEADERS + ${sdrbase_HEADERS} + limerfe/limerfecontroller.h + ) + include_directories(${LIMESUITE_INCLUDE_DIR}) + set(sdrbase_LIMERFE_LIB ${LIMESUITE_LIBRARY}) +endif (LIMERFE_FOUND) + # serialdv now required add_definitions(-DDSD_USE_SERIALDV) include_directories(${LIBSERIALDV_INCLUDE_DIR}) @@ -132,6 +145,7 @@ set(sdrbase_SOURCES util/syncmessenger.cpp util/samplesourceserializer.cpp util/simpleserializer.cpp + util/serialutil.cpp #util/spinlock.cpp util/uid.cpp util/timeutil.cpp @@ -280,6 +294,7 @@ set(sdrbase_HEADERS util/syncmessenger.h util/samplesourceserializer.h util/simpleserializer.h + util/serialutil.h #util/spinlock.h util/uid.h util/timeutil.h @@ -313,6 +328,7 @@ target_link_libraries(sdrbase ${OPUS_LIBRARIES} ${sdrbase_FFTW3F_LIB} ${sdrbase_SERIALDV_LIB} + ${sdrbase_LIMERFE_LIB} Qt5::Core Qt5::Multimedia httpserver diff --git a/sdrbase/limerfe/limerfecontroller.cpp b/sdrbase/limerfe/limerfecontroller.cpp new file mode 100644 index 000000000..df67897b3 --- /dev/null +++ b/sdrbase/limerfe/limerfecontroller.cpp @@ -0,0 +1,531 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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 "limerfecontroller.h" + +const std::map LimeRFEController::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"} +}; + +LimeRFEController::LimeRFESettings::LimeRFESettings() +{ + 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_txRxDriven = false; + m_rxOn = false; + m_txOn = false; +} + +LimeRFEController::LimeRFEController() : + m_rfeDevice(nullptr) +{} + +LimeRFEController::~LimeRFEController() +{ + if (m_rfeDevice) { + closeDevice(); + } +} + +int LimeRFEController::openDevice(const std::string& serialDeviceName) +{ + if (m_rfeDevice) { + closeDevice(); + } + + rfe_dev_t *rfeDevice = RFE_Open(serialDeviceName.c_str(), nullptr); + + if (rfeDevice != (void *) -1) { + m_rfeDevice = rfeDevice; + return 0; + } + else + { + return -1; + } +} + +void LimeRFEController::closeDevice() +{ + RFE_Close(m_rfeDevice); + m_rfeDevice = nullptr; +} + +int LimeRFEController::configure() +{ + if (!m_rfeDevice) { + return -1; + } + + int rc = RFE_ConfigureState(m_rfeDevice, m_rfeBoardState); + + if (rc != 0) { + qInfo("LimeRFEController::configure: %s", getError(rc).c_str()); + } + + return rc; +} + +int LimeRFEController::getState() +{ + if (!m_rfeDevice) { + return -1; + } + + int rc = RFE_GetState(m_rfeDevice, &m_rfeBoardState); + + qDebug() << "LimeRFEController::getState: " + << "attValue: " << (int) m_rfeBoardState.attValue + << "channelIDRX: " << (int) m_rfeBoardState.channelIDRX + << "channelIDTX: " << (int) m_rfeBoardState.channelIDTX + << "enableSWR: " << (int) m_rfeBoardState.enableSWR + << "mode: " << (int) m_rfeBoardState.mode + << "notchOnOff: " << (int) m_rfeBoardState.notchOnOff + << "selPortRX: " << (int) m_rfeBoardState.selPortRX + << "selPortTX: " << (int) m_rfeBoardState.selPortTX + << "sourceSWR: " << (int) m_rfeBoardState.sourceSWR; + + if (rc != 0) { + qInfo("LimeRFEController::getState: %s", getError(rc).c_str()); + } + + return rc; +} + +std::string LimeRFEController::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 LimeRFEController::setRx(LimeRFESettings& settings, bool rxOn) +{ + if (!m_rfeDevice) { + return -1; + } + + if (settings.m_txRxDriven) { + return 0; + } + + 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 LimeRFEController::setTx(LimeRFESettings& settings, bool txOn) +{ + if (!m_rfeDevice) { + return -1; + } + + if (settings.m_txRxDriven) { + return 0; + } + + 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_rxOn = txOn; + } + + return rc; +} + +int LimeRFEController::driveTx(LimeRFESettings& settings, bool txOn) +{ + + if (!m_rfeDevice) + { + qDebug("LimeRFEController::driveTx: not open"); + return -1; + } + + if (settings.m_rxChannels == ChannelsCellular) + { + qDebug("LimeRFEController::driveTx: do nothing for cellular bands"); + return 0; // cellular is TRX anyway + } + + int mode = txOn ? RFE_MODE_TX : RFE_MODE_RX; + int rc = RFE_Mode(m_rfeDevice, mode); + + if (rc == 0) + { + settings.m_rxOn = !txOn; + settings.m_txOn = txOn; + qDebug("LimeRFEController::driveTx: done: Rx: %s Tx: %s", settings.m_rxOn ? "on" : "off", settings.m_txOn ? "on" : "off"); + } + else + { + qInfo("LimeRFEController::driveTx: %s error: %s", txOn ? "on" : "off", getError(rc).c_str()); + } + + return rc; +} + +void LimeRFEController::settingsToState(const LimeRFESettings& settings) +{ + if (settings.m_rxChannels == ChannelsCellular) + { + if (settings.m_rxCellularChannel == CellularBand1) + { + m_rfeBoardState.channelIDRX = RFE_CID_CELL_BAND01; + m_rfeBoardState.mode = RFE_MODE_TXRX; + } + else if (settings.m_rxCellularChannel == CellularBand2) + { + m_rfeBoardState.channelIDRX = RFE_CID_CELL_BAND02; + m_rfeBoardState.mode = RFE_MODE_TXRX; + } + else if (settings.m_rxCellularChannel == CellularBand38) + { + m_rfeBoardState.channelIDRX = RFE_CID_CELL_BAND38; + } + else if (settings.m_rxCellularChannel == 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 + { + if (settings.m_rxChannels == ChannelsWideband) + { + if (settings.m_rxWidebandChannel == WidebandLow) { + m_rfeBoardState.channelIDRX = RFE_CID_WB_1000; + } else if (settings.m_rxWidebandChannel == WidebandHigh) { + m_rfeBoardState.channelIDRX = RFE_CID_WB_4000; + } + } + else if (settings.m_rxChannels == ChannelsHAM) + { + if (settings.m_rxHAMChannel == HAM_30M) { + m_rfeBoardState.channelIDRX = RFE_CID_HAM_0030; + } else if (settings.m_rxHAMChannel == HAM_50_70MHz) { + m_rfeBoardState.channelIDRX = RFE_CID_HAM_0070; + } else if (settings.m_rxHAMChannel == HAM_144_146MHz) { + m_rfeBoardState.channelIDRX = RFE_CID_HAM_0145; + } else if (settings.m_rxHAMChannel == HAM_220_225MHz) { + m_rfeBoardState.channelIDRX = RFE_CID_HAM_0220; + } else if (settings.m_rxHAMChannel == HAM_430_440MHz) { + m_rfeBoardState.channelIDRX = RFE_CID_HAM_0435; + } else if (settings.m_rxHAMChannel == HAM_902_928MHz) { + m_rfeBoardState.channelIDRX = RFE_CID_HAM_0920; + } else if (settings.m_rxHAMChannel == HAM_1240_1325MHz) { + m_rfeBoardState.channelIDRX = RFE_CID_HAM_1280; + } else if (settings.m_rxHAMChannel == HAM_2300_2450MHz) { + m_rfeBoardState.channelIDRX = RFE_CID_HAM_2400; + } else if (settings.m_rxHAMChannel == HAM_3300_3500MHz) { + m_rfeBoardState.channelIDRX = RFE_CID_HAM_3500; + } + } + + if (settings.m_rxPort == RxPortJ3) { + m_rfeBoardState.selPortRX = RFE_PORT_1; + } else if (settings.m_rxPort == RxPortJ5) { + m_rfeBoardState.selPortRX = RFE_PORT_3; + } + + if (settings.m_txRxDriven) + { + m_rfeBoardState.channelIDTX = m_rfeBoardState.channelIDRX; + } + else + { + if (settings.m_txChannels == ChannelsWideband) + { + if (settings.m_txWidebandChannel == WidebandLow) { + m_rfeBoardState.channelIDTX = RFE_CID_WB_1000; + } else if (settings.m_txWidebandChannel == WidebandHigh) { + m_rfeBoardState.channelIDTX = RFE_CID_WB_4000; + } + } + else if (settings.m_txChannels == ChannelsHAM) + { + if (settings.m_txHAMChannel == HAM_30M) { + m_rfeBoardState.channelIDTX = RFE_CID_HAM_0030; + } else if (settings.m_txHAMChannel == HAM_50_70MHz) { + m_rfeBoardState.channelIDTX = RFE_CID_HAM_0070; + } else if (settings.m_txHAMChannel == HAM_144_146MHz) { + m_rfeBoardState.channelIDTX = RFE_CID_HAM_0145; + } else if (settings.m_txHAMChannel == HAM_220_225MHz) { + m_rfeBoardState.channelIDTX = RFE_CID_HAM_0220; + } else if (settings.m_txHAMChannel == HAM_430_440MHz) { + m_rfeBoardState.channelIDTX = RFE_CID_HAM_0435; + } else if (settings.m_txHAMChannel == HAM_902_928MHz) { + m_rfeBoardState.channelIDTX = RFE_CID_HAM_0920; + } else if (settings.m_txHAMChannel == HAM_1240_1325MHz) { + m_rfeBoardState.channelIDTX = RFE_CID_HAM_1280; + } else if (settings.m_txHAMChannel == HAM_2300_2450MHz) { + m_rfeBoardState.channelIDTX = RFE_CID_HAM_2400; + } else if (settings.m_txHAMChannel == HAM_3300_3500MHz) { + m_rfeBoardState.channelIDTX = RFE_CID_HAM_3500; + } + } + } + + if (settings.m_txPort == TxPortJ3) { + m_rfeBoardState.selPortTX = RFE_PORT_1; + } else if (settings.m_txPort == TxPortJ4) { + m_rfeBoardState.selPortTX = RFE_PORT_2; + } else if (settings.m_txPort == TxPortJ5) { + m_rfeBoardState.selPortTX = RFE_PORT_3; + } + } + + m_rfeBoardState.attValue = settings.m_attenuationFactor < 0 ? 0 : settings.m_attenuationFactor > 7 ? 7 : settings.m_attenuationFactor; + m_rfeBoardState.notchOnOff = settings.m_amfmNotch; +} + +void LimeRFEController::stateToSettings(LimeRFESettings& settings) +{ + if (m_rfeBoardState.channelIDRX == RFE_CID_CELL_BAND01) + { + settings.m_rxChannels = ChannelsCellular; + settings.m_rxCellularChannel = CellularBand1; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_CELL_BAND02) + { + settings.m_rxChannels = ChannelsCellular; + settings.m_rxCellularChannel = CellularBand2; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_CELL_BAND07) + { + settings.m_rxChannels = ChannelsCellular; + settings.m_rxCellularChannel = CellularBand7; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_CELL_BAND38) + { + settings.m_rxChannels = ChannelsCellular; + settings.m_rxCellularChannel = CellularBand38; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_WB_1000) + { + settings.m_rxChannels = ChannelsWideband; + settings.m_rxWidebandChannel = WidebandLow; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_WB_4000) + { + settings.m_rxChannels = ChannelsWideband; + settings.m_rxWidebandChannel = WidebandHigh; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_HAM_0030) + { + settings.m_rxChannels = ChannelsHAM; + settings.m_rxHAMChannel = HAM_30M; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_HAM_0070) + { + settings.m_rxChannels = ChannelsHAM; + settings.m_rxHAMChannel = HAM_50_70MHz; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_HAM_0145) + { + settings.m_rxChannels = ChannelsHAM; + settings.m_rxHAMChannel = HAM_144_146MHz; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_HAM_0220) + { + settings.m_rxChannels = ChannelsHAM; + settings.m_rxHAMChannel = HAM_220_225MHz; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_HAM_0435) + { + settings.m_rxChannels = ChannelsHAM; + settings.m_rxHAMChannel = HAM_430_440MHz; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_HAM_0920) + { + settings.m_rxChannels = ChannelsHAM; + settings.m_rxHAMChannel = HAM_902_928MHz; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_HAM_1280) + { + settings.m_rxChannels = ChannelsHAM; + settings.m_rxHAMChannel = HAM_1240_1325MHz; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_HAM_2400) + { + settings.m_rxChannels = ChannelsHAM; + settings.m_rxHAMChannel = HAM_2300_2450MHz; + } + else if (m_rfeBoardState.channelIDRX == RFE_CID_HAM_3500) + { + settings.m_rxChannels = ChannelsHAM; + settings.m_rxHAMChannel = HAM_3300_3500MHz; + } + + if (m_rfeBoardState.selPortRX == RFE_PORT_1) { + settings.m_rxPort = RxPortJ3; + } else if (m_rfeBoardState.selPortRX == RFE_PORT_3) { + settings.m_rxPort = RxPortJ5; + } + + if (m_rfeBoardState.channelIDTX == RFE_CID_CELL_BAND01) + { + settings.m_txChannels = ChannelsCellular; + settings.m_txCellularChannel = CellularBand1; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_CELL_BAND02) + { + settings.m_txChannels = ChannelsCellular; + settings.m_txCellularChannel = CellularBand2; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_CELL_BAND07) + { + settings.m_txChannels = ChannelsCellular; + settings.m_txCellularChannel = CellularBand7; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_CELL_BAND38) + { + settings.m_txChannels = ChannelsCellular; + settings.m_txCellularChannel = CellularBand38; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_WB_1000) + { + settings.m_txChannels = ChannelsWideband; + settings.m_txWidebandChannel = WidebandLow; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_WB_4000) + { + settings.m_txChannels = ChannelsWideband; + settings.m_txWidebandChannel = WidebandHigh; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_HAM_0030) + { + settings.m_txChannels = ChannelsHAM; + settings.m_txHAMChannel = HAM_30M; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_HAM_0070) + { + settings.m_txChannels = ChannelsHAM; + settings.m_txHAMChannel = HAM_50_70MHz; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_HAM_0145) + { + settings.m_txChannels = ChannelsHAM; + settings.m_txHAMChannel = HAM_144_146MHz; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_HAM_0220) + { + settings.m_txChannels = ChannelsHAM; + settings.m_txHAMChannel = HAM_220_225MHz; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_HAM_0435) + { + settings.m_txChannels = ChannelsHAM; + settings.m_txHAMChannel = HAM_430_440MHz; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_HAM_0920) + { + settings.m_txChannels = ChannelsHAM; + settings.m_txHAMChannel = HAM_902_928MHz; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_HAM_1280) + { + settings.m_txChannels = ChannelsHAM; + settings.m_txHAMChannel = HAM_1240_1325MHz; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_HAM_2400) + { + settings.m_txChannels = ChannelsHAM; + settings.m_txHAMChannel = HAM_2300_2450MHz; + } + else if (m_rfeBoardState.channelIDTX == RFE_CID_HAM_3500) + { + settings.m_txChannels = ChannelsHAM; + settings.m_txHAMChannel = HAM_3300_3500MHz; + } + + if (m_rfeBoardState.selPortTX == RFE_PORT_1) { + settings.m_txPort = TxPortJ3; + } else if (m_rfeBoardState.selPortTX == RFE_PORT_2) { + settings.m_txPort = TxPortJ4; + } else if (m_rfeBoardState.selPortTX == RFE_PORT_3) { + settings.m_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; + } +} diff --git a/sdrbase/limerfe/limerfecontroller.h b/sdrbase/limerfe/limerfecontroller.h new file mode 100644 index 000000000..cd604a10f --- /dev/null +++ b/sdrbase/limerfe/limerfecontroller.h @@ -0,0 +1,120 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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_LIMERFECONTROLLER_H_ +#define SDRBASE_LIMERFE_LIMERFECONTROLLER_H_ + +#include +#include +#include "lime/limeRFE.h" +#include "export.h" + +class SDRBASE_API LimeRFEController +{ +public: + 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, + CellularBand7, + CellularBand38 + }; + + enum RxPort + { + RxPortJ3, //!< Rx/Tx + RxPortJ5 //!< Rx/Tx HF + }; + + enum TxPort + { + TxPortJ3, //!< Rx/Tx + TxPortJ4, //!< Tx + TxPortJ5 //!< Rx/Tx HF + }; + + struct LimeRFESettings + { + LimeRFESettings(); + // Rx + LimeRFEController::ChannelGroups m_rxChannels; + LimeRFEController::WidebandChannel m_rxWidebandChannel; + LimeRFEController::HAMChannel m_rxHAMChannel; + LimeRFEController::CellularChannel m_rxCellularChannel; + LimeRFEController::RxPort m_rxPort; + unsigned int m_attenuationFactor; //!< Attenuation is 2 times this factor in dB (0..7 => 0..14dB) + bool m_amfmNotch; + // Tx + LimeRFEController::ChannelGroups m_txChannels; + LimeRFEController::WidebandChannel m_txWidebandChannel; + LimeRFEController::HAMChannel m_txHAMChannel; + LimeRFEController::CellularChannel m_txCellularChannel; + LimeRFEController::TxPort m_txPort; + // Rx/Tx + bool m_txRxDriven; //!< Tx settings set according to Rx settings + bool m_rxOn; + bool m_txOn; + }; + + LimeRFEController(); + ~LimeRFEController(); + + int openDevice(const std::string& serialDeviceName); + void closeDevice(); + int configure(); + int getState(); + static std::string getError(int errorCode); + int setRx(LimeRFESettings& settings, bool rxOn); //!< Used by USB driver + int setTx(LimeRFESettings& settings, bool txOn); //!< USed by USB driver + int driveTx(LimeRFESettings& settings, bool txOn); //!< Used by the device set trigger + + void settingsToState(const LimeRFESettings& settings); + void stateToSettings(LimeRFESettings& settings); + +private: + rfe_dev_t *m_rfeDevice; + rfe_boardState m_rfeBoardState; + static const std::map m_errorCodesMap; +}; + +#endif // SDRBASE_LIMERFE_LIMERFECONTROLLER_H_ diff --git a/sdrbase/util/serialutil.cpp b/sdrbase/util/serialutil.cpp new file mode 100644 index 000000000..c84fddb4c --- /dev/null +++ b/sdrbase/util/serialutil.cpp @@ -0,0 +1,122 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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 + +#if defined(__WINDOWS__) +#include +#include +#include +#elif defined(__linux__) +#include +#include +#include +#include +#endif + +#include "serialutil.h" + +#if defined(__WINDOWS__) +void SerialUtil::getComPorts(std::vector& comPorts, const std::string& regexStr) +{ + (void) regexStr; + TCHAR lpTargetPath[5000]; // buffer to store the path of the COMPORTS + DWORD test; + bool gotPort = 0; // in case the port is not found + + char portName[100]; + + for (int i = 0; i<255; i++) // checking ports from COM0 to COM255 + { + sprintf(portName, "COM%d", i); + + test = QueryDosDeviceA((LPCSTR)portName, (LPSTR)lpTargetPath, 5000); + + // Test the return value and error if any + if (test != 0) //QueryDosDevice returns zero if it didn't find an object + { + comPorts.push_back(std::string(portName)); + } + + if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + lpTargetPath[10000]; // in case the buffer got filled, increase size of the buffer. + continue; + } + } +} +#elif defined(__linux__) +void SerialUtil::getComPorts(std::vector& comPorts, const std::string& regexStr) +{ + int n; + struct dirent **namelist; + comPorts.clear(); + const char* sysdir = "/sys/class/tty/"; + struct stat fileStat; + std::regex devRegex(regexStr); + std::smatch devMatch; + std::string devString = "/dev/"; + + // Scan through /sys/class/tty - it contains all tty-devices in the system + n = scandir(sysdir, &namelist, NULL, alphasort); + if (n < 0) + { + perror("scandir"); + } + else + { + while (n--) + { + if (strcmp(namelist[n]->d_name, "..") && strcmp(namelist[n]->d_name, ".")) + { + // Construct full absolute file path + std::string fullpath = sysdir; + std::string devName = std::string(namelist[n]->d_name); + fullpath += devName; + fullpath += std::string("/device"); + + if (lstat(fullpath.c_str(), &fileStat) == 0) + { + if (regexStr.size() != 0) + { + std::regex_search(devName, devMatch, devRegex); + + if (devMatch.size() != 0) { + comPorts.push_back(devString + devName); + } + } + else + { + comPorts.push_back(devString + devName); + } + } + } + + free(namelist[n]); + } + + free(namelist); + } +} +#else // not supported +void SerialUtil::getComPorts(std::vector& comPorts, const std::string& regexStr) +{ + (void) comPorts; + (void) regexStr; +} +#endif \ No newline at end of file diff --git a/sdrbase/util/serialutil.h b/sdrbase/util/serialutil.h new file mode 100644 index 000000000..aa737348a --- /dev/null +++ b/sdrbase/util/serialutil.h @@ -0,0 +1,31 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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_UTIL_SERIALUTIL_H_ +#define SDRBASE_UTIL_SERIALUTIL_H_ + +#include +#include +#include "export.h" + +class SDRBASE_API SerialUtil +{ +public: + static void getComPorts(std::vector& comPorts, const std::string& regexStr); +}; + +#endif // SDRBASE_UTIL_SERIALUTIL_H_ diff --git a/sdrgui/CMakeLists.txt b/sdrgui/CMakeLists.txt index 21e7b11dd..67c73c393 100644 --- a/sdrgui/CMakeLists.txt +++ b/sdrgui/CMakeLists.txt @@ -176,6 +176,23 @@ set(sdrgui_FORMS soapygui/arginfogui.ui ) +if (LIMERFE_FOUND) + set(sdrgui_SOURCES + ${sdrgui_SOURCES} + limerfegui/limerfeusbdialog.cpp + ) + set(sdrgui_HEADERS + ${sdrgui_HEADERS} + limerfegui/limerfeusbdialog.h + ) + set(sdrgui_FORMS + ${sdrgui_FORMS} + limerfegui/limerfeusbdialog.ui + ) + include_directories(${LIMESUITE_INCLUDE_DIR}) + set(sdrgui_LIMERFE_LIB ${LIMESUITE_LIBRARY}) +endif (LIMERFE_FOUND) + qt5_wrap_ui(sdrgui_FORMS_HEADERS ${sdrgui_FORMS}) include_directories( @@ -199,6 +216,7 @@ target_link_libraries(sdrgui Qt5::OpenGL Qt5::Multimedia ${OPENGL_LIBRARIES} + ${sdrgui_LIMERFE_LIB} sdrbase logging ) diff --git a/sdrgui/limerfegui/limerfeusbdialog.cpp b/sdrgui/limerfegui/limerfeusbdialog.cpp new file mode 100644 index 000000000..b67048ec1 --- /dev/null +++ b/sdrgui/limerfegui/limerfeusbdialog.cpp @@ -0,0 +1,454 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 F4EXB // +// written by Edouard Griffiths // +// // +// 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/serialutil.h" +#include "dsp/dspengine.h" + +#include "limerfeusbdialog.h" +#include "ui_limerfeusbdialog.h" + +LimeRFEUSBDialog::LimeRFEUSBDialog(QWidget* parent) : + QDialog(parent), + ui(new Ui::LimeRFEUSBDialog), + m_rxTxToggle(false) +{ + ui->setupUi(this); + 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) { + ui->device->addItem(QString(it->c_str())); + } + + displaySettings(); // default values +} + +LimeRFEUSBDialog::~LimeRFEUSBDialog() +{ + delete ui; +} + +void LimeRFEUSBDialog::displaySettings() +{ + 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(); +} + +void LimeRFEUSBDialog::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 LimeRFEUSBDialog::setRxChannels() +{ + ui->rxChannel->blockSignals(true); + ui->rxPort->blockSignals(true); + ui->rxChannel->clear(); + ui->rxPort->clear(); + + if (m_settings.m_rxChannels == LimeRFEController::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 == LimeRFEController::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 LimeRFEController::HAM_30M: + case LimeRFEController::HAM_50_70MHz: + case LimeRFEController::HAM_144_146MHz: + case LimeRFEController::HAM_220_225MHz: + case LimeRFEController::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 LimeRFEController::HAM_902_928MHz: + case LimeRFEController::HAM_1240_1325MHz: + case LimeRFEController::HAM_2300_2450MHz: + case LimeRFEController::HAM_3300_3500MHz: + ui->rxPort->addItem("TX/RX (J3)"); + ui->rxPort->setEnabled(false); + m_settings.m_rxPort = LimeRFEController::RxPortJ3; + ui->rxPort->setCurrentIndex((int) m_settings.m_rxPort); + break; + default: + break; + } + } + else if (m_settings.m_rxChannels == LimeRFEController::ChannelsCellular) + { + ui->rxChannel->addItem("Band1"); + ui->rxChannel->addItem("Band2"); + 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 = LimeRFEController::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 LimeRFEUSBDialog::setTxChannels() +{ + ui->txChannel->blockSignals(true); + ui->txPort->blockSignals(true); + ui->txChannel->clear(); + ui->txPort->clear(); + + if (m_settings.m_txChannels == LimeRFEController::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 == LimeRFEController::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 LimeRFEController::HAM_30M: + case LimeRFEController::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 = LimeRFEController::TxPortJ5; + ui->txPort->setCurrentIndex((int) m_settings.m_txPort); + break; + case LimeRFEController::HAM_144_146MHz: + case LimeRFEController::HAM_220_225MHz: + case LimeRFEController::HAM_430_440MHz: + case LimeRFEController::HAM_902_928MHz: + case LimeRFEController::HAM_1240_1325MHz: + case LimeRFEController::HAM_2300_2450MHz: + case LimeRFEController::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 == LimeRFEController::ChannelsCellular) + { + ui->txChannel->addItem("Band1"); + ui->txChannel->addItem("Band2"); + 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 = LimeRFEController::TxPortJ3; + ui->txPort->setEnabled(false); + ui->txPort->setCurrentIndex((int) m_settings.m_txPort); + } + + ui->txChannelGroup->setCurrentIndex((int) m_settings.m_txChannels); + ui->txPort->blockSignals(false); + ui->txChannel->blockSignals(false); +} + +void LimeRFEUSBDialog::on_openDevice_clicked() +{ + int rc = m_controller.openDevice(ui->device->currentText().toStdString()); + ui->statusText->append(QString("Open %1: %2").arg(ui->device->currentText()).arg(m_controller.getError(rc).c_str())); + + if (rc != 0) { + return; + } + + rc = m_controller.getState(); + ui->statusText->append(QString("Get state: %1").arg(m_controller.getError(rc).c_str())); +} + +void LimeRFEUSBDialog::on_closeDevice_clicked() +{ + ui->statusText->clear(); + m_controller.closeDevice(); + ui->statusText->setText("Cloed"); +} + +void LimeRFEUSBDialog::on_deviceToGUI_clicked() +{ + int rc = m_controller.getState(); + + if (rc != 0) + { + ui->statusText->setText(m_controller.getError(rc).c_str()); + return; + } + + m_controller.stateToSettings(m_settings); + displaySettings(); +} + +void LimeRFEUSBDialog::on_rxChannelGroup_currentIndexChanged(int index) +{ + m_settings.m_rxChannels = (LimeRFEController::ChannelGroups) index; + setRxChannels(); + + if (m_settings.m_txRxDriven) + { + m_settings.m_txChannels = m_settings.m_rxChannels; + ui->txChannelGroup->setCurrentIndex((int) m_settings.m_txChannels); + } +} + +void LimeRFEUSBDialog::on_rxChannel_currentIndexChanged(int index) +{ + if (m_settings.m_rxChannels == LimeRFEController::ChannelsWideband) { + m_settings.m_rxWidebandChannel = (LimeRFEController::WidebandChannel) index; + } else if (m_settings.m_rxChannels == LimeRFEController::ChannelsHAM) { + m_settings.m_rxHAMChannel = (LimeRFEController::HAMChannel) index; + } else if (m_settings.m_rxChannels == LimeRFEController::ChannelsCellular) { + m_settings.m_rxCellularChannel = (LimeRFEController::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(); + } +} + +void LimeRFEUSBDialog::on_rxPort_currentIndexChanged(int index) +{ + m_settings.m_rxPort = (LimeRFEController::RxPort) index; +} + +void LimeRFEUSBDialog::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); +} + +void LimeRFEUSBDialog::on_txChannelGroup_currentIndexChanged(int index) +{ + m_settings.m_txChannels = (LimeRFEController::ChannelGroups) index; + setTxChannels(); +} + +void LimeRFEUSBDialog::on_txChannel_currentIndexChanged(int index) +{ + if (m_settings.m_txChannels == LimeRFEController::ChannelsWideband) { + m_settings.m_txWidebandChannel = (LimeRFEController::WidebandChannel) index; + } else if (m_settings.m_txChannels == LimeRFEController::ChannelsHAM) { + m_settings.m_txHAMChannel = (LimeRFEController::HAMChannel) index; + } else if (m_settings.m_txChannels == LimeRFEController::ChannelsCellular) { + m_settings.m_txCellularChannel = (LimeRFEController::CellularChannel) index; + } + + setTxChannels(); +} + +void LimeRFEUSBDialog::on_txPort_currentIndexChanged(int index) +{ + m_settings.m_txPort = (LimeRFEController::TxPort) index; +} + +void LimeRFEUSBDialog::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_controller.setTx(m_settings, false); // stop Tx first + ui->statusText->append(QString("Stop TX: %1").arg(m_controller.getError(rc).c_str())); + } + + rc = m_controller.setRx(m_settings, m_settings.m_rxOn); // Rx on or off + ui->statusText->append(QString("RX: %1").arg(m_controller.getError(rc).c_str())); + + if (!checked) // Rx off + { + rc = m_controller.setTx(m_settings, true); // start Tx next + ui->statusText->append(QString("Start TX: %1").arg(m_controller.getError(rc).c_str())); + } + } + else + { + rc = m_controller.setRx(m_settings, m_settings.m_rxOn); + ui->statusText->setText(m_controller.getError(rc).c_str()); + } + + displayMode(); +} + +void LimeRFEUSBDialog::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_controller.setRx(m_settings, false); // stop Rx first + ui->statusText->append(QString("Stop RX: %1").arg(m_controller.getError(rc).c_str())); + } + + rc = m_controller.setTx(m_settings, m_settings.m_txOn); // Tx on or off + ui->statusText->append(QString("TX: %1").arg(m_controller.getError(rc).c_str())); + + if (!checked) // Tx off + { + rc = m_controller.setRx(m_settings, true); // start Rx next + ui->statusText->append(QString("Start RX: %1").arg(m_controller.getError(rc).c_str())); + } + } + else + { + rc = m_controller.setTx(m_settings, m_settings.m_txOn); + ui->statusText->setText(m_controller.getError(rc).c_str()); + } + + displayMode(); +} + +void LimeRFEUSBDialog::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_controller.setTx(m_settings, m_settings.m_txOn); + ui->statusText->setText(m_controller.getError(rc).c_str()); + displayMode(); + } +} + +void LimeRFEUSBDialog::on_apply_clicked() +{ + ui->statusText->clear(); + m_controller.settingsToState(m_settings); + int rc = m_controller.configure(); + ui->statusText->setText(m_controller.getError(rc).c_str()); +} diff --git a/sdrgui/limerfegui/limerfeusbdialog.h b/sdrgui/limerfegui/limerfeusbdialog.h new file mode 100644 index 000000000..280e0d644 --- /dev/null +++ b/sdrgui/limerfegui/limerfeusbdialog.h @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 F4EXB // +// written by Edouard Griffiths // +// // +// 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 SDRGUI_LIMERFEGUI_LIMERFEUSBDIALOG_H_ +#define SDRGUI_LIMERFEGUI_LIMERFEUSBDIALOG_H_ + +#include + +#include "limerfe/limerfecontroller.h" +#include "export.h" + +namespace Ui { + class LimeRFEUSBDialog; +} + +class SDRGUI_API LimeRFEUSBDialog : public QDialog { + Q_OBJECT + +public: + explicit LimeRFEUSBDialog(QWidget* parent = nullptr); + ~LimeRFEUSBDialog(); + +private: + void displaySettings(); + void displayMode(); + void setRxChannels(); + void setTxChannels(); + + Ui::LimeRFEUSBDialog* ui; + LimeRFEController m_controller; + LimeRFEController::LimeRFESettings m_settings; + bool m_rxTxToggle; + +private slots: + 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_txFollowsRx_clicked(); + void on_txChannelGroup_currentIndexChanged(int index); + void on_txChannel_currentIndexChanged(int index); + void on_txPort_currentIndexChanged(int index); + void on_modeRx_toggled(bool checked); + void on_modeTx_toggled(bool checked); + void on_rxTxToggle_clicked(); + void on_apply_clicked(); +}; + +#endif // SDRGUI_LIMERFEGUI_LIMERFEUSBDIALOG_H_ diff --git a/sdrgui/limerfegui/limerfeusbdialog.ui b/sdrgui/limerfegui/limerfeusbdialog.ui new file mode 100644 index 000000000..abd4482ec --- /dev/null +++ b/sdrgui/limerfegui/limerfeusbdialog.ui @@ -0,0 +1,589 @@ + + + LimeRFEUSBDialog + + + + 0 + 0 + 411 + 436 + + + + LimeRFE USB control + + + + + 310 + 390 + 81 + 32 + + + + Dismiss dialog + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + 10 + 10 + 31 + 31 + + + + Dev + + + + + + 210 + 10 + 51 + 27 + + + + Open device + + + Open + + + + + + 270 + 10 + 51 + 27 + + + + Close Device + + + Close + + + + + + 50 + 10 + 151 + 27 + + + + Device + + + + + + 330 + 10 + 51 + 27 + + + + Transfer data to GUI + + + to GUI + + + + + + 0 + 40 + 401 + 16 + + + + Qt::Horizontal + + + + + + 10 + 50 + 91 + 27 + + + + Rx channel + + + + + + 10 + 80 + 151 + 27 + + + + Rx channel group + + + + Wideband + + + + + HAM + + + + + Cellular + + + + + + + 180 + 80 + 221 + 27 + + + + Rx channel range + + + + + + 10 + 110 + 61 + 27 + + + + Rx port + + + + + + 70 + 110 + 131 + 27 + + + + Rx port + + + + Tx/Rx (J3) + + + + + Tx/Rx HF (J5) + + + + + + + 210 + 110 + 31 + 27 + + + + Att + + + + + + 240 + 110 + 51 + 27 + + + + Rx attenuation + + + + 0 + + + + + 2 + + + + + 4 + + + + + 6 + + + + + 8 + + + + + 10 + + + + + 12 + + + + + 14 + + + + + + + 300 + 110 + 21 + 27 + + + + dB + + + + + + 330 + 110 + 71 + 27 + + + + AM/FM notch filter + + + Notch + + + + + + 0 + 140 + 401 + 16 + + + + Qt::Horizontal + + + + + + 10 + 150 + 91 + 27 + + + + Tx channel + + + + + + 110 + 150 + 111 + 27 + + + + Channel same as Rx + + + Same as Rx + + + + + + 10 + 180 + 151 + 27 + + + + Tx channel group + + + + Wideband + + + + + HAM + + + + + Cellular + + + + + + + 180 + 180 + 221 + 27 + + + + Tx channel range + + + + + + 10 + 210 + 61 + 27 + + + + Tx port + + + + + + 70 + 210 + 131 + 27 + + + + Tx port + + + + Tx/Rx (J3) + + + + + Tx (J4) + + + + + + + 0 + 240 + 401 + 16 + + + + Qt::Horizontal + + + + + + 10 + 280 + 51 + 27 + + + + Switch Rx + + + RX + + + true + + + + + + 70 + 280 + 51 + 27 + + + + Switch Tx + + + TX + + + true + + + + + + 80 + 250 + 111 + 27 + + + + Rx/Tx state + + + None + + + + + + 10 + 250 + 91 + 27 + + + + Mode + + + + + + 10 + 390 + 71 + 27 + + + + Apply changes + + + Apply + + + + + + 10 + 320 + 391 + 61 + + + + Messages + + + + + + 130 + 280 + 71 + 27 + + + + Rx/Tx toggle + + + Toggle + + + + + + + + + buttonBox + accepted() + LimeRFEUSBDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + LimeRFEUSBDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/sdrgui/mainwindow.cpp b/sdrgui/mainwindow.cpp index bd189acb7..29add6fbc 100644 --- a/sdrgui/mainwindow.cpp +++ b/sdrgui/mainwindow.cpp @@ -80,6 +80,10 @@ #include #include +#if defined(HAS_LIMERFE) and not defined(__APPLE__) +#include "limerfegui/limerfeusbdialog.h" +#endif + MESSAGE_CLASS_DEFINITION(MainWindow::MsgLoadPreset, Message) MESSAGE_CLASS_DEFINITION(MainWindow::MsgSavePreset, Message) MESSAGE_CLASS_DEFINITION(MainWindow::MsgDeletePreset, Message) @@ -246,6 +250,9 @@ MainWindow::MainWindow(qtwebapp::LoggerWithFile *logger, const MainParser& parse #ifdef __APPLE__ ui->menuPreferences->removeAction(ui->action_AMBE); #endif +#if not defined(HAS_LIMERFE) or defined(__APPLE__) + ui->menuPreferences->removeAction(ui->action_LimeRFE); +#endif delete splash; @@ -1601,6 +1608,17 @@ void MainWindow::on_action_AMBE_triggered() #endif } +void MainWindow::on_action_LimeRFE_triggered() +{ + qDebug("MainWindow::on_action_LimeRFE_triggered"); +#if defined(HAS_LIMERFE) and not defined(__APPLE__) + qDebug("MainWindow::on_action_LimeRFE_triggered: activated"); + LimeRFEUSBDialog *limeRFEUSBDialog = new LimeRFEUSBDialog(this); + limeRFEUSBDialog->setModal(false); + limeRFEUSBDialog->show(); +#endif +} + void MainWindow::sampleSourceChanged() { // Do it in the currently selected source tab diff --git a/sdrgui/mainwindow.h b/sdrgui/mainwindow.h index 0acaa3a81..e5a84bfe3 100644 --- a/sdrgui/mainwindow.h +++ b/sdrgui/mainwindow.h @@ -393,6 +393,7 @@ private slots: void on_action_Audio_triggered(); void on_action_Logging_triggered(); void on_action_AMBE_triggered(); + void on_action_LimeRFE_triggered(); void on_action_My_Position_triggered(); void on_action_DeviceUserArguments_triggered(); void sampleSourceChanged(); diff --git a/sdrgui/mainwindow.ui b/sdrgui/mainwindow.ui index 5f1ef57eb..99ce82a4b 100644 --- a/sdrgui/mainwindow.ui +++ b/sdrgui/mainwindow.ui @@ -125,8 +125,9 @@ - + + @@ -943,6 +944,11 @@ AMBE + + + LimeRFE + + presetDock channelDock commandsDock