Merge pull request #180 from cjcliffe/soapy-settings

SoapySDR Settings support
This commit is contained in:
Charles J. Cliffe 2015-11-08 17:10:42 -05:00
commit 02b06ea270
16 changed files with 797 additions and 739 deletions

View File

@ -2,7 +2,7 @@ cmake_minimum_required (VERSION 2.8)
SET(CUBICSDR_VERSION_MAJOR "0")
SET(CUBICSDR_VERSION_MINOR "1")
SET(CUBICSDR_VERSION_PATCH "15")
SET(CUBICSDR_VERSION_PATCH "16")
SET(CUBICSDR_VERSION_REL "alpha")
SET(CUBICSDR_VERSION "${CUBICSDR_VERSION_MAJOR}.${CUBICSDR_VERSION_MINOR}.${CUBICSDR_VERSION_PATCH}-${CUBICSDR_VERSION_REL}")
@ -425,6 +425,14 @@ IF (APPLE AND BUNDLE_APP)
PROJECT(CubicSDR)
SET(MACOSX_BUNDLE_BUNDLE_NAME CubicSDR)
set(BUNDLE_SOAPY_MODS OFF CACHE BOOL "Bundle local SoapySDR modules")
IF (BUNDLE_SOAPY_MODS)
ADD_DEFINITIONS(
-DBUNDLE_SOAPY_MODS=1
)
ENDIF()
ADD_DEFINITIONS(
-std=c++0x
-pthread
@ -466,7 +474,7 @@ IF (APPLE AND BUNDLE_APP)
${PROJECT_SOURCE_DIR}/icon/CubicSDR.icns
PROPERTIES
MACOSX_PACKAGE_LOCATION Resources
)
)
target_link_libraries(CubicSDR ${LIQUID_LIB} ${FFTW_LIB} ${wxWidgets_LIBRARIES} ${OPENGL_LIBRARIES} ${OTHER_LIBRARIES})
SET_TARGET_PROPERTIES(CubicSDR PROPERTIES MACOSX_BUNDLE TRUE)
@ -478,16 +486,49 @@ IF (APPLE AND BUNDLE_APP)
# MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION}"
MACOSX_BUNDLE_GUI_IDENTIFIER "com.cubicproductions.cubicsdr"
MACOSX_BUNDLE_ICON_FILE CubicSDR.icns
)
)
SET(APPS "${CMAKE_BINARY_DIR}/${EX_PLATFORM_NAME}/CubicSDR.app")
# SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
# SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
IF (BUNDLE_SOAPY_MODS)
message(STATUS "SOAPY_ROOT: ${SOAPY_SDR_ROOT}")
file(GLOB SOAPY_MODS ${SOAPY_SDR_ROOT}/lib/SoapySDR/modules/*.so)
FOREACH(SOAPY_MOD_FILE ${SOAPY_MODS})
INSTALL( FILES "${SOAPY_MOD_FILE}"
DESTINATION "${APPS}/Contents/MacOS/modules"
COMPONENT Runtime
)
ENDFOREACH()
ENDIF(BUNDLE_SOAPY_MODS)
INSTALL(CODE "
SET(BU_COPY_FULL_FRAMEWORK_CONTENTS ON)
SET(BU_COPY_FULL_FRAMEWORK_CONTENTS ON)
include(BundleUtilities)
fixup_bundle(\"${APPS}\" \"\" \"/usr/local/lib\")
" COMPONENT Runtime)
IF (BUNDLE_SOAPY_MODS)
FOREACH(SOAPY_MOD_FILE ${SOAPY_MODS})
GET_FILENAME_COMPONENT(SOAPY_MOD_NAME ${SOAPY_MOD_FILE} NAME)
IF(${SOAPY_MOD_NAME} STREQUAL "libsdrPlaySupport.so") # prevent inclusion of libmirsdrapi-rsp.so
message(STATUS "Excluding libsdrPlaySupport.so")
CONTINUE()
ELSE()
message(STATUS "Bundling ${SOAPY_MOD_NAME} from ${SOAPY_MOD_FILE}")
ENDIF()
INSTALL(CODE "
fixup_bundle(\"${APPS}\" \"${APPS}/Contents/MacOS/modules/${SOAPY_MOD_NAME}\" \"/usr/local/lib\")
" COMPONENT Runtime)
ENDFOREACH()
ENDIF(BUNDLE_SOAPY_MODS)
INSTALL(CODE "
VERIFY_APP(\"${APPS}\")
" COMPONENT Runtime)

View File

@ -2,9 +2,7 @@
#include "CubicSDR.h"
DeviceConfig::DeviceConfig() : deviceId("") {
iqSwap.store(0);
ppm.store(0);
directSampling.store(false);
offset.store(0);
}
@ -20,14 +18,6 @@ int DeviceConfig::getPPM() {
return ppm.load();
}
void DeviceConfig::setDirectSampling(int mode) {
directSampling.store(mode);
}
int DeviceConfig::getDirectSampling() {
return directSampling.load();
}
void DeviceConfig::setOffset(long long offset) {
this->offset.store(offset);
}
@ -36,14 +26,6 @@ long long DeviceConfig::getOffset() {
return offset.load();
}
void DeviceConfig::setIQSwap(bool iqSwap) {
this->iqSwap.store(iqSwap);
}
bool DeviceConfig::getIQSwap() {
return iqSwap.load();
}
void DeviceConfig::setDeviceId(std::string deviceId) {
busy_lock.lock();
this->deviceId = deviceId;
@ -64,8 +46,6 @@ void DeviceConfig::save(DataNode *node) {
busy_lock.lock();
*node->newChild("id") = deviceId;
*node->newChild("ppm") = (int)ppm;
*node->newChild("iq_swap") = iqSwap;
*node->newChild("direct_sampling") = directSampling;
*node->newChild("offset") = offset;
busy_lock.unlock();
}
@ -79,32 +59,6 @@ void DeviceConfig::load(DataNode *node) {
setPPM(ppmValue);
std::cout << "Loaded PPM for device '" << deviceId << "' at " << ppmValue << "ppm" << std::endl;
}
if (node->hasAnother("iq_swap")) {
DataNode *iq_swap_node = node->getNext("iq_swap");
int iqSwapValue = 0;
iq_swap_node->element()->get(iqSwapValue);
setIQSwap(iqSwapValue?true:false);
std::cout << "Loaded I/Q Swap for device '" << deviceId << "' as " << (iqSwapValue?"swapped":"not swapped") << std::endl;
}
if (node->hasAnother("direct_sampling")) {
DataNode *direct_sampling_node = node->getNext("direct_sampling");
int directSamplingValue = 0;
direct_sampling_node->element()->get(directSamplingValue);
setDirectSampling(directSamplingValue);
std::cout << "Loaded Direct Sampling Mode for device '" << deviceId << "': ";
switch (directSamplingValue) {
case 0:
std::cout << "off" << std::endl;
break;
case 1:
std::cout << "I-ADC" << std::endl;
break;
case 2:
std::cout << "Q-ADC" << std::endl;
break;
}
}
if (node->hasAnother("offset")) {
DataNode *offset_node = node->getNext("offset");
long long offsetValue = 0;

View File

@ -17,15 +17,9 @@ public:
void setPPM(int ppm);
int getPPM();
void setDirectSampling(int mode);
int getDirectSampling();
void setOffset(long long offset);
long long getOffset();
void setIQSwap(bool iqSwap);
bool getIQSwap();
void setDeviceId(std::string deviceId);
std::string getDeviceId();
@ -36,8 +30,7 @@ private:
std::string deviceId;
std::mutex busy_lock;
std::atomic_int ppm, directSampling;
std::atomic_bool iqSwap;
std::atomic_int ppm;
std::atomic_llong offset;
};

View File

@ -196,6 +196,7 @@ AppFrame::AppFrame() :
waterfallDataThread->setInputQueue("IQDataInput", wxGetApp().getWaterfallVisualQueue());
waterfallDataThread->setOutputQueue("FFTDataOutput", waterfallCanvas->getVisualDataQueue());
waterfallDataThread->getProcessor()->setHideDC(true);
t_FFTData = new std::thread(&FFTVisualDataThread::threadMain, waterfallDataThread);
@ -254,24 +255,9 @@ AppFrame::AppFrame() :
menuBar->Append(menu, wxT("&File"));
menu = new wxMenu;
menu->Append(wxID_SET_FREQ_OFFSET, "Frequency Offset");
menu->Append(wxID_SET_PPM, "Device PPM");
iqSwapMenuItem = menu->AppendCheckItem(wxID_SET_SWAP_IQ, "Swap I/Q");
wxMenu *dsMenu = new wxMenu;
directSamplingMenuItems[0] = dsMenu->AppendRadioItem(wxID_SET_DS_OFF, "Off");
directSamplingMenuItems[1] = dsMenu->AppendRadioItem(wxID_SET_DS_I, "I-ADC");
directSamplingMenuItems[2] = dsMenu->AppendRadioItem(wxID_SET_DS_Q, "Q-ADC");
menu->AppendSubMenu(dsMenu, "Direct Sampling");
agcMenuItem = menu->AppendCheckItem(wxID_AGC_CONTROL, "Automatic Gain");
agcMenuItem->Check(wxGetApp().getAGCMode());
menuBar->Append(menu, wxT("&Settings"));
settingsMenu = new wxMenu;
menuBar->Append(settingsMenu, wxT("&Settings"));
menu = new wxMenu;
@ -442,26 +428,64 @@ void AppFrame::updateDeviceParams() {
return;
}
if (!devInfo) {
deviceChanged.store(false);
return;
}
std::string deviceId = devInfo->getName();
DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(deviceId);
int dsMode = devConfig->getDirectSampling();
if (dsMode > 0 && dsMode <= 2) {
directSamplingMenuItems[devConfig->getDirectSampling()]->Check();
// Build settings menu
wxMenu *newSettingsMenu = new wxMenu;
newSettingsMenu->Append(wxID_SET_FREQ_OFFSET, "Frequency Offset");
if (devInfo->getRxChannel()->hasCORR()) {
newSettingsMenu->Append(wxID_SET_PPM, "Device PPM");
}
if (devConfig->getIQSwap()) {
iqSwapMenuItem->Check();
}
agcMenuItem = newSettingsMenu->AppendCheckItem(wxID_AGC_CONTROL, "Automatic Gain");
agcMenuItem->Check(wxGetApp().getAGCMode());
// Build sample rate menu from device info
SoapySDR::ArgInfoList::const_iterator args_i;
int i = 0;
settingArgs = devInfo->getSettingsArgInfo();
for (args_i = settingArgs.begin(); args_i != settingArgs.end(); args_i++) {
SoapySDR::ArgInfo arg = (*args_i);
std::string currentVal = wxGetApp().getSDRThread()->readSetting(arg.key);
if (arg.type == SoapySDR::ArgInfo::BOOL) {
wxMenuItem *item = newSettingsMenu->AppendCheckItem(wxID_SETTINGS_BASE+i, arg.name, arg.description);
item->Check(currentVal=="true");
i++;
} else if (arg.type == SoapySDR::ArgInfo::INT) {
newSettingsMenu->Append(wxID_SETTINGS_BASE+i, arg.name, arg.description);
i++;
} else if (arg.type == SoapySDR::ArgInfo::FLOAT) {
newSettingsMenu->Append(wxID_SETTINGS_BASE+i, arg.name, arg.description);
i++;
} else if (arg.type == SoapySDR::ArgInfo::STRING) {
if (arg.options.size()) {
wxMenu *subMenu = new wxMenu;
int j = 0;
for (std::vector<std::string>::iterator str_i = arg.options.begin(); str_i != arg.options.end(); str_i++) {
std::string optName = (*str_i);
std::string displayName = optName;
if (arg.optionNames.size()) {
displayName = arg.optionNames[j];
}
wxMenuItem *item = subMenu->AppendRadioItem(wxID_SETTINGS_BASE+i, displayName);
if (currentVal == (*str_i)) {
item->Check();
}
j++;
i++;
}
newSettingsMenu->AppendSubMenu(subMenu, arg.name, arg.description);
} else {
newSettingsMenu->Append(wxID_SETTINGS_BASE+i, arg.name, arg.description);
i++;
}
}
}
settingsIdMax = wxID_SETTINGS_BASE+i;
menuBar->Replace(1, newSettingsMenu, wxT("&Settings"));
settingsMenu = newSettingsMenu;
// Build sample rate menu
sampleRates = devInfo->getRxChannel()->getSampleRates();
sampleRateMenuItems.erase(sampleRateMenuItems.begin(),sampleRateMenuItems.end());
@ -520,19 +544,19 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
wxGetApp().saveConfig();
}
} else if (event.GetId() == wxID_SET_DS_OFF) {
wxGetApp().setDirectSampling(0);
wxGetApp().saveConfig();
// wxGetApp().setDirectSampling(0);
// wxGetApp().saveConfig();
} else if (event.GetId() == wxID_SET_DS_I) {
wxGetApp().setDirectSampling(1);
wxGetApp().saveConfig();
// wxGetApp().setDirectSampling(1);
// wxGetApp().saveConfig();
} else if (event.GetId() == wxID_SET_DS_Q) {
wxGetApp().setDirectSampling(2);
wxGetApp().saveConfig();
// wxGetApp().setDirectSampling(2);
// wxGetApp().saveConfig();
} else if (event.GetId() == wxID_SET_SWAP_IQ) {
bool swap_state = !wxGetApp().getSwapIQ();
wxGetApp().setSwapIQ(swap_state);
wxGetApp().saveConfig();
iqSwapMenuItem->Check(swap_state);
// bool swap_state = !wxGetApp().getSwapIQ();
// wxGetApp().setSwapIQ(swap_state);
// wxGetApp().saveConfig();
// iqSwapMenuItem->Check(swap_state);
} else if (event.GetId() == wxID_AGC_CONTROL) {
if (wxGetApp().getDevice() == NULL) {
agcMenuItem->Check();
@ -623,6 +647,53 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
ThemeMgr::mgr.setTheme(COLOR_THEME_RADAR);
}
if (event.GetId() >= wxID_SETTINGS_BASE && event.GetId() < settingsIdMax) {
int setIdx = event.GetId()-wxID_SETTINGS_BASE;
int menuIdx = 0;
for (std::vector<SoapySDR::ArgInfo>::iterator arg_i = settingArgs.begin(); arg_i != settingArgs.end(); arg_i++) {
SoapySDR::ArgInfo &arg = (*arg_i);
if (arg.type == SoapySDR::ArgInfo::STRING && arg.options.size() && setIdx >= menuIdx && setIdx < menuIdx+arg.options.size()) {
int optIdx = setIdx-menuIdx;
wxGetApp().getSDRThread()->writeSetting(arg.key, arg.options[optIdx]);
break;
} else if (arg.type == SoapySDR::ArgInfo::STRING && arg.options.size()) {
menuIdx += arg.options.size();
} else if (menuIdx == setIdx) {
if (arg.type == SoapySDR::ArgInfo::BOOL) {
wxGetApp().getSDRThread()->writeSetting(arg.key, (wxGetApp().getSDRThread()->readSetting(arg.key)=="true")?"false":"true");
break;
} else if (arg.type == SoapySDR::ArgInfo::STRING) {
menuIdx++;
} else if (arg.type == SoapySDR::ArgInfo::INT) {
int currentVal;
try {
currentVal = std::stoi(wxGetApp().getSDRThread()->readSetting(arg.key));
} catch (std::invalid_argument e) {
currentVal = 0;
}
int intVal = wxGetNumberFromUser(arg.description, arg.units, arg.name, currentVal, arg.range.minimum(), arg.range.maximum(), this);
if (intVal != -1) {
wxGetApp().getSDRThread()->writeSetting(arg.key, std::to_string(intVal));
}
break;
} else if (arg.type == SoapySDR::ArgInfo::FLOAT) {
wxString floatVal = wxGetTextFromUser(arg.description, arg.name, wxGetApp().getSDRThread()->readSetting(arg.key));
try {
wxGetApp().getSDRThread()->writeSetting(arg.key, floatVal.ToStdString());
} catch (std::invalid_argument e) {
// ...
}
break;
} else {
menuIdx++;
}
} else {
menuIdx++;
}
}
}
if (event.GetId() >= wxID_THEME_DEFAULT && event.GetId() <= wxID_THEME_RADAR) {
demodTuner->Refresh();
demodModeSelector->Refresh();
@ -664,24 +735,7 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
}
break;
}
// std::vector<SDRDeviceInfo *> *devs = wxGetApp().getDevices();
// if (event.GetId() >= wxID_DEVICE_ID && event.GetId() <= wxID_DEVICE_ID + devs->size()) {
// int devId = event.GetId() - wxID_DEVICE_ID;
// wxGetApp().setDevice(devId);
//
// SDRDeviceInfo *dev = (*wxGetApp().getDevices())[devId];
// DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(dev->getDeviceId());
//
// int dsMode = devConfig->getDirectSampling();
//
// if (dsMode >= 0 && dsMode <= 2) {
// directSamplingMenuItems[devConfig->getDirectSampling()]->Check();
// }
//
// iqSwapMenuItem->Check(devConfig->getIQSwap());
// }
if (event.GetId() >= wxID_BANDWIDTH_BASE && event.GetId() < wxID_BANDWIDTH_BASE+sampleRates.size()) {
wxGetApp().setSampleRate(sampleRates[event.GetId()-wxID_BANDWIDTH_BASE]);
}
@ -892,7 +946,6 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
// wxGetApp().getSpectrumDistributor()->run();
SpectrumVisualProcessor *proc = wxGetApp().getSpectrumProcessor();
proc->setHideDC(true);
if (spectrumAvgMeter->inputChanged()) {
float val = spectrumAvgMeter->getInputValue();
@ -919,7 +972,6 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
dproc->setCenterFrequency(demodWaterfallCanvas->getCenterFrequency());
SpectrumVisualProcessor *wproc = waterfallDataThread->getProcessor();
wproc->setHideDC(true);
if (waterfallSpeedMeter->inputChanged()) {
float val = waterfallSpeedMeter->getInputValue();

View File

@ -45,12 +45,13 @@
#define wxID_BANDWIDTH_BASE 2150
#define wxID_BANDWIDTH_MANUAL 2200
#define wxID_SETTINGS_BASE 2300
#define wxID_DEVICE_ID 3500
#define wxID_AUDIO_BANDWIDTH_BASE 9000
#define wxID_AUDIO_DEVICE_MULTIPLIER 50
// Define a new frame type
class AppFrame: public wxFrame {
public:
@ -102,9 +103,11 @@ private:
std::map<int, wxMenuItem *> audioSampleRateMenuItems;
std::map<int, wxMenuItem *> directSamplingMenuItems;
wxMenuBar *menuBar;
wxMenuItem *iqSwapMenuItem;
wxMenu *sampleRateMenu;
wxMenuItem *agcMenuItem;
wxMenu *settingsMenu;
SoapySDR::ArgInfoList settingArgs;
int settingsIdMax;
std::vector<long> sampleRates;
std::string currentSessionFile;

View File

@ -112,7 +112,7 @@ long long strToFrequency(std::string freqStr) {
}
CubicSDR::CubicSDR() : appframe(NULL), m_glContext(NULL), frequency(0), offset(0), ppm(0), snap(1), sampleRate(DEFAULT_SAMPLE_RATE), directSamplingMode(0),
CubicSDR::CubicSDR() : appframe(NULL), m_glContext(NULL), frequency(0), offset(0), ppm(0), snap(1), sampleRate(DEFAULT_SAMPLE_RATE),
sdrThread(NULL), sdrPostThread(NULL), spectrumVisualThread(NULL), demodVisualThread(NULL), pipeSDRIQData(NULL), pipeIQVisualData(NULL), pipeAudioVisualData(NULL), t_SDR(NULL), t_PostSDR(NULL) {
sampleRateInitialized.store(false);
agcMode.store(true);
@ -141,7 +141,6 @@ bool CubicSDR::OnInit() {
frequency = wxGetApp().getConfig()->getCenterFreq();
offset = 0;
ppm = 0;
directSamplingMode = 0;
devicesReady.store(false);
deviceSelectorOpen.store(false);
@ -160,6 +159,7 @@ bool CubicSDR::OnInit() {
getDemodSpectrumProcessor()->setInput(pipeDemodIQVisualData);
getSpectrumProcessor()->setInput(pipeIQVisualData);
getSpectrumProcessor()->setHideDC(true);
pipeAudioVisualData = new DemodulatorThreadOutputQueue();
pipeAudioVisualData->set_max_num_items(1);
@ -270,6 +270,16 @@ bool CubicSDR::OnCmdLineParsed(wxCmdLineParser& parser) {
config.load();
#ifdef BUNDLE_SOAPY_MODS
if (parser.Found("l")) {
useLocalMod.store(true);
} else {
useLocalMod.store(false);
}
#else
useLocalMod.store(false);
#endif
return true;
}
@ -296,6 +306,9 @@ void CubicSDR::removeRemote(std::string remoteAddr) {
void CubicSDR::sdrThreadNotify(SDRThread::SDRThreadState state, std::string message) {
notify_busy.lock();
if (state == SDRThread::SDR_THREAD_INITIALIZED) {
appframe->initDeviceParams(getDevice());
}
if (state == SDRThread::SDR_THREAD_MESSAGE) {
notifyMessage = message;
}
@ -351,28 +364,6 @@ void CubicSDR::setOffset(long long ofs) {
config.getDevice(dev->getDeviceId())->setOffset(ofs);
}
void CubicSDR::setDirectSampling(int mode) {
directSamplingMode = mode;
sdrThread->setDirectSampling(mode);
SDRDeviceInfo *dev = getDevice();
config.getDevice(dev->getDeviceId())->setDirectSampling(mode);
}
int CubicSDR::getDirectSampling() {
return directSamplingMode;
}
void CubicSDR::setSwapIQ(bool swapIQ) {
sdrThread->setIQSwap(swapIQ);
SDRDeviceInfo *dev = getDevice();
config.getDevice(dev->getDeviceId())->setIQSwap(swapIQ);
}
bool CubicSDR::getSwapIQ() {
return sdrThread->getIQSwap();
}
long long CubicSDR::getFrequency() {
return frequency;
}
@ -392,6 +383,10 @@ void CubicSDR::setDevice(SDRDeviceInfo *dev) {
}
}
for (SoapySDR::Kwargs::const_iterator i = settingArgs.begin(); i != settingArgs.end(); i++) {
sdrThread->writeSetting(i->first, i->second);
}
sdrThread->setStreamArgs(streamArgs);
sdrThread->setDevice(dev);
DeviceConfig *devConfig = config.getDevice(dev->getDeviceId());
@ -441,13 +436,9 @@ void CubicSDR::setDevice(SDRDeviceInfo *dev) {
setSampleRate(sampleRate);
setPPM(devConfig->getPPM());
setDirectSampling(devConfig->getDirectSampling());
setSwapIQ(devConfig->getIQSwap());
setOffset(devConfig->getOffset());
t_SDR = new std::thread(&SDRThread::threadMain, sdrThread);
appframe->initDeviceParams(dev);
}
}
@ -487,6 +478,11 @@ SDRPostThread *CubicSDR::getSDRPostThread() {
return sdrPostThread;
}
SDRThread *CubicSDR::getSDRThread() {
return sdrThread;
}
void CubicSDR::bindDemodulator(DemodulatorInstance *demod) {
if (!demod) {
return;
@ -617,3 +613,14 @@ float CubicSDR::getGain(std::string name) {
return sdrThread->getGain(name);
}
void CubicSDR::setStreamArgs(SoapySDR::Kwargs streamArgs_in) {
streamArgs = streamArgs_in;
}
void CubicSDR::setDeviceArgs(SoapySDR::Kwargs settingArgs_in) {
settingArgs = settingArgs_in;
}
bool CubicSDR::getUseLocalMod() {
return useLocalMod.load();
}

View File

@ -58,12 +58,6 @@ public:
void setOffset(long long ofs);
long long getOffset();
void setDirectSampling(int mode);
int getDirectSampling();
void setSwapIQ(bool swapIQ);
bool getSwapIQ();
void setSampleRate(long long rate_in);
long long getSampleRate();
@ -82,7 +76,8 @@ public:
DemodulatorMgr &getDemodMgr();
SDRPostThread *getSDRPostThread();
SDRThread *getSDRThread();
void bindDemodulator(DemodulatorInstance *demod);
void removeDemodulator(DemodulatorInstance *demod);
@ -114,6 +109,10 @@ public:
void setGain(std::string name, float gain_in);
float getGain(std::string name);
void setStreamArgs(SoapySDR::Kwargs streamArgs_in);
void setDeviceArgs(SoapySDR::Kwargs settingArgs_in);
bool getUseLocalMod();
private:
AppFrame *appframe;
AppConfig config;
@ -126,7 +125,6 @@ private:
long long offset;
int ppm, snap;
long long sampleRate;
int directSamplingMode;
std::atomic_bool agcMode;
SDRThread *sdrThread;
@ -146,19 +144,33 @@ private:
SDRDevicesDialog *deviceSelectorDialog;
SoapySDR::Kwargs streamArgs;
SoapySDR::Kwargs settingArgs;
std::thread *t_SDR, *t_SDREnum, *t_PostSDR, *t_SpectrumVisual, *t_DemodVisual;
std::atomic_bool devicesReady;
std::atomic_bool deviceSelectorOpen;
std::atomic_bool sampleRateInitialized;
std::atomic_bool useLocalMod;
std::string notifyMessage;
std::mutex notify_busy;
};
#ifdef BUNDLE_SOAPY_MODS
static const wxCmdLineEntryDesc commandLineInfo [] =
{
{ wxCMD_LINE_SWITCH, "h", "help", "Command line parameter help", wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
{ wxCMD_LINE_OPTION, "c", "config", "Specify a named configuration to use, i.e. '-c ham'" },
{ wxCMD_LINE_SWITCH, "l", "localmod", "Check local SoapySDR modules instead of bundled first." },
{ wxCMD_LINE_NONE }
};
#else
static const wxCmdLineEntryDesc commandLineInfo [] =
{
{ wxCMD_LINE_SWITCH, "h", "help", "Command line parameter help", wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
{ wxCMD_LINE_OPTION, "c", "config", "Specify a named configuration to use, i.e. '-c ham'" },
{ wxCMD_LINE_NONE }
};
#endif
DECLARE_APP(CubicSDR)

View File

@ -10,7 +10,8 @@ SDRDevicesDialog::SDRDevicesDialog( wxWindow* parent ): devFrame( parent ) {
m_addRemoteButton->Disable();
m_useSelectedButton->Disable();
m_deviceTimer.Start(250);
}
}
void SDRDevicesDialog::OnClose( wxCloseEvent& event ) {
wxGetApp().setDeviceSelectorClosed();
@ -21,7 +22,105 @@ void SDRDevicesDialog::OnDeleteItem( wxTreeEvent& event ) {
event.Skip();
}
wxPGProperty *SDRDevicesDialog::addArgInfoProperty(wxPropertyGrid *pg, SoapySDR::ArgInfo arg) {
wxPGProperty *prop = NULL;
int intVal;
double floatVal;
std::vector<std::string>::iterator stringIter;
switch (arg.type) {
case SoapySDR::ArgInfo::INT:
try {
intVal = std::stoi(arg.value);
} catch (std::invalid_argument e) {
intVal = 0;
}
prop = pg->Append( new wxIntProperty(arg.name, wxPG_LABEL, intVal) );
if (arg.range.minimum() != arg.range.maximum()) {
pg->SetPropertyAttribute( prop, wxPG_ATTR_MIN, arg.range.minimum());
pg->SetPropertyAttribute( prop, wxPG_ATTR_MAX, arg.range.maximum());
}
break;
case SoapySDR::ArgInfo::FLOAT:
try {
floatVal = std::stod(arg.value);
} catch (std::invalid_argument e) {
floatVal = 0;
}
prop = pg->Append( new wxFloatProperty(arg.name, wxPG_LABEL, floatVal) );
if (arg.range.minimum() != arg.range.maximum()) {
pg->SetPropertyAttribute( prop, wxPG_ATTR_MIN, arg.range.minimum());
pg->SetPropertyAttribute( prop, wxPG_ATTR_MAX, arg.range.maximum());
}
break;
case SoapySDR::ArgInfo::BOOL:
prop = pg->Append( new wxBoolProperty(arg.name, wxPG_LABEL, (arg.value=="true")) );
break;
case SoapySDR::ArgInfo::STRING:
if (arg.options.size()) {
intVal = 0;
prop = pg->Append( new wxEnumProperty(arg.name, wxPG_LABEL) );
for (stringIter = arg.options.begin(); stringIter != arg.options.end(); stringIter++) {
std::string optName = (*stringIter);
std::string displayName = optName;
if (arg.optionNames.size()) {
displayName = arg.optionNames[intVal];
}
prop->AddChoice(displayName);
if ((*stringIter)==arg.value) {
prop->SetChoiceSelection(intVal);
}
intVal++;
}
} else {
prop = pg->Append( new wxStringProperty(arg.name, wxPG_LABEL, arg.value) );
}
break;
}
if (prop != NULL) {
prop->SetHelpString(arg.key + ": " + arg.description);
}
return prop;
}
void SDRDevicesDialog::OnSelectionChanged( wxTreeEvent& event ) {
wxTreeItemId selId = devTree->GetSelection();
dev = getSelectedDevice(selId);
props.erase(props.begin(), props.end());
if (dev) {
m_propertyGrid->Clear();
m_propertyGrid->Append(new wxPropertyCategory("Run-time Settings"));
SoapySDR::ArgInfoList::const_iterator args_i;
SoapySDR::ArgInfoList args = dev->getSettingsArgInfo();
for (args_i = args.begin(); args_i != args.end(); args_i++) {
SoapySDR::ArgInfo arg = (*args_i);
props.push_back(addArgInfoProperty(m_propertyGrid, arg));
}
if (dev->getRxChannel()) {
args = dev->getRxChannel()->getStreamArgsInfo();
if (args.size()) {
m_propertyGrid->Append(new wxPropertyCategory("Stream Settings"));
for (args_i = args.begin(); args_i != args.end(); args_i++) {
SoapySDR::ArgInfo arg = (*args_i);
props.push_back(addArgInfoProperty(m_propertyGrid, arg));
}
}
}
}
event.Skip();
}
@ -46,12 +145,66 @@ void SDRDevicesDialog::OnAddRemote( wxMouseEvent& event ) {
}
SDRDeviceInfo *SDRDevicesDialog::getSelectedDevice(wxTreeItemId selId) {
devItems_i = devItems.find(selId);
if (devItems_i != devItems.end()) {
return devItems[selId];
}
return NULL;
}
void SDRDevicesDialog::OnUseSelected( wxMouseEvent& event ) {
wxTreeItemId selId = devTree->GetSelection();
devItems_i = devItems.find(selId);
if (devItems_i != devItems.end()) {
dev = devItems[selId];
dev = getSelectedDevice(selId);
if (dev != NULL) {
int i = 0;
SoapySDR::ArgInfoList::const_iterator args_i;
SoapySDR::ArgInfoList args = dev->getSettingsArgInfo();
SoapySDR::Kwargs settingArgs;
SoapySDR::Kwargs streamArgs;
for (args_i = args.begin(); args_i != args.end(); args_i++) {
SoapySDR::ArgInfo arg = (*args_i);
wxPGProperty *prop = props[i];
if (arg.type == SoapySDR::ArgInfo::STRING && arg.options.size()) {
settingArgs[arg.key] = arg.options[prop->GetChoiceSelection()];
} else if (arg.type == SoapySDR::ArgInfo::BOOL) {
settingArgs[arg.key] = (prop->GetValueAsString()=="True")?"true":"false";
} else {
settingArgs[arg.key] = prop->GetValueAsString();
}
i++;
}
if (dev->getRxChannel()) {
args = dev->getRxChannel()->getStreamArgsInfo();
if (args.size()) {
for (args_i = args.begin(); args_i != args.end(); args_i++) {
SoapySDR::ArgInfo arg = (*args_i);
wxPGProperty *prop = props[i];
if (arg.type == SoapySDR::ArgInfo::STRING && arg.options.size()) {
streamArgs[arg.key] = arg.options[prop->GetChoiceSelection()];
} else if (arg.type == SoapySDR::ArgInfo::BOOL) {
streamArgs[arg.key] = (prop->GetValueAsString()=="True")?"true":"false";
} else {
streamArgs[arg.key] = prop->GetValueAsString();
}
i++;
}
}
}
wxGetApp().setDeviceArgs(settingArgs);
wxGetApp().setStreamArgs(streamArgs);
wxGetApp().setDevice(dev);
Close();
}

View File

@ -44,7 +44,7 @@
<property name="minimum_size"></property>
<property name="name">devFrame</property>
<property name="pos"></property>
<property name="size">392,467</property>
<property name="size">700,467</property>
<property name="style">wxDEFAULT_FRAME_STYLE</property>
<property name="subclass"></property>
<property name="title">CubicSDR :: SDR Devices</property>
@ -490,11 +490,11 @@
<property name="name">bSizer5</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">1</property>
<object class="wxButton" expanded="1">
<object class="wxButton" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -578,11 +578,11 @@
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="1">
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">1</property>
<object class="wxButton" expanded="1">
<object class="wxButton" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -674,9 +674,9 @@
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="flag">wxEXPAND | wxALL</property>
<property name="proportion">1</property>
<object class="wxNotebook" expanded="1">
<object class="wxPanel" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -687,7 +687,6 @@
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="bitmapsize"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
@ -700,10 +699,10 @@
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">0</property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">1</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
@ -712,7 +711,7 @@
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">devTabs</property>
<property name="name">m_panel61</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
@ -722,13 +721,12 @@
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="window_style">wxTAB_TRAVERSAL</property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
@ -745,8 +743,6 @@
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnNotebookPageChanged"></event>
<event name="OnNotebookPageChanging"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
@ -754,385 +750,178 @@
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
<object class="notebookpage" expanded="0">
<property name="bitmap"></property>
<property name="label">Device</property>
<property name="select">0</property>
<object class="wxPanel" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">0</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">devInfoPanel</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style">wxTAB_TRAVERSAL</property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
<object class="wxBoxSizer" expanded="0">
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bSizer7</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">SoapySDR Device Options</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="name">devInfoSizer</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxListCtrl" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_DevInfoList</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style">wxLC_ICON</property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnListBeginDrag"></event>
<event name="OnListBeginLabelEdit"></event>
<event name="OnListBeginRDrag"></event>
<event name="OnListCacheHint"></event>
<event name="OnListColBeginDrag"></event>
<event name="OnListColClick"></event>
<event name="OnListColDragging"></event>
<event name="OnListColEndDrag"></event>
<event name="OnListColRightClick"></event>
<event name="OnListDeleteAllItems"></event>
<event name="OnListDeleteItem"></event>
<event name="OnListEndLabelEdit"></event>
<event name="OnListInsertItem"></event>
<event name="OnListItemActivated"></event>
<event name="OnListItemDeselected"></event>
<event name="OnListItemFocused"></event>
<event name="OnListItemMiddleClick"></event>
<event name="OnListItemRightClick"></event>
<event name="OnListItemSelected"></event>
<event name="OnListKeyDown"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<property name="moveable">1</property>
<property name="name">m_staticText1</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
</object>
<object class="notebookpage" expanded="0">
<property name="bitmap"></property>
<property name="label">Parameters</property>
<property name="select">0</property>
<object class="wxPanel" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">devParamsPanel</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style">wxTAB_TRAVERSAL</property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
<object class="wxBoxSizer" expanded="0">
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxPropertyGrid" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="bitmap"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="extra_style"></property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="include_advanced">1</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="name">devParamsSizer</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxListCtrl" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_ParamInfoList</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style">wxLC_ICON</property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnListBeginDrag"></event>
<event name="OnListBeginLabelEdit"></event>
<event name="OnListBeginRDrag"></event>
<event name="OnListCacheHint"></event>
<event name="OnListColBeginDrag"></event>
<event name="OnListColClick"></event>
<event name="OnListColDragging"></event>
<event name="OnListColEndDrag"></event>
<event name="OnListColRightClick"></event>
<event name="OnListDeleteAllItems"></event>
<event name="OnListDeleteItem"></event>
<event name="OnListEndLabelEdit"></event>
<event name="OnListInsertItem"></event>
<event name="OnListItemActivated"></event>
<event name="OnListItemDeselected"></event>
<event name="OnListItemFocused"></event>
<event name="OnListItemMiddleClick"></event>
<event name="OnListItemRightClick"></event>
<event name="OnListItemSelected"></event>
<event name="OnListKeyDown"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<property name="moveable">1</property>
<property name="name">m_propertyGrid</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style">wxPG_DEFAULT_STYLE</property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnPropertyGridChanged"></event>
<event name="OnPropertyGridChanging"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
</object>

View File

@ -21,10 +21,14 @@ public:
void OnDeviceTimer( wxTimerEvent& event );
private:
SDRDeviceInfo *getSelectedDevice(wxTreeItemId selId);
wxPGProperty *addArgInfoProperty(wxPropertyGrid *pg, SoapySDR::ArgInfo arg);
bool refresh;
std::map<std::string, std::vector<SDRDeviceInfo *>* > devs;
std::vector<SDRDeviceInfo *>::iterator devs_i;
std::map<wxTreeItemId, SDRDeviceInfo *> devItems;
std::map<wxTreeItemId, SDRDeviceInfo *>::iterator devItems_i;
SDRDeviceInfo *dev = NULL;
std::vector<wxPGProperty *> props;
};

View File

@ -52,35 +52,22 @@ devFrame::devFrame( wxWindow* parent, wxWindowID id, const wxString& title, cons
bSizer6->Fit( m_panel6 );
bSizer4->Add( m_panel6, 1, wxEXPAND | wxALL, 5 );
devTabs = new wxNotebook( m_panel3, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
devTabs->Hide();
m_panel61 = new wxPanel( m_panel3, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer7;
bSizer7 = new wxBoxSizer( wxVERTICAL );
devInfoPanel = new wxPanel( devTabs, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* devInfoSizer;
devInfoSizer = new wxBoxSizer( wxVERTICAL );
m_staticText1 = new wxStaticText( m_panel61, wxID_ANY, wxT("SoapySDR Device Options"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText1->Wrap( -1 );
bSizer7->Add( m_staticText1, 0, wxALL, 5 );
m_DevInfoList = new wxListCtrl( devInfoPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_ICON );
devInfoSizer->Add( m_DevInfoList, 1, wxEXPAND, 5 );
m_propertyGrid = new wxPropertyGrid(m_panel61, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxPG_DEFAULT_STYLE);
bSizer7->Add( m_propertyGrid, 1, wxALL|wxEXPAND, 5 );
devInfoPanel->SetSizer( devInfoSizer );
devInfoPanel->Layout();
devInfoSizer->Fit( devInfoPanel );
devTabs->AddPage( devInfoPanel, wxT("Device"), false );
devParamsPanel = new wxPanel( devTabs, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* devParamsSizer;
devParamsSizer = new wxBoxSizer( wxVERTICAL );
m_ParamInfoList = new wxListCtrl( devParamsPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_ICON );
devParamsSizer->Add( m_ParamInfoList, 1, wxEXPAND, 5 );
devParamsPanel->SetSizer( devParamsSizer );
devParamsPanel->Layout();
devParamsSizer->Fit( devParamsPanel );
devTabs->AddPage( devParamsPanel, wxT("Parameters"), false );
bSizer4->Add( devTabs, 1, wxEXPAND, 5 );
m_panel61->SetSizer( bSizer7 );
m_panel61->Layout();
bSizer7->Fit( m_panel61 );
bSizer4->Add( m_panel61, 1, wxEXPAND | wxALL, 5 );
m_panel3->SetSizer( bSizer4 );

View File

@ -20,11 +20,12 @@
#include <wx/button.h>
#include <wx/sizer.h>
#include <wx/panel.h>
#include <wx/listctrl.h>
#include <wx/stattext.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/notebook.h>
#include <wx/propgrid/propgrid.h>
#include <wx/propgrid/advprops.h>
#include <wx/timer.h>
#include <wx/frame.h>
@ -46,11 +47,9 @@ class devFrame : public wxFrame
wxPanel* m_panel4;
wxButton* m_addRemoteButton;
wxButton* m_useSelectedButton;
wxNotebook* devTabs;
wxPanel* devInfoPanel;
wxListCtrl* m_DevInfoList;
wxPanel* devParamsPanel;
wxListCtrl* m_ParamInfoList;
wxPanel* m_panel61;
wxStaticText* m_staticText1;
wxPropertyGrid* m_propertyGrid;
wxTimer m_deviceTimer;
// Virtual event handlers, overide them in your derived class
@ -65,7 +64,7 @@ class devFrame : public wxFrame
public:
devFrame( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("CubicSDR :: SDR Devices"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 392,467 ), long style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
devFrame( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("CubicSDR :: SDR Devices"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 700,467 ), long style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
~devFrame();

View File

@ -81,7 +81,7 @@ void ScopeVisualProcessor::process() {
renderData->channels = audioInputData->channels;
renderData->inputRate = audioInputData->inputRate;
renderData->sampleRate = audioInputData->sampleRate;
if (renderData->waveform_points.size() != iMax * 2) {
renderData->waveform_points.resize(iMax * 2);
}
@ -112,7 +112,6 @@ void ScopeVisualProcessor::process() {
}
renderData->spectrum = false;
distribute(renderData);
}
@ -137,7 +136,14 @@ void ScopeVisualProcessor::process() {
}
}
}
renderData = outputBuffers.getBuffer();
renderData->channels = audioInputData->channels;
renderData->inputRate = audioInputData->inputRate;
renderData->sampleRate = audioInputData->sampleRate;
audioInputData->decRefCount();
fftwf_execute(fftw_plan);
@ -175,12 +181,10 @@ void ScopeVisualProcessor::process() {
int outSize = fftSize/2;
if (audioInputData->sampleRate != audioInputData->inputRate) {
outSize = (int)floor((float)outSize * ((float)audioInputData->sampleRate/(float)audioInputData->inputRate));
if (renderData->sampleRate != renderData->inputRate) {
outSize = (int)floor((float)outSize * ((float)renderData->sampleRate/(float)renderData->inputRate));
}
renderData = outputBuffers.getBuffer();
if (renderData->waveform_points.size() != outSize*2) {
renderData->waveform_points.resize(outSize*2);
}
@ -194,12 +198,10 @@ void ScopeVisualProcessor::process() {
renderData->fft_floor = fft_floor_maa;
renderData->fft_ceil = fft_ceil_maa;
renderData->fft_size = fftSize/2;
renderData->inputRate = audioInputData->inputRate;
renderData->sampleRate = audioInputData->sampleRate;
renderData->spectrum = true;
distribute(renderData);
} else {
audioInputData->decRefCount();
}
audioInputData->decRefCount();
}
}

View File

@ -36,31 +36,44 @@ std::vector<SDRDeviceInfo *> *SDREnumerator::enumerate_devices(std::string remot
std::cout << "\tAPI Version: v" << SoapySDR::getAPIVersion() << std::endl;
std::cout << "\tABI Version: v" << SoapySDR::getABIVersion() << std::endl;
std::cout << "\tInstall root: " << SoapySDR::getRootPath() << std::endl;
modules = SoapySDR::listModules();
for (size_t i = 0; i < modules.size(); i++) {
std::cout << "\tModule found: " << modules[i] << std::endl;
}
if (modules.empty()) {
std::cout << "No modules found!" << std::endl;
}
std::cout << "\tLoading modules... " << std::flush;
std::cout << "\tLoading modules... " << std::endl;
#ifdef BUNDLE_SOAPY_MODS
wxFileName exePath = wxFileName(wxStandardPaths::Get().GetExecutablePath());
std::vector<std::string> localMods = SoapySDR::listModules(exePath.GetPath().ToStdString() + "/modules/");
for (std::vector<std::string>::iterator mods_i = localMods.begin(); mods_i != localMods.end(); mods_i++) {
wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, "Initializing bundled SoapySDR module " + (*mods_i) + "..");
SoapySDR::loadModule(*mods_i);
}
wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, "Loading SoapySDR modules..");
bool localModPref = wxGetApp().getUseLocalMod();
if (localModPref) {
wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, "Loading SoapySDR modules..");
std::cout << "Checking local system SoapySDR modules.." << std::flush;
SoapySDR::loadModules();
}
SoapySDR::loadModules();
wxFileName exePath = wxFileName(wxStandardPaths::Get().GetExecutablePath());
std::vector<std::string> localMods = SoapySDR::listModules(exePath.GetPath().ToStdString() + "/modules/");
for (std::vector<std::string>::iterator mods_i = localMods.begin(); mods_i != localMods.end(); mods_i++) {
wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, "Initializing bundled SoapySDR module " + (*mods_i) + "..");
std::cout << "Loading bundled SoapySDR module " << (*mods_i) << ".." << std::endl;
SoapySDR::loadModule(*mods_i);
}
if (!localModPref) {
wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, "Loading SoapySDR modules..");
std::cout << "Checking system SoapySDR modules.." << std::flush;
SoapySDR::loadModules();
}
#else
wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, "Loading SoapySDR modules..");
SoapySDR::loadModules();
#endif
std::cout << "done" << std::endl;
wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, "done.");
std::cout << "done." << std::endl;
// modules = SoapySDR::listModules();
// for (size_t i = 0; i < modules.size(); i++) {
// std::cout << "\tModule found: " << modules[i] << std::endl;
// }
// if (modules.empty()) {
// std::cout << "No modules found!" << std::endl;
// }
if (SDREnumerator::factories.size()) {
SDREnumerator::factories.erase(SDREnumerator::factories.begin(), SDREnumerator::factories.end());
}
@ -108,19 +121,6 @@ std::vector<SDRDeviceInfo *> *SDREnumerator::enumerate_devices(std::string remot
SDRDeviceInfo *dev = new SDRDeviceInfo();
SoapySDR::Kwargs deviceArgs = results[i];
SoapySDR::Kwargs streamArgs;
if (isRemote) {
wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, "Querying remote " + remoteAddr + " device #" + std::to_string(i));
// deviceArgs["remote"] = remoteAddr;
if (deviceArgs.count("rtl") != 0) {
streamArgs["remote:mtu"] = "8192";
streamArgs["remote:format"] = "CS8";
streamArgs["remote:window"] = "16384000";
}
} else {
wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, std::string("Found local device #") + std::to_string(i));
}
for (SoapySDR::Kwargs::const_iterator it = deviceArgs.begin(); it != deviceArgs.end(); ++it) {
std::cout << " " << it->first << " = " << it->second << std::endl;
@ -132,7 +132,6 @@ std::vector<SDRDeviceInfo *> *SDREnumerator::enumerate_devices(std::string remot
}
dev->setDeviceArgs(deviceArgs);
dev->setStreamArgs(streamArgs);
std::cout << "Make device " << i << std::endl;
try {
@ -188,6 +187,29 @@ std::vector<SDRDeviceInfo *> *SDREnumerator::enumerate_devices(std::string remot
dev->addChannel(chan);
}
SoapySDR::Kwargs streamArgs;
if (isRemote) {
wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, "Querying remote " + remoteAddr + " device #" + std::to_string(i));
// if (deviceArgs.count("rtl") != 0) {
// streamArgs["remote:mtu"] = "8192";
// streamArgs["remote:window"] = "16384000";
// }
double fullScale = 0;
std::string nativeFormat = device->getNativeStreamFormat(SOAPY_SDR_RX, dev->getRxChannel()->getChannel(), fullScale);
if (nativeFormat.length()) {
streamArgs["remote:format"] = nativeFormat;
}
} else {
wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, std::string("Found local device #") + std::to_string(i));
}
dev->setStreamArgs(streamArgs);
dev->setSettingsInfo(device->getSettingInfo());
SoapySDR::Device::unmake(device);

View File

@ -15,7 +15,6 @@ SDRThread::SDRThread() : IOThread() {
frequency.store(0);
offset.store(0);
ppm.store(0);
direct_sampling_mode.store(0);
numElems.store(0);
@ -23,26 +22,34 @@ SDRThread::SDRThread() : IOThread() {
freq_changed.store(false);
offset_changed.store(false);
ppm_changed .store(false);
direct_sampling_changed.store(false);
device_changed.store(false);
iq_swap.store(false);
iq_swap_changed.store(false);
hasPPM.store(false);
hasHardwareDC.store(false);
numChannels.store(8);
hasDirectSampling.store(false);
hasIQSwap.store(false);
agc_mode.store(true);
agc_mode_changed.store(false);
gain_value_changed.store(false);
setting_value_changed.store(false);
}
SDRThread::~SDRThread() {
}
SoapySDR::Kwargs SDRThread::combineArgs(SoapySDR::Kwargs a, SoapySDR::Kwargs b) {
SoapySDR::Kwargs c;
SoapySDR::Kwargs::iterator i;
for (i = a.begin(); i != a.end(); i++) {
c[i->first] = i->second;
}
for (i = b.begin(); i != b.end(); i++) {
c[i->first] = i->second;
}
return c;
}
void SDRThread::init() {
SDRDeviceInfo *devInfo = deviceInfo.load();
deviceConfig.store(wxGetApp().getConfig()->getDevice(devInfo->getDeviceId()));
@ -51,12 +58,6 @@ void SDRThread::init() {
ppm.store(devConfig->getPPM());
ppm_changed.store(true);
direct_sampling_mode.store(devConfig->getDirectSampling());
direct_sampling_changed.store(true);
iq_swap.store(devConfig->getIQSwap());
iq_swap_changed.store(true);
std::string driverName = devInfo->getDriver();
offset = devConfig->getOffset();
@ -65,7 +66,7 @@ void SDRThread::init() {
wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, std::string("Initializing device."));
device = SoapySDR::Device::make(args);
stream = device->setupStream(SOAPY_SDR_RX,"CF32", std::vector<size_t>(), devInfo->getStreamArgs());
stream = device->setupStream(SOAPY_SDR_RX,"CF32", std::vector<size_t>(), combineArgs(devInfo->getStreamArgs(),streamArgs));
wxGetApp().sdrEnumThreadNotify(SDREnumerator::SDR_ENUM_MESSAGE, std::string("Activating stream."));
device->setSampleRate(SOAPY_SDR_RX,0,sampleRate.load());
@ -85,14 +86,6 @@ void SDRThread::init() {
} else {
hasHardwareDC.store(false);
}
std::vector<std::string> settingNames = devInfo->getSettingNames();
if (std::find(settingNames.begin(), settingNames.end(), "direct_samp") != settingNames.end()) {
hasDirectSampling.store(true);
}
if (std::find(settingNames.begin(), settingNames.end(), "iq_swap") != settingNames.end()) {
hasIQSwap.store(true);
}
device->setGainMode(SOAPY_SDR_RX,0,agc_mode.load());
@ -101,6 +94,30 @@ void SDRThread::init() {
inpBuffer.data.resize(numElems.load());
buffs[0] = malloc(numElems * 2 * sizeof(float));
SoapySDR::ArgInfoList settingsInfo = device->getSettingInfo();
SoapySDR::ArgInfoList::const_iterator settings_i;
if (!setting_value_changed.load()) {
settings.erase(settings.begin(), settings.end());
settingChanged.erase(settingChanged.begin(), settingChanged.end());
}
setting_busy.lock();
for (settings_i = settingsInfo.begin(); settings_i != settingsInfo.end(); settings_i++) {
SoapySDR::ArgInfo setting = (*settings_i);
if ((settingChanged.find(setting.key) != settingChanged.end()) && (settings.find(setting.key) != settings.end())) {
device->writeSetting(setting.key, settings[setting.key]);
settingChanged[setting.key] = false;
} else {
settings[setting.key] = device->readSetting(setting.key);
settingChanged[setting.key] = false;
}
}
setting_value_changed.store(false);
setting_busy.unlock();
wxGetApp().sdrThreadNotify(SDRThread::SDR_THREAD_INITIALIZED, std::string("Device Initialized."));
}
void SDRThread::deinit() {
@ -159,65 +176,10 @@ void SDRThread::readLoop() {
updateGains();
while (!terminated.load()) {
if (offset_changed.load()) {
if (!freq_changed.load()) {
frequency.store(frequency.load());
freq_changed.store(true);
}
offset_changed.store(false);
}
if (rate_changed.load()) {
device->setSampleRate(SOAPY_SDR_RX,0,sampleRate.load());
sampleRate.store(device->getSampleRate(SOAPY_SDR_RX,0));
numChannels.store(getOptimalChannelCount(sampleRate.load()));
numElems.store(getOptimalElementCount(sampleRate.load(), 60));
inpBuffer.data.resize(numElems.load());
free(buffs[0]);
buffs[0] = malloc(numElems.load() * 2 * sizeof(float));
rate_changed.store(false);
}
if (ppm_changed.load() && hasPPM.load()) {
device->setFrequency(SOAPY_SDR_RX,0,"CORR",ppm.load());
ppm_changed.store(false);
}
if (freq_changed.load()) {
device->setFrequency(SOAPY_SDR_RX,0,"RF",frequency.load() - offset.load());
freq_changed.store(false);
}
if (hasDirectSampling.load() && direct_sampling_changed.load()) {
device->writeSetting("direct_samp", std::to_string(direct_sampling_mode));
direct_sampling_changed.store(false);
}
if (hasIQSwap.load() && iq_swap_changed.load()) {
device->writeSetting("iq_swap", iq_swap.load()?"true":"false");
iq_swap_changed.store(false);
}
if (agc_mode_changed.load()) {
SDRDeviceInfo *devInfo = deviceInfo.load();
device->setGainMode(SOAPY_SDR_RX,devInfo->getRxChannel()->getChannel(),agc_mode.load());
agc_mode_changed.store(false);
if (!agc_mode.load()) {
updateGains();
}
}
if (gain_value_changed.load() && !agc_mode.load()) {
SDRDeviceInfo *devInfo = deviceInfo.load();
gain_busy.lock();
for (std::map<std::string,bool>::iterator gci = gainChanged.begin(); gci != gainChanged.end(); gci++) {
if (gci->second) {
device->setGain(SOAPY_SDR_RX, devInfo->getRxChannel()->getChannel(), gci->first, gainValues[gci->first]);
gainChanged[gci->first] = false;
}
}
gain_busy.unlock();
gain_value_changed.store(false);
}
updateSettings();
readStream(iqDataOutQueue);
}
buffers.purge();
}
@ -236,6 +198,76 @@ void SDRThread::updateGains() {
gain_value_changed.store(false);
}
void SDRThread::updateSettings() {
if (offset_changed.load()) {
if (!freq_changed.load()) {
frequency.store(frequency.load());
freq_changed.store(true);
}
offset_changed.store(false);
}
if (rate_changed.load()) {
device->setSampleRate(SOAPY_SDR_RX,0,sampleRate.load());
sampleRate.store(device->getSampleRate(SOAPY_SDR_RX,0));
numChannels.store(getOptimalChannelCount(sampleRate.load()));
numElems.store(getOptimalElementCount(sampleRate.load(), 60));
inpBuffer.data.resize(numElems.load());
free(buffs[0]);
buffs[0] = malloc(numElems.load() * 2 * sizeof(float));
rate_changed.store(false);
}
if (ppm_changed.load() && hasPPM.load()) {
device->setFrequency(SOAPY_SDR_RX,0,"CORR",ppm.load());
ppm_changed.store(false);
}
if (freq_changed.load()) {
device->setFrequency(SOAPY_SDR_RX,0,"RF",frequency.load() - offset.load());
freq_changed.store(false);
}
if (agc_mode_changed.load()) {
SDRDeviceInfo *devInfo = deviceInfo.load();
device->setGainMode(SOAPY_SDR_RX,devInfo->getRxChannel()->getChannel(),agc_mode.load());
agc_mode_changed.store(false);
if (!agc_mode.load()) {
updateGains();
}
}
if (gain_value_changed.load() && !agc_mode.load()) {
SDRDeviceInfo *devInfo = deviceInfo.load();
gain_busy.lock();
for (std::map<std::string,bool>::iterator gci = gainChanged.begin(); gci != gainChanged.end(); gci++) {
if (gci->second) {
device->setGain(SOAPY_SDR_RX, devInfo->getRxChannel()->getChannel(), gci->first, gainValues[gci->first]);
gainChanged[gci->first] = false;
}
}
gain_busy.unlock();
gain_value_changed.store(false);
}
if (setting_value_changed.load()) {
setting_busy.lock();
for (std::map<std::string, bool>::iterator sci = settingChanged.begin(); sci != settingChanged.end(); sci++) {
if (sci->second) {
device->writeSetting(sci->first, settings[sci->first]);
settingChanged[sci->first] = false;
}
}
setting_value_changed.store(false);
setting_busy.unlock();
}
}
void SDRThread::run() {
//#ifdef __APPLE__
@ -346,25 +378,6 @@ int SDRThread::getPPM() {
return ppm.load();
}
void SDRThread::setDirectSampling(int dsMode) {
direct_sampling_mode.store(dsMode);
direct_sampling_changed.store(true);
std::cout << "Set direct sampling mode: " << this->direct_sampling_mode.load() << std::endl;
}
int SDRThread::getDirectSampling() {
return direct_sampling_mode.load();
}
void SDRThread::setIQSwap(bool iqSwap) {
iq_swap.store(iqSwap);
iq_swap_changed.store(true);
}
bool SDRThread::getIQSwap() {
return iq_swap.load();
}
void SDRThread::setAGCMode(bool mode) {
agc_mode.store(mode);
agc_mode_changed.store(true);
@ -388,3 +401,23 @@ float SDRThread::getGain(std::string name) {
gain_busy.unlock();
return val;
}
void SDRThread::writeSetting(std::string name, std::string value) {
setting_busy.lock();
settings[name] = value;
settingChanged[name] = true;
setting_value_changed.store(true);
setting_busy.unlock();
}
std::string SDRThread::readSetting(std::string name) {
std::string val;
setting_busy.lock();
val = device->readSetting(name);
setting_busy.unlock();
return val;
}
void SDRThread::setStreamArgs(SoapySDR::Kwargs streamArgs_in) {
streamArgs = streamArgs_in;
}

View File

@ -48,7 +48,7 @@ private:
public:
SDRThread();
~SDRThread();
enum SDRThreadState { SDR_THREAD_MESSAGE, SDR_THREAD_TERMINATED, SDR_THREAD_FAILED };
enum SDRThreadState { SDR_THREAD_MESSAGE, SDR_THREAD_INITIALIZED, SDR_THREAD_TERMINATED, SDR_THREAD_FAILED };
void run();
@ -69,21 +69,22 @@ public:
void setPPM(int ppm);
int getPPM();
void setDirectSampling(int dsMode);
int getDirectSampling();
void setIQSwap(bool iqSwap);
bool getIQSwap();
void setAGCMode(bool mode);
bool getAGCMode();
void setGain(std::string name, float value);
float getGain(std::string name);
void writeSetting(std::string name, std::string value);
std::string readSetting(std::string name);
void setStreamArgs(SoapySDR::Kwargs streamArgs);
protected:
void updateGains();
void updateSettings();
SoapySDR::Kwargs combineArgs(SoapySDR::Kwargs a, SoapySDR::Kwargs b);
SoapySDR::Stream *stream;
SoapySDR::Device *device;
void *buffs[1];
@ -91,15 +92,21 @@ protected:
SDRThreadIQData inpBuffer;
std::atomic<DeviceConfig *> deviceConfig;
std::atomic<SDRDeviceInfo *> deviceInfo;
std::mutex setting_busy;
std::map<std::string, std::string> settings;
std::map<std::string, bool> settingChanged;
std::atomic<uint32_t> sampleRate;
std::atomic_llong frequency, offset;
std::atomic_int ppm, direct_sampling_mode, numElems, numChannels;
std::atomic_bool hasPPM, hasHardwareDC, hasDirectSampling, hasIQSwap;
std::atomic_bool iq_swap, agc_mode, rate_changed, freq_changed, offset_changed,
ppm_changed, direct_sampling_changed, device_changed, iq_swap_changed, agc_mode_changed, gain_value_changed;
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;
std::mutex gain_busy;
std::map<std::string, float> gainValues;
std::map<std::string, bool> gainChanged;
SoapySDR::Kwargs streamArgs;
};