initial hamlib integration and frequency control

This commit is contained in:
Charles J. Cliffe 2016-01-03 19:00:26 -05:00
parent 2c885b272f
commit 08dc9af1c5
9 changed files with 322 additions and 12 deletions

View File

@ -521,6 +521,7 @@ include_directories (
${PROJECT_SOURCE_DIR}/src/visual ${PROJECT_SOURCE_DIR}/src/visual
${PROJECT_SOURCE_DIR}/src/process ${PROJECT_SOURCE_DIR}/src/process
${PROJECT_SOURCE_DIR}/src/ui ${PROJECT_SOURCE_DIR}/src/ui
${PROJECT_SOURCE_DIR}/src/rig
${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/src
${PROJECT_SOURCE_DIR}/external/rtaudio ${PROJECT_SOURCE_DIR}/external/rtaudio
${PROJECT_SOURCE_DIR}/external/lodepng ${PROJECT_SOURCE_DIR}/external/lodepng

View File

@ -152,6 +152,11 @@ AppConfig::AppConfig() : configName("") {
centerFreq.store(100000000); centerFreq.store(100000000);
waterfallLinesPerSec.store(DEFAULT_WATERFALL_LPS); waterfallLinesPerSec.store(DEFAULT_WATERFALL_LPS);
spectrumAvgSpeed.store(0.65f); spectrumAvgSpeed.store(0.65f);
#ifdef USE_HAMLIB
rigModel.store(1);
rigRate.store(57600);
rigPort = "/dev/ttyUSB0";
#endif
} }
DeviceConfig *AppConfig::getDevice(std::string deviceId) { DeviceConfig *AppConfig::getDevice(std::string deviceId) {
@ -298,6 +303,13 @@ bool AppConfig::save() {
device_config_i->second->save(device_node); 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(); std::string cfgFileName = getConfigFileName();
if (!cfg.SaveToFileXML(cfgFileName)) { if (!cfg.SaveToFileXML(cfgFileName)) {
@ -412,6 +424,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; return true;
} }
@ -419,3 +452,32 @@ bool AppConfig::reset() {
return true; 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

@ -75,6 +75,17 @@ public:
void setSpectrumAvgSpeed(float avgSpeed); void setSpectrumAvgSpeed(float avgSpeed);
float getSpectrumAvgSpeed(); 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); void setConfigName(std::string configName);
std::string getConfigFileName(bool ignoreName=false); std::string getConfigFileName(bool ignoreName=false);
bool save(); bool save();
@ -91,4 +102,8 @@ private:
std::atomic_llong centerFreq; std::atomic_llong centerFreq;
std::atomic_int waterfallLinesPerSec; std::atomic_int waterfallLinesPerSec;
std::atomic<float> spectrumAvgSpeed; 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) EVT_SPLITTER_UNSPLIT(wxID_ANY, AppFrame::OnUnSplit)
wxEND_EVENT_TABLE() wxEND_EVENT_TABLE()
#ifdef USE_HAMLIB
#include "RigThread.h"
#endif
AppFrame::AppFrame() : AppFrame::AppFrame() :
wxFrame(NULL, wxID_ANY, CUBICSDR_TITLE), activeDemodulator(NULL) { wxFrame(NULL, wxID_ANY, CUBICSDR_TITLE), activeDemodulator(NULL) {
@ -409,6 +412,72 @@ AppFrame::AppFrame() :
menuBar->Append(menu, wxT("Audio &Sample Rate")); 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<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();
}
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); SetMenuBar(menuBar);
CreateStatusBar(); CreateStatusBar();
@ -821,6 +890,46 @@ 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;
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
} }
void AppFrame::OnClose(wxCloseEvent& event) { void AppFrame::OnClose(wxCloseEvent& event) {
@ -837,6 +946,11 @@ void AppFrame::OnClose(wxCloseEvent& event) {
wxGetApp().getConfig()->setCenterFreq(wxGetApp().getFrequency()); wxGetApp().getConfig()->setCenterFreq(wxGetApp().getFrequency());
wxGetApp().getConfig()->setSpectrumAvgSpeed(wxGetApp().getSpectrumProcessor()->getFFTAverageRate()); wxGetApp().getConfig()->setSpectrumAvgSpeed(wxGetApp().getSpectrumProcessor()->getFFTAverageRate());
wxGetApp().getConfig()->setWaterfallLinesPerSec(waterfallDataThread->getLinesPerSecond()); wxGetApp().getConfig()->setWaterfallLinesPerSec(waterfallDataThread->getLinesPerSecond());
#ifdef USE_HAMLIB
wxGetApp().getConfig()->setRigModel(rigModel);
wxGetApp().getConfig()->setRigRate(rigSerialRate);
wxGetApp().getConfig()->setRigPort(rigPort);
#endif
wxGetApp().getConfig()->save(); wxGetApp().getConfig()->save();
event.Skip(); event.Skip();
} }

View File

@ -53,6 +53,13 @@
#define wxID_AUDIO_BANDWIDTH_BASE 9000 #define wxID_AUDIO_BANDWIDTH_BASE 9000
#define wxID_AUDIO_DEVICE_MULTIPLIER 50 #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 // Define a new frame type
class AppFrame: public wxFrame { class AppFrame: public wxFrame {
public: public:
@ -129,5 +136,18 @@ private:
std::atomic_bool modemPropertiesUpdated; std::atomic_bool modemPropertiesUpdated;
ModemArgInfoList newModemArgs; ModemArgInfoList newModemArgs;
#ifdef USE_HAMLIB
wxMenu *rigMenu;
wxMenuItem *rigEnableMenuItem;
wxMenuItem *rigPortMenuItem;
std::map<int, wxMenuItem *> rigSerialMenuItems;
std::map<int, wxMenuItem *> rigModelMenuItems;
int rigModel;
int rigSerialRate;
std::vector<int> rigSerialRates;
std::string rigPort;
int numRigs;
#endif
wxDECLARE_EVENT_TABLE(); wxDECLARE_EVENT_TABLE();
}; };

View File

@ -18,6 +18,10 @@
#include "CoreFoundation/CoreFoundation.h" #include "CoreFoundation/CoreFoundation.h"
#endif #endif
#ifdef USE_HAMLIB
#include "RigThread.h"
#endif
IMPLEMENT_APP(CubicSDR) IMPLEMENT_APP(CubicSDR)
//#ifdef ENABLE_DIGITAL_LAB //#ifdef ENABLE_DIGITAL_LAB
@ -164,6 +168,13 @@ bool CubicSDR::OnInit() {
wxApp::SetAppName("CubicSDR"); wxApp::SetAppName("CubicSDR");
#ifdef USE_HAMLIB
t_Rig = nullptr;
rigThread = nullptr;
RigThread::enumerate();
#endif
Modem::addModemFactory(new ModemFM); Modem::addModemFactory(new ModemFM);
Modem::addModemFactory(new ModemFMStereo); Modem::addModemFactory(new ModemFMStereo);
Modem::addModemFactory(new ModemAM); Modem::addModemFactory(new ModemAM);
@ -712,3 +723,51 @@ bool CubicSDR::getUseLocalMod() {
std::string CubicSDR::getModulePath() { std::string CubicSDR::getModulePath() {
return modulePath; 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" #include "ModemST.h"
#endif #endif
#ifdef USE_HAMLIB
class RigThread;
#endif
#include <wx/cmdline.h> #include <wx/cmdline.h>
#define NUM_DEMODULATORS 1 #define NUM_DEMODULATORS 1
@ -142,6 +146,13 @@ public:
bool getUseLocalMod(); bool getUseLocalMod();
std::string getModulePath(); std::string getModulePath();
#ifdef USE_HAMLIB
RigThread *getRigThread();
void initRig(int rigModel, std::string rigPort, int rigSerialRate);
void stopRig();
bool rigIsActive();
#endif
private: private:
AppFrame *appframe; AppFrame *appframe;
AppConfig config; AppConfig config;
@ -184,6 +195,10 @@ private:
std::string notifyMessage; std::string notifyMessage;
std::string modulePath; std::string modulePath;
std::mutex notify_busy; std::mutex notify_busy;
#ifdef USE_HAMLIB
RigThread *rigThread;
std::thread *t_Rig;
#endif
}; };
#ifdef BUNDLE_SOAPY_MODS #ifdef BUNDLE_SOAPY_MODS

View File

@ -4,18 +4,23 @@ std::vector<const struct rig_caps *> RigThread::rigCaps;
RigThread::RigThread() { RigThread::RigThread() {
terminated.store(true); terminated.store(true);
freq = wxGetApp().getFrequency();
} }
RigThread::~RigThread() { RigThread::~RigThread() {
} }
void RigThread::enumerate() { RigList &RigThread::enumerate() {
rig_set_debug(RIG_DEBUG_ERR); if (RigThread::rigCaps.empty()) {
rig_load_all_backends(); rig_set_debug(RIG_DEBUG_ERR);
RigThread::rigCaps.clear(); rig_load_all_backends();
rig_list_foreach(RigThread::add_hamlib_rig, 0);
std::sort(RigThread::rigCaps.begin(), RigThread::rigCaps.end(), rigGreater()); 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) 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); strncpy(rig->state.rigport.pathname, rigFile.c_str(), FILPATHLEN - 1);
rig->state.rigport.parm.serial.rate = serialRate; rig->state.rigport.parm.serial.rate = serialRate;
retcode = rig_open(rig); 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); char *info_buf = (char *)rig_get_info(rig);
std::cout << "Rig info: " << info_buf << std::endl; std::cout << "Rig info: " << info_buf << std::endl;
@ -49,15 +61,25 @@ void RigThread::run() {
if (freq != newFreq) { if (freq != newFreq) {
freq = newFreq; freq = newFreq;
rig_set_freq(rig, RIG_VFO_CURR, freq); 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); freqChanged.store(false);
} else { } 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); rig_close(rig);

View File

@ -14,6 +14,8 @@ struct rigGreater
} }
}; };
typedef std::vector<const struct rig_caps *> RigList;
class RigThread : public IOThread { class RigThread : public IOThread {
public: public:
RigThread(); RigThread();
@ -25,7 +27,7 @@ public:
freq_t getFrequency(); freq_t getFrequency();
void setFrequency(freq_t new_freq); void setFrequency(freq_t new_freq);
static void enumerate(); static RigList &enumerate();
static int add_hamlib_rig(const struct rig_caps *rc, void* f); static int add_hamlib_rig(const struct rig_caps *rc, void* f);
private: private:
@ -37,5 +39,5 @@ private:
freq_t freq; freq_t freq;
freq_t newFreq; freq_t newFreq;
std::atomic_bool freqChanged; std::atomic_bool freqChanged;
static std::vector<const struct rig_caps *> rigCaps; static RigList rigCaps;
}; };