From 2c885b272f96fc2d12e757ea6a91352f0509c4f9 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Sun, 3 Jan 2016 15:39:29 -0500 Subject: [PATCH 1/9] Import hamlib setup from SoapyAudio, prep new RigThread --- CMakeLists.txt | 35 +++++++++++ cmake/Modules/Findhamlib.cmake | 59 ++++++++++++++++++ cmake/Modules/LibFindMacros.cmake | 99 +++++++++++++++++++++++++++++++ src/rig/RigThread.cpp | 80 +++++++++++++++++++++++++ src/rig/RigThread.h | 41 +++++++++++++ 5 files changed, 314 insertions(+) create mode 100644 cmake/Modules/Findhamlib.cmake create mode 100644 cmake/Modules/LibFindMacros.cmake create mode 100644 src/rig/RigThread.cpp create mode 100644 src/rig/RigThread.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ab7f52..06f143e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,25 @@ ENDIF() set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") +option(USE_HAMLIB ON "Support hamlib for radio control functions.") + +if (USE_HAMLIB) + find_package(hamlib REQUIRED) + + if (NOT hamlib_FOUND) + message(FATAL_ERROR "hamlib development files not found...") + endif () + + include_directories(${hamlib_INCLUDE_DIRS}) + if (${hamlib_STATIC_FOUND}) + link_libraries(${hamlib_STATIC_LIBRARIES}) + else() + link_libraries(${hamlib_LIBRARIES}) + endif() + + ADD_DEFINITIONS(-DUSE_HAMLIB) +endif () + macro(configure_files srcDir destDir globStr) message(STATUS "Copying ${srcDir}/${globStr} to directory ${destDir}") make_directory(${destDir}) @@ -433,6 +452,19 @@ IF(ENABLE_LIQUID_EXPERIMENTAL) ENDIF() ENDIF() + +IF (USE_HAMLIB) + SET (cubicsdr_headers + ${cubicsdr_headers} + src/rig/RigThread.h + ) + SET (cubicsdr_sources + ${cubicsdr_sources} + src/rig/RigThread.cpp + ) +ENDIF() + + SET (CUBICSDR_RESOURCES ${PROJECT_SOURCE_DIR}/font/vera_sans_mono12.fnt ${PROJECT_SOURCE_DIR}/font/vera_sans_mono16.fnt @@ -453,6 +485,9 @@ set(REG_EXT "[^/]*([.]cpp|[.]c|[.]h|[.]hpp)$") SOURCE_GROUP("Base" REGULAR_EXPRESSION "src/${REG_EXT}") SOURCE_GROUP("Forms\\SDRDevices" REGULAR_EXPRESSION "src/forms/SDRDevices/${REG_EXT}") SOURCE_GROUP("SDR" REGULAR_EXPRESSION "src/sdr/${REG_EXT}") +IF(USE_HAMLIB) + SOURCE_GROUP("Rig" REGULAR_EXPRESSION "src/rig/${REG_EXT}") +ENDIF() SOURCE_GROUP("Demodulator" REGULAR_EXPRESSION "src/demod/${REG_EXT}") SOURCE_GROUP("Modem" REGULAR_EXPRESSION "src/modules/modem/${REG_EXT}") SOURCE_GROUP("Modem\\Analog" REGULAR_EXPRESSION "src/modules/modem/analog/${REG_EXT}") diff --git a/cmake/Modules/Findhamlib.cmake b/cmake/Modules/Findhamlib.cmake new file mode 100644 index 0000000..abed74b --- /dev/null +++ b/cmake/Modules/Findhamlib.cmake @@ -0,0 +1,59 @@ +# - Try to find hamlib +# Once done, this will define: +# +# hamlib_FOUND - system has Hamlib-2 +# hamlib_INCLUDE_DIRS - the Hamlib-2 include directories +# hamlib_LIBRARIES - link these to use Hamlib-2 +# hamlib_STATIC_FOUND - system has Hamlib-2 static archive +# hamlib_STATIC_LIBRARIES - link these to use Hamlib-2 static archive + +include (LibFindMacros) + +# pkg-config? +find_path (__hamlib_pc_path NAMES hamlib.pc + PATH_SUFFIXES lib/pkgconfig +) +if (__hamlib_pc_path) + set (ENV{PKG_CONFIG_PATH} "${__hamlib_pc_path}" "$ENV{PKG_CONFIG_PATH}") + unset (__hamlib_pc_path CACHE) +endif () + +# Use pkg-config to get hints about paths, libs and, flags +unset (__pkg_config_checked_hamlib CACHE) +libfind_pkg_check_modules (PC_HAMLIB hamlib) + +if (NOT PC_HAMLIB_STATIC_LIBRARIES) + if (WIN32) + set (PC_HAMLIB_STATIC_LIBRARIES hamlib ws2_32) + else () + set (PC_HAMLIB_STATIC_LIBRARIES hamlib m dl usb) + endif () +endif () + +# The libraries +libfind_library (hamlib hamlib) +libfind_library (hamlib_STATIC libhamlib.a) + +find_path (hamlib_INCLUDE_DIR hamlib/rig.h) + +# Set the include dir variables and the libraries and let libfind_process do the rest +set (hamlib_PROCESS_INCLUDES hamlib_INCLUDE_DIR) +set (hamlib_PROCESS_LIBS hamlib_LIBRARY) +libfind_process (hamlib) + +set (hamlib_STATIC_PROCESS_INCLUDES hamlib_STATIC_INCLUDE_DIR) +set (hamlib_STATIC_PROCESS_LIBS hamlib_STATIC_LIBRARY PC_HAMLIB_STATIC_LIBRARIES) +libfind_process (hamlib_STATIC) + +# make sure we return a full path for the library we return +if (hamlib_FOUND) + list (REMOVE_ITEM hamlib_LIBRARIES hamlib) + if (hamlib_STATIC_LIBRARIES) + list (REMOVE_ITEM hamlib_STATIC_LIBRARIES hamlib) + endif () +endif () + +# Handle the QUIETLY and REQUIRED arguments and set HAMLIB_FOUND to +# TRUE if all listed variables are TRUE +include (FindPackageHandleStandardArgs) +find_package_handle_standard_args (hamlib DEFAULT_MSG hamlib_INCLUDE_DIRS hamlib_LIBRARY hamlib_LIBRARIES) diff --git a/cmake/Modules/LibFindMacros.cmake b/cmake/Modules/LibFindMacros.cmake new file mode 100644 index 0000000..69975c5 --- /dev/null +++ b/cmake/Modules/LibFindMacros.cmake @@ -0,0 +1,99 @@ +# Works the same as find_package, but forwards the "REQUIRED" and "QUIET" arguments +# used for the current package. For this to work, the first parameter must be the +# prefix of the current package, then the prefix of the new package etc, which are +# passed to find_package. +macro (libfind_package PREFIX) + set (LIBFIND_PACKAGE_ARGS ${ARGN}) + if (${PREFIX}_FIND_QUIETLY) + set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} QUIET) + endif (${PREFIX}_FIND_QUIETLY) + if (${PREFIX}_FIND_REQUIRED) + set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} REQUIRED) + endif (${PREFIX}_FIND_REQUIRED) + find_package(${LIBFIND_PACKAGE_ARGS}) +endmacro (libfind_package) + +# CMake developers made the UsePkgConfig system deprecated in the same release (2.6) +# where they added pkg_check_modules. Consequently I need to support both in my scripts +# to avoid those deprecated warnings. Here's a helper that does just that. +# Works identically to pkg_check_modules, except that no checks are needed prior to use. +macro (libfind_pkg_check_modules PREFIX PKGNAME) + if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) + include(UsePkgConfig) + pkgconfig(${PKGNAME} ${PREFIX}_INCLUDE_DIRS ${PREFIX}_LIBRARY_DIRS ${PREFIX}_LDFLAGS ${PREFIX}_CFLAGS) + else (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) + find_package(PkgConfig) + if (PKG_CONFIG_FOUND) + pkg_check_modules(${PREFIX} ${PKGNAME}) + endif (PKG_CONFIG_FOUND) + endif (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) +endmacro (libfind_pkg_check_modules) + +# Do the final processing once the paths have been detected. +# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain +# all the variables, each of which contain one include directory. +# Ditto for ${PREFIX}_PROCESS_LIBS and library files. +# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES. +# Also handles errors in case library detection was required, etc. +macro (libfind_process PREFIX) + # Skip processing if already processed during this run + if (NOT ${PREFIX}_FOUND) + # Start with the assumption that the library was found + set (${PREFIX}_FOUND TRUE) + + # Process all includes and set _FOUND to false if any are missing + foreach (i ${${PREFIX}_PROCESS_INCLUDES}) + if (${i}) + set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIRS} ${${i}}) + mark_as_advanced(${i}) + else (${i}) + set (${PREFIX}_FOUND FALSE) + endif (${i}) + endforeach (i) + + # Process all libraries and set _FOUND to false if any are missing + foreach (i ${${PREFIX}_PROCESS_LIBS}) + if (${i}) + set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARIES} ${${i}}) + mark_as_advanced(${i}) + else (${i}) + set (${PREFIX}_FOUND FALSE) + endif (${i}) + endforeach (i) + + # Print message and/or exit on fatal error + if (${PREFIX}_FOUND) + if (NOT ${PREFIX}_FIND_QUIETLY) + message (STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}") + endif (NOT ${PREFIX}_FIND_QUIETLY) + else (${PREFIX}_FOUND) + if (${PREFIX}_FIND_REQUIRED) + foreach (i ${${PREFIX}_PROCESS_INCLUDES} ${${PREFIX}_PROCESS_LIBS}) + message("${i}=${${i}}") + endforeach (i) + message (FATAL_ERROR "Required library ${PREFIX} NOT FOUND.\nInstall the library (dev version) and try again. If the library is already installed, use ccmake to set the missing variables manually.") + endif (${PREFIX}_FIND_REQUIRED) + endif (${PREFIX}_FOUND) + endif (NOT ${PREFIX}_FOUND) +endmacro (libfind_process) + +macro(libfind_library PREFIX basename) + set(TMP "") + if(MSVC80) + set(TMP -vc80) + endif(MSVC80) + if(MSVC90) + set(TMP -vc90) + endif(MSVC90) + set(${PREFIX}_LIBNAMES ${basename}${TMP}) + if(${ARGC} GREATER 2) + set(${PREFIX}_LIBNAMES ${basename}${TMP}-${ARGV2}) + string(REGEX REPLACE "\\." "_" TMP ${${PREFIX}_LIBNAMES}) + set(${PREFIX}_LIBNAMES ${${PREFIX}_LIBNAMES} ${TMP}) + endif(${ARGC} GREATER 2) + find_library(${PREFIX}_LIBRARY + NAMES ${${PREFIX}_LIBNAMES} + PATHS ${${PREFIX}_PKGCONF_LIBRARY_DIRS} + ) +endmacro(libfind_library) + diff --git a/src/rig/RigThread.cpp b/src/rig/RigThread.cpp new file mode 100644 index 0000000..e186363 --- /dev/null +++ b/src/rig/RigThread.cpp @@ -0,0 +1,80 @@ +#include "RigThread.h" + +std::vector RigThread::rigCaps; + +RigThread::RigThread() { + terminated.store(true); +} + +RigThread::~RigThread() { + +} + +void RigThread::enumerate() { + rig_set_debug(RIG_DEBUG_ERR); + rig_load_all_backends(); + RigThread::rigCaps.clear(); + rig_list_foreach(RigThread::add_hamlib_rig, 0); + std::sort(RigThread::rigCaps.begin(), RigThread::rigCaps.end(), rigGreater()); +} + +int RigThread::add_hamlib_rig(const struct rig_caps *rc, void* f) +{ + rigCaps.push_back(rc); + return 1; +} + +void RigThread::initRig(rig_model_t rig_model, std::string rig_file, int serial_rate) { + rigModel = rig_model; + rigFile = rig_file; + serialRate = serial_rate; +}; + +void RigThread::run() { + int retcode, status; + + std::cout << "Rig thread starting." << std::endl; + + rig = rig_init(rigModel); + strncpy(rig->state.rigport.pathname, rigFile.c_str(), FILPATHLEN - 1); + rig->state.rigport.parm.serial.rate = serialRate; + retcode = rig_open(rig); + char *info_buf = (char *)rig_get_info(rig); + std::cout << "Rig info: " << info_buf << std::endl; + + while (!terminated.load()) { + std::this_thread::sleep_for(std::chrono::milliseconds(150)); + if (freqChanged.load()) { + status = rig_get_freq(rig, RIG_VFO_CURR, &freq); + if (freq != newFreq) { + freq = newFreq; + rig_set_freq(rig, RIG_VFO_CURR, freq); + std::cout << "Set Rig Freq: %f" << newFreq << std::endl; + } + + freqChanged.store(false); + } else { + status = rig_get_freq(rig, RIG_VFO_CURR, &freq); + } + + std::cout << "Rig Freq: " << freq << std::endl; + } + + rig_close(rig); + + std::cout << "Rig thread exiting." << std::endl; +}; + +freq_t RigThread::getFrequency() { + if (freqChanged.load()) { + return newFreq; + } else { + return freq; + } +} + +void RigThread::setFrequency(freq_t new_freq) { + newFreq = new_freq; + freqChanged.store(true); +} + diff --git a/src/rig/RigThread.h b/src/rig/RigThread.h new file mode 100644 index 0000000..60c4c85 --- /dev/null +++ b/src/rig/RigThread.h @@ -0,0 +1,41 @@ +#pragma once + +#include "IOThread.h" +#include "CubicSDR.h" +#include +#include + +struct rigGreater +{ + bool operator()( const struct rig_caps *lx, const struct rig_caps *rx ) const { + std::string ln(std::string(std::string(lx->mfg_name) + " " + std::string(lx->model_name))); + std::string rn(std::string(std::string(rx->mfg_name) + " " + std::string(rx->model_name))); + return ln.compare(rn)<0; + } +}; + +class RigThread : public IOThread { +public: + RigThread(); + ~RigThread(); + + void initRig(rig_model_t rig_model, std::string rig_file, int serial_rate); + void run(); + + freq_t getFrequency(); + void setFrequency(freq_t new_freq); + + static void enumerate(); + static int add_hamlib_rig(const struct rig_caps *rc, void* f); + +private: + RIG *rig; + rig_model_t rigModel; + std::string rigFile; + int serialRate; + + freq_t freq; + freq_t newFreq; + std::atomic_bool freqChanged; + static std::vector rigCaps; +}; \ No newline at end of file From 08dc9af1c514ea0a0fa00a29fb9c3eaba851776e Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Sun, 3 Jan 2016 19:00:26 -0500 Subject: [PATCH 2/9] initial hamlib integration and frequency control --- CMakeLists.txt | 1 + src/AppConfig.cpp | 62 ++++++++++++++++++++++ src/AppConfig.h | 15 ++++++ src/AppFrame.cpp | 116 +++++++++++++++++++++++++++++++++++++++++- src/AppFrame.h | 20 ++++++++ src/CubicSDR.cpp | 59 +++++++++++++++++++++ src/CubicSDR.h | 15 ++++++ src/rig/RigThread.cpp | 40 +++++++++++---- src/rig/RigThread.h | 6 ++- 9 files changed, 322 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 06f143e..064d612 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -521,6 +521,7 @@ include_directories ( ${PROJECT_SOURCE_DIR}/src/visual ${PROJECT_SOURCE_DIR}/src/process ${PROJECT_SOURCE_DIR}/src/ui + ${PROJECT_SOURCE_DIR}/src/rig ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/external/rtaudio ${PROJECT_SOURCE_DIR}/external/lodepng diff --git a/src/AppConfig.cpp b/src/AppConfig.cpp index b16cb34..7502071 100644 --- a/src/AppConfig.cpp +++ b/src/AppConfig.cpp @@ -152,6 +152,11 @@ AppConfig::AppConfig() : configName("") { centerFreq.store(100000000); waterfallLinesPerSec.store(DEFAULT_WATERFALL_LPS); spectrumAvgSpeed.store(0.65f); +#ifdef USE_HAMLIB + rigModel.store(1); + rigRate.store(57600); + rigPort = "/dev/ttyUSB0"; +#endif } DeviceConfig *AppConfig::getDevice(std::string deviceId) { @@ -297,6 +302,13 @@ bool AppConfig::save() { DataNode *device_node = devices_node->newChild("device"); device_config_i->second->save(device_node); } + +#ifdef USE_HAMLIB + DataNode *rig_node = cfg.rootNode()->newChild("rig"); + *rig_node->newChild("model") = rigModel.load(); + *rig_node->newChild("rate") = rigRate.load(); + *rig_node->newChild("port") = rigPort; +#endif std::string cfgFileName = getConfigFileName(); @@ -411,6 +423,27 @@ bool AppConfig::load() { } } } + +#ifdef USE_HAMLIB + if (cfg.rootNode()->hasAnother("rig")) { + DataNode *rig_node = cfg.rootNode()->getNext("rig"); + + if (rig_node->hasAnother("model")) { + int loadModel; + rig_node->getNext("model")->element()->get(loadModel); + winMax.store(loadModel?loadModel:1); + } + if (rig_node->hasAnother("rate")) { + int loadRate; + rig_node->getNext("rate")->element()->get(loadRate); + winMax.store(loadRate?loadRate:57600); + } + if (rig_node->hasAnother("port")) { + rigPort = rig_node->getNext("port")->element()->toString(); + } + } +#endif + return true; } @@ -419,3 +452,32 @@ bool AppConfig::reset() { return true; } + + +#if USE_HAMLIB + +int AppConfig::getRigModel() { + return rigModel.load(); +} + +void AppConfig::setRigModel(int rigModel) { + this->rigModel.store(rigModel); +} + +int AppConfig::getRigRate() { + return rigRate.load(); +} + +void AppConfig::setRigRate(int rigRate) { + this->rigRate.store(rigRate); +} + +std::string AppConfig::getRigPort() { + return rigPort; +} + +void AppConfig::setRigPort(std::string rigPort) { + this->rigPort = rigPort; +} + +#endif diff --git a/src/AppConfig.h b/src/AppConfig.h index 4d69489..0306dea 100644 --- a/src/AppConfig.h +++ b/src/AppConfig.h @@ -75,6 +75,17 @@ public: void setSpectrumAvgSpeed(float avgSpeed); float getSpectrumAvgSpeed(); +#if USE_HAMLIB + int getRigModel(); + void setRigModel(int rigModel); + + int getRigRate(); + void setRigRate(int rigRate); + + std::string getRigPort(); + void setRigPort(std::string rigPort); +#endif + void setConfigName(std::string configName); std::string getConfigFileName(bool ignoreName=false); bool save(); @@ -91,4 +102,8 @@ private: std::atomic_llong centerFreq; std::atomic_int waterfallLinesPerSec; std::atomic spectrumAvgSpeed; +#if USE_HAMLIB + std::atomic_int rigModel, rigRate; + std::string rigPort; +#endif }; diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 8366421..9e5f69e 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -38,6 +38,9 @@ EVT_SPLITTER_DCLICK(wxID_ANY, AppFrame::OnDoubleClickSash) EVT_SPLITTER_UNSPLIT(wxID_ANY, AppFrame::OnUnSplit) wxEND_EVENT_TABLE() +#ifdef USE_HAMLIB +#include "RigThread.h" +#endif AppFrame::AppFrame() : wxFrame(NULL, wxID_ANY, CUBICSDR_TITLE), activeDemodulator(NULL) { @@ -409,6 +412,72 @@ AppFrame::AppFrame() : menuBar->Append(menu, wxT("Audio &Sample Rate")); +#ifdef USE_HAMLIB + + rigModel = wxGetApp().getConfig()->getRigModel(); + rigSerialRate = wxGetApp().getConfig()->getRigRate(); + rigPort = wxGetApp().getConfig()->getRigPort(); + + rigMenu = new wxMenu; + + rigEnableMenuItem = rigMenu->AppendCheckItem(wxID_RIG_TOGGLE, wxT("Enable Rig")); + + wxMenu *rigModelMenu = new wxMenu; + RigList &rl = RigThread::enumerate(); + numRigs = rl.size(); + + int modelMenuId = wxID_RIG_MODEL_BASE; + for (RigList::const_iterator ri = rl.begin(); ri != rl.end(); ri++) { + std::string modelString((*ri)->mfg_name); + modelString.append(" "); + modelString.append((*ri)->model_name); + + rigModelMenuItems[(*ri)->rig_model] = rigModelMenu->AppendRadioItem(modelMenuId, modelString, wxT("Description?")); + + if (rigModel == (*ri)->rig_model) { + rigModelMenuItems[(*ri)->rig_model]->Check(); + } + + modelMenuId++; + } + + rigMenu->AppendSubMenu(rigModelMenu, wxT("Model")); + + wxMenu *rigSerialMenu = new wxMenu; + + rigSerialRates.push_back(1200); + rigSerialRates.push_back(2400); + rigSerialRates.push_back(4800); + rigSerialRates.push_back(9600); + rigSerialRates.push_back(19200); + rigSerialRates.push_back(38400); + rigSerialRates.push_back(57600); + rigSerialRates.push_back(115200); + rigSerialRates.push_back(128000); + rigSerialRates.push_back(256000); + + int rateMenuId = wxID_RIG_SERIAL_BASE; + for (std::vector::const_iterator rate_i = rigSerialRates.begin(); rate_i != rigSerialRates.end(); rate_i++) { + std::string rateString; + rateString.append(std::to_string((*rate_i))); + rateString.append(" baud"); + + rigSerialMenuItems[(*rate_i)] = rigSerialMenu->AppendRadioItem(rateMenuId, rateString, wxT("Description?")); + + if (rigSerialRate == (*rate_i)) { + rigSerialMenuItems[(*rate_i)]->Check(); + } + + rateMenuId++; + } + + rigMenu->AppendSubMenu(rigSerialMenu, wxT("Serial Rate")); + + rigPortMenuItem = rigMenu->Append(wxID_RIG_PORT, wxT("Control Port")); + + menuBar->Append(rigMenu, wxT("&Rig Control")); +#endif + SetMenuBar(menuBar); CreateStatusBar(); @@ -820,6 +889,46 @@ void AppFrame::OnMenu(wxCommandEvent& event) { i++; } } + +#ifdef USE_HAMLIB + bool resetRig = false; + if (event.GetId() >= wxID_RIG_MODEL_BASE && event.GetId() < wxID_RIG_MODEL_BASE+numRigs) { + int rigIdx = event.GetId()-wxID_RIG_MODEL_BASE; + RigList &rl = RigThread::enumerate(); + rigModel = rl[rigIdx]->rig_model; + resetRig = true; + } + + if (event.GetId() >= wxID_RIG_SERIAL_BASE && event.GetId() < wxID_RIG_SERIAL_BASE+rigSerialRates.size()) { + int serialIdx = event.GetId()-wxID_RIG_SERIAL_BASE; + rigSerialRate = rigSerialRates[serialIdx]; + resetRig = true; + } + + if (event.GetId() == wxID_RIG_PORT) { + wxString stringVal = wxGetTextFromUser("Rig Serial / COM / Address", "Rig Control Port", rigPort); + std::string rigPortStr = stringVal.ToStdString(); + if (rigPortStr != "") { + rigPort = rigPortStr; + resetRig = true; + } + } + + if (event.GetId() == wxID_RIG_TOGGLE) { + resetRig = false; + if (!wxGetApp().rigIsActive()) { + wxGetApp().stopRig(); + wxGetApp().initRig(rigModel, rigPort, rigSerialRate); + } else { + wxGetApp().stopRig(); + } + } + + if (wxGetApp().rigIsActive() && resetRig) { + wxGetApp().stopRig(); + wxGetApp().initRig(rigModel, rigPort, rigSerialRate); + } +#endif } @@ -837,6 +946,11 @@ void AppFrame::OnClose(wxCloseEvent& event) { wxGetApp().getConfig()->setCenterFreq(wxGetApp().getFrequency()); wxGetApp().getConfig()->setSpectrumAvgSpeed(wxGetApp().getSpectrumProcessor()->getFFTAverageRate()); wxGetApp().getConfig()->setWaterfallLinesPerSec(waterfallDataThread->getLinesPerSecond()); +#ifdef USE_HAMLIB + wxGetApp().getConfig()->setRigModel(rigModel); + wxGetApp().getConfig()->setRigRate(rigSerialRate); + wxGetApp().getConfig()->setRigPort(rigPort); +#endif wxGetApp().getConfig()->save(); event.Skip(); } @@ -1116,7 +1230,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) { if (!this->IsActive()) { std::this_thread::sleep_for(std::chrono::milliseconds(25)); } - + event.RequestMore(); } diff --git a/src/AppFrame.h b/src/AppFrame.h index 5d8f4ad..6076c1e 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -53,6 +53,13 @@ #define wxID_AUDIO_BANDWIDTH_BASE 9000 #define wxID_AUDIO_DEVICE_MULTIPLIER 50 +#ifdef USE_HAMLIB +#define wxID_RIG_TOGGLE 11900 +#define wxID_RIG_PORT 11901 +#define wxID_RIG_SERIAL_BASE 11950 +#define wxID_RIG_MODEL_BASE 12000 +#endif + // Define a new frame type class AppFrame: public wxFrame { public: @@ -129,5 +136,18 @@ private: std::atomic_bool modemPropertiesUpdated; ModemArgInfoList newModemArgs; +#ifdef USE_HAMLIB + wxMenu *rigMenu; + wxMenuItem *rigEnableMenuItem; + wxMenuItem *rigPortMenuItem; + std::map rigSerialMenuItems; + std::map rigModelMenuItems; + int rigModel; + int rigSerialRate; + std::vector rigSerialRates; + std::string rigPort; + int numRigs; +#endif + wxDECLARE_EVENT_TABLE(); }; diff --git a/src/CubicSDR.cpp b/src/CubicSDR.cpp index ba56b2f..2555e9a 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -18,6 +18,10 @@ #include "CoreFoundation/CoreFoundation.h" #endif +#ifdef USE_HAMLIB +#include "RigThread.h" +#endif + IMPLEMENT_APP(CubicSDR) //#ifdef ENABLE_DIGITAL_LAB @@ -164,6 +168,13 @@ bool CubicSDR::OnInit() { wxApp::SetAppName("CubicSDR"); +#ifdef USE_HAMLIB + t_Rig = nullptr; + rigThread = nullptr; + + RigThread::enumerate(); +#endif + Modem::addModemFactory(new ModemFM); Modem::addModemFactory(new ModemFMStereo); Modem::addModemFactory(new ModemAM); @@ -712,3 +723,51 @@ bool CubicSDR::getUseLocalMod() { std::string CubicSDR::getModulePath() { return modulePath; } + +#ifdef USE_HAMLIB +RigThread *CubicSDR::getRigThread() { + return rigThread; +} + +void CubicSDR::initRig(int rigModel, std::string rigPort, int rigSerialRate) { + if (rigThread) { + if (!rigThread->isTerminated()) { + rigThread->terminate(); + } + delete rigThread; + rigThread = nullptr; + } + if (t_Rig && t_Rig->joinable()) { + t_Rig->join(); + delete t_Rig; + t_Rig = nullptr; + } + rigThread = new RigThread(); + rigThread->initRig(rigModel, rigPort, rigSerialRate); + t_Rig = new std::thread(&RigThread::threadMain, rigThread); +} + +void CubicSDR::stopRig() { + if (!rigThread) { + return; + } + + if (rigThread) { + if (!rigThread->isTerminated()) { + rigThread->terminate(); + } + delete rigThread; + rigThread = nullptr; + } + if (t_Rig && t_Rig->joinable()) { + t_Rig->join(); + delete t_Rig; + t_Rig = nullptr; + } +} + +bool CubicSDR::rigIsActive() { + return (rigThread && !rigThread->isTerminated()); +} + +#endif \ No newline at end of file diff --git a/src/CubicSDR.h b/src/CubicSDR.h index 5895f6b..e188ff7 100644 --- a/src/CubicSDR.h +++ b/src/CubicSDR.h @@ -54,6 +54,10 @@ #include "ModemST.h" #endif +#ifdef USE_HAMLIB +class RigThread; +#endif + #include #define NUM_DEMODULATORS 1 @@ -142,6 +146,13 @@ public: bool getUseLocalMod(); std::string getModulePath(); +#ifdef USE_HAMLIB + RigThread *getRigThread(); + void initRig(int rigModel, std::string rigPort, int rigSerialRate); + void stopRig(); + bool rigIsActive(); +#endif + private: AppFrame *appframe; AppConfig config; @@ -184,6 +195,10 @@ private: std::string notifyMessage; std::string modulePath; std::mutex notify_busy; +#ifdef USE_HAMLIB + RigThread *rigThread; + std::thread *t_Rig; +#endif }; #ifdef BUNDLE_SOAPY_MODS diff --git a/src/rig/RigThread.cpp b/src/rig/RigThread.cpp index e186363..971da1f 100644 --- a/src/rig/RigThread.cpp +++ b/src/rig/RigThread.cpp @@ -4,18 +4,23 @@ std::vector RigThread::rigCaps; RigThread::RigThread() { terminated.store(true); + freq = wxGetApp().getFrequency(); } RigThread::~RigThread() { } -void RigThread::enumerate() { - rig_set_debug(RIG_DEBUG_ERR); - rig_load_all_backends(); - RigThread::rigCaps.clear(); - rig_list_foreach(RigThread::add_hamlib_rig, 0); - std::sort(RigThread::rigCaps.begin(), RigThread::rigCaps.end(), rigGreater()); +RigList &RigThread::enumerate() { + if (RigThread::rigCaps.empty()) { + rig_set_debug(RIG_DEBUG_ERR); + rig_load_all_backends(); + + rig_list_foreach(RigThread::add_hamlib_rig, 0); + std::sort(RigThread::rigCaps.begin(), RigThread::rigCaps.end(), rigGreater()); + std::cout << "Loaded " << RigThread::rigCaps.size() << " rig models via hamlib." << std::endl; + } + return RigThread::rigCaps; } int RigThread::add_hamlib_rig(const struct rig_caps *rc, void* f) @@ -39,6 +44,13 @@ void RigThread::run() { strncpy(rig->state.rigport.pathname, rigFile.c_str(), FILPATHLEN - 1); rig->state.rigport.parm.serial.rate = serialRate; retcode = rig_open(rig); + + if (retcode != 0) { + std::cout << "Rig failed to init. " << std::endl; + terminated.store(true); + return; + } + char *info_buf = (char *)rig_get_info(rig); std::cout << "Rig info: " << info_buf << std::endl; @@ -49,15 +61,25 @@ void RigThread::run() { if (freq != newFreq) { freq = newFreq; rig_set_freq(rig, RIG_VFO_CURR, freq); - std::cout << "Set Rig Freq: %f" << newFreq << std::endl; +// std::cout << "Set Rig Freq: %f" << newFreq << std::endl; } freqChanged.store(false); } else { - status = rig_get_freq(rig, RIG_VFO_CURR, &freq); + freq_t checkFreq; + + status = rig_get_freq(rig, RIG_VFO_CURR, &checkFreq); + + if (checkFreq != freq) { + freq = checkFreq; + wxGetApp().setFrequency((long long)checkFreq); + } else if (wxGetApp().getFrequency() != freq) { + freq = wxGetApp().getFrequency(); + rig_set_freq(rig, RIG_VFO_CURR, freq); + } } - std::cout << "Rig Freq: " << freq << std::endl; +// std::cout << "Rig Freq: " << freq << std::endl; } rig_close(rig); diff --git a/src/rig/RigThread.h b/src/rig/RigThread.h index 60c4c85..9d6d80d 100644 --- a/src/rig/RigThread.h +++ b/src/rig/RigThread.h @@ -14,6 +14,8 @@ struct rigGreater } }; +typedef std::vector RigList; + class RigThread : public IOThread { public: RigThread(); @@ -25,7 +27,7 @@ public: freq_t getFrequency(); void setFrequency(freq_t new_freq); - static void enumerate(); + static RigList &enumerate(); static int add_hamlib_rig(const struct rig_caps *rc, void* f); private: @@ -37,5 +39,5 @@ private: freq_t freq; freq_t newFreq; std::atomic_bool freqChanged; - static std::vector rigCaps; + static RigList rigCaps; }; \ No newline at end of file From 947641bbea4b869833ba269c3105c5123f0b1ed0 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Sun, 3 Jan 2016 23:52:53 -0500 Subject: [PATCH 3/9] Missing rig_cleanup --- src/rig/RigThread.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rig/RigThread.cpp b/src/rig/RigThread.cpp index 971da1f..aa0bd7c 100644 --- a/src/rig/RigThread.cpp +++ b/src/rig/RigThread.cpp @@ -83,6 +83,7 @@ void RigThread::run() { } rig_close(rig); + rig_cleanup(rig); std::cout << "Rig thread exiting." << std::endl; }; From 1b4b11f20f2914846b1fd0cdb0f2f2a08f5ca39a Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Mon, 4 Jan 2016 22:21:33 -0500 Subject: [PATCH 4/9] Version bump. --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 064d612..b8a5ab0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,8 +2,8 @@ cmake_minimum_required (VERSION 2.8) SET(CUBICSDR_VERSION_MAJOR "0") SET(CUBICSDR_VERSION_MINOR "1") -SET(CUBICSDR_VERSION_PATCH "20") -SET(CUBICSDR_VERSION_REL "alpha") +SET(CUBICSDR_VERSION_PATCH "21") +SET(CUBICSDR_VERSION_REL "alpha-rig_control") SET(CUBICSDR_VERSION "${CUBICSDR_VERSION_MAJOR}.${CUBICSDR_VERSION_MINOR}.${CUBICSDR_VERSION_PATCH}-${CUBICSDR_VERSION_REL}") SET(CPACK_PACKAGE_VERSION "${CUBICSDR_VERSION_MAJOR}.${CUBICSDR_VERSION_MINOR}.${CUBICSDR_VERSION_PATCH}") From 0aa7b572b504465862cc1428b724943baebfe9e8 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Mon, 4 Jan 2016 22:50:21 -0500 Subject: [PATCH 5/9] Update Findhamlib.cmake with one from George L. Emigh - AB4BD, fix CMakeLists.txt project order --- CMakeLists.txt | 19 +++--- cmake/Modules/Findhamlib.cmake | 104 +++++++++++++++--------------- cmake/Modules/LibFindMacros.cmake | 99 ---------------------------- 3 files changed, 60 insertions(+), 162 deletions(-) delete mode 100644 cmake/Modules/LibFindMacros.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 064d612..683a643 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,9 @@ cmake_minimum_required (VERSION 2.8) +project (CubicSDR) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/") + SET(CUBICSDR_VERSION_MAJOR "0") SET(CUBICSDR_VERSION_MINOR "1") SET(CUBICSDR_VERSION_PATCH "20") @@ -34,23 +38,18 @@ ADD_DEFINITIONS( ENDIF() ENDIF() -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") -option(USE_HAMLIB ON "Support hamlib for radio control functions.") +set(USE_HAMLIB ON CACHE BOOL "Support hamlib for radio control functions.") if (USE_HAMLIB) find_package(hamlib REQUIRED) - if (NOT hamlib_FOUND) + if (NOT HAMLIB_FOUND) message(FATAL_ERROR "hamlib development files not found...") endif () - include_directories(${hamlib_INCLUDE_DIRS}) - if (${hamlib_STATIC_FOUND}) - link_libraries(${hamlib_STATIC_LIBRARIES}) - else() - link_libraries(${hamlib_LIBRARIES}) - endif() + include_directories(${HAMLIB_INCLUDE_DIR}) + link_libraries(${HAMLIB_LIBRARY}) ADD_DEFINITIONS(-DUSE_HAMLIB) endif () @@ -89,8 +88,6 @@ macro(configure_files_recurse srcDir destDir) endforeach(templateFile) endmacro(configure_files_recurse) -project (CubicSDR) - if( CMAKE_SIZEOF_VOID_P EQUAL 8 ) MESSAGE( "64 bit compiler detected" ) SET( EX_PLATFORM 64 ) diff --git a/cmake/Modules/Findhamlib.cmake b/cmake/Modules/Findhamlib.cmake index abed74b..ea8d6ea 100644 --- a/cmake/Modules/Findhamlib.cmake +++ b/cmake/Modules/Findhamlib.cmake @@ -1,59 +1,59 @@ -# - Try to find hamlib -# Once done, this will define: +# - Try to find Hamlib +# Author: George L. Emigh - AB4BD +# +# Change Log: Charles J. Cliffe +# Updates: +# Jan 2015 - Add /opt/ paths for OSX MacPorts +# TODO: +# Windows support +# Static support # -# hamlib_FOUND - system has Hamlib-2 -# hamlib_INCLUDE_DIRS - the Hamlib-2 include directories -# hamlib_LIBRARIES - link these to use Hamlib-2 -# hamlib_STATIC_FOUND - system has Hamlib-2 static archive -# hamlib_STATIC_LIBRARIES - link these to use Hamlib-2 static archive +# HAMLIB_FOUND - system has Hamlib +# HAMLIB_LIBRARY - location of the library for hamlib +# HAMLIB_INCLUDE_DIR - location of the include files for hamlib -include (LibFindMacros) +set(HAMLIB_FOUND FALSE) -# pkg-config? -find_path (__hamlib_pc_path NAMES hamlib.pc - PATH_SUFFIXES lib/pkgconfig +find_path(HAMLIB_INCLUDE_DIR + NAMES rig.h + PATHS + /usr/include/hamlib + /usr/include + /usr/local/include/hamlib + /usr/local/include + /opt/local/include/hamlib + /opt/local/include + /opt/local/include/hamlib ) -if (__hamlib_pc_path) - set (ENV{PKG_CONFIG_PATH} "${__hamlib_pc_path}" "$ENV{PKG_CONFIG_PATH}") - unset (__hamlib_pc_path CACHE) -endif () -# Use pkg-config to get hints about paths, libs and, flags -unset (__pkg_config_checked_hamlib CACHE) -libfind_pkg_check_modules (PC_HAMLIB hamlib) +find_library(HAMLIB_LIBRARY + NAMES hamlib + PATHS + /usr/lib64/hamlib + /usr/lib/hamlib + /usr/lib64 + /usr/lib + /usr/local/lib64/hamlib + /usr/local/lib/hamlib + /usr/local/lib64 + /usr/local/lib + /opt/local/lib + /opt/local/lib/hamlib +) -if (NOT PC_HAMLIB_STATIC_LIBRARIES) - if (WIN32) - set (PC_HAMLIB_STATIC_LIBRARIES hamlib ws2_32) - else () - set (PC_HAMLIB_STATIC_LIBRARIES hamlib m dl usb) - endif () -endif () +if(HAMLIB_INCLUDE_DIR AND HAMLIB_LIBRARY) + set(HAMLIB_FOUND TRUE) + message(STATUS "Hamlib version: ${VERSION}") + message(STATUS "Found hamlib library directory at: ${HAMLIB_LIBRARY}") + message(STATUS "Found hamlib include directory at: ${HAMLIB_INCLUDE_DIR}") +endif(HAMLIB_INCLUDE_DIR AND HAMLIB_LIBRARY) -# The libraries -libfind_library (hamlib hamlib) -libfind_library (hamlib_STATIC libhamlib.a) - -find_path (hamlib_INCLUDE_DIR hamlib/rig.h) - -# Set the include dir variables and the libraries and let libfind_process do the rest -set (hamlib_PROCESS_INCLUDES hamlib_INCLUDE_DIR) -set (hamlib_PROCESS_LIBS hamlib_LIBRARY) -libfind_process (hamlib) - -set (hamlib_STATIC_PROCESS_INCLUDES hamlib_STATIC_INCLUDE_DIR) -set (hamlib_STATIC_PROCESS_LIBS hamlib_STATIC_LIBRARY PC_HAMLIB_STATIC_LIBRARIES) -libfind_process (hamlib_STATIC) - -# make sure we return a full path for the library we return -if (hamlib_FOUND) - list (REMOVE_ITEM hamlib_LIBRARIES hamlib) - if (hamlib_STATIC_LIBRARIES) - list (REMOVE_ITEM hamlib_STATIC_LIBRARIES hamlib) - endif () -endif () - -# Handle the QUIETLY and REQUIRED arguments and set HAMLIB_FOUND to -# TRUE if all listed variables are TRUE -include (FindPackageHandleStandardArgs) -find_package_handle_standard_args (hamlib DEFAULT_MSG hamlib_INCLUDE_DIRS hamlib_LIBRARY hamlib_LIBRARIES) +IF(NOT HAMLIB_FOUND) + IF(NOT HAMLIB_FIND_QUIETLY) + MESSAGE(STATUS "HAMLIB was not found.") + ELSE(NOT HAMLIB_FIND_QUIETLY) + IF(HAMLIB_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "HAMLIB was not found.") + ENDIF(HAMLIB_FIND_REQUIRED) + ENDIF(NOT HAMLIB_FIND_QUIETLY) +ENDIF(NOT HAMLIB_FOUND) \ No newline at end of file diff --git a/cmake/Modules/LibFindMacros.cmake b/cmake/Modules/LibFindMacros.cmake deleted file mode 100644 index 69975c5..0000000 --- a/cmake/Modules/LibFindMacros.cmake +++ /dev/null @@ -1,99 +0,0 @@ -# Works the same as find_package, but forwards the "REQUIRED" and "QUIET" arguments -# used for the current package. For this to work, the first parameter must be the -# prefix of the current package, then the prefix of the new package etc, which are -# passed to find_package. -macro (libfind_package PREFIX) - set (LIBFIND_PACKAGE_ARGS ${ARGN}) - if (${PREFIX}_FIND_QUIETLY) - set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} QUIET) - endif (${PREFIX}_FIND_QUIETLY) - if (${PREFIX}_FIND_REQUIRED) - set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} REQUIRED) - endif (${PREFIX}_FIND_REQUIRED) - find_package(${LIBFIND_PACKAGE_ARGS}) -endmacro (libfind_package) - -# CMake developers made the UsePkgConfig system deprecated in the same release (2.6) -# where they added pkg_check_modules. Consequently I need to support both in my scripts -# to avoid those deprecated warnings. Here's a helper that does just that. -# Works identically to pkg_check_modules, except that no checks are needed prior to use. -macro (libfind_pkg_check_modules PREFIX PKGNAME) - if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) - include(UsePkgConfig) - pkgconfig(${PKGNAME} ${PREFIX}_INCLUDE_DIRS ${PREFIX}_LIBRARY_DIRS ${PREFIX}_LDFLAGS ${PREFIX}_CFLAGS) - else (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) - find_package(PkgConfig) - if (PKG_CONFIG_FOUND) - pkg_check_modules(${PREFIX} ${PKGNAME}) - endif (PKG_CONFIG_FOUND) - endif (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) -endmacro (libfind_pkg_check_modules) - -# Do the final processing once the paths have been detected. -# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain -# all the variables, each of which contain one include directory. -# Ditto for ${PREFIX}_PROCESS_LIBS and library files. -# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES. -# Also handles errors in case library detection was required, etc. -macro (libfind_process PREFIX) - # Skip processing if already processed during this run - if (NOT ${PREFIX}_FOUND) - # Start with the assumption that the library was found - set (${PREFIX}_FOUND TRUE) - - # Process all includes and set _FOUND to false if any are missing - foreach (i ${${PREFIX}_PROCESS_INCLUDES}) - if (${i}) - set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIRS} ${${i}}) - mark_as_advanced(${i}) - else (${i}) - set (${PREFIX}_FOUND FALSE) - endif (${i}) - endforeach (i) - - # Process all libraries and set _FOUND to false if any are missing - foreach (i ${${PREFIX}_PROCESS_LIBS}) - if (${i}) - set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARIES} ${${i}}) - mark_as_advanced(${i}) - else (${i}) - set (${PREFIX}_FOUND FALSE) - endif (${i}) - endforeach (i) - - # Print message and/or exit on fatal error - if (${PREFIX}_FOUND) - if (NOT ${PREFIX}_FIND_QUIETLY) - message (STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}") - endif (NOT ${PREFIX}_FIND_QUIETLY) - else (${PREFIX}_FOUND) - if (${PREFIX}_FIND_REQUIRED) - foreach (i ${${PREFIX}_PROCESS_INCLUDES} ${${PREFIX}_PROCESS_LIBS}) - message("${i}=${${i}}") - endforeach (i) - message (FATAL_ERROR "Required library ${PREFIX} NOT FOUND.\nInstall the library (dev version) and try again. If the library is already installed, use ccmake to set the missing variables manually.") - endif (${PREFIX}_FIND_REQUIRED) - endif (${PREFIX}_FOUND) - endif (NOT ${PREFIX}_FOUND) -endmacro (libfind_process) - -macro(libfind_library PREFIX basename) - set(TMP "") - if(MSVC80) - set(TMP -vc80) - endif(MSVC80) - if(MSVC90) - set(TMP -vc90) - endif(MSVC90) - set(${PREFIX}_LIBNAMES ${basename}${TMP}) - if(${ARGC} GREATER 2) - set(${PREFIX}_LIBNAMES ${basename}${TMP}-${ARGV2}) - string(REGEX REPLACE "\\." "_" TMP ${${PREFIX}_LIBNAMES}) - set(${PREFIX}_LIBNAMES ${${PREFIX}_LIBNAMES} ${TMP}) - endif(${ARGC} GREATER 2) - find_library(${PREFIX}_LIBRARY - NAMES ${${PREFIX}_LIBNAMES} - PATHS ${${PREFIX}_PKGCONF_LIBRARY_DIRS} - ) -endmacro(libfind_library) - From 6471287045edb3d2a478faaab2c6b1a948384bb3 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Tue, 5 Jan 2016 00:46:03 -0500 Subject: [PATCH 6/9] Findhamlib.cmake tweaks --- cmake/Modules/Findhamlib.cmake | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/cmake/Modules/Findhamlib.cmake b/cmake/Modules/Findhamlib.cmake index ea8d6ea..543643f 100644 --- a/cmake/Modules/Findhamlib.cmake +++ b/cmake/Modules/Findhamlib.cmake @@ -4,6 +4,7 @@ # Change Log: Charles J. Cliffe # Updates: # Jan 2015 - Add /opt/ paths for OSX MacPorts +# - Fix HAMLIB_INCLUDE_DIR absolute search # TODO: # Windows support # Static support @@ -15,15 +16,11 @@ set(HAMLIB_FOUND FALSE) find_path(HAMLIB_INCLUDE_DIR - NAMES rig.h + NAMES hamlib/rig.h PATHS - /usr/include/hamlib /usr/include - /usr/local/include/hamlib /usr/local/include - /opt/local/include/hamlib /opt/local/include - /opt/local/include/hamlib ) find_library(HAMLIB_LIBRARY @@ -43,7 +40,7 @@ find_library(HAMLIB_LIBRARY if(HAMLIB_INCLUDE_DIR AND HAMLIB_LIBRARY) set(HAMLIB_FOUND TRUE) - message(STATUS "Hamlib version: ${VERSION}") + # message(STATUS "Hamlib version: ${VERSION}") message(STATUS "Found hamlib library directory at: ${HAMLIB_LIBRARY}") message(STATUS "Found hamlib include directory at: ${HAMLIB_INCLUDE_DIR}") endif(HAMLIB_INCLUDE_DIR AND HAMLIB_LIBRARY) From 1699c50676485417da65bcd4c0814e8ddeeb58e0 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Thu, 7 Jan 2016 00:35:02 -0500 Subject: [PATCH 7/9] Internal frequency locking support --- src/CubicSDR.cpp | 19 +++++++++++++++++++ src/CubicSDR.h | 6 ++++++ src/sdr/SoapySDRThread.cpp | 27 ++++++++++++++++++++++++++- src/sdr/SoapySDRThread.h | 8 ++++++-- 4 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/CubicSDR.cpp b/src/CubicSDR.cpp index 2555e9a..c97638b 100644 --- a/src/CubicSDR.cpp +++ b/src/CubicSDR.cpp @@ -449,6 +449,25 @@ long long CubicSDR::getFrequency() { return frequency; } + +void CubicSDR::lockFrequency(long long freq) { + frequency_locked.store(true); + lock_freq.store(freq); + + if (sdrThread && !sdrThread->isTerminated()) { + sdrThread->lockFrequency(freq); + } +} + +bool CubicSDR::isFrequencyLocked() { + return frequency_locked.load(); +} + +void CubicSDR::unlockFrequency() { + frequency_locked.store(false); + sdrThread->unlockFrequency(); +} + void CubicSDR::setSampleRate(long long rate_in) { sampleRate = rate_in; sdrThread->setSampleRate(sampleRate); diff --git a/src/CubicSDR.h b/src/CubicSDR.h index e188ff7..abace68 100644 --- a/src/CubicSDR.h +++ b/src/CubicSDR.h @@ -84,6 +84,10 @@ public: void setFrequency(long long freq); long long getFrequency(); + + void lockFrequency(long long freq); + bool isFrequencyLocked(); + void unlockFrequency(); void setOffset(long long ofs); long long getOffset(); @@ -195,6 +199,8 @@ private: std::string notifyMessage; std::string modulePath; std::mutex notify_busy; + std::atomic_bool frequency_locked; + std::atomic_llong lock_freq; #ifdef USE_HAMLIB RigThread *rigThread; std::thread *t_Rig; diff --git a/src/sdr/SoapySDRThread.cpp b/src/sdr/SoapySDRThread.cpp index 08410ca..3e8ad32 100644 --- a/src/sdr/SoapySDRThread.cpp +++ b/src/sdr/SoapySDRThread.cpp @@ -33,6 +33,9 @@ SDRThread::SDRThread() : IOThread(), buffers("SDRThreadBuffers") { agc_mode_changed.store(false); gain_value_changed.store(false); setting_value_changed.store(false); + frequency_lock_init.store(false); + frequency_locked.store(false); + lock_freq.store(0); } SDRThread::~SDRThread() { @@ -241,7 +244,12 @@ void SDRThread::updateSettings() { } if (freq_changed.load()) { - device->setFrequency(SOAPY_SDR_RX,0,"RF",frequency.load() - offset.load()); + if (frequency_locked.load() && !frequency_lock_init.load()) { + device->setFrequency(SOAPY_SDR_RX,0,"RF",lock_freq.load()); + frequency_lock_init.store(true); + } else if (!frequency_locked.load()) { + device->setFrequency(SOAPY_SDR_RX,0,"RF",frequency.load() - offset.load()); + } freq_changed.store(false); } @@ -372,6 +380,23 @@ long long SDRThread::getFrequency() { return frequency.load(); } +void SDRThread::lockFrequency(long long freq) { + lock_freq.store(freq); + frequency_locked.store(true); + frequency_lock_init.store(false); + setFrequency(freq); +} + +bool SDRThread::isFrequencyLocked() { + return frequency_locked.load(); +} + +void SDRThread::unlockFrequency() { + frequency_locked.store(false); + frequency_lock_init.store(false); + freq_changed.store(true); +} + void SDRThread::setOffset(long long ofs) { offset.store(ofs); offset_changed.store(true); diff --git a/src/sdr/SoapySDRThread.h b/src/sdr/SoapySDRThread.h index 4c21103..978920e 100644 --- a/src/sdr/SoapySDRThread.h +++ b/src/sdr/SoapySDRThread.h @@ -60,6 +60,10 @@ public: void setFrequency(long long freq); long long getFrequency(); + void lockFrequency(long long freq); + bool isFrequencyLocked(); + void unlockFrequency(); + void setOffset(long long ofs); long long getOffset(); @@ -98,11 +102,11 @@ protected: std::map settingChanged; std::atomic sampleRate; - std::atomic_llong frequency, offset; + std::atomic_llong frequency, offset, lock_freq; std::atomic_int ppm, numElems, numChannels; std::atomic_bool hasPPM, hasHardwareDC; std::atomic_bool agc_mode, rate_changed, freq_changed, offset_changed, - ppm_changed, device_changed, agc_mode_changed, gain_value_changed, setting_value_changed; + ppm_changed, device_changed, agc_mode_changed, gain_value_changed, setting_value_changed, frequency_locked, frequency_lock_init; std::mutex gain_busy; std::map gainValues; From 936a6403286dff5a0f420e03b91a96e7e682647d Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Sat, 9 Jan 2016 00:09:46 -0500 Subject: [PATCH 8/9] Per-Rig-Per-SDR IF frequency lock control and save/load --- src/AppConfig.cpp | 31 +++++++++++++++++++++ src/AppConfig.h | 4 +++ src/AppFrame.cpp | 71 +++++++++++++++++++++++++++++++++++++++++++---- src/AppFrame.h | 3 ++ 4 files changed, 104 insertions(+), 5 deletions(-) diff --git a/src/AppConfig.cpp b/src/AppConfig.cpp index 7502071..264d6ed 100644 --- a/src/AppConfig.cpp +++ b/src/AppConfig.cpp @@ -55,6 +55,12 @@ void DeviceConfig::save(DataNode *node) { for (ConfigSettings::const_iterator set_i = settings.begin(); set_i != settings.end(); set_i++) { *settingsNode->newChild(set_i->first.c_str()) = set_i->second; } + DataNode *rigIFs = node->newChild("rig_ifs"); + for (std::map::const_iterator rigIF_i = rigIF.begin(); rigIF_i != rigIF.end(); rigIF_i++) { + DataNode *ifNode = rigIFs->newChild("rig_if"); + *ifNode->newChild("model") = rigIF_i->first; + *ifNode->newChild("sdr_if") = rigIF_i->second; + } busy_lock.unlock(); } @@ -98,6 +104,21 @@ void DeviceConfig::load(DataNode *node) { } } } + if (node->hasAnother("rig_ifs")) { + DataNode *rigIFNodes = node->getNext("rig_ifs"); + while (rigIFNodes->hasAnother("rig_if")) { + DataNode *rigIFNode = rigIFNodes->getNext("rig_if"); + if (rigIFNode->hasAnother("model") && rigIFNode->hasAnother("sdr_if")) { + int load_model; + long long load_freq; + + rigIFNode->getNext("model")->element()->get(load_model); + rigIFNode->getNext("sdr_if")->element()->get(load_freq); + + rigIF[load_model] = load_freq; + } + } + } busy_lock.unlock(); } @@ -140,6 +161,16 @@ ConfigSettings DeviceConfig::getSettings() { return settings; } +void DeviceConfig::setRigIF(int rigType, long long freq) { + rigIF[rigType] = freq; +} + +long long DeviceConfig::getRigIF(int rigType) { + if (rigIF.find(rigType) != rigIF.end()) { + return rigIF[rigType]; + } + return 0; +} AppConfig::AppConfig() : configName("") { winX.store(0); diff --git a/src/AppConfig.h b/src/AppConfig.h index 0306dea..b7e7f7c 100644 --- a/src/AppConfig.h +++ b/src/AppConfig.h @@ -35,6 +35,9 @@ public: void setSetting(std::string key, std::string value); std::string getSetting(std::string key, std::string defaultValue); + void setRigIF(int rigType, long long freq); + long long getRigIF(int rigType); + void save(DataNode *node); void load(DataNode *node); @@ -46,6 +49,7 @@ private: std::atomic_llong offset; ConfigSettings streamOpts; std::map settings; + std::map rigIF; }; class AppConfig { diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 9e5f69e..e2e78ae 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -417,11 +417,13 @@ AppFrame::AppFrame() : rigModel = wxGetApp().getConfig()->getRigModel(); rigSerialRate = wxGetApp().getConfig()->getRigRate(); rigPort = wxGetApp().getConfig()->getRigPort(); - + rigMenu = new wxMenu; rigEnableMenuItem = rigMenu->AppendCheckItem(wxID_RIG_TOGGLE, wxT("Enable Rig")); + rigMenu->Append(wxID_RIG_SDR_IF, wxT("SDR-IF")); + wxMenu *rigModelMenu = new wxMenu; RigList &rl = RigThread::enumerate(); numRigs = rl.size(); @@ -435,7 +437,7 @@ AppFrame::AppFrame() : rigModelMenuItems[(*ri)->rig_model] = rigModelMenu->AppendRadioItem(modelMenuId, modelString, wxT("Description?")); if (rigModel == (*ri)->rig_model) { - rigModelMenuItems[(*ri)->rig_model]->Check(); + rigModelMenuItems[(*ri)->rig_model]->Check(true); } modelMenuId++; @@ -465,7 +467,7 @@ AppFrame::AppFrame() : rigSerialMenuItems[(*rate_i)] = rigSerialMenu->AppendRadioItem(rateMenuId, rateString, wxT("Description?")); if (rigSerialRate == (*rate_i)) { - rigSerialMenuItems[(*rate_i)]->Check(); + rigSerialMenuItems[(*rate_i)]->Check(true); } rateMenuId++; @@ -590,7 +592,7 @@ void AppFrame::updateDeviceParams() { } wxMenuItem *item = subMenu->AppendRadioItem(wxID_SETTINGS_BASE+i, displayName); if (currentVal == (*str_i)) { - item->Check(); + item->Check(true); } j++; i++; @@ -648,6 +650,21 @@ void AppFrame::updateDeviceParams() { agcMenuItem->Check(wxGetApp().getAGCMode()); + +#if USE_HAMLIB + std::string deviceId = devInfo->getDeviceId(); + DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(deviceId); + + if (wxGetApp().rigIsActive()) { + rigSDRIF = devConfig->getRigIF(rigModel); + if (rigSDRIF) { + wxGetApp().lockFrequency(rigSDRIF); + } else { + wxGetApp().unlockFrequency(); + } + } +#endif + deviceChanged.store(false); } @@ -681,7 +698,7 @@ void AppFrame::OnMenu(wxCommandEvent& event) { // iqSwapMenuItem->Check(swap_state); } else if (event.GetId() == wxID_AGC_CONTROL) { if (wxGetApp().getDevice() == NULL) { - agcMenuItem->Check(); + agcMenuItem->Check(true); return; } if (!wxGetApp().getAGCMode()) { @@ -891,11 +908,24 @@ void AppFrame::OnMenu(wxCommandEvent& event) { } #ifdef USE_HAMLIB + bool resetRig = false; if (event.GetId() >= wxID_RIG_MODEL_BASE && event.GetId() < wxID_RIG_MODEL_BASE+numRigs) { int rigIdx = event.GetId()-wxID_RIG_MODEL_BASE; RigList &rl = RigThread::enumerate(); rigModel = rl[rigIdx]->rig_model; + if (devInfo != nullptr) { + std::string deviceId = devInfo->getDeviceId(); + DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(deviceId); + rigSDRIF = devConfig->getRigIF(rigModel); + if (rigSDRIF) { + wxGetApp().lockFrequency(rigSDRIF); + } else { + wxGetApp().unlockFrequency(); + } + } else { + wxGetApp().unlockFrequency(); + } resetRig = true; } @@ -919,8 +949,39 @@ void AppFrame::OnMenu(wxCommandEvent& event) { if (!wxGetApp().rigIsActive()) { wxGetApp().stopRig(); wxGetApp().initRig(rigModel, rigPort, rigSerialRate); + + if (devInfo != nullptr) { + std::string deviceId = devInfo->getDeviceId(); + DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(deviceId); + rigSDRIF = devConfig->getRigIF(rigModel); + if (rigSDRIF) { + wxGetApp().lockFrequency(rigSDRIF); + } else { + wxGetApp().unlockFrequency(); + } + } else { + wxGetApp().unlockFrequency(); + } } else { wxGetApp().stopRig(); + wxGetApp().unlockFrequency(); + } + } + + if (event.GetId() == wxID_RIG_SDR_IF) { + if (devInfo != nullptr) { + std::string deviceId = devInfo->getDeviceId(); + DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(deviceId); + long long freqRigIF = wxGetNumberFromUser("Rig SDR-IF Frequency", "Frequency (Hz)", "Frequency", devConfig->getRigIF(rigModel), 0, 2000000000); + if (freqRigIF != -1) { + rigSDRIF = freqRigIF; + devConfig->setRigIF(rigModel, rigSDRIF); + } + if (rigSDRIF && wxGetApp().rigIsActive()) { + wxGetApp().lockFrequency(rigSDRIF); + } else { + wxGetApp().unlockFrequency(); + } } } diff --git a/src/AppFrame.h b/src/AppFrame.h index 6076c1e..3ebe09a 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -56,6 +56,7 @@ #ifdef USE_HAMLIB #define wxID_RIG_TOGGLE 11900 #define wxID_RIG_PORT 11901 +#define wxID_RIG_SDR_IF 11902 #define wxID_RIG_SERIAL_BASE 11950 #define wxID_RIG_MODEL_BASE 12000 #endif @@ -140,10 +141,12 @@ private: wxMenu *rigMenu; wxMenuItem *rigEnableMenuItem; wxMenuItem *rigPortMenuItem; + wxMenuItem *sdrIFMenuItem; std::map rigSerialMenuItems; std::map rigModelMenuItems; int rigModel; int rigSerialRate; + long long rigSDRIF; std::vector rigSerialRates; std::string rigPort; int numRigs; From 1344121f55329ce62c95b80c34553b42e4f96973 Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Sun, 10 Jan 2016 13:54:43 -0500 Subject: [PATCH 9/9] Fix loading rig save data --- src/AppConfig.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AppConfig.cpp b/src/AppConfig.cpp index 264d6ed..ae110d1 100644 --- a/src/AppConfig.cpp +++ b/src/AppConfig.cpp @@ -462,12 +462,12 @@ bool AppConfig::load() { if (rig_node->hasAnother("model")) { int loadModel; rig_node->getNext("model")->element()->get(loadModel); - winMax.store(loadModel?loadModel:1); + rigModel.store(loadModel?loadModel:1); } if (rig_node->hasAnother("rate")) { int loadRate; rig_node->getNext("rate")->element()->get(loadRate); - winMax.store(loadRate?loadRate:57600); + rigRate.store(loadRate?loadRate:57600); } if (rig_node->hasAnother("port")) { rigPort = rig_node->getNext("port")->element()->toString();