From 08dc9af1c514ea0a0fa00a29fb9c3eaba851776e Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Sun, 3 Jan 2016 19:00:26 -0500 Subject: [PATCH] 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