Merge pull request #29 from cjcliffe/change-iqrate

Change IQ Sample Rate and Input Device
This commit is contained in:
Charles J. Cliffe 2015-01-12 00:53:30 -05:00
commit 1afcd9ff3b
23 changed files with 429 additions and 149 deletions

View File

@ -21,15 +21,15 @@ Basic Goals and Status:
---------------------- ----------------------
- Simple UI - Simple UI
- Devices - Devices
- [x] RTL-SDR (RTL2832U) - [x] RTL-SDR
- [ ] HackRF - [ ] HackRF
- [ ] Whatever else I can get my hands on - [ ] Whatever else I can get my hands on
- Minimal configuration - Minimal configuration
- [ ] Device Selection - [x] Device Selection
- [ ] Bandwidth - [x] Bandwidth
- [ ] Default audio device and settings
- [x] Color scheme - [x] Color scheme
- [x] Load/Save session - [x] Load/Save session
- [ ] Default audio device and settings
- Neat Visuals - Neat Visuals
- [x] Scope - [x] Scope
- [x] Spectrum - [x] Spectrum
@ -52,7 +52,7 @@ Basic Goals and Status:
- [x] Display separate zoomed-in view of current waterfall and spectrum, allow adjustments - [x] Display separate zoomed-in view of current waterfall and spectrum, allow adjustments
- [x] Display signal level and allow squelch control - [x] Display signal level and allow squelch control
- [x] Display audio output selection - [x] Display audio output selection
- [ ] Volume control - [x] Volume control
- [ ] Basic noise reduction / filter controls? - [ ] Basic noise reduction / filter controls?
- Basic Input Controls - Basic Input Controls
- [x] Drag spectrum to change center frequency - [x] Drag spectrum to change center frequency

View File

@ -158,19 +158,61 @@ AppFrame::AppFrame() :
menuBar->Append(menu, wxT("Active Demodulator &Output")); menuBar->Append(menu, wxT("Active Demodulator &Output"));
menu = new wxMenu; menu = new wxMenu;
menu->Append(wxID_THEME_DEFAULT, "Default"); menu->AppendRadioItem(wxID_THEME_DEFAULT, "Default")->Check(true);
menu->Append(wxID_THEME_RADAR, "RADAR"); menu->AppendRadioItem(wxID_THEME_RADAR, "RADAR");
menu->Append(wxID_THEME_BW, "Black & White"); menu->AppendRadioItem(wxID_THEME_BW, "Black & White");
menu->Append(wxID_THEME_SHARP, "Sharp"); menu->AppendRadioItem(wxID_THEME_SHARP, "Sharp");
menu->Append(wxID_THEME_RAD, "Rad"); menu->AppendRadioItem(wxID_THEME_RAD, "Rad");
menu->Append(wxID_THEME_TOUCH, "Touch"); menu->AppendRadioItem(wxID_THEME_TOUCH, "Touch");
menu->Append(wxID_THEME_HD, "HD"); menu->AppendRadioItem(wxID_THEME_HD, "HD");
menuBar->Append(menu, wxT("&Color Scheme")); menuBar->Append(menu, wxT("&Color Scheme"));
menu = new wxMenu;
sampleRateMenuItems[wxID_BANDWIDTH_1000M] = menu->AppendRadioItem(wxID_BANDWIDTH_1000M, "1.0M");
sampleRateMenuItems[wxID_BANDWIDTH_1500M] = menu->AppendRadioItem(wxID_BANDWIDTH_1500M, "1.5M");
sampleRateMenuItems[wxID_BANDWIDTH_2000M] = menu->AppendRadioItem(wxID_BANDWIDTH_2000M, "2.0M");
sampleRateMenuItems[wxID_BANDWIDTH_2500M] = menu->AppendRadioItem(wxID_BANDWIDTH_2500M, "2.5M");
sampleRateMenuItems[wxID_BANDWIDTH_2880M] = menu->AppendRadioItem(wxID_BANDWIDTH_2880M, "2.88M");
sampleRateMenuItems[wxID_BANDWIDTH_3200M] = menu->AppendRadioItem(wxID_BANDWIDTH_3200M, "3.2M");
#ifdef __APPLE
sampleRateMenuItems[wxID_BANDWIDTH_2000M]->Check(true);
#else
sampleRateMenuItems[wxID_BANDWIDTH_2500M]->Check(true);
#endif
menuBar->Append(menu, wxT("&Input Bandwidth"));
std::vector<SDRDeviceInfo *> *devs = wxGetApp().getDevices();
std::vector<SDRDeviceInfo *>::iterator devs_i;
if (devs->size() > 1) {
menu = new wxMenu;
int p = 0;
for (devs_i = devs->begin(); devs_i != devs->end(); devs_i++) {
std::string devName = (*devs_i)->getName();
if ((*devs_i)->isAvailable()) {
devName.append(": ");
devName.append((*devs_i)->getProduct());
devName.append(" [");
devName.append((*devs_i)->getSerial());
devName.append("]");
} else {
devName.append(" (In Use?)");
}
menu->AppendRadioItem(wxID_DEVICE_ID+p, devName)->Check(wxGetApp().getDevice() == p);
p++;
}
menuBar->Append(menu,wxT("&Device"));
}
SetMenuBar(menuBar); SetMenuBar(menuBar);
@ -262,6 +304,32 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
waterfallCanvas->setTheme(COLOR_THEME_RADAR); waterfallCanvas->setTheme(COLOR_THEME_RADAR);
demodWaterfallCanvas->setTheme(COLOR_THEME_RADAR); demodWaterfallCanvas->setTheme(COLOR_THEME_RADAR);
} }
switch (event.GetId()) {
case wxID_BANDWIDTH_1000M:
wxGetApp().setSampleRate(1000000);
break;
case wxID_BANDWIDTH_1500M:
wxGetApp().setSampleRate(1500000);
break;
case wxID_BANDWIDTH_2000M:
wxGetApp().setSampleRate(2000000);
break;
case wxID_BANDWIDTH_2500M:
wxGetApp().setSampleRate(2500000);
break;
case wxID_BANDWIDTH_2880M:
wxGetApp().setSampleRate(2880000);
break;
case wxID_BANDWIDTH_3200M:
wxGetApp().setSampleRate(3200000);
break;
}
std::vector<SDRDeviceInfo *> *devs = wxGetApp().getDevices();
if (event.GetId() >= wxID_DEVICE_ID && event.GetId() <= wxID_DEVICE_ID+devs->size()) {
wxGetApp().setDevice(event.GetId()-wxID_DEVICE_ID);
}
} }
void AppFrame::OnClose(wxCommandEvent& WXUNUSED(event)) { void AppFrame::OnClose(wxCommandEvent& WXUNUSED(event)) {
@ -307,8 +375,8 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
} }
unsigned int demodBw = (unsigned int) ceil((float) demod->getParams().bandwidth * 2.5); unsigned int demodBw = (unsigned int) ceil((float) demod->getParams().bandwidth * 2.5);
if (demodBw > SRATE / 2) { if (demodBw > wxGetApp().getSampleRate() / 2) {
demodBw = SRATE / 2; demodBw = wxGetApp().getSampleRate() / 2;
} }
if (demodBw < 80000) { if (demodBw < 80000) {
demodBw = 80000; demodBw = 80000;
@ -399,9 +467,8 @@ void AppFrame::saveSession(std::string fileName) {
s.SaveToFileXML(fileName); s.SaveToFileXML(fileName);
currentSessionFile = fileName; currentSessionFile = fileName;
std::string filePart = fileName.substr(fileName.find_last_of(filePathSeparator)+1); std::string filePart = fileName.substr(fileName.find_last_of(filePathSeparator) + 1);
GetStatusBar()->SetStatusText(wxString::Format(wxT("Saved session: %s"), currentSessionFile.c_str())); GetStatusBar()->SetStatusText(wxString::Format(wxT("Saved session: %s"), currentSessionFile.c_str()));
SetTitle(wxString::Format(wxT("%s: %s"), CUBICSDR_TITLE, filePart.c_str())); SetTitle(wxString::Format(wxT("%s: %s"), CUBICSDR_TITLE, filePart.c_str()));
} }
@ -425,8 +492,8 @@ bool AppFrame::loadSession(std::string fileName) {
std::cout << "\tCenter Frequency: " << center_freq << std::endl; std::cout << "\tCenter Frequency: " << center_freq << std::endl;
std::cout << "\tOffset: " << offset << std::endl; std::cout << "\tOffset: " << offset << std::endl;
wxGetApp().setOffset(offset);
wxGetApp().setFrequency(center_freq); wxGetApp().setFrequency(center_freq);
wxGetApp().setOffset(offset);
DataNode *demodulators = l.rootNode()->getNext("demodulators"); DataNode *demodulators = l.rootNode()->getNext("demodulators");
@ -494,7 +561,7 @@ bool AppFrame::loadSession(std::string fileName) {
currentSessionFile = fileName; currentSessionFile = fileName;
std::string filePart = fileName.substr(fileName.find_last_of(filePathSeparator)+1); std::string filePart = fileName.substr(fileName.find_last_of(filePathSeparator) + 1);
GetStatusBar()->SetStatusText(wxString::Format(wxT("Loaded session file: %s"), currentSessionFile.c_str())); GetStatusBar()->SetStatusText(wxString::Format(wxT("Loaded session file: %s"), currentSessionFile.c_str()));
SetTitle(wxString::Format(wxT("%s: %s"), CUBICSDR_TITLE, filePart.c_str())); SetTitle(wxString::Format(wxT("%s: %s"), CUBICSDR_TITLE, filePart.c_str()));

View File

@ -24,6 +24,16 @@
#define wxID_THEME_HD 2105 #define wxID_THEME_HD 2105
#define wxID_THEME_RADAR 2106 #define wxID_THEME_RADAR 2106
#define wxID_BANDWIDTH_1000M 2152
#define wxID_BANDWIDTH_1500M 2153
#define wxID_BANDWIDTH_2000M 2154
#define wxID_BANDWIDTH_2500M 2155
#define wxID_BANDWIDTH_2880M 2156
#define wxID_BANDWIDTH_3200M 2158
#define wxID_DEVICE_ID 3500
// Define a new frame type // Define a new frame type
class AppFrame: public wxFrame { class AppFrame: public wxFrame {
public: public:
@ -59,6 +69,9 @@ private:
std::map<int,RtAudio::DeviceInfo> outputDevices; std::map<int,RtAudio::DeviceInfo> outputDevices;
std::map<int,wxMenuItem *> outputDeviceMenuItems; std::map<int,wxMenuItem *> outputDeviceMenuItems;
std::map<int,wxMenuItem *> sampleRateMenuItems;
std::string currentSessionFile; std::string currentSessionFile;
wxDECLARE_EVENT_TABLE(); wxDECLARE_EVENT_TABLE();

View File

@ -39,6 +39,32 @@ bool CubicSDR::OnInit() {
sdrPostThread->setIQDataInQueue(iqPostDataQueue); sdrPostThread->setIQDataInQueue(iqPostDataQueue);
sdrPostThread->setIQVisualQueue(iqVisualQueue); sdrPostThread->setIQVisualQueue(iqVisualQueue);
std::vector<SDRDeviceInfo *>::iterator devs_i;
SDRThread::enumerate_rtl(&devs);
if (devs.size() > 1) {
wxArrayString choices;
for (devs_i = devs.begin(); devs_i != devs.end(); devs_i++) {
std::string devName = (*devs_i)->getName();
if ((*devs_i)->isAvailable()) {
devName.append(": ");
devName.append((*devs_i)->getProduct());
devName.append(" [");
devName.append((*devs_i)->getSerial());
devName.append("]");
} else {
devName.append(" (In Use?)");
}
choices.Add(devName);
}
int devId = wxGetSingleChoiceIndex(wxT("Devices"),wxT("Choose Input Device"),choices);
std::cout << "Chosen: " << devId << std::endl;
sdrThread->setDeviceId(devId);
}
t_PostSDR = new std::thread(&SDRPostThread::threadMain, sdrPostThread); t_PostSDR = new std::thread(&SDRPostThread::threadMain, sdrPostThread);
t_SDR = new std::thread(&SDRThread::threadMain, sdrThread); t_SDR = new std::thread(&SDRThread::threadMain, sdrThread);
@ -82,7 +108,6 @@ int CubicSDR::OnExit() {
delete m_glContext; delete m_glContext;
#ifdef __APPLE__ #ifdef __APPLE__
AudioThread::deviceCleanup(); AudioThread::deviceCleanup();
#endif #endif
@ -103,8 +128,8 @@ PrimaryGLContext& CubicSDR::GetContext(wxGLCanvas *canvas) {
} }
void CubicSDR::setFrequency(long long freq) { void CubicSDR::setFrequency(long long freq) {
if (freq < SRATE/2) { if (freq < sampleRate / 2) {
freq = SRATE/2; freq = sampleRate / 2;
} }
frequency = freq; frequency = freq;
SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_TUNE); SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_TUNE);
@ -146,9 +171,36 @@ void CubicSDR::bindDemodulator(DemodulatorInstance *demod) {
sdrPostThread->bindDemodulator(demod); sdrPostThread->bindDemodulator(demod);
} }
void CubicSDR::setSampleRate(long long rate_in) {
sampleRate = rate_in;
SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_SET_SAMPLERATE);
command.llong_value = rate_in;
threadCmdQueueSDR->push(command);
setFrequency(frequency);
}
long long CubicSDR::getSampleRate() {
return sampleRate;
}
void CubicSDR::removeDemodulator(DemodulatorInstance *demod) { void CubicSDR::removeDemodulator(DemodulatorInstance *demod) {
if (!demod) { if (!demod) {
return; return;
} }
sdrPostThread->removeDemodulator(demod); sdrPostThread->removeDemodulator(demod);
} }
std::vector<SDRDeviceInfo*>* CubicSDR::getDevices() {
return &devs;
}
void CubicSDR::setDevice(int deviceId) {
sdrThread->setDeviceId(deviceId);
SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_SET_DEVICE);
command.llong_value = deviceId;
threadCmdQueueSDR->push(command);
}
int CubicSDR::getDevice() {
return sdrThread->getDeviceId();
}

View File

@ -20,7 +20,7 @@
class CubicSDR: public wxApp { class CubicSDR: public wxApp {
public: public:
CubicSDR() : CubicSDR() :
m_glContext(NULL), frequency(DEFAULT_FREQ), sdrThread(NULL), sdrPostThread(NULL), threadCmdQueueSDR(NULL), iqVisualQueue(NULL), iqPostDataQueue(NULL), audioVisualQueue(NULL), t_SDR(NULL), t_PostSDR(NULL) { m_glContext(NULL), frequency(DEFAULT_FREQ), sdrThread(NULL), sdrPostThread(NULL), threadCmdQueueSDR(NULL), iqVisualQueue(NULL), iqPostDataQueue(NULL), audioVisualQueue(NULL), t_SDR(NULL), t_PostSDR(NULL), sampleRate(DEFAULT_SAMPLE_RATE) {
} }
@ -35,6 +35,13 @@ public:
void setOffset(long long ofs); void setOffset(long long ofs);
long long getOffset(); long long getOffset();
void setSampleRate(long long rate_in);
long long getSampleRate();
std::vector<SDRDeviceInfo *> *getDevices();
void setDevice(int deviceId);
int getDevice();
DemodulatorThreadOutputQueue* getAudioVisualQueue(); DemodulatorThreadOutputQueue* getAudioVisualQueue();
DemodulatorThreadInputQueue* getIQVisualQueue(); DemodulatorThreadInputQueue* getIQVisualQueue();
DemodulatorMgr &getDemodMgr(); DemodulatorMgr &getDemodMgr();
@ -44,11 +51,13 @@ public:
private: private:
PrimaryGLContext *m_glContext; PrimaryGLContext *m_glContext;
std::vector<SDRDeviceInfo *> devs;
DemodulatorMgr demodMgr; DemodulatorMgr demodMgr;
long long frequency; long long frequency;
long long offset; long long offset;
long long sampleRate;
SDRThread *sdrThread; SDRThread *sdrThread;
SDRPostThread *sdrPostThread; SDRPostThread *sdrPostThread;

View File

@ -12,10 +12,10 @@ const char filePathSeparator =
#ifdef __APPLE__ #ifdef __APPLE__
#define BUF_SIZE (16384*2) #define BUF_SIZE (16384*2)
#define SRATE 2000000 #define DEFAULT_SAMPLE_RATE 2000000
#else #else
#define BUF_SIZE (16384*5) #define BUF_SIZE (16384*5)
#define SRATE 2500000 #define DEFAULT_SAMPLE_RATE 2500000
#endif #endif
#define DEFAULT_FFT_SIZE 2048 #define DEFAULT_FFT_SIZE 2048

View File

@ -421,13 +421,12 @@ void AudioThread::threadMain() {
} }
#endif #endif
std::cout << "Audio thread done." << std::endl;
if (threadQueueNotify != NULL) { if (threadQueueNotify != NULL) {
DemodulatorThreadCommand tCmd(DemodulatorThreadCommand::DEMOD_THREAD_CMD_AUDIO_TERMINATED); DemodulatorThreadCommand tCmd(DemodulatorThreadCommand::DEMOD_THREAD_CMD_AUDIO_TERMINATED);
tCmd.context = this; tCmd.context = this;
threadQueueNotify->push(tCmd); threadQueueNotify->push(tCmd);
} }
std::cout << "Audio thread done." << std::endl;
} }
void AudioThread::terminate() { void AudioThread::terminate() {

View File

@ -14,7 +14,6 @@
#define DEMOD_TYPE_USB 4 #define DEMOD_TYPE_USB 4
#define DEMOD_TYPE_DSB 5 #define DEMOD_TYPE_DSB 5
class DemodulatorThread; class DemodulatorThread;
class DemodulatorThreadCommand { class DemodulatorThreadCommand {
public: public:
@ -59,11 +58,11 @@ public:
class DemodulatorThreadIQData: public ReferenceCounter { class DemodulatorThreadIQData: public ReferenceCounter {
public: public:
long long frequency; long long frequency;
unsigned int bandwidth; long long sampleRate;
std::vector<liquid_float_complex> data; std::vector<liquid_float_complex> data;
DemodulatorThreadIQData() : DemodulatorThreadIQData() :
frequency(0), bandwidth(0) { frequency(0), sampleRate(0) {
} }
@ -75,13 +74,13 @@ public:
class DemodulatorThreadPostIQData: public ReferenceCounter { class DemodulatorThreadPostIQData: public ReferenceCounter {
public: public:
std::vector<liquid_float_complex> data; std::vector<liquid_float_complex> data;
int bandwidth; long long sampleRate;
msresamp_rrrf audioResampler; msresamp_rrrf audioResampler;
msresamp_rrrf stereoResampler; msresamp_rrrf stereoResampler;
double audioResampleRatio; double audioResampleRatio;
DemodulatorThreadPostIQData() : DemodulatorThreadPostIQData() :
bandwidth(0), audioResampler(NULL), stereoResampler(NULL), audioResampleRatio(0) { sampleRate(0), audioResampler(NULL), stereoResampler(NULL), audioResampleRatio(0) {
} }
@ -121,14 +120,14 @@ typedef ThreadQueue<DemodulatorThreadControlCommand> DemodulatorThreadControlCom
class DemodulatorThreadParameters { class DemodulatorThreadParameters {
public: public:
long long frequency; long long frequency;
unsigned int inputRate; long long sampleRate;
unsigned int bandwidth; // set equal to disable second stage re-sampling? unsigned int bandwidth; // set equal to disable second stage re-sampling?
unsigned int audioSampleRate; unsigned int audioSampleRate;
int demodType; int demodType;
DemodulatorThreadParameters() : DemodulatorThreadParameters() :
frequency(0), inputRate(SRATE), bandwidth(200000), audioSampleRate( frequency(0), sampleRate(DEFAULT_SAMPLE_RATE), bandwidth(200000), audioSampleRate(
AUDIO_FREQUENCY), demodType(DEMOD_TYPE_FM) { AUDIO_FREQUENCY), demodType(DEMOD_TYPE_FM) {
} }

View File

@ -126,12 +126,14 @@ bool DemodulatorInstance::isTerminated() {
case DemodulatorThreadCommand::DEMOD_THREAD_CMD_AUDIO_TERMINATED: case DemodulatorThreadCommand::DEMOD_THREAD_CMD_AUDIO_TERMINATED:
t_Audio->join(); t_Audio->join();
audioTerminated = true; audioTerminated = true;
delete t_Audio;
break; break;
case DemodulatorThreadCommand::DEMOD_THREAD_CMD_DEMOD_TERMINATED: case DemodulatorThreadCommand::DEMOD_THREAD_CMD_DEMOD_TERMINATED:
#ifdef __APPLE__ #ifdef __APPLE__
pthread_join(t_Demod, NULL); pthread_join(t_Demod, NULL);
#else #else
t_Demod->join(); t_Demod->join();
delete t_Demod;
#endif #endif
demodTerminated = true; demodTerminated = true;
break; break;
@ -140,6 +142,7 @@ bool DemodulatorInstance::isTerminated() {
pthread_join(t_PreDemod, NULL); pthread_join(t_PreDemod, NULL);
#else #else
t_PreDemod->join(); t_PreDemod->join();
delete t_PreDemod;
#endif #endif
preDemodTerminated = true; preDemodTerminated = true;
break; break;

View File

@ -6,6 +6,7 @@
#endif #endif
#include "DemodulatorPreThread.h" #include "DemodulatorPreThread.h"
#include "CubicSDR.h"
DemodulatorPreThread::DemodulatorPreThread(DemodulatorThreadInputQueue* iqInputQueue, DemodulatorThreadPostInputQueue* iqOutputQueue, DemodulatorPreThread::DemodulatorPreThread(DemodulatorThreadInputQueue* iqInputQueue, DemodulatorThreadPostInputQueue* iqOutputQueue,
DemodulatorThreadControlCommandQueue *threadQueueControl, DemodulatorThreadCommandQueue* threadQueueNotify) : DemodulatorThreadControlCommandQueue *threadQueueControl, DemodulatorThreadCommandQueue* threadQueueNotify) :
@ -26,7 +27,7 @@ DemodulatorPreThread::DemodulatorPreThread(DemodulatorThreadInputQueue* iqInputQ
void DemodulatorPreThread::initialize() { void DemodulatorPreThread::initialize() {
initialized = false; initialized = false;
iqResampleRatio = (double) (params.bandwidth) / (double) params.inputRate; iqResampleRatio = (double) (params.bandwidth) / (double) params.sampleRate;
audioResampleRatio = (double) (params.audioSampleRate) / (double) params.bandwidth; audioResampleRatio = (double) (params.audioSampleRate) / (double) params.bandwidth;
float As = 120.0f; // stop-band attenuation [dB] float As = 120.0f; // stop-band attenuation [dB]
@ -77,10 +78,10 @@ void DemodulatorPreThread::threadMain() {
iqInputQueue->pop(inp); iqInputQueue->pop(inp);
bool bandwidthChanged = false; bool bandwidthChanged = false;
DemodulatorThreadParameters bandwidthParams = params; bool rateChanged = false;
DemodulatorThreadParameters tempParams = params;
if (!commandQueue->empty()) { if (!commandQueue->empty()) {
bool paramsChanged = false;
while (!commandQueue->empty()) { while (!commandQueue->empty()) {
DemodulatorThreadCommand command; DemodulatorThreadCommand command;
commandQueue->pop(command); commandQueue->pop(command);
@ -89,10 +90,11 @@ void DemodulatorPreThread::threadMain() {
if (command.llong_value < 1500) { if (command.llong_value < 1500) {
command.llong_value = 1500; command.llong_value = 1500;
} }
if (command.llong_value > SRATE) { if (command.llong_value > params.sampleRate) {
command.llong_value = SRATE; tempParams.bandwidth = params.sampleRate;
} else {
tempParams.bandwidth = command.llong_value;
} }
bandwidthParams.bandwidth = command.llong_value;
bandwidthChanged = true; bandwidthChanged = true;
break; break;
case DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_FREQUENCY: case DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_FREQUENCY:
@ -100,16 +102,21 @@ void DemodulatorPreThread::threadMain() {
break; break;
} }
} }
}
if (bandwidthChanged) { if (inp->sampleRate != tempParams.sampleRate) {
DemodulatorWorkerThreadCommand command(DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_BUILD_FILTERS); tempParams.sampleRate = inp->sampleRate;
command.audioSampleRate = bandwidthParams.audioSampleRate; rateChanged = true;
command.bandwidth = bandwidthParams.bandwidth; }
command.frequency = bandwidthParams.frequency;
command.inputRate = bandwidthParams.inputRate;
workerQueue->push(command); if (bandwidthChanged || rateChanged) {
} DemodulatorWorkerThreadCommand command(DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_BUILD_FILTERS);
command.sampleRate = tempParams.sampleRate;
command.audioSampleRate = tempParams.audioSampleRate;
command.bandwidth = tempParams.bandwidth;
command.frequency = tempParams.frequency;
workerQueue->push(command);
} }
if (!initialized) { if (!initialized) {
@ -118,21 +125,21 @@ void DemodulatorPreThread::threadMain() {
// Requested frequency is not center, shift it into the center! // Requested frequency is not center, shift it into the center!
if (inp->frequency != params.frequency) { if (inp->frequency != params.frequency) {
if ((params.frequency - inp->frequency) != shiftFrequency) { if ((params.frequency - inp->frequency) != shiftFrequency || rateChanged) {
shiftFrequency = params.frequency - inp->frequency; shiftFrequency = params.frequency - inp->frequency;
if (abs(shiftFrequency) <= (int) ((double) (SRATE / 2) * 1.5)) { if (abs(shiftFrequency) <= (int) ((double) (wxGetApp().getSampleRate() / 2) * 1.5)) {
nco_crcf_set_frequency(freqShifter, (2.0 * M_PI) * (((double) abs(shiftFrequency)) / ((double) SRATE))); nco_crcf_set_frequency(freqShifter, (2.0 * M_PI) * (((double) abs(shiftFrequency)) / ((double) wxGetApp().getSampleRate())));
} }
} }
} }
if (abs(shiftFrequency) > (int) ((double) (SRATE / 2) * 1.5)) { if (abs(shiftFrequency) > (int) ((double) (wxGetApp().getSampleRate() / 2) * 1.5)) {
continue; continue;
} }
// std::lock_guard < std::mutex > lock(inp->m_mutex); // std::lock_guard < std::mutex > lock(inp->m_mutex);
std::vector<liquid_float_complex> *data = &inp->data; std::vector<liquid_float_complex> *data = &inp->data;
if (data->size()) { if (data->size() && (inp->sampleRate == params.sampleRate)) {
int bufSize = data->size(); int bufSize = data->size();
if (in_buf_data.size() != bufSize) { if (in_buf_data.size() != bufSize) {
@ -193,7 +200,7 @@ void DemodulatorPreThread::threadMain() {
resamp->audioResampleRatio = audioResampleRatio; resamp->audioResampleRatio = audioResampleRatio;
resamp->audioResampler = audioResampler; resamp->audioResampler = audioResampler;
resamp->stereoResampler = stereoResampler; resamp->stereoResampler = stereoResampler;
resamp->bandwidth = params.bandwidth; resamp->sampleRate = params.bandwidth;
iqOutputQueue->push(resamp); iqOutputQueue->push(resamp);
} }
@ -209,16 +216,16 @@ void DemodulatorPreThread::threadMain() {
case DemodulatorWorkerThreadResult::DEMOD_WORKER_THREAD_RESULT_FILTERS: case DemodulatorWorkerThreadResult::DEMOD_WORKER_THREAD_RESULT_FILTERS:
msresamp_crcf_destroy(iqResampler); msresamp_crcf_destroy(iqResampler);
iqResampler = result.resampler; iqResampler = result.iqResampler;
audioResampler = result.audioResampler; audioResampler = result.audioResampler;
stereoResampler = result.stereoResampler; stereoResampler = result.stereoResampler;
iqResampleRatio = result.resamplerRatio; iqResampleRatio = result.iqResampleRatio;
audioResampleRatio = result.audioResamplerRatio; audioResampleRatio = result.audioResamplerRatio;
params.audioSampleRate = result.audioSampleRate; params.audioSampleRate = result.audioSampleRate;
params.bandwidth = result.bandwidth; params.bandwidth = result.bandwidth;
params.inputRate = result.inputRate; params.sampleRate = result.sampleRate;
break; break;
} }
@ -232,10 +239,10 @@ void DemodulatorPreThread::threadMain() {
delete iqDataDel; delete iqDataDel;
} }
std::cout << "Demodulator preprocessor thread done." << std::endl;
DemodulatorThreadCommand tCmd(DemodulatorThreadCommand::DEMOD_THREAD_CMD_DEMOD_PREPROCESS_TERMINATED); DemodulatorThreadCommand tCmd(DemodulatorThreadCommand::DEMOD_THREAD_CMD_DEMOD_PREPROCESS_TERMINATED);
tCmd.context = this; tCmd.context = this;
threadQueueNotify->push(tCmd); threadQueueNotify->push(tCmd);
std::cout << "Demodulator preprocessor thread done." << std::endl;
} }
void DemodulatorPreThread::terminate() { void DemodulatorPreThread::terminate() {
@ -243,4 +250,6 @@ void DemodulatorPreThread::terminate() {
DemodulatorThreadIQData *inp = new DemodulatorThreadIQData; // push dummy to nudge queue DemodulatorThreadIQData *inp = new DemodulatorThreadIQData; // push dummy to nudge queue
iqInputQueue->push(inp); iqInputQueue->push(inp);
workerThread->terminate(); workerThread->terminate();
t_Worker->detach();
delete t_Worker;
} }

View File

@ -217,7 +217,7 @@ void DemodulatorThread::threadMain() {
demodStereoData.resize(bufSize); demodStereoData.resize(bufSize);
} }
double freq = (2.0 * M_PI) * (((double) abs(38000)) / ((double) inp->bandwidth)); double freq = (2.0 * M_PI) * (((double) abs(38000)) / ((double) inp->sampleRate));
if (stereoShiftFrequency != freq) { if (stereoShiftFrequency != freq) {
nco_crcf_set_frequency(stereoShifter, freq); nco_crcf_set_frequency(stereoShifter, freq);
@ -406,10 +406,10 @@ void DemodulatorThread::threadMain() {
delete audioDataDel; delete audioDataDel;
} }
std::cout << "Demodulator thread done." << std::endl;
DemodulatorThreadCommand tCmd(DemodulatorThreadCommand::DEMOD_THREAD_CMD_DEMOD_TERMINATED); DemodulatorThreadCommand tCmd(DemodulatorThreadCommand::DEMOD_THREAD_CMD_DEMOD_TERMINATED);
tCmd.context = this; tCmd.context = this;
threadQueueNotify->push(tCmd); threadQueueNotify->push(tCmd);
std::cout << "Demodulator thread done." << std::endl;
} }
void DemodulatorThread::setVisualOutputQueue(DemodulatorThreadOutputQueue *tQueue) { void DemodulatorThread::setVisualOutputQueue(DemodulatorThreadOutputQueue *tQueue) {

View File

@ -31,21 +31,21 @@ void DemodulatorWorkerThread::threadMain() {
done = commandQueue->empty(); done = commandQueue->empty();
} }
if (filterChanged) { if (filterChanged && !terminated) {
DemodulatorWorkerThreadResult result(DemodulatorWorkerThreadResult::DEMOD_WORKER_THREAD_RESULT_FILTERS); DemodulatorWorkerThreadResult result(DemodulatorWorkerThreadResult::DEMOD_WORKER_THREAD_RESULT_FILTERS);
result.resamplerRatio = (double) (filterCommand.bandwidth) / (double) filterCommand.inputRate; result.iqResampleRatio = (double) (filterCommand.bandwidth) / (double) filterCommand.sampleRate;
result.audioResamplerRatio = (double) (filterCommand.audioSampleRate) / (double) filterCommand.bandwidth; result.audioResamplerRatio = (double) (filterCommand.audioSampleRate) / (double) filterCommand.bandwidth;
float As = 60.0f; // stop-band attenuation [dB] float As = 60.0f; // stop-band attenuation [dB]
result.resampler = msresamp_crcf_create(result.resamplerRatio, As); result.iqResampler = msresamp_crcf_create(result.iqResampleRatio, As);
result.audioResampler = msresamp_rrrf_create(result.audioResamplerRatio, As); result.audioResampler = msresamp_rrrf_create(result.audioResamplerRatio, As);
result.stereoResampler = msresamp_rrrf_create(result.audioResamplerRatio, As); result.stereoResampler = msresamp_rrrf_create(result.audioResamplerRatio, As);
result.audioSampleRate = filterCommand.audioSampleRate; result.audioSampleRate = filterCommand.audioSampleRate;
result.bandwidth = filterCommand.bandwidth; result.bandwidth = filterCommand.bandwidth;
result.inputRate = filterCommand.inputRate; result.sampleRate = filterCommand.sampleRate;
resultQueue->push(result); resultQueue->push(result);
} }

View File

@ -22,26 +22,26 @@ public:
}; };
DemodulatorWorkerThreadResult() : DemodulatorWorkerThreadResult() :
cmd(DEMOD_WORKER_THREAD_RESULT_NULL), resampler(NULL), resamplerRatio(0), audioResampler(NULL), stereoResampler(NULL), audioResamplerRatio( cmd(DEMOD_WORKER_THREAD_RESULT_NULL), iqResampler(NULL), iqResampleRatio(0), audioResampler(NULL), stereoResampler(NULL), audioResamplerRatio(
0), inputRate(0), bandwidth(0), audioSampleRate(0) { 0), sampleRate(0), bandwidth(0), audioSampleRate(0) {
} }
DemodulatorWorkerThreadResult(DemodulatorThreadResultEnum cmd) : DemodulatorWorkerThreadResult(DemodulatorThreadResultEnum cmd) :
cmd(cmd), resampler(NULL), resamplerRatio(0), audioResampler(NULL), stereoResampler(NULL), audioResamplerRatio(0), inputRate(0), bandwidth( cmd(cmd), iqResampler(NULL), iqResampleRatio(0), audioResampler(NULL), stereoResampler(NULL), audioResamplerRatio(0), sampleRate(0), bandwidth(
0), audioSampleRate(0) { 0), audioSampleRate(0) {
} }
DemodulatorThreadResultEnum cmd; DemodulatorThreadResultEnum cmd;
msresamp_crcf resampler; msresamp_crcf iqResampler;
double resamplerRatio; double iqResampleRatio;
msresamp_rrrf audioResampler; msresamp_rrrf audioResampler;
msresamp_rrrf stereoResampler; msresamp_rrrf stereoResampler;
double audioResamplerRatio; double audioResamplerRatio;
unsigned int inputRate; long long sampleRate;
unsigned int bandwidth; unsigned int bandwidth;
unsigned int audioSampleRate; unsigned int audioSampleRate;
@ -54,19 +54,19 @@ public:
}; };
DemodulatorWorkerThreadCommand() : DemodulatorWorkerThreadCommand() :
cmd(DEMOD_WORKER_THREAD_CMD_NULL), frequency(0), inputRate(0), bandwidth(0), audioSampleRate(0) { cmd(DEMOD_WORKER_THREAD_CMD_NULL), frequency(0), sampleRate(0), bandwidth(0), audioSampleRate(0) {
} }
DemodulatorWorkerThreadCommand(DemodulatorThreadCommandEnum cmd) : DemodulatorWorkerThreadCommand(DemodulatorThreadCommandEnum cmd) :
cmd(cmd), frequency(0), inputRate(0), bandwidth(0), audioSampleRate(0) { cmd(cmd), frequency(0), sampleRate(0), bandwidth(0), audioSampleRate(0) {
} }
DemodulatorThreadCommandEnum cmd; DemodulatorThreadCommandEnum cmd;
long long frequency; long long frequency;
unsigned int inputRate; long long sampleRate;
unsigned int bandwidth; unsigned int bandwidth;
unsigned int audioSampleRate; unsigned int audioSampleRate;
}; };

View File

@ -6,7 +6,7 @@
#include <deque> #include <deque>
SDRPostThread::SDRPostThread() : SDRPostThread::SDRPostThread() :
sample_rate(SRATE), iqDataOutQueue(NULL), iqDataInQueue(NULL), iqVisualQueue(NULL), terminated(false), dcFilter(NULL), num_vis_samples(2048) { iqDataOutQueue(NULL), iqDataInQueue(NULL), iqVisualQueue(NULL), terminated(false), dcFilter(NULL), num_vis_samples(2048) {
} }
SDRPostThread::~SDRPostThread() { SDRPostThread::~SDRPostThread() {
@ -90,7 +90,7 @@ void SDRPostThread::threadMain() {
DemodulatorThreadIQData *pipeDataOut = new DemodulatorThreadIQData; DemodulatorThreadIQData *pipeDataOut = new DemodulatorThreadIQData;
pipeDataOut->frequency = data_in->frequency; pipeDataOut->frequency = data_in->frequency;
pipeDataOut->bandwidth = data_in->bandwidth; pipeDataOut->sampleRate = data_in->sampleRate;
pipeDataOut->data.assign(dataOut.begin(), dataOut.end()); pipeDataOut->data.assign(dataOut.begin(), dataOut.end());
iqDataOutQueue.load()->push(pipeDataOut); iqDataOutQueue.load()->push(pipeDataOut);
} }
@ -98,7 +98,7 @@ void SDRPostThread::threadMain() {
if (iqVisualQueue != NULL && iqVisualQueue.load()->empty()) { if (iqVisualQueue != NULL && iqVisualQueue.load()->empty()) {
DemodulatorThreadIQData *visualDataOut = new DemodulatorThreadIQData; DemodulatorThreadIQData *visualDataOut = new DemodulatorThreadIQData;
visualDataOut->frequency = data_in->frequency; visualDataOut->frequency = data_in->frequency;
visualDataOut->bandwidth = data_in->bandwidth; visualDataOut->sampleRate = data_in->sampleRate;
visualDataOut->data.assign(dataOut.begin(), dataOut.begin() + num_vis_samples); visualDataOut->data.assign(dataOut.begin(), dataOut.begin() + num_vis_samples);
iqVisualQueue.load()->push(visualDataOut); iqVisualQueue.load()->push(visualDataOut);
} }
@ -131,7 +131,7 @@ void SDRPostThread::threadMain() {
for (i = demodulators.begin(); i != demodulators.end(); i++) { for (i = demodulators.begin(); i != demodulators.end(); i++) {
DemodulatorInstance *demod = *i; DemodulatorInstance *demod = *i;
if (demod->getFrequency() != data_in->frequency if (demod->getFrequency() != data_in->frequency
&& abs(data_in->frequency - demod->getFrequency()) > (SRATE / 2)) { && abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) {
continue; continue;
} }
activeDemods++; activeDemods++;
@ -155,7 +155,7 @@ void SDRPostThread::threadMain() {
// std::lock_guard < std::mutex > lock(demodDataOut->m_mutex); // std::lock_guard < std::mutex > lock(demodDataOut->m_mutex);
demodDataOut->frequency = data_in->frequency; demodDataOut->frequency = data_in->frequency;
demodDataOut->bandwidth = data_in->bandwidth; demodDataOut->sampleRate = data_in->sampleRate;
demodDataOut->setRefCount(activeDemods); demodDataOut->setRefCount(activeDemods);
demodDataOut->data.assign(dataOut.begin(), dataOut.end()); demodDataOut->data.assign(dataOut.begin(), dataOut.end());
@ -165,12 +165,12 @@ void SDRPostThread::threadMain() {
DemodulatorThreadInputQueue *demodQueue = demod->threadQueueDemod; DemodulatorThreadInputQueue *demodQueue = demod->threadQueueDemod;
if (demod->getFrequency() != data_in->frequency if (demod->getFrequency() != data_in->frequency
&& abs(data_in->frequency - demod->getFrequency()) > (SRATE / 2)) { && abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) {
if (demod->isActive()) { if (demod->isActive()) {
demod->setActive(false); demod->setActive(false);
DemodulatorThreadIQData *dummyDataOut = new DemodulatorThreadIQData; DemodulatorThreadIQData *dummyDataOut = new DemodulatorThreadIQData;
dummyDataOut->frequency = data_in->frequency; dummyDataOut->frequency = data_in->frequency;
dummyDataOut->bandwidth = data_in->bandwidth; dummyDataOut->sampleRate = data_in->sampleRate;
demodQueue->push(dummyDataOut); demodQueue->push(dummyDataOut);
} }
} else if (!demod->isActive()) { } else if (!demod->isActive()) {

View File

@ -22,8 +22,6 @@ public:
void terminate(); void terminate();
protected: protected:
uint32_t sample_rate;
std::atomic<SDRThreadIQDataQueue *> iqDataInQueue; std::atomic<SDRThreadIQDataQueue *> iqDataInQueue;
std::atomic<DemodulatorThreadInputQueue *> iqDataOutQueue; std::atomic<DemodulatorThreadInputQueue *> iqDataOutQueue;
std::atomic<DemodulatorThreadInputQueue *> iqVisualQueue; std::atomic<DemodulatorThreadInputQueue *> iqVisualQueue;

View File

@ -4,16 +4,16 @@
#include "CubicSDR.h" #include "CubicSDR.h"
SDRThread::SDRThread(SDRThreadCommandQueue* pQueue) : SDRThread::SDRThread(SDRThreadCommandQueue* pQueue) :
commandQueue(pQueue), iqDataOutQueue(NULL), terminated(false), offset(0) { commandQueue(pQueue), iqDataOutQueue(NULL), terminated(false), offset(0), deviceId(-1) {
dev = NULL; dev = NULL;
sampleRate = SRATE; sampleRate = DEFAULT_SAMPLE_RATE;
} }
SDRThread::~SDRThread() { SDRThread::~SDRThread() {
rtlsdr_close(dev); rtlsdr_close(dev);
} }
int SDRThread::enumerate_rtl() { int SDRThread::enumerate_rtl(std::vector<SDRDeviceInfo *> *devs) {
int first_available = -1; int first_available = -1;
@ -24,37 +24,51 @@ int SDRThread::enumerate_rtl() {
std::cout << "RTL Devices: " << rtl_count << std::endl; std::cout << "RTL Devices: " << rtl_count << std::endl;
for (int i = 0; i < rtl_count; i++) { for (int i = 0; i < rtl_count; i++) {
std::cout << "Device #" << i << ": " << rtlsdr_get_device_name(i) << std::endl; std::string deviceName(rtlsdr_get_device_name(i));
std::string deviceManufacturer;
std::string deviceProduct;
std::string deviceTuner;
std::string deviceSerial;
bool deviceAvailable = false;
std::cout << "Device #" << i << ": " << deviceName << std::endl;
if (rtlsdr_get_device_usb_strings(i, manufact, product, serial) == 0) { if (rtlsdr_get_device_usb_strings(i, manufact, product, serial) == 0) {
std::cout << "\tManufacturer: " << manufact << ", Product Name: " << product << ", Serial: " << serial << std::endl; std::cout << "\tManufacturer: " << manufact << ", Product Name: " << product << ", Serial: " << serial << std::endl;
rtlsdr_open(&dev, i); deviceSerial = serial;
deviceAvailable = true;
deviceProduct = product;
deviceManufacturer = manufact;
rtlsdr_dev_t *devTest;
rtlsdr_open(&devTest, i);
std::cout << "\t Tuner type: "; std::cout << "\t Tuner type: ";
switch (rtlsdr_get_tuner_type(dev)) { switch (rtlsdr_get_tuner_type(devTest)) {
case RTLSDR_TUNER_UNKNOWN: case RTLSDR_TUNER_UNKNOWN:
std::cout << "Unknown"; deviceTuner = "Unknown";
break; break;
case RTLSDR_TUNER_E4000: case RTLSDR_TUNER_E4000:
std::cout << "Elonics E4000"; deviceTuner = "Elonics E4000";
break; break;
case RTLSDR_TUNER_FC0012: case RTLSDR_TUNER_FC0012:
std::cout << "Fitipower FC0012"; deviceTuner = "Fitipower FC0012";
break; break;
case RTLSDR_TUNER_FC0013: case RTLSDR_TUNER_FC0013:
std::cout << "Fitipower FC0013"; deviceTuner = "Fitipower FC0013";
break; break;
case RTLSDR_TUNER_FC2580: case RTLSDR_TUNER_FC2580:
std::cout << "Fitipower FC2580"; deviceTuner = "Fitipower FC2580";
break; break;
case RTLSDR_TUNER_R820T: case RTLSDR_TUNER_R820T:
std::cout << "Rafael Micro R820T"; deviceTuner = "Rafael Micro R820T";
break; break;
case RTLSDR_TUNER_R828D: case RTLSDR_TUNER_R828D:
deviceTuner = "Rafael Micro R828D";
break; break;
} }
std::cout << std::endl; std::cout << deviceTuner << std::endl;
/* /*
int num_gains = rtlsdr_get_tuner_gains(dev, NULL); int num_gains = rtlsdr_get_tuner_gains(dev, NULL);
@ -73,7 +87,7 @@ int SDRThread::enumerate_rtl() {
free(gains); free(gains);
*/ */
rtlsdr_close(dev); rtlsdr_close(devTest);
if (first_available == -1) { if (first_available == -1) {
first_available = i; first_available = i;
} }
@ -82,6 +96,15 @@ int SDRThread::enumerate_rtl() {
std::cout << "\tUnable to access device #" << i << " (in use?)" << std::endl; std::cout << "\tUnable to access device #" << i << " (in use?)" << std::endl;
} }
if (devs != NULL) {
SDRDeviceInfo *devInfo = new SDRDeviceInfo();
devInfo->setName(deviceName);
devInfo->setAvailable(deviceAvailable);
devInfo->setProduct(deviceProduct);
devInfo->setSerial(deviceSerial);
devInfo->setManufacturer(deviceManufacturer);
devs->push_back(devInfo);
}
} }
return first_available; return first_available;
@ -92,35 +115,36 @@ void SDRThread::threadMain() {
#ifdef __APPLE__ #ifdef __APPLE__
pthread_t tID = pthread_self(); // ID of this thread pthread_t tID = pthread_self(); // ID of this thread
int priority = sched_get_priority_max( SCHED_FIFO) - 1; int priority = sched_get_priority_max( SCHED_FIFO) - 1;
sched_param prio = {priority}; // scheduling priority of thread sched_param prio = { priority }; // scheduling priority of thread
pthread_setschedparam(tID, SCHED_FIFO, &prio); pthread_setschedparam(tID, SCHED_FIFO, &prio);
#endif #endif
std::cout << "SDR thread initializing.." << std::endl; std::cout << "SDR thread initializing.." << std::endl;
int devCount = rtlsdr_get_device_count(); int devCount = rtlsdr_get_device_count();
int firstDevAvailable = enumerate_rtl(); if (deviceId == -1) {
deviceId = enumerate_rtl(NULL);
}
if (firstDevAvailable == -1) { if (deviceId == -1) {
std::cout << "No devices found.. SDR Thread exiting.." << std::endl; std::cout << "No devices found.. SDR Thread exiting.." << std::endl;
return; return;
} else { } else {
std::cout << "Using first available RTL-SDR device #" << firstDevAvailable << std::endl; std::cout << "Using device #" << deviceId << std::endl;
} }
signed char buf[BUF_SIZE]; signed char buf[BUF_SIZE];
long long frequency = DEFAULT_FREQ; long long frequency = DEFAULT_FREQ;
unsigned int bandwidth = SRATE;
rtlsdr_open(&dev, firstDevAvailable); rtlsdr_open(&dev, deviceId);
rtlsdr_set_sample_rate(dev, bandwidth); rtlsdr_set_sample_rate(dev, sampleRate);
rtlsdr_set_center_freq(dev, frequency); rtlsdr_set_center_freq(dev, frequency - offset);
rtlsdr_set_agc_mode(dev, 1); rtlsdr_set_agc_mode(dev, 1);
rtlsdr_set_offset_tuning(dev, 0); rtlsdr_set_offset_tuning(dev, 0);
rtlsdr_reset_buffer(dev); rtlsdr_reset_buffer(dev);
sampleRate = rtlsdr_get_sample_rate(dev); // sampleRate = rtlsdr_get_sample_rate(dev);
std::cout << "Sample Rate is: " << sampleRate << std::endl; std::cout << "Sample Rate is: " << sampleRate << std::endl;
@ -138,8 +162,12 @@ void SDRThread::threadMain() {
if (!cmdQueue->empty()) { if (!cmdQueue->empty()) {
bool freq_changed = false; bool freq_changed = false;
bool offset_changed = false; bool offset_changed = false;
bool rate_changed = false;
bool device_changed = false;
long long new_freq; long long new_freq;
long long new_offset; long long new_offset;
long long new_rate;
int new_device;
while (!cmdQueue->empty()) { while (!cmdQueue->empty()) {
SDRThreadCommand command; SDRThreadCommand command;
@ -149,8 +177,8 @@ void SDRThread::threadMain() {
case SDRThreadCommand::SDR_THREAD_CMD_TUNE: case SDRThreadCommand::SDR_THREAD_CMD_TUNE:
freq_changed = true; freq_changed = true;
new_freq = command.llong_value; new_freq = command.llong_value;
if (new_freq < SRATE / 2) { if (new_freq < sampleRate / 2) {
new_freq = SRATE / 2; new_freq = sampleRate / 2;
} }
std::cout << "Set frequency: " << new_freq << std::endl; std::cout << "Set frequency: " << new_freq << std::endl;
break; break;
@ -159,19 +187,41 @@ void SDRThread::threadMain() {
new_offset = command.llong_value; new_offset = command.llong_value;
std::cout << "Set offset: " << new_offset << std::endl; std::cout << "Set offset: " << new_offset << std::endl;
break; break;
case SDRThreadCommand::SDR_THREAD_CMD_SET_SAMPLERATE:
rate_changed = true;
new_rate = command.llong_value;
std::cout << "Set sample rate: " << new_rate << std::endl;
break;
case SDRThreadCommand::SDR_THREAD_CMD_SET_DEVICE:
device_changed = true;
new_device = (int) command.llong_value;
std::cout << "Set device: " << new_device << std::endl;
break;
default: default:
break; break;
} }
} }
if (device_changed) {
rtlsdr_close(dev);
rtlsdr_open(&dev, new_device);
rtlsdr_set_sample_rate(dev, sampleRate);
rtlsdr_set_center_freq(dev, frequency - offset);
rtlsdr_set_agc_mode(dev, 1);
rtlsdr_set_offset_tuning(dev, 0);
rtlsdr_reset_buffer(dev);
}
if (offset_changed && !freq_changed) { if (offset_changed && !freq_changed) {
new_freq = frequency; new_freq = frequency;
freq_changed = true; freq_changed = true;
offset = new_offset; offset = new_offset;
} }
if (freq_changed) { if (rate_changed) {
sampleRate = new_rate;
rtlsdr_set_sample_rate(dev, new_rate);
} else if (freq_changed) {
frequency = new_freq; frequency = new_freq;
rtlsdr_set_center_freq(dev, frequency-offset); rtlsdr_set_center_freq(dev, frequency - offset);
} }
} }
@ -194,7 +244,7 @@ void SDRThread::threadMain() {
// std::lock_guard < std::mutex > lock(dataOut->m_mutex); // std::lock_guard < std::mutex > lock(dataOut->m_mutex);
dataOut->setRefCount(1); dataOut->setRefCount(1);
dataOut->frequency = frequency; dataOut->frequency = frequency;
dataOut->bandwidth = bandwidth; dataOut->sampleRate = sampleRate;
if (dataOut->data.capacity() < n_read) { if (dataOut->data.capacity() < n_read) {
dataOut->data.reserve(n_read); dataOut->data.reserve(n_read);

View File

@ -14,10 +14,71 @@
#include "ThreadQueue.h" #include "ThreadQueue.h"
#include "DemodulatorMgr.h" #include "DemodulatorMgr.h"
class SDRDeviceInfo {
public:
SDRDeviceInfo() : name(""), serial(""), available(false) { }
bool isAvailable() const {
return available;
}
void setAvailable(bool available) {
this->available = available;
}
const std::string& getName() const {
return name;
}
void setName(const std::string& name) {
this->name = name;
}
const std::string& getSerial() const {
return serial;
}
void setSerial(const std::string& serial) {
this->serial = serial;
}
const std::string& getTuner() const {
return tuner;
}
void setTuner(const std::string& tuner) {
this->tuner = tuner;
}
const std::string& getManufacturer() const {
return manufacturer;
}
void setManufacturer(const std::string& manufacturer) {
this->manufacturer = manufacturer;
}
const std::string& getProduct() const {
return product;
}
void setProduct(const std::string& product) {
this->product = product;
}
private:
std::string name;
std::string serial;
std::string product;
std::string manufacturer;
std::string tuner;
bool available;
};
class SDRThreadCommand { class SDRThreadCommand {
public: public:
enum SDRThreadCommandEnum { enum SDRThreadCommandEnum {
SDR_THREAD_CMD_NULL, SDR_THREAD_CMD_TUNE, SDR_THREAD_CMD_SET_OFFSET SDR_THREAD_CMD_NULL, SDR_THREAD_CMD_TUNE, SDR_THREAD_CMD_SET_OFFSET, SDR_THREAD_CMD_SET_SAMPLERATE, SDR_THREAD_CMD_SET_DEVICE
}; };
SDRThreadCommand() : SDRThreadCommand() :
@ -37,16 +98,16 @@ public:
class SDRThreadIQData: public ReferenceCounter { class SDRThreadIQData: public ReferenceCounter {
public: public:
long long frequency; long long frequency;
unsigned int bandwidth; long long sampleRate;
std::vector<signed char> data; std::vector<signed char> data;
SDRThreadIQData() : SDRThreadIQData() :
frequency(0), bandwidth(0) { frequency(0), sampleRate(DEFAULT_SAMPLE_RATE) {
} }
SDRThreadIQData(unsigned int bandwidth, long long frequency, std::vector<signed char> *data) : SDRThreadIQData(long long bandwidth, long long frequency, std::vector<signed char> *data) :
frequency(frequency), bandwidth(bandwidth) { frequency(frequency), sampleRate(bandwidth) {
} }
@ -65,7 +126,7 @@ public:
SDRThread(SDRThreadCommandQueue* pQueue); SDRThread(SDRThreadCommandQueue* pQueue);
~SDRThread(); ~SDRThread();
int enumerate_rtl(); static int enumerate_rtl(std::vector<SDRDeviceInfo *> *devs);
void threadMain(); void threadMain();
@ -74,6 +135,15 @@ public:
} }
void terminate(); void terminate();
int getDeviceId() const {
return deviceId;
}
void setDeviceId(int deviceId) {
this->deviceId = deviceId;
}
protected: protected:
uint32_t sampleRate; uint32_t sampleRate;
long long offset; long long offset;
@ -81,4 +151,5 @@ protected:
std::atomic<SDRThreadIQDataQueue*> iqDataOutQueue; std::atomic<SDRThreadIQDataQueue*> iqDataOutQueue;
std::atomic<bool> terminated; std::atomic<bool> terminated;
int deviceId;
}; };

View File

@ -37,7 +37,7 @@ void InteractiveCanvas::setView(long long center_freq_in, int bandwidth_in) {
void InteractiveCanvas::disableView() { void InteractiveCanvas::disableView() {
isView = false; isView = false;
centerFreq = wxGetApp().getFrequency(); centerFreq = wxGetApp().getFrequency();
bandwidth = SRATE; bandwidth = wxGetApp().getSampleRate();
lastBandwidth = 0; lastBandwidth = 0;
} }
@ -69,7 +69,7 @@ unsigned int InteractiveCanvas::getBandwidth() {
if (isView) { if (isView) {
return bandwidth; return bandwidth;
} else { } else {
return SRATE; return wxGetApp().getSampleRate();
} }
} }

View File

@ -96,6 +96,9 @@ void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, float r, float
if (!demod) { if (!demod) {
return; return;
} }
if (!srate) {
srate = wxGetApp().getSampleRate();
}
GLint vp[4]; GLint vp[4];
glGetIntegerv( GL_VIEWPORT, vp); glGetIntegerv( GL_VIEWPORT, vp);
@ -171,6 +174,9 @@ void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, float r, float g, f
if (!demod) { if (!demod) {
return; return;
} }
if (!srate) {
srate = wxGetApp().getSampleRate();
}
if (center_freq == -1) { if (center_freq == -1) {
center_freq = wxGetApp().getFrequency(); center_freq = wxGetApp().getFrequency();
@ -271,6 +277,10 @@ void PrimaryGLContext::DrawFreqSelector(float uxPos, float r, float g, float b,
bw = demod->getBandwidth(); bw = demod->getBandwidth();
} }
if (!srate) {
srate = wxGetApp().getSampleRate();
}
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_2D);

View File

@ -23,9 +23,9 @@ public:
void BeginDraw(); void BeginDraw();
void EndDraw(); void EndDraw();
void DrawFreqSelector(float uxPos, float r = 1, float g = 1, float b = 1, float w = 0, long long center_freq = -1, long long srate = SRATE); void DrawFreqSelector(float uxPos, float r = 1, float g = 1, float b = 1, float w = 0, long long center_freq = -1, long long srate = 0);
void DrawDemod(DemodulatorInstance *demod, float r = 1, float g = 1, float b = 1, long long center_freq = -1, long long srate = SRATE); void DrawDemod(DemodulatorInstance *demod, float r = 1, float g = 1, float b = 1, long long center_freq = -1, long long srate = 0);
void DrawDemodInfo(DemodulatorInstance *demod, float r = 1, float g = 1, float b = 1, long long center_freq = -1, long long srate = SRATE); void DrawDemodInfo(DemodulatorInstance *demod, float r = 1, float g = 1, float b = 1, long long center_freq = -1, long long srate = 0);
static GLFont &getFont(GLFontSize esize); static GLFont &getFont(GLFontSize esize);

View File

@ -196,16 +196,16 @@ void SpectrumCanvas::OnMouseMoved(wxMouseEvent& event) {
long long bwOfs = (centerFreq > freq) ? ((long long) bandwidth / 2) : (-(long long) bandwidth / 2); long long bwOfs = (centerFreq > freq) ? ((long long) bandwidth / 2) : (-(long long) bandwidth / 2);
long long freqEdge = centerFreq + bwOfs; long long freqEdge = centerFreq + bwOfs;
if (abs(freq - freqEdge) > (SRATE / 2)) { if (abs(freq - freqEdge) > (wxGetApp().getSampleRate() / 2)) {
freqChange = -((centerFreq > freq) ? (freqEdge - freq - (SRATE / 2)) : (freqEdge - freq + (SRATE / 2))); freqChange = -((centerFreq > freq) ? (freqEdge - freq - (wxGetApp().getSampleRate() / 2)) : (freqEdge - freq + (wxGetApp().getSampleRate() / 2)));
} else { } else {
freqChange = 0; freqChange = 0;
} }
} }
if (freqChange) { if (freqChange) {
if (freq - freqChange < SRATE/2) { if (freq - freqChange < wxGetApp().getSampleRate()/2) {
freq = SRATE/2; freq = wxGetApp().getSampleRate()/2;
} else { } else {
freq -= freqChange; freq -= freqChange;
} }

View File

@ -67,7 +67,7 @@ void TuningCanvas::OnIdle(wxIdleEvent &event) {
dragAccum += mouseTracker.getMouseX() - mouseTracker.getOriginMouseX(); dragAccum += mouseTracker.getMouseX() - mouseTracker.getOriginMouseX();
if (uxDown > 0.275) { if (uxDown > 0.275) {
wxGetApp().setFrequency(wxGetApp().getFrequency() + (int) (mouseTracker.getOriginDeltaMouseX() * SRATE * 15.0)); wxGetApp().setFrequency(wxGetApp().getFrequency() + (int) (mouseTracker.getOriginDeltaMouseX() * (float)wxGetApp().getSampleRate() * 15.0));
} }
if (abs(dragAccum * 10.0) >= 1) { if (abs(dragAccum * 10.0) >= 1) {

View File

@ -214,7 +214,7 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) {
freq = wxGetApp().getFrequency(); freq = wxGetApp().getFrequency();
originalFreq = freq; originalFreq = freq;
if (shiftDown) { if (shiftDown) {
freq += SRATE * 10; freq += wxGetApp().getSampleRate() * 10;
if (isView) { if (isView) {
setView(centerFreq + (freq - originalFreq), getBandwidth()); setView(centerFreq + (freq - originalFreq), getBandwidth());
if (spectrumCanvas) { if (spectrumCanvas) {
@ -222,7 +222,7 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) {
} }
} }
} else { } else {
freq += SRATE / 2; freq += wxGetApp().getSampleRate() / 2;
if (isView) { if (isView) {
setView(centerFreq + (freq - originalFreq), getBandwidth()); setView(centerFreq + (freq - originalFreq), getBandwidth());
if (spectrumCanvas) { if (spectrumCanvas) {
@ -237,10 +237,10 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) {
freq = wxGetApp().getFrequency(); freq = wxGetApp().getFrequency();
originalFreq = freq; originalFreq = freq;
if (shiftDown) { if (shiftDown) {
if ((freq - SRATE * 10) < SRATE / 2) { if ((freq - wxGetApp().getSampleRate() * 10) < wxGetApp().getSampleRate() / 2) {
freq = SRATE / 2; freq = wxGetApp().getSampleRate() / 2;
} else { } else {
freq -= SRATE * 10; freq -= wxGetApp().getSampleRate() * 10;
} }
if (isView) { if (isView) {
setView(centerFreq + (freq - originalFreq), getBandwidth()); setView(centerFreq + (freq - originalFreq), getBandwidth());
@ -249,10 +249,10 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) {
} }
} }
} else { } else {
if ((freq - SRATE / 2) < SRATE / 2) { if ((freq - wxGetApp().getSampleRate() / 2) < wxGetApp().getSampleRate() / 2) {
freq = SRATE / 2; freq = wxGetApp().getSampleRate() / 2;
} else { } else {
freq -= SRATE / 2; freq -= wxGetApp().getSampleRate() / 2;
} }
if (isView) { if (isView) {
setView(centerFreq + (freq - originalFreq), getBandwidth()); setView(centerFreq + (freq - originalFreq), getBandwidth());
@ -339,8 +339,8 @@ void WaterfallCanvas::setData(DemodulatorThreadIQData *input) {
if (isView) { if (isView) {
bw = getBandwidth(); bw = getBandwidth();
bw = (long long) ceil((long double) bw * currentZoom); bw = (long long) ceil((long double) bw * currentZoom);
if (bw >= SRATE) { if (bw >= wxGetApp().getSampleRate()) {
bw = SRATE; bw = wxGetApp().getSampleRate();
disableView(); disableView();
if (spectrumCanvas) { if (spectrumCanvas) {
spectrumCanvas->disableView(); spectrumCanvas->disableView();
@ -361,11 +361,11 @@ void WaterfallCanvas::setData(DemodulatorThreadIQData *input) {
} }
} }
} }
if (centerFreq < freq && (centerFreq - bandwidth / 2) < (freq - SRATE / 2)) { if (centerFreq < freq && (centerFreq - bandwidth / 2) < (freq - wxGetApp().getSampleRate() / 2)) {
centerFreq = (freq - SRATE / 2) + bandwidth / 2; centerFreq = (freq - wxGetApp().getSampleRate() / 2) + bandwidth / 2;
} }
if (centerFreq > freq && (centerFreq + bandwidth / 2) > (freq + SRATE / 2)) { if (centerFreq > freq && (centerFreq + bandwidth / 2) > (freq + wxGetApp().getSampleRate() / 2)) {
centerFreq = (freq + SRATE / 2) - bandwidth / 2; centerFreq = (freq + wxGetApp().getSampleRate() / 2) - bandwidth / 2;
} }
} }
@ -385,16 +385,16 @@ void WaterfallCanvas::setData(DemodulatorThreadIQData *input) {
} }
if (isView) { if (isView) {
if (!input->frequency || !input->bandwidth) { if (!input->frequency || !input->sampleRate) {
return; return;
} }
if (centerFreq != input->frequency) { if (centerFreq != input->frequency) {
if ((centerFreq - input->frequency) != shiftFrequency || lastInputBandwidth != input->bandwidth) { if ((centerFreq - input->frequency) != shiftFrequency || lastInputBandwidth != input->sampleRate) {
if (abs(input->frequency - centerFreq) < (SRATE / 2)) { if (abs(input->frequency - centerFreq) < (wxGetApp().getSampleRate() / 2)) {
shiftFrequency = centerFreq - input->frequency; shiftFrequency = centerFreq - input->frequency;
nco_crcf_reset(freqShifter); nco_crcf_reset(freqShifter);
nco_crcf_set_frequency(freqShifter, (2.0 * M_PI) * (((double) abs(shiftFrequency)) / ((double) input->bandwidth))); nco_crcf_set_frequency(freqShifter, (2.0 * M_PI) * (((double) abs(shiftFrequency)) / ((double) input->sampleRate)));
} }
} }
@ -414,8 +414,8 @@ void WaterfallCanvas::setData(DemodulatorThreadIQData *input) {
shiftBuffer.assign(input->data.begin(), input->data.end()); shiftBuffer.assign(input->data.begin(), input->data.end());
} }
if (!resampler || bandwidth != lastBandwidth || lastInputBandwidth != input->bandwidth) { if (!resampler || bandwidth != lastBandwidth || lastInputBandwidth != input->sampleRate) {
resamplerRatio = (double) (bandwidth) / (double) input->bandwidth; resamplerRatio = (double) (bandwidth) / (double) input->sampleRate;
float As = 120.0f; float As = 120.0f;
@ -425,7 +425,7 @@ void WaterfallCanvas::setData(DemodulatorThreadIQData *input) {
resampler = msresamp_crcf_create(resamplerRatio, As); resampler = msresamp_crcf_create(resamplerRatio, As);
lastBandwidth = bandwidth; lastBandwidth = bandwidth;
lastInputBandwidth = input->bandwidth; lastInputBandwidth = input->sampleRate;
} }
int out_size = ceil((double) (input->data.size()) * resamplerRatio) + 512; int out_size = ceil((double) (input->data.size()) * resamplerRatio) + 512;
@ -562,8 +562,8 @@ void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) {
int currentBW = demod->getBandwidth(); int currentBW = demod->getBandwidth();
currentBW = currentBW + bwDiff; currentBW = currentBW + bwDiff;
if (currentBW > SRATE) { if (currentBW > wxGetApp().getSampleRate()) {
currentBW = SRATE; currentBW = wxGetApp().getSampleRate();
} }
if (currentBW < MIN_BANDWIDTH) { if (currentBW < MIN_BANDWIDTH) {
currentBW = MIN_BANDWIDTH; currentBW = MIN_BANDWIDTH;