Merge pull request #244 from cjcliffe/rig_control

hamlib rig control (CAT, rotors, antennas, etc)
This commit is contained in:
Charles J. Cliffe 2016-01-10 14:32:28 -05:00
commit 01e441b142
12 changed files with 684 additions and 11 deletions

View File

@ -1,9 +1,13 @@
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")
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}")
@ -34,7 +38,21 @@ ADD_DEFINITIONS(
ENDIF()
ENDIF()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
set(USE_HAMLIB ON CACHE BOOL "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_DIR})
link_libraries(${HAMLIB_LIBRARY})
ADD_DEFINITIONS(-DUSE_HAMLIB)
endif ()
macro(configure_files srcDir destDir globStr)
message(STATUS "Copying ${srcDir}/${globStr} to directory ${destDir}")
@ -70,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 )
@ -433,6 +449,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 +482,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}")
@ -486,6 +518,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

View File

@ -0,0 +1,56 @@
# - Try to find Hamlib
# Author: George L. Emigh - AB4BD
#
# Change Log: Charles J. Cliffe <cj@cubicproductions.com>
# Updates:
# Jan 2015 - Add /opt/ paths for OSX MacPorts
# - Fix HAMLIB_INCLUDE_DIR absolute search
# TODO:
# Windows support
# Static support
#
# HAMLIB_FOUND - system has Hamlib
# HAMLIB_LIBRARY - location of the library for hamlib
# HAMLIB_INCLUDE_DIR - location of the include files for hamlib
set(HAMLIB_FOUND FALSE)
find_path(HAMLIB_INCLUDE_DIR
NAMES hamlib/rig.h
PATHS
/usr/include
/usr/local/include
/opt/local/include
)
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(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)
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)

View File

@ -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<int, long long>::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);
@ -152,6 +183,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 +333,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 +454,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);
rigModel.store(loadModel?loadModel:1);
}
if (rig_node->hasAnother("rate")) {
int loadRate;
rig_node->getNext("rate")->element()->get(loadRate);
rigRate.store(loadRate?loadRate:57600);
}
if (rig_node->hasAnother("port")) {
rigPort = rig_node->getNext("port")->element()->toString();
}
}
#endif
return true;
}
@ -419,3 +483,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

View File

@ -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<std::string, std::string> settings;
std::map<int, long long> rigIF;
};
class AppConfig {
@ -75,6 +79,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 +106,8 @@ private:
std::atomic_llong centerFreq;
std::atomic_int waterfallLinesPerSec;
std::atomic<float> spectrumAvgSpeed;
#if USE_HAMLIB
std::atomic_int rigModel, rigRate;
std::string rigPort;
#endif
};

View File

@ -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,74 @@ 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"));
rigMenu->Append(wxID_RIG_SDR_IF, wxT("SDR-IF"));
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(true);
}
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<int>::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(true);
}
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();
@ -521,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++;
@ -579,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);
}
@ -612,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()) {
@ -820,6 +906,90 @@ 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;
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;
}
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);
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();
}
}
}
if (wxGetApp().rigIsActive() && resetRig) {
wxGetApp().stopRig();
wxGetApp().initRig(rigModel, rigPort, rigSerialRate);
}
#endif
}
@ -837,6 +1007,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 +1291,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
if (!this->IsActive()) {
std::this_thread::sleep_for(std::chrono::milliseconds(25));
}
event.RequestMore();
}

View File

@ -53,6 +53,14 @@
#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_SDR_IF 11902
#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 +137,20 @@ private:
std::atomic_bool modemPropertiesUpdated;
ModemArgInfoList newModemArgs;
#ifdef USE_HAMLIB
wxMenu *rigMenu;
wxMenuItem *rigEnableMenuItem;
wxMenuItem *rigPortMenuItem;
wxMenuItem *sdrIFMenuItem;
std::map<int, wxMenuItem *> rigSerialMenuItems;
std::map<int, wxMenuItem *> rigModelMenuItems;
int rigModel;
int rigSerialRate;
long long rigSDRIF;
std::vector<int> rigSerialRates;
std::string rigPort;
int numRigs;
#endif
wxDECLARE_EVENT_TABLE();
};

View File

@ -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);
@ -438,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);
@ -712,3 +742,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

View File

@ -54,6 +54,10 @@
#include "ModemST.h"
#endif
#ifdef USE_HAMLIB
class RigThread;
#endif
#include <wx/cmdline.h>
#define NUM_DEMODULATORS 1
@ -80,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();
@ -142,6 +150,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 +199,12 @@ 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;
#endif
};
#ifdef BUNDLE_SOAPY_MODS

103
src/rig/RigThread.cpp Normal file
View File

@ -0,0 +1,103 @@
#include "RigThread.h"
std::vector<const struct rig_caps *> RigThread::rigCaps;
RigThread::RigThread() {
terminated.store(true);
freq = wxGetApp().getFrequency();
}
RigThread::~RigThread() {
}
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)
{
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);
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;
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 {
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;
}
rig_close(rig);
rig_cleanup(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);
}

43
src/rig/RigThread.h Normal file
View File

@ -0,0 +1,43 @@
#pragma once
#include "IOThread.h"
#include "CubicSDR.h"
#include <hamlib/rig.h>
#include <hamlib/riglist.h>
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;
}
};
typedef std::vector<const struct rig_caps *> RigList;
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 RigList &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 RigList rigCaps;
};

View File

@ -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);

View File

@ -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<std::string, bool> settingChanged;
std::atomic<uint32_t> 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<std::string, float> gainValues;