mirror of
https://github.com/cjcliffe/CubicSDR.git
synced 2025-08-04 06:32:25 -04:00
commit
5c0aee5ecb
34
README.md
34
README.md
@ -86,6 +86,33 @@ Features and Status:
|
|||||||
- [ ] Playback
|
- [ ] Playback
|
||||||
- Audio
|
- Audio
|
||||||
- [ ] Recording
|
- [ ] Recording
|
||||||
|
- Implement digital demodulation supported by liquid-dsp: (http://liquidsdr.org/doc/modem.html)
|
||||||
|
- [ ] Demodulator Lab
|
||||||
|
- [ ] Toggle current demodulator exclusively into "Lab" mode
|
||||||
|
- [ ] Additional visualizations for audio and I/Q stream
|
||||||
|
- [ ] Audio Spectrum
|
||||||
|
- [ ] Constellation / X-Y Scope
|
||||||
|
- [ ] Digital demodulation status and controls
|
||||||
|
- [ ] Demodulator AGC, Equalization controls
|
||||||
|
- [ ] Lock AGC and Equalization when digital lock obtained
|
||||||
|
- [ ] Digital output
|
||||||
|
- [ ] Output console
|
||||||
|
- [ ] Capture file (auto?)
|
||||||
|
- [ ] Network output
|
||||||
|
- [ ] Block device output
|
||||||
|
- [ ] Digital modes available to implement
|
||||||
|
- [ ] PSK
|
||||||
|
- [ ] DPSK
|
||||||
|
- [ ] ASK
|
||||||
|
- [ ] QAM
|
||||||
|
- [ ] APSK
|
||||||
|
- [ ] BPSK
|
||||||
|
- [ ] QPSK
|
||||||
|
- [ ] OOK
|
||||||
|
- [ ] SQAM
|
||||||
|
- [ ] Star Modem
|
||||||
|
- [ ] MFSK
|
||||||
|
- [ ] CPFSK
|
||||||
- Optimization
|
- Optimization
|
||||||
- [x] Eliminate large waterfall texture uploads
|
- [x] Eliminate large waterfall texture uploads
|
||||||
- [ ] Update visuals to OpenGL 3.x
|
- [ ] Update visuals to OpenGL 3.x
|
||||||
@ -93,8 +120,9 @@ Features and Status:
|
|||||||
- [ ] Resolve driver/platform vertical sync issues
|
- [ ] Resolve driver/platform vertical sync issues
|
||||||
- [ ] Group and divide IQ data distribution workload instead of 100% distribution per instance
|
- [ ] Group and divide IQ data distribution workload instead of 100% distribution per instance
|
||||||
|
|
||||||
Advanced Goals:
|
|
||||||
---------------
|
Advanced Goals and ideas:
|
||||||
|
------------------------
|
||||||
- Design a plan for expansion via modules (dylib/dll/lua)
|
- Design a plan for expansion via modules (dylib/dll/lua)
|
||||||
- Support shell-based stdin/stdout tools for direct output/playback to/from CLI audio processing apps (i.e. DSD on OSX)
|
- Support shell-based stdin/stdout tools for direct output/playback to/from CLI audio processing apps (i.e. DSD on OSX)
|
||||||
- Update visuals to support OpenGL ES
|
- Update visuals to support OpenGL ES
|
||||||
@ -102,8 +130,6 @@ Advanced Goals:
|
|||||||
- Support multiple simultaneous device usage
|
- Support multiple simultaneous device usage
|
||||||
* Categorize devices by antenna connections
|
* Categorize devices by antenna connections
|
||||||
* Allow locked frequencies to activate unused devices to continue demodulation on same antenna
|
* Allow locked frequencies to activate unused devices to continue demodulation on same antenna
|
||||||
- Implement digital demodulation supported by liquid-dsp: (http://liquidsdr.org/doc/modem.html)
|
|
||||||
* PSK, DPSK, ASK, QAM, APSK, BPSK, QPSK, OOK, SQAM, Star Modem(?)
|
|
||||||
- Integrate LUA
|
- Integrate LUA
|
||||||
* Expose liquid-dsp functionality
|
* Expose liquid-dsp functionality
|
||||||
* Scriptable liquid-dsp demodulation
|
* Scriptable liquid-dsp demodulation
|
||||||
|
@ -1,36 +1,76 @@
|
|||||||
#include "AppConfig.h"
|
#include "AppConfig.h"
|
||||||
|
#include "CubicSDR.h"
|
||||||
|
|
||||||
DeviceConfig::DeviceConfig() : ppm(0), deviceId("") {
|
DeviceConfig::DeviceConfig() : deviceId("") {
|
||||||
|
ppm.store(0);
|
||||||
|
directSampling.store(false);
|
||||||
|
offset.store(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceConfig::DeviceConfig(std::string deviceId) : ppm(0) {
|
DeviceConfig::DeviceConfig(std::string deviceId) : DeviceConfig() {
|
||||||
this->deviceId = deviceId;
|
this->deviceId = deviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceConfig::setPPM(int ppm) {
|
void DeviceConfig::setPPM(int ppm) {
|
||||||
this->ppm = ppm;
|
this->ppm.store(ppm);
|
||||||
}
|
}
|
||||||
|
|
||||||
int DeviceConfig::getPPM() {
|
int DeviceConfig::getPPM() {
|
||||||
return ppm;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
void DeviceConfig::setDeviceId(std::string deviceId) {
|
||||||
|
busy_lock.lock();
|
||||||
this->deviceId = deviceId;
|
this->deviceId = deviceId;
|
||||||
|
busy_lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string DeviceConfig::getDeviceId() {
|
std::string DeviceConfig::getDeviceId() {
|
||||||
return deviceId;
|
std::string tmp;
|
||||||
|
|
||||||
|
busy_lock.lock();
|
||||||
|
tmp = deviceId;
|
||||||
|
busy_lock.unlock();
|
||||||
|
|
||||||
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceConfig::save(DataNode *node) {
|
void DeviceConfig::save(DataNode *node) {
|
||||||
node->newChild("id")->element()->set(deviceId);
|
busy_lock.lock();
|
||||||
DataNode *ppm_node = node->newChild("ppm");
|
*node->newChild("id") = deviceId;
|
||||||
ppm_node->element()->set((int)ppm);
|
*node->newChild("ppm") = (int)ppm;
|
||||||
|
*node->newChild("iq_swap") = iqSwap;
|
||||||
|
*node->newChild("direct_sampling") = directSampling;
|
||||||
|
*node->newChild("offset") = offset;
|
||||||
|
busy_lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceConfig::load(DataNode *node) {
|
void DeviceConfig::load(DataNode *node) {
|
||||||
|
busy_lock.lock();
|
||||||
if (node->hasAnother("ppm")) {
|
if (node->hasAnother("ppm")) {
|
||||||
DataNode *ppm_node = node->getNext("ppm");
|
DataNode *ppm_node = node->getNext("ppm");
|
||||||
int ppmValue = 0;
|
int ppmValue = 0;
|
||||||
@ -38,11 +78,59 @@ void DeviceConfig::load(DataNode *node) {
|
|||||||
setPPM(ppmValue);
|
setPPM(ppmValue);
|
||||||
std::cout << "Loaded PPM for device '" << deviceId << "' at " << ppmValue << "ppm" << std::endl;
|
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;
|
||||||
|
offset_node->element()->get(offsetValue);
|
||||||
|
setOffset(offsetValue);
|
||||||
|
std::cout << "Loaded offset for device '" << deviceId << "' at " << offsetValue << "Hz" << std::endl;
|
||||||
|
}
|
||||||
|
busy_lock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
AppConfig::AppConfig() {
|
||||||
|
winX.store(0);
|
||||||
|
winY.store(0);
|
||||||
|
winW.store(0);
|
||||||
|
winH.store(0);
|
||||||
|
winMax.store(false);
|
||||||
|
themeId.store(0);
|
||||||
|
snap.store(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
DeviceConfig *AppConfig::getDevice(std::string deviceId) {
|
DeviceConfig *AppConfig::getDevice(std::string deviceId) {
|
||||||
DeviceConfig *conf = &deviceConfig[deviceId];
|
if (deviceConfig.find(deviceId) == deviceConfig.end()) {
|
||||||
|
deviceConfig[deviceId] = new DeviceConfig();
|
||||||
|
}
|
||||||
|
DeviceConfig *conf = deviceConfig[deviceId];
|
||||||
conf->setDeviceId(deviceId);
|
conf->setDeviceId(deviceId);
|
||||||
return conf;
|
return conf;
|
||||||
}
|
}
|
||||||
@ -65,18 +153,76 @@ std::string AppConfig::getConfigDir() {
|
|||||||
return dataDir;
|
return dataDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AppConfig::setWindow(wxPoint winXY, wxSize winWH) {
|
||||||
|
winX.store(winXY.x);
|
||||||
|
winY.store(winXY.y);
|
||||||
|
winW.store(winWH.x);
|
||||||
|
winH.store(winWH.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppConfig::setWindowMaximized(bool max) {
|
||||||
|
winMax.store(max);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AppConfig::getWindowMaximized() {
|
||||||
|
return winMax.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
wxRect *AppConfig::getWindow() {
|
||||||
|
wxRect *r = NULL;
|
||||||
|
if (winH.load() && winW.load()) {
|
||||||
|
r = new wxRect(winX.load(),winY.load(),winW.load(),winH.load());
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AppConfig::setTheme(int themeId) {
|
||||||
|
this->themeId.store(themeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AppConfig::getTheme() {
|
||||||
|
return themeId.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AppConfig::setSnap(long long snapVal) {
|
||||||
|
this->snap.store(snapVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
long long AppConfig::getSnap() {
|
||||||
|
return snap.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool AppConfig::save() {
|
bool AppConfig::save() {
|
||||||
DataTree cfg;
|
DataTree cfg;
|
||||||
|
|
||||||
cfg.rootNode()->setName("cubicsdr_config");
|
cfg.rootNode()->setName("cubicsdr_config");
|
||||||
|
|
||||||
|
if (winW.load() && winH.load()) {
|
||||||
|
DataNode *window_node = cfg.rootNode()->newChild("window");
|
||||||
|
|
||||||
|
*window_node->newChild("x") = winX.load();
|
||||||
|
*window_node->newChild("y") = winY.load();
|
||||||
|
*window_node->newChild("w") = winW.load();
|
||||||
|
*window_node->newChild("h") = winH.load();
|
||||||
|
|
||||||
|
*window_node->newChild("max") = winMax.load();
|
||||||
|
*window_node->newChild("theme") = themeId.load();
|
||||||
|
*window_node->newChild("snap") = snap.load();
|
||||||
|
}
|
||||||
|
|
||||||
DataNode *devices_node = cfg.rootNode()->newChild("devices");
|
DataNode *devices_node = cfg.rootNode()->newChild("devices");
|
||||||
|
|
||||||
std::map<std::string, DeviceConfig>::iterator device_config_i;
|
std::map<std::string, DeviceConfig *>::iterator device_config_i;
|
||||||
for (device_config_i = deviceConfig.begin(); device_config_i != deviceConfig.end(); device_config_i++) {
|
for (device_config_i = deviceConfig.begin(); device_config_i != deviceConfig.end(); device_config_i++) {
|
||||||
DataNode *device_node = devices_node->newChild("device");
|
DataNode *device_node = devices_node->newChild("device");
|
||||||
device_config_i->second.save(device_node);
|
device_config_i->second->save(device_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string cfgFileDir = getConfigDir();
|
std::string cfgFileDir = getConfigDir();
|
||||||
|
|
||||||
wxFileName cfgFile = wxFileName(cfgFileDir, "config.xml");
|
wxFileName cfgFile = wxFileName(cfgFileDir, "config.xml");
|
||||||
@ -110,6 +256,42 @@ bool AppConfig::load() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cfg.rootNode()->hasAnother("window")) {
|
||||||
|
int x,y,w,h;
|
||||||
|
int max;
|
||||||
|
|
||||||
|
DataNode *win_node = cfg.rootNode()->getNext("window");
|
||||||
|
|
||||||
|
if (win_node->hasAnother("w") && win_node->hasAnother("h") && win_node->hasAnother("x") && win_node->hasAnother("y")) {
|
||||||
|
win_node->getNext("x")->element()->get(x);
|
||||||
|
win_node->getNext("y")->element()->get(y);
|
||||||
|
win_node->getNext("w")->element()->get(w);
|
||||||
|
win_node->getNext("h")->element()->get(h);
|
||||||
|
|
||||||
|
winX.store(x);
|
||||||
|
winY.store(y);
|
||||||
|
winW.store(w);
|
||||||
|
winH.store(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (win_node->hasAnother("max")) {
|
||||||
|
win_node->getNext("max")->element()->get(max);
|
||||||
|
winMax.store(max?true:false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (win_node->hasAnother("theme")) {
|
||||||
|
int theme;
|
||||||
|
win_node->getNext("theme")->element()->get(theme);
|
||||||
|
themeId.store(theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (win_node->hasAnother("snap")) {
|
||||||
|
long long snapVal;
|
||||||
|
win_node->getNext("snap")->element()->get(snapVal);
|
||||||
|
snap.store(snapVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (cfg.rootNode()->hasAnother("devices")) {
|
if (cfg.rootNode()->hasAnother("devices")) {
|
||||||
DataNode *devices_node = cfg.rootNode()->getNext("devices");
|
DataNode *devices_node = cfg.rootNode()->getNext("devices");
|
||||||
|
|
||||||
|
@ -3,10 +3,12 @@
|
|||||||
#include <wx/stdpaths.h>
|
#include <wx/stdpaths.h>
|
||||||
#include <wx/dir.h>
|
#include <wx/dir.h>
|
||||||
#include <wx/filename.h>
|
#include <wx/filename.h>
|
||||||
|
#include <wx/panel.h>
|
||||||
|
#include <atomic>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include "DataTree.h"
|
#include "DataTree.h"
|
||||||
|
|
||||||
|
|
||||||
class DeviceConfig {
|
class DeviceConfig {
|
||||||
public:
|
public:
|
||||||
DeviceConfig();
|
DeviceConfig();
|
||||||
@ -15,6 +17,15 @@ public:
|
|||||||
void setPPM(int ppm);
|
void setPPM(int ppm);
|
||||||
int getPPM();
|
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);
|
void setDeviceId(std::string deviceId);
|
||||||
std::string getDeviceId();
|
std::string getDeviceId();
|
||||||
|
|
||||||
@ -23,18 +34,39 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::string deviceId;
|
std::string deviceId;
|
||||||
int ppm;
|
std::mutex busy_lock;
|
||||||
|
|
||||||
|
std::atomic_int ppm, directSampling;
|
||||||
|
std::atomic_bool iqSwap;
|
||||||
|
std::atomic_llong offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AppConfig {
|
class AppConfig {
|
||||||
public:
|
public:
|
||||||
|
AppConfig();
|
||||||
std::string getConfigDir();
|
std::string getConfigDir();
|
||||||
DeviceConfig *getDevice(std::string deviceId);
|
DeviceConfig *getDevice(std::string deviceId);
|
||||||
|
|
||||||
|
void setWindow(wxPoint winXY, wxSize winWH);
|
||||||
|
wxRect *getWindow();
|
||||||
|
|
||||||
|
void setWindowMaximized(bool max);
|
||||||
|
bool getWindowMaximized();
|
||||||
|
|
||||||
|
void setTheme(int themeId);
|
||||||
|
int getTheme();
|
||||||
|
|
||||||
|
void setSnap(long long snapVal);
|
||||||
|
long long getSnap();
|
||||||
|
|
||||||
bool save();
|
bool save();
|
||||||
bool load();
|
bool load();
|
||||||
bool reset();
|
bool reset();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<std::string, DeviceConfig> deviceConfig;
|
std::map<std::string, DeviceConfig *> deviceConfig;
|
||||||
|
std::atomic_int winX,winY,winW,winH;
|
||||||
|
std::atomic_bool winMax;
|
||||||
|
std::atomic_int themeId;
|
||||||
|
std::atomic_llong snap;
|
||||||
};
|
};
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
wxBEGIN_EVENT_TABLE(AppFrame, wxFrame)
|
wxBEGIN_EVENT_TABLE(AppFrame, wxFrame)
|
||||||
//EVT_MENU(wxID_NEW, AppFrame::OnNewWindow)
|
//EVT_MENU(wxID_NEW, AppFrame::OnNewWindow)
|
||||||
EVT_MENU(wxID_CLOSE, AppFrame::OnClose)
|
EVT_CLOSE(AppFrame::OnClose)
|
||||||
EVT_MENU(wxID_ANY, AppFrame::OnMenu)
|
EVT_MENU(wxID_ANY, AppFrame::OnMenu)
|
||||||
EVT_COMMAND(wxID_ANY, wxEVT_THREAD, AppFrame::OnThread)
|
EVT_COMMAND(wxID_ANY, wxEVT_THREAD, AppFrame::OnThread)
|
||||||
EVT_IDLE(AppFrame::OnIdle)
|
EVT_IDLE(AppFrame::OnIdle)
|
||||||
@ -57,6 +57,7 @@ AppFrame::AppFrame() :
|
|||||||
demodModeSelector->addChoice(DEMOD_TYPE_LSB, "LSB");
|
demodModeSelector->addChoice(DEMOD_TYPE_LSB, "LSB");
|
||||||
demodModeSelector->addChoice(DEMOD_TYPE_USB, "USB");
|
demodModeSelector->addChoice(DEMOD_TYPE_USB, "USB");
|
||||||
demodModeSelector->addChoice(DEMOD_TYPE_DSB, "DSB");
|
demodModeSelector->addChoice(DEMOD_TYPE_DSB, "DSB");
|
||||||
|
demodModeSelector->addChoice(DEMOD_TYPE_RAW, "I/Q");
|
||||||
demodModeSelector->setSelection(DEMOD_TYPE_FM);
|
demodModeSelector->setSelection(DEMOD_TYPE_FM);
|
||||||
demodModeSelector->setHelpTip("Choose modulation type: Frequency Modulation, Amplitude Modulation and Lower, Upper or Double Side-Band.");
|
demodModeSelector->setHelpTip("Choose modulation type: Frequency Modulation, Amplitude Modulation and Lower, Upper or Double Side-Band.");
|
||||||
demodTray->Add(demodModeSelector, 2, wxEXPAND | wxALL, 0);
|
demodTray->Add(demodModeSelector, 2, wxEXPAND | wxALL, 0);
|
||||||
@ -156,9 +157,9 @@ AppFrame::AppFrame() :
|
|||||||
|
|
||||||
wxMenu *dsMenu = new wxMenu;
|
wxMenu *dsMenu = new wxMenu;
|
||||||
|
|
||||||
dsMenu->AppendRadioItem(wxID_SET_DS_OFF, "Off");
|
directSamplingMenuItems[0] = dsMenu->AppendRadioItem(wxID_SET_DS_OFF, "Off");
|
||||||
dsMenu->AppendRadioItem(wxID_SET_DS_I, "I-ADC");
|
directSamplingMenuItems[1] = dsMenu->AppendRadioItem(wxID_SET_DS_I, "I-ADC");
|
||||||
dsMenu->AppendRadioItem(wxID_SET_DS_Q, "Q-ADC");
|
directSamplingMenuItems[2] = dsMenu->AppendRadioItem(wxID_SET_DS_Q, "Q-ADC");
|
||||||
|
|
||||||
menu->AppendSubMenu(dsMenu, "Direct Sampling");
|
menu->AppendSubMenu(dsMenu, "Direct Sampling");
|
||||||
|
|
||||||
@ -195,13 +196,15 @@ AppFrame::AppFrame() :
|
|||||||
|
|
||||||
menu = new wxMenu;
|
menu = new wxMenu;
|
||||||
|
|
||||||
menu->AppendRadioItem(wxID_THEME_DEFAULT, "Default")->Check(true);
|
int themeId = wxGetApp().getConfig()->getTheme();
|
||||||
menu->AppendRadioItem(wxID_THEME_RADAR, "RADAR");
|
|
||||||
menu->AppendRadioItem(wxID_THEME_BW, "Black & White");
|
menu->AppendRadioItem(wxID_THEME_DEFAULT, "Default")->Check(themeId==COLOR_THEME_DEFAULT);
|
||||||
menu->AppendRadioItem(wxID_THEME_SHARP, "Sharp");
|
menu->AppendRadioItem(wxID_THEME_RADAR, "RADAR")->Check(themeId==COLOR_THEME_RADAR);
|
||||||
menu->AppendRadioItem(wxID_THEME_RAD, "Rad");
|
menu->AppendRadioItem(wxID_THEME_BW, "Black & White")->Check(themeId==COLOR_THEME_BW);
|
||||||
menu->AppendRadioItem(wxID_THEME_TOUCH, "Touch");
|
menu->AppendRadioItem(wxID_THEME_SHARP, "Sharp")->Check(themeId==COLOR_THEME_SHARP);
|
||||||
menu->AppendRadioItem(wxID_THEME_HD, "HD");
|
menu->AppendRadioItem(wxID_THEME_RAD, "Rad")->Check(themeId==COLOR_THEME_RAD);
|
||||||
|
menu->AppendRadioItem(wxID_THEME_TOUCH, "Touch")->Check(themeId==COLOR_THEME_TOUCH);
|
||||||
|
menu->AppendRadioItem(wxID_THEME_HD, "HD")->Check(themeId==COLOR_THEME_HD);
|
||||||
|
|
||||||
menuBar->Append(menu, wxT("&Color Scheme"));
|
menuBar->Append(menu, wxT("&Color Scheme"));
|
||||||
|
|
||||||
@ -307,8 +310,26 @@ AppFrame::AppFrame() :
|
|||||||
SetMenuBar(menuBar);
|
SetMenuBar(menuBar);
|
||||||
|
|
||||||
CreateStatusBar();
|
CreateStatusBar();
|
||||||
|
|
||||||
|
wxRect *win = wxGetApp().getConfig()->getWindow();
|
||||||
|
if (win) {
|
||||||
|
this->SetPosition(win->GetPosition());
|
||||||
|
this->SetClientSize(win->GetSize());
|
||||||
|
} else {
|
||||||
SetClientSize(1280, 600);
|
SetClientSize(1280, 600);
|
||||||
Centre();
|
Centre();
|
||||||
|
}
|
||||||
|
bool max = wxGetApp().getConfig()->getWindowMaximized();
|
||||||
|
|
||||||
|
if (max) {
|
||||||
|
this->Maximize();
|
||||||
|
}
|
||||||
|
|
||||||
|
long long freqSnap = wxGetApp().getConfig()->getSnap();
|
||||||
|
wxGetApp().setFrequencySnap(freqSnap);
|
||||||
|
|
||||||
|
ThemeMgr::mgr.setTheme(wxGetApp().getConfig()->getTheme());
|
||||||
|
|
||||||
Show();
|
Show();
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -333,6 +354,22 @@ AppFrame::~AppFrame() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AppFrame::initDeviceParams(std::string deviceId) {
|
||||||
|
DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(deviceId);
|
||||||
|
|
||||||
|
int dsMode = devConfig->getDirectSampling();
|
||||||
|
|
||||||
|
if (dsMode > 0 && dsMode <= 2) {
|
||||||
|
directSamplingMenuItems[devConfig->getDirectSampling()]->Check();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devConfig->getIQSwap()) {
|
||||||
|
iqSwapMenuItem->Check();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void AppFrame::OnMenu(wxCommandEvent& event) {
|
void AppFrame::OnMenu(wxCommandEvent& event) {
|
||||||
if (event.GetId() >= wxID_RT_AUDIO_DEVICE && event.GetId() < wxID_RT_AUDIO_DEVICE + devices.size()) {
|
if (event.GetId() >= wxID_RT_AUDIO_DEVICE && event.GetId() < wxID_RT_AUDIO_DEVICE + devices.size()) {
|
||||||
if (activeDemodulator) {
|
if (activeDemodulator) {
|
||||||
@ -344,16 +381,21 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
|
|||||||
"Frequency Offset", wxGetApp().getOffset(), -2000000000, 2000000000, this);
|
"Frequency Offset", wxGetApp().getOffset(), -2000000000, 2000000000, this);
|
||||||
if (ofs != -1) {
|
if (ofs != -1) {
|
||||||
wxGetApp().setOffset(ofs);
|
wxGetApp().setOffset(ofs);
|
||||||
|
wxGetApp().saveConfig();
|
||||||
}
|
}
|
||||||
} else if (event.GetId() == wxID_SET_DS_OFF) {
|
} else if (event.GetId() == wxID_SET_DS_OFF) {
|
||||||
wxGetApp().setDirectSampling(0);
|
wxGetApp().setDirectSampling(0);
|
||||||
|
wxGetApp().saveConfig();
|
||||||
} else if (event.GetId() == wxID_SET_DS_I) {
|
} else if (event.GetId() == wxID_SET_DS_I) {
|
||||||
wxGetApp().setDirectSampling(1);
|
wxGetApp().setDirectSampling(1);
|
||||||
|
wxGetApp().saveConfig();
|
||||||
} else if (event.GetId() == wxID_SET_DS_Q) {
|
} else if (event.GetId() == wxID_SET_DS_Q) {
|
||||||
wxGetApp().setDirectSampling(2);
|
wxGetApp().setDirectSampling(2);
|
||||||
|
wxGetApp().saveConfig();
|
||||||
} else if (event.GetId() == wxID_SET_SWAP_IQ) {
|
} else if (event.GetId() == wxID_SET_SWAP_IQ) {
|
||||||
bool swap_state = !wxGetApp().getSwapIQ();
|
bool swap_state = !wxGetApp().getSwapIQ();
|
||||||
wxGetApp().setSwapIQ(swap_state);
|
wxGetApp().setSwapIQ(swap_state);
|
||||||
|
wxGetApp().saveConfig();
|
||||||
iqSwapMenuItem->Check(swap_state);
|
iqSwapMenuItem->Check(swap_state);
|
||||||
} else if (event.GetId() == wxID_SET_PPM) {
|
} else if (event.GetId() == wxID_SET_PPM) {
|
||||||
long ofs = wxGetNumberFromUser("Frequency correction for device in PPM.\ni.e. -51 for -51 PPM\n\nNote: you can adjust PPM interactively\nby holding ALT over the frequency tuning bar.\n", "Parts per million (PPM)",
|
long ofs = wxGetNumberFromUser("Frequency correction for device in PPM.\ni.e. -51 for -51 PPM\n\nNote: you can adjust PPM interactively\nby holding ALT over the frequency tuning bar.\n", "Parts per million (PPM)",
|
||||||
@ -453,7 +495,19 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
|
|||||||
|
|
||||||
std::vector<SDRDeviceInfo *> *devs = wxGetApp().getDevices();
|
std::vector<SDRDeviceInfo *> *devs = wxGetApp().getDevices();
|
||||||
if (event.GetId() >= wxID_DEVICE_ID && event.GetId() <= wxID_DEVICE_ID + devs->size()) {
|
if (event.GetId() >= wxID_DEVICE_ID && event.GetId() <= wxID_DEVICE_ID + devs->size()) {
|
||||||
wxGetApp().setDevice(event.GetId() - wxID_DEVICE_ID);
|
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_AUDIO_BANDWIDTH_BASE) {
|
if (event.GetId() >= wxID_AUDIO_BANDWIDTH_BASE) {
|
||||||
@ -483,8 +537,13 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppFrame::OnClose(wxCommandEvent& WXUNUSED(event)) {
|
void AppFrame::OnClose(wxCloseEvent& event) {
|
||||||
Close(false);
|
wxGetApp().getConfig()->setWindow(this->GetPosition(), this->GetClientSize());
|
||||||
|
wxGetApp().getConfig()->setWindowMaximized(this->IsMaximized());
|
||||||
|
wxGetApp().getConfig()->setTheme(ThemeMgr::mgr.getTheme());
|
||||||
|
wxGetApp().getConfig()->setSnap(wxGetApp().getFrequencySnap());
|
||||||
|
wxGetApp().getConfig()->save();
|
||||||
|
event.Skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppFrame::OnNewWindow(wxCommandEvent& WXUNUSED(event)) {
|
void AppFrame::OnNewWindow(wxCommandEvent& WXUNUSED(event)) {
|
||||||
@ -622,7 +681,6 @@ void AppFrame::saveSession(std::string fileName) {
|
|||||||
DataNode *header = s.rootNode()->newChild("header");
|
DataNode *header = s.rootNode()->newChild("header");
|
||||||
*header->newChild("version") = std::string(CUBICSDR_VERSION);
|
*header->newChild("version") = std::string(CUBICSDR_VERSION);
|
||||||
*header->newChild("center_freq") = wxGetApp().getFrequency();
|
*header->newChild("center_freq") = wxGetApp().getFrequency();
|
||||||
*header->newChild("offset") = wxGetApp().getOffset();
|
|
||||||
|
|
||||||
DataNode *demods = s.rootNode()->newChild("demodulators");
|
DataNode *demods = s.rootNode()->newChild("demodulators");
|
||||||
|
|
||||||
@ -661,14 +719,11 @@ bool AppFrame::loadSession(std::string fileName) {
|
|||||||
|
|
||||||
std::string version(*header->getNext("version"));
|
std::string version(*header->getNext("version"));
|
||||||
long long center_freq = *header->getNext("center_freq");
|
long long center_freq = *header->getNext("center_freq");
|
||||||
long long offset = *header->getNext("offset");
|
|
||||||
|
|
||||||
std::cout << "Loading " << version << " session file" << std::endl;
|
std::cout << "Loading " << version << " session file" << std::endl;
|
||||||
std::cout << "\tCenter Frequency: " << center_freq << std::endl;
|
std::cout << "\tCenter Frequency: " << center_freq << std::endl;
|
||||||
std::cout << "\tOffset: " << offset << std::endl;
|
|
||||||
|
|
||||||
wxGetApp().setFrequency(center_freq);
|
wxGetApp().setFrequency(center_freq);
|
||||||
wxGetApp().setOffset(offset);
|
|
||||||
|
|
||||||
DataNode *demodulators = l.rootNode()->getNext("demodulators");
|
DataNode *demodulators = l.rootNode()->getNext("demodulators");
|
||||||
|
|
||||||
@ -716,7 +771,7 @@ bool AppFrame::loadSession(std::string fileName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
newDemod->run();
|
newDemod->run();
|
||||||
|
newDemod->setActive(false);
|
||||||
wxGetApp().bindDemodulator(newDemod);
|
wxGetApp().bindDemodulator(newDemod);
|
||||||
|
|
||||||
std::cout << "\tAdded demodulator at frequency " << freq << " type " << type << std::endl;
|
std::cout << "\tAdded demodulator at frequency " << freq << " type " << type << std::endl;
|
||||||
|
@ -59,13 +59,14 @@ public:
|
|||||||
~AppFrame();
|
~AppFrame();
|
||||||
void OnThread(wxCommandEvent& event);
|
void OnThread(wxCommandEvent& event);
|
||||||
void OnEventInput(wxThreadEvent& event);
|
void OnEventInput(wxThreadEvent& event);
|
||||||
|
void initDeviceParams(std::string deviceId);
|
||||||
|
|
||||||
void saveSession(std::string fileName);
|
void saveSession(std::string fileName);
|
||||||
bool loadSession(std::string fileName);
|
bool loadSession(std::string fileName);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void OnMenu(wxCommandEvent& event);
|
void OnMenu(wxCommandEvent& event);
|
||||||
void OnClose(wxCommandEvent& event);
|
void OnClose(wxCloseEvent& event);
|
||||||
void OnNewWindow(wxCommandEvent& event);
|
void OnNewWindow(wxCommandEvent& event);
|
||||||
void OnIdle(wxIdleEvent& event);
|
void OnIdle(wxIdleEvent& event);
|
||||||
|
|
||||||
@ -88,6 +89,7 @@ private:
|
|||||||
std::map<int, wxMenuItem *> outputDeviceMenuItems;
|
std::map<int, wxMenuItem *> outputDeviceMenuItems;
|
||||||
std::map<int, wxMenuItem *> sampleRateMenuItems;
|
std::map<int, wxMenuItem *> sampleRateMenuItems;
|
||||||
std::map<int, wxMenuItem *> audioSampleRateMenuItems;
|
std::map<int, wxMenuItem *> audioSampleRateMenuItems;
|
||||||
|
std::map<int, wxMenuItem *> directSamplingMenuItems;
|
||||||
wxMenuItem *iqSwapMenuItem;
|
wxMenuItem *iqSwapMenuItem;
|
||||||
|
|
||||||
std::string currentSessionFile;
|
std::string currentSessionFile;
|
||||||
|
@ -67,6 +67,7 @@ bool CubicSDR::OnInit() {
|
|||||||
std::vector<SDRDeviceInfo *>::iterator devs_i;
|
std::vector<SDRDeviceInfo *>::iterator devs_i;
|
||||||
|
|
||||||
SDRThread::enumerate_rtl(&devs);
|
SDRThread::enumerate_rtl(&devs);
|
||||||
|
SDRDeviceInfo *dev = NULL;
|
||||||
|
|
||||||
if (devs.size() > 1) {
|
if (devs.size() > 1) {
|
||||||
wxArrayString choices;
|
wxArrayString choices;
|
||||||
@ -85,15 +86,35 @@ bool CubicSDR::OnInit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int devId = wxGetSingleChoiceIndex(wxT("Devices"), wxT("Choose Input Device"), choices);
|
int devId = wxGetSingleChoiceIndex(wxT("Devices"), wxT("Choose Input Device"), choices);
|
||||||
|
if (devId == -1) { // User chose to cancel
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = devs[devId];
|
||||||
|
|
||||||
std::cout << "Chosen: " << devId << std::endl;
|
|
||||||
sdrThread->setDeviceId(devId);
|
sdrThread->setDeviceId(devId);
|
||||||
|
} else if (devs.size() == 1) {
|
||||||
|
dev = devs[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dev) {
|
||||||
|
wxMessageDialog *info;
|
||||||
|
info = new wxMessageDialog(NULL, wxT("\x28\u256F\xB0\u25A1\xB0\uFF09\u256F\uFE35\x20\u253B\u2501\u253B"), wxT("RTL-SDR device not found"), wxOK | wxICON_ERROR);
|
||||||
|
info->ShowModal();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
appframe = new AppFrame();
|
appframe = new AppFrame();
|
||||||
|
if (dev != NULL) {
|
||||||
|
appframe->initDeviceParams(dev->getDeviceId());
|
||||||
|
DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(dev->getDeviceId());
|
||||||
|
ppm = devConfig->getPPM();
|
||||||
|
offset = devConfig->getOffset();
|
||||||
|
directSamplingMode = devConfig->getDirectSampling();
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
int main_policy;
|
int main_policy;
|
||||||
@ -169,6 +190,9 @@ void CubicSDR::setOffset(long long ofs) {
|
|||||||
SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_SET_OFFSET);
|
SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_SET_OFFSET);
|
||||||
command.llong_value = ofs;
|
command.llong_value = ofs;
|
||||||
threadCmdQueueSDR->push(command);
|
threadCmdQueueSDR->push(command);
|
||||||
|
|
||||||
|
SDRDeviceInfo *dev = (*getDevices())[getDevice()];
|
||||||
|
config.getDevice(dev->getDeviceId())->setOffset(ofs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CubicSDR::setDirectSampling(int mode) {
|
void CubicSDR::setDirectSampling(int mode) {
|
||||||
@ -176,6 +200,9 @@ void CubicSDR::setDirectSampling(int mode) {
|
|||||||
SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_SET_DIRECT_SAMPLING);
|
SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_SET_DIRECT_SAMPLING);
|
||||||
command.llong_value = mode;
|
command.llong_value = mode;
|
||||||
threadCmdQueueSDR->push(command);
|
threadCmdQueueSDR->push(command);
|
||||||
|
|
||||||
|
SDRDeviceInfo *dev = (*getDevices())[getDevice()];
|
||||||
|
config.getDevice(dev->getDeviceId())->setDirectSampling(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CubicSDR::getDirectSampling() {
|
int CubicSDR::getDirectSampling() {
|
||||||
@ -184,6 +211,8 @@ int CubicSDR::getDirectSampling() {
|
|||||||
|
|
||||||
void CubicSDR::setSwapIQ(bool swapIQ) {
|
void CubicSDR::setSwapIQ(bool swapIQ) {
|
||||||
sdrPostThread->setSwapIQ(swapIQ);
|
sdrPostThread->setSwapIQ(swapIQ);
|
||||||
|
SDRDeviceInfo *dev = (*getDevices())[getDevice()];
|
||||||
|
config.getDevice(dev->getDeviceId())->setIQSwap(swapIQ);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CubicSDR::getSwapIQ() {
|
bool CubicSDR::getSwapIQ() {
|
||||||
@ -244,11 +273,12 @@ void CubicSDR::setDevice(int deviceId) {
|
|||||||
threadCmdQueueSDR->push(command);
|
threadCmdQueueSDR->push(command);
|
||||||
|
|
||||||
SDRDeviceInfo *dev = (*getDevices())[deviceId];
|
SDRDeviceInfo *dev = (*getDevices())[deviceId];
|
||||||
|
DeviceConfig *devConfig = config.getDevice(dev->getDeviceId());
|
||||||
|
|
||||||
SDRThreadCommand command_ppm(SDRThreadCommand::SDR_THREAD_CMD_SET_PPM);
|
setPPM(devConfig->getPPM());
|
||||||
ppm = config.getDevice(dev->getDeviceId())->getPPM();
|
setDirectSampling(devConfig->getDirectSampling());
|
||||||
command_ppm.llong_value = ppm;
|
setSwapIQ(devConfig->getIQSwap());
|
||||||
threadCmdQueueSDR->push(command_ppm);
|
setOffset(devConfig->getOffset());
|
||||||
}
|
}
|
||||||
|
|
||||||
int CubicSDR::getDevice() {
|
int CubicSDR::getDevice() {
|
||||||
@ -276,7 +306,6 @@ void CubicSDR::setPPM(int ppm_in) {
|
|||||||
SDRDeviceInfo *dev = (*getDevices())[getDevice()];
|
SDRDeviceInfo *dev = (*getDevices())[getDevice()];
|
||||||
|
|
||||||
config.getDevice(dev->getDeviceId())->setPPM(ppm_in);
|
config.getDevice(dev->getDeviceId())->setPPM(ppm_in);
|
||||||
config.save();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int CubicSDR::getPPM() {
|
int CubicSDR::getPPM() {
|
||||||
|
@ -22,7 +22,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), sampleRate(DEFAULT_SAMPLE_RATE), offset(0), snap(1) {
|
appframe(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), offset(0), snap(1), directSamplingMode(0), ppm(0) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,5 +53,5 @@ public:
|
|||||||
return refCount.load();
|
return refCount.load();
|
||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
std::atomic<int> refCount;
|
std::atomic_int refCount;
|
||||||
};
|
};
|
||||||
|
@ -65,7 +65,7 @@ std::string FrequencyDialog::frequencyToStr(long long freq) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
long long FrequencyDialog::strToFrequency(std::string freqStr) {
|
long long FrequencyDialog::strToFrequency(std::string freqStr) {
|
||||||
std::string filterStr = filterChars(freqStr, std::string("0123456789.MKGmkg"));
|
std::string filterStr = filterChars(freqStr, std::string("0123456789.MKGHmkgh"));
|
||||||
|
|
||||||
int numLen = filterStr.find_first_not_of("0123456789.");
|
int numLen = filterStr.find_first_not_of("0123456789.");
|
||||||
|
|
||||||
@ -90,8 +90,10 @@ long long FrequencyDialog::strToFrequency(std::string freqStr) {
|
|||||||
freqTemp *= 1.0e6;
|
freqTemp *= 1.0e6;
|
||||||
} else if (suffixStr.find_first_of("Kk") != std::string::npos) {
|
} else if (suffixStr.find_first_of("Kk") != std::string::npos) {
|
||||||
freqTemp *= 1.0e3;
|
freqTemp *= 1.0e3;
|
||||||
|
} else if (suffixStr.find_first_of("Hh") != std::string::npos) {
|
||||||
|
// ...
|
||||||
}
|
}
|
||||||
} else if (numPartStr.find_first_of(".") != std::string::npos) {
|
} else if (numPartStr.find_first_of(".") != std::string::npos || freqTemp <= 3000) {
|
||||||
freqTemp *= 1.0e6;
|
freqTemp *= 1.0e6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,12 +52,12 @@ public:
|
|||||||
|
|
||||||
AudioThreadInput *currentInput;
|
AudioThreadInput *currentInput;
|
||||||
AudioThreadInputQueue *inputQueue;
|
AudioThreadInputQueue *inputQueue;
|
||||||
std::atomic<unsigned int> audioQueuePtr;
|
std::atomic_uint audioQueuePtr;
|
||||||
std::atomic<unsigned int> underflowCount;
|
std::atomic_uint underflowCount;
|
||||||
std::atomic<bool> terminated;
|
std::atomic_bool terminated;
|
||||||
std::atomic<bool> initialized;
|
std::atomic_bool initialized;
|
||||||
std::atomic<bool> active;
|
std::atomic_bool active;
|
||||||
std::atomic<int> outputDevice;
|
std::atomic_int outputDevice;
|
||||||
std::atomic<float> gain;
|
std::atomic<float> gain;
|
||||||
|
|
||||||
AudioThread(AudioThreadInputQueue *inputQueue, DemodulatorThreadCommandQueue* threadQueueNotify);
|
AudioThread(AudioThreadInputQueue *inputQueue, DemodulatorThreadCommandQueue* threadQueueNotify);
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
#define DEMOD_TYPE_LSB 3
|
#define DEMOD_TYPE_LSB 3
|
||||||
#define DEMOD_TYPE_USB 4
|
#define DEMOD_TYPE_USB 4
|
||||||
#define DEMOD_TYPE_DSB 5
|
#define DEMOD_TYPE_DSB 5
|
||||||
|
#define DEMOD_TYPE_RAW 6
|
||||||
|
|
||||||
|
|
||||||
class DemodulatorThread;
|
class DemodulatorThread;
|
||||||
class DemodulatorThreadCommand {
|
class DemodulatorThreadCommand {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
DemodulatorInstance::DemodulatorInstance() :
|
DemodulatorInstance::DemodulatorInstance() :
|
||||||
t_Demod(NULL), t_PreDemod(NULL), t_Audio(NULL), threadQueueDemod(NULL), demodulatorThread(NULL), terminated(true), audioTerminated(true), demodTerminated(
|
t_Demod(NULL), t_PreDemod(NULL), t_Audio(NULL), threadQueueDemod(NULL), demodulatorThread(NULL), terminated(true), audioTerminated(true), demodTerminated(
|
||||||
true), preDemodTerminated(true), active(false), squelch(false), stereo(false), currentFrequency(0), currentBandwidth(0), currentOutputDevice(-1) {
|
true), preDemodTerminated(true), active(false), squelch(false), stereo(false), tracking(false), follow(false), currentAudioSampleRate(0), currentFrequency(0), currentBandwidth(0), currentOutputDevice(-1), currentAudioGain(1.0) {
|
||||||
|
|
||||||
label = new std::string("Unnamed");
|
label = new std::string("Unnamed");
|
||||||
threadQueueDemod = new DemodulatorThreadInputQueue;
|
threadQueueDemod = new DemodulatorThreadInputQueue;
|
||||||
@ -220,13 +220,12 @@ void DemodulatorInstance::setOutputDevice(int device_id) {
|
|||||||
if (!active) {
|
if (!active) {
|
||||||
audioThread->setInitOutputDevice(device_id);
|
audioThread->setInitOutputDevice(device_id);
|
||||||
} else if (audioThread) {
|
} else if (audioThread) {
|
||||||
setAudioSampleRate(AudioThread::deviceSampleRate[device_id]);
|
|
||||||
|
|
||||||
AudioThreadCommand command;
|
AudioThreadCommand command;
|
||||||
command.cmd = AudioThreadCommand::AUDIO_THREAD_CMD_SET_DEVICE;
|
command.cmd = AudioThreadCommand::AUDIO_THREAD_CMD_SET_DEVICE;
|
||||||
command.int_value = device_id;
|
command.int_value = device_id;
|
||||||
audioThread->getCommandQueue()->push(command);
|
audioThread->getCommandQueue()->push(command);
|
||||||
}
|
}
|
||||||
|
setAudioSampleRate(AudioThread::deviceSampleRate[device_id]);
|
||||||
currentOutputDevice = device_id;
|
currentOutputDevice = device_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,15 +244,28 @@ void DemodulatorInstance::checkBandwidth() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DemodulatorInstance::setDemodulatorType(int demod_type_in) {
|
void DemodulatorInstance::setDemodulatorType(int demod_type_in) {
|
||||||
if (!active) {
|
|
||||||
currentDemodType = demod_type_in;
|
currentDemodType = demod_type_in;
|
||||||
|
|
||||||
|
if (currentDemodType == DEMOD_TYPE_RAW) {
|
||||||
|
if (currentAudioSampleRate) {
|
||||||
|
setBandwidth(currentAudioSampleRate);
|
||||||
|
} else {
|
||||||
|
setBandwidth(AudioThread::deviceSampleRate[getOutputDevice()]);
|
||||||
|
}
|
||||||
|
} else if (currentDemodType == DEMOD_TYPE_USB || currentDemodType == DEMOD_TYPE_LSB || currentDemodType == DEMOD_TYPE_DSB || currentDemodType == DEMOD_TYPE_AM) {
|
||||||
|
demodulatorThread->setAGC(false);
|
||||||
|
} else {
|
||||||
|
demodulatorThread->setAGC(true);
|
||||||
|
}
|
||||||
|
setGain(getGain());
|
||||||
|
|
||||||
|
if (!active) {
|
||||||
checkBandwidth();
|
checkBandwidth();
|
||||||
demodulatorPreThread->getParams().demodType = currentDemodType;
|
demodulatorPreThread->getParams().demodType = currentDemodType;
|
||||||
demodulatorThread->setDemodulatorType(currentDemodType);
|
demodulatorThread->setDemodulatorType(currentDemodType);
|
||||||
} else if (demodulatorThread && threadQueueControl) {
|
} else if (demodulatorThread && threadQueueControl) {
|
||||||
DemodulatorThreadControlCommand command;
|
DemodulatorThreadControlCommand command;
|
||||||
command.cmd = DemodulatorThreadControlCommand::DEMOD_THREAD_CMD_CTL_TYPE;
|
command.cmd = DemodulatorThreadControlCommand::DEMOD_THREAD_CMD_CTL_TYPE;
|
||||||
currentDemodType = demod_type_in;
|
|
||||||
command.demodType = demod_type_in;
|
command.demodType = demod_type_in;
|
||||||
checkBandwidth();
|
checkBandwidth();
|
||||||
threadQueueControl->push(command);
|
threadQueueControl->push(command);
|
||||||
@ -265,6 +277,13 @@ int DemodulatorInstance::getDemodulatorType() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DemodulatorInstance::setBandwidth(int bw) {
|
void DemodulatorInstance::setBandwidth(int bw) {
|
||||||
|
if (currentDemodType == DEMOD_TYPE_RAW) {
|
||||||
|
if (currentAudioSampleRate) {
|
||||||
|
bw = currentAudioSampleRate;
|
||||||
|
} else {
|
||||||
|
bw = AudioThread::deviceSampleRate[getOutputDevice()];
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!active) {
|
if (!active) {
|
||||||
currentBandwidth = bw;
|
currentBandwidth = bw;
|
||||||
checkBandwidth();
|
checkBandwidth();
|
||||||
@ -321,6 +340,9 @@ void DemodulatorInstance::setAudioSampleRate(int sampleRate) {
|
|||||||
command.llong_value = sampleRate;
|
command.llong_value = sampleRate;
|
||||||
threadQueueCommand->push(command);
|
threadQueueCommand->push(command);
|
||||||
}
|
}
|
||||||
|
if (currentDemodType == DEMOD_TYPE_RAW) {
|
||||||
|
setBandwidth(currentAudioSampleRate);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int DemodulatorInstance::getAudioSampleRate() {
|
int DemodulatorInstance::getAudioSampleRate() {
|
||||||
@ -332,11 +354,23 @@ int DemodulatorInstance::getAudioSampleRate() {
|
|||||||
|
|
||||||
|
|
||||||
void DemodulatorInstance::setGain(float gain_in) {
|
void DemodulatorInstance::setGain(float gain_in) {
|
||||||
|
currentAudioGain = gain_in;
|
||||||
|
|
||||||
|
if (currentDemodType == DEMOD_TYPE_RAW) {
|
||||||
|
if (gain_in < 0.25) {
|
||||||
|
audioThread->setGain(1.0);
|
||||||
|
demodulatorThread->setAGC(false);
|
||||||
|
} else {
|
||||||
audioThread->setGain(gain_in);
|
audioThread->setGain(gain_in);
|
||||||
|
demodulatorThread->setAGC(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
audioThread->setGain(gain_in);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float DemodulatorInstance::getGain() {
|
float DemodulatorInstance::getGain() {
|
||||||
return audioThread->getGain();
|
return currentAudioGain;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DemodulatorInstance::isFollow() {
|
bool DemodulatorInstance::isFollow() {
|
||||||
|
@ -87,18 +87,19 @@ private:
|
|||||||
void checkBandwidth();
|
void checkBandwidth();
|
||||||
|
|
||||||
std::atomic<std::string *> label; //
|
std::atomic<std::string *> label; //
|
||||||
bool terminated; //
|
std::atomic_bool terminated; //
|
||||||
bool demodTerminated; //
|
std::atomic_bool demodTerminated; //
|
||||||
bool audioTerminated; //
|
std::atomic_bool audioTerminated; //
|
||||||
bool preDemodTerminated;
|
std::atomic_bool preDemodTerminated;
|
||||||
std::atomic<bool> active;
|
std::atomic_bool active;
|
||||||
std::atomic<bool> squelch;
|
std::atomic_bool squelch;
|
||||||
std::atomic<bool> stereo;
|
std::atomic_bool stereo;
|
||||||
|
|
||||||
long long currentFrequency;
|
std::atomic_llong currentFrequency;
|
||||||
int currentBandwidth;
|
std::atomic_int currentBandwidth;
|
||||||
int currentDemodType;
|
std::atomic_int currentDemodType;
|
||||||
int currentOutputDevice;
|
std::atomic_int currentOutputDevice;
|
||||||
int currentAudioSampleRate;
|
std::atomic_int currentAudioSampleRate;
|
||||||
bool follow, tracking;
|
std::atomic<float> currentAudioGain;
|
||||||
|
std::atomic_bool follow, tracking;
|
||||||
};
|
};
|
||||||
|
@ -68,8 +68,8 @@ protected:
|
|||||||
nco_crcf freqShifter;
|
nco_crcf freqShifter;
|
||||||
int shiftFrequency;
|
int shiftFrequency;
|
||||||
|
|
||||||
std::atomic<bool> terminated;
|
std::atomic_bool terminated;
|
||||||
std::atomic<bool> initialized;
|
std::atomic_bool initialized;
|
||||||
|
|
||||||
DemodulatorWorkerThread *workerThread;
|
DemodulatorWorkerThread *workerThread;
|
||||||
std::thread *t_Worker;
|
std::thread *t_Worker;
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
DemodulatorThread::DemodulatorThread(DemodulatorThreadPostInputQueue* iqInputQueue, DemodulatorThreadControlCommandQueue *threadQueueControl,
|
DemodulatorThread::DemodulatorThread(DemodulatorThreadPostInputQueue* iqInputQueue, DemodulatorThreadControlCommandQueue *threadQueueControl,
|
||||||
DemodulatorThreadCommandQueue* threadQueueNotify) :
|
DemodulatorThreadCommandQueue* threadQueueNotify) :
|
||||||
iqInputQueue(iqInputQueue), audioVisOutputQueue(NULL), audioOutputQueue(NULL), iqAutoGain(NULL), amOutputCeil(1), amOutputCeilMA(1), amOutputCeilMAA(
|
iqInputQueue(iqInputQueue), audioVisOutputQueue(NULL), audioOutputQueue(NULL), iqAutoGain(NULL), amOutputCeil(1), amOutputCeilMA(1), amOutputCeilMAA(
|
||||||
1), stereo(false), terminated(
|
1), stereo(false), agcEnabled(true), terminated(
|
||||||
false), demodulatorType(DEMOD_TYPE_FM), threadQueueNotify(threadQueueNotify), threadQueueControl(threadQueueControl), squelchLevel(0), signalLevel(
|
false), demodulatorType(DEMOD_TYPE_FM), threadQueueNotify(threadQueueNotify), threadQueueControl(threadQueueControl), squelchLevel(0), signalLevel(
|
||||||
0), squelchEnabled(false), audioSampleRate(0) {
|
0), squelchEnabled(false), audioSampleRate(0) {
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ void DemodulatorThread::threadMain() {
|
|||||||
|
|
||||||
// Automatic IQ gain
|
// Automatic IQ gain
|
||||||
iqAutoGain = agc_crcf_create();
|
iqAutoGain = agc_crcf_create();
|
||||||
agc_crcf_set_bandwidth(iqAutoGain, 0.9);
|
agc_crcf_set_bandwidth(iqAutoGain, 0.1);
|
||||||
|
|
||||||
AudioThreadInput *ati_vis = new AudioThreadInput;
|
AudioThreadInput *ati_vis = new AudioThreadInput;
|
||||||
ati_vis->data.reserve(DEMOD_VIS_SIZE);
|
ati_vis->data.reserve(DEMOD_VIS_SIZE);
|
||||||
@ -171,27 +171,37 @@ void DemodulatorThread::threadMain() {
|
|||||||
currentSignalLevel = agc_crcf_get_signal_level(iqAutoGain);
|
currentSignalLevel = agc_crcf_get_signal_level(iqAutoGain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<liquid_float_complex> *inputData;
|
||||||
|
|
||||||
|
if (agcEnabled) {
|
||||||
|
inputData = &agcData;
|
||||||
|
} else {
|
||||||
|
inputData = &inp->data;
|
||||||
|
}
|
||||||
|
|
||||||
if (demodulatorType == DEMOD_TYPE_FM) {
|
if (demodulatorType == DEMOD_TYPE_FM) {
|
||||||
freqdem_demodulate_block(demodFM, &agcData[0], bufSize, &demodOutputData[0]);
|
freqdem_demodulate_block(demodFM, &(*inputData)[0], bufSize, &demodOutputData[0]);
|
||||||
|
} else if (demodulatorType == DEMOD_TYPE_RAW) {
|
||||||
|
// do nothing here..
|
||||||
} else {
|
} else {
|
||||||
float p;
|
float p;
|
||||||
switch (demodulatorType.load()) {
|
switch (demodulatorType.load()) {
|
||||||
case DEMOD_TYPE_LSB:
|
case DEMOD_TYPE_LSB:
|
||||||
for (int i = 0; i < bufSize; i++) { // Reject upper band
|
for (int i = 0; i < bufSize; i++) { // Reject upper band
|
||||||
resamp2_cccf_filter_execute(ssbFilt,inp->data[i],&x,&y);
|
resamp2_cccf_filter_execute(ssbFilt,(*inputData)[i],&x,&y);
|
||||||
ampmodem_demodulate(demodAM, x, &demodOutputData[i]);
|
ampmodem_demodulate(demodAM, x, &demodOutputData[i]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DEMOD_TYPE_USB:
|
case DEMOD_TYPE_USB:
|
||||||
for (int i = 0; i < bufSize; i++) { // Reject lower band
|
for (int i = 0; i < bufSize; i++) { // Reject lower band
|
||||||
resamp2_cccf_filter_execute(ssbFilt,inp->data[i],&x,&y);
|
resamp2_cccf_filter_execute(ssbFilt,(*inputData)[i],&x,&y);
|
||||||
ampmodem_demodulate(demodAM, y, &demodOutputData[i]);
|
ampmodem_demodulate(demodAM, y, &demodOutputData[i]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DEMOD_TYPE_AM:
|
case DEMOD_TYPE_AM:
|
||||||
case DEMOD_TYPE_DSB:
|
case DEMOD_TYPE_DSB:
|
||||||
for (int i = 0; i < bufSize; i++) {
|
for (int i = 0; i < bufSize; i++) {
|
||||||
ampmodem_demodulate(demodAM, inp->data[i], &demodOutputData[i]);
|
ampmodem_demodulate(demodAM, (*inputData)[i], &demodOutputData[i]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -222,6 +232,10 @@ void DemodulatorThread::threadMain() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsigned int numAudioWritten;
|
unsigned int numAudioWritten;
|
||||||
|
|
||||||
|
if (demodulatorType == DEMOD_TYPE_RAW) {
|
||||||
|
numAudioWritten = bufSize;
|
||||||
|
} else {
|
||||||
msresamp_rrrf_execute(audioResampler, &demodOutputData[0], bufSize, &resampledOutputData[0], &numAudioWritten);
|
msresamp_rrrf_execute(audioResampler, &demodOutputData[0], bufSize, &resampledOutputData[0], &numAudioWritten);
|
||||||
|
|
||||||
if (stereo && inp->sampleRate >= 100000) {
|
if (stereo && inp->sampleRate >= 100000) {
|
||||||
@ -276,6 +290,7 @@ void DemodulatorThread::threadMain() {
|
|||||||
|
|
||||||
msresamp_rrrf_execute(stereoResampler, &demodStereoData[0], bufSize, &resampledStereoData[0], &numAudioWritten);
|
msresamp_rrrf_execute(stereoResampler, &demodStereoData[0], bufSize, &resampledStereoData[0], &numAudioWritten);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (currentSignalLevel > signalLevel) {
|
if (currentSignalLevel > signalLevel) {
|
||||||
signalLevel = signalLevel + (currentSignalLevel - signalLevel) * 0.5;
|
signalLevel = signalLevel + (currentSignalLevel - signalLevel) * 0.5;
|
||||||
@ -303,7 +318,17 @@ void DemodulatorThread::threadMain() {
|
|||||||
ati->sampleRate = audioSampleRate;
|
ati->sampleRate = audioSampleRate;
|
||||||
ati->setRefCount(1);
|
ati->setRefCount(1);
|
||||||
|
|
||||||
if (stereo && inp->sampleRate >= 100000) {
|
if (demodulatorType == DEMOD_TYPE_RAW) {
|
||||||
|
ati->channels = 2;
|
||||||
|
if (ati->data.capacity() < (numAudioWritten * 2)) {
|
||||||
|
ati->data.reserve(numAudioWritten * 2);
|
||||||
|
}
|
||||||
|
ati->data.resize(numAudioWritten * 2);
|
||||||
|
for (int i = 0; i < numAudioWritten; i++) {
|
||||||
|
ati->data[i * 2] = (*inputData)[i].real;
|
||||||
|
ati->data[i * 2 + 1] = (*inputData)[i].imag;
|
||||||
|
}
|
||||||
|
} else if (stereo && inp->sampleRate >= 100000) {
|
||||||
ati->channels = 2;
|
ati->channels = 2;
|
||||||
if (ati->data.capacity() < (numAudioWritten * 2)) {
|
if (ati->data.capacity() < (numAudioWritten * 2)) {
|
||||||
ati->data.reserve(numAudioWritten * 2);
|
ati->data.reserve(numAudioWritten * 2);
|
||||||
@ -334,8 +359,6 @@ void DemodulatorThread::threadMain() {
|
|||||||
ati->peak = p;
|
ati->peak = p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
audioOutputQueue->push(ati);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,19 +367,26 @@ void DemodulatorThread::threadMain() {
|
|||||||
ati_vis->busy_update.lock();
|
ati_vis->busy_update.lock();
|
||||||
|
|
||||||
int num_vis = DEMOD_VIS_SIZE;
|
int num_vis = DEMOD_VIS_SIZE;
|
||||||
if (stereo && inp->sampleRate >= 100000) {
|
if (demodulatorType == DEMOD_TYPE_RAW || (stereo && inp->sampleRate >= 100000)) {
|
||||||
ati_vis->channels = 2;
|
ati_vis->channels = 2;
|
||||||
int stereoSize = ati->data.size();
|
int stereoSize = ati->data.size();
|
||||||
if (stereoSize > DEMOD_VIS_SIZE) {
|
if (stereoSize > DEMOD_VIS_SIZE * 2) {
|
||||||
stereoSize = DEMOD_VIS_SIZE;
|
stereoSize = DEMOD_VIS_SIZE * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
ati_vis->data.resize(stereoSize);
|
ati_vis->data.resize(stereoSize);
|
||||||
|
|
||||||
|
if (demodulatorType == DEMOD_TYPE_RAW) {
|
||||||
|
for (int i = 0; i < stereoSize / 2; i++) {
|
||||||
|
ati_vis->data[i] = agcData[i].real * 0.75;
|
||||||
|
ati_vis->data[i + stereoSize / 2] = agcData[i].imag * 0.75;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
for (int i = 0; i < stereoSize / 2; i++) {
|
for (int i = 0; i < stereoSize / 2; i++) {
|
||||||
ati_vis->data[i] = ati->data[i * 2];
|
ati_vis->data[i] = ati->data[i * 2];
|
||||||
ati_vis->data[i + stereoSize / 2] = ati->data[i * 2 + 1];
|
ati_vis->data[i + stereoSize / 2] = ati->data[i * 2 + 1];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ati_vis->channels = 1;
|
ati_vis->channels = 1;
|
||||||
if (numAudioWritten > bufSize) {
|
if (numAudioWritten > bufSize) {
|
||||||
@ -379,6 +409,11 @@ void DemodulatorThread::threadMain() {
|
|||||||
|
|
||||||
ati_vis->busy_update.unlock();
|
ati_vis->busy_update.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ati != NULL) {
|
||||||
|
audioOutputQueue->push(ati);
|
||||||
|
}
|
||||||
|
|
||||||
if (!threadQueueControl->empty()) {
|
if (!threadQueueControl->empty()) {
|
||||||
int newDemodType = DEMOD_TYPE_NULL;
|
int newDemodType = DEMOD_TYPE_NULL;
|
||||||
|
|
||||||
@ -489,16 +524,25 @@ void DemodulatorThread::terminate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DemodulatorThread::setStereo(bool state) {
|
void DemodulatorThread::setStereo(bool state) {
|
||||||
stereo = state;
|
stereo.store(state);
|
||||||
std::cout << "Stereo " << (state ? "Enabled" : "Disabled") << std::endl;
|
std::cout << "Stereo " << (state ? "Enabled" : "Disabled") << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DemodulatorThread::isStereo() {
|
bool DemodulatorThread::isStereo() {
|
||||||
return stereo;
|
return stereo.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DemodulatorThread::setAGC(bool state) {
|
||||||
|
agcEnabled.store(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DemodulatorThread::getAGC() {
|
||||||
|
return agcEnabled.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
float DemodulatorThread::getSignalLevel() {
|
float DemodulatorThread::getSignalLevel() {
|
||||||
return signalLevel;
|
return signalLevel.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DemodulatorThread::setSquelchLevel(float signal_level_in) {
|
void DemodulatorThread::setSquelchLevel(float signal_level_in) {
|
||||||
|
@ -31,6 +31,9 @@ public:
|
|||||||
void setStereo(bool state);
|
void setStereo(bool state);
|
||||||
bool isStereo();
|
bool isStereo();
|
||||||
|
|
||||||
|
void setAGC(bool state);
|
||||||
|
bool getAGC();
|
||||||
|
|
||||||
float getSignalLevel();
|
float getSignalLevel();
|
||||||
void setSquelchLevel(float signal_level_in);
|
void setSquelchLevel(float signal_level_in);
|
||||||
float getSquelchLevel();
|
float getSquelchLevel();
|
||||||
@ -72,9 +75,10 @@ protected:
|
|||||||
float amOutputCeilMA;
|
float amOutputCeilMA;
|
||||||
float amOutputCeilMAA;
|
float amOutputCeilMAA;
|
||||||
|
|
||||||
std::atomic<bool> stereo;
|
std::atomic_bool stereo;
|
||||||
std::atomic<bool> terminated;
|
std::atomic_bool agcEnabled;
|
||||||
std::atomic<int> demodulatorType;
|
std::atomic_bool terminated;
|
||||||
|
std::atomic_int demodulatorType;
|
||||||
int audioSampleRate;
|
int audioSampleRate;
|
||||||
|
|
||||||
DemodulatorThreadCommandQueue* threadQueueNotify;
|
DemodulatorThreadCommandQueue* threadQueueNotify;
|
||||||
|
@ -93,5 +93,5 @@ protected:
|
|||||||
DemodulatorThreadWorkerCommandQueue *commandQueue;
|
DemodulatorThreadWorkerCommandQueue *commandQueue;
|
||||||
DemodulatorThreadWorkerResultQueue *resultQueue;
|
DemodulatorThreadWorkerResultQueue *resultQueue;
|
||||||
|
|
||||||
std::atomic<bool> terminated;
|
std::atomic_bool terminated;
|
||||||
};
|
};
|
||||||
|
@ -31,10 +31,10 @@ protected:
|
|||||||
|
|
||||||
std::mutex busy_demod;
|
std::mutex busy_demod;
|
||||||
std::vector<DemodulatorInstance *> demodulators;
|
std::vector<DemodulatorInstance *> demodulators;
|
||||||
std::atomic<bool> terminated;
|
std::atomic_bool terminated;
|
||||||
iirfilt_crcf dcFilter;
|
iirfilt_crcf dcFilter;
|
||||||
int num_vis_samples;
|
int num_vis_samples;
|
||||||
std::atomic<bool> swapIQ;
|
std::atomic_bool swapIQ;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<liquid_float_complex> _lut;
|
std::vector<liquid_float_complex> _lut;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
SDRThread::SDRThread(SDRThreadCommandQueue* pQueue) :
|
SDRThread::SDRThread(SDRThreadCommandQueue* pQueue) :
|
||||||
commandQueue(pQueue), iqDataOutQueue(NULL), terminated(false), offset(0), deviceId(-1) {
|
commandQueue(pQueue), iqDataOutQueue(NULL), terminated(false), offset(0), deviceId(-1) {
|
||||||
dev = NULL;
|
dev = NULL;
|
||||||
sampleRate = DEFAULT_SAMPLE_RATE;
|
sampleRate.store(DEFAULT_SAMPLE_RATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDRThread::~SDRThread() {
|
SDRThread::~SDRThread() {
|
||||||
@ -122,6 +122,7 @@ void SDRThread::threadMain() {
|
|||||||
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();
|
||||||
|
|
||||||
std::vector<SDRDeviceInfo *> devs;
|
std::vector<SDRDeviceInfo *> devs;
|
||||||
if (deviceId == -1) {
|
if (deviceId == -1) {
|
||||||
deviceId = enumerate_rtl(&devs);
|
deviceId = enumerate_rtl(&devs);
|
||||||
@ -136,16 +137,20 @@ void SDRThread::threadMain() {
|
|||||||
std::cout << "Using device #" << deviceId << std::endl;
|
std::cout << "Using device #" << deviceId << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(devs[deviceId]->getDeviceId());
|
||||||
|
|
||||||
signed char buf[BUF_SIZE];
|
signed char buf[BUF_SIZE];
|
||||||
|
|
||||||
long long frequency = DEFAULT_FREQ;
|
long long frequency = DEFAULT_FREQ;
|
||||||
int ppm = wxGetApp().getConfig()->getDevice(devs[deviceId]->getDeviceId())->getPPM();
|
int ppm = devConfig->getPPM();
|
||||||
int direct_sampling_mode = 0;
|
int direct_sampling_mode = devConfig->getDirectSampling();;
|
||||||
int buf_size = BUF_SIZE;
|
int buf_size = BUF_SIZE;
|
||||||
|
offset.store(devConfig->getOffset());
|
||||||
|
wxGetApp().setSwapIQ(devConfig->getIQSwap());
|
||||||
|
|
||||||
rtlsdr_open(&dev, deviceId);
|
rtlsdr_open(&dev, deviceId);
|
||||||
rtlsdr_set_sample_rate(dev, sampleRate);
|
rtlsdr_set_sample_rate(dev, sampleRate.load());
|
||||||
rtlsdr_set_center_freq(dev, frequency - offset);
|
rtlsdr_set_center_freq(dev, frequency - offset.load());
|
||||||
rtlsdr_set_freq_correction(dev, ppm);
|
rtlsdr_set_freq_correction(dev, ppm);
|
||||||
rtlsdr_set_agc_mode(dev, 1);
|
rtlsdr_set_agc_mode(dev, 1);
|
||||||
rtlsdr_set_offset_tuning(dev, 0);
|
rtlsdr_set_offset_tuning(dev, 0);
|
||||||
@ -153,7 +158,7 @@ void SDRThread::threadMain() {
|
|||||||
|
|
||||||
// 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.load() << std::endl;
|
||||||
|
|
||||||
int n_read;
|
int n_read;
|
||||||
double seconds = 0.0;
|
double seconds = 0.0;
|
||||||
@ -174,8 +179,8 @@ void SDRThread::threadMain() {
|
|||||||
bool ppm_changed = false;
|
bool ppm_changed = false;
|
||||||
bool direct_sampling_changed = false;
|
bool direct_sampling_changed = false;
|
||||||
long long new_freq = frequency;
|
long long new_freq = frequency;
|
||||||
long long new_offset = offset;
|
long long new_offset = offset.load();
|
||||||
long long new_rate = sampleRate;
|
long long new_rate = sampleRate.load();
|
||||||
int new_device = deviceId;
|
int new_device = deviceId;
|
||||||
int new_ppm = ppm;
|
int new_ppm = ppm;
|
||||||
|
|
||||||
@ -187,8 +192,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 < sampleRate / 2) {
|
if (new_freq < sampleRate.load() / 2) {
|
||||||
new_freq = sampleRate / 2;
|
new_freq = sampleRate.load() / 2;
|
||||||
}
|
}
|
||||||
// std::cout << "Set frequency: " << new_freq << std::endl;
|
// std::cout << "Set frequency: " << new_freq << std::endl;
|
||||||
break;
|
break;
|
||||||
@ -231,8 +236,8 @@ void SDRThread::threadMain() {
|
|||||||
if (device_changed) {
|
if (device_changed) {
|
||||||
rtlsdr_close(dev);
|
rtlsdr_close(dev);
|
||||||
rtlsdr_open(&dev, new_device);
|
rtlsdr_open(&dev, new_device);
|
||||||
rtlsdr_set_sample_rate(dev, sampleRate);
|
rtlsdr_set_sample_rate(dev, sampleRate.load());
|
||||||
rtlsdr_set_center_freq(dev, frequency - offset);
|
rtlsdr_set_center_freq(dev, frequency - offset.load());
|
||||||
rtlsdr_set_freq_correction(dev, ppm);
|
rtlsdr_set_freq_correction(dev, ppm);
|
||||||
rtlsdr_set_agc_mode(dev, 1);
|
rtlsdr_set_agc_mode(dev, 1);
|
||||||
rtlsdr_set_offset_tuning(dev, 0);
|
rtlsdr_set_offset_tuning(dev, 0);
|
||||||
@ -244,16 +249,16 @@ void SDRThread::threadMain() {
|
|||||||
new_freq = frequency;
|
new_freq = frequency;
|
||||||
freq_changed = true;
|
freq_changed = true;
|
||||||
}
|
}
|
||||||
offset = new_offset;
|
offset.store(new_offset);
|
||||||
}
|
}
|
||||||
if (rate_changed) {
|
if (rate_changed) {
|
||||||
rtlsdr_set_sample_rate(dev, new_rate);
|
rtlsdr_set_sample_rate(dev, new_rate);
|
||||||
rtlsdr_reset_buffer(dev);
|
rtlsdr_reset_buffer(dev);
|
||||||
sampleRate = rtlsdr_get_sample_rate(dev);
|
sampleRate.store(rtlsdr_get_sample_rate(dev));
|
||||||
}
|
}
|
||||||
if (freq_changed) {
|
if (freq_changed) {
|
||||||
frequency = new_freq;
|
frequency = new_freq;
|
||||||
rtlsdr_set_center_freq(dev, frequency - offset);
|
rtlsdr_set_center_freq(dev, frequency - offset.load());
|
||||||
}
|
}
|
||||||
if (ppm_changed) {
|
if (ppm_changed) {
|
||||||
ppm = new_ppm;
|
ppm = new_ppm;
|
||||||
@ -283,7 +288,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->sampleRate = sampleRate;
|
dataOut->sampleRate = sampleRate.load();
|
||||||
|
|
||||||
if (dataOut->data.capacity() < n_read) {
|
if (dataOut->data.capacity() < n_read) {
|
||||||
dataOut->data.reserve(n_read);
|
dataOut->data.reserve(n_read);
|
||||||
@ -295,7 +300,7 @@ void SDRThread::threadMain() {
|
|||||||
|
|
||||||
memcpy(&dataOut->data[0], buf, n_read);
|
memcpy(&dataOut->data[0], buf, n_read);
|
||||||
|
|
||||||
double time_slice = (double) n_read / (double) sampleRate;
|
double time_slice = (double) n_read / (double) sampleRate.load();
|
||||||
seconds += time_slice;
|
seconds += time_slice;
|
||||||
|
|
||||||
if (iqDataOutQueue.load() != NULL) {
|
if (iqDataOutQueue.load() != NULL) {
|
||||||
|
@ -140,19 +140,19 @@ public:
|
|||||||
void terminate();
|
void terminate();
|
||||||
|
|
||||||
int getDeviceId() const {
|
int getDeviceId() const {
|
||||||
return deviceId;
|
return deviceId.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDeviceId(int deviceId) {
|
void setDeviceId(int deviceId) {
|
||||||
this->deviceId = deviceId;
|
this->deviceId.store(deviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint32_t sampleRate;
|
std::atomic<uint32_t> sampleRate;
|
||||||
long long offset;
|
std::atomic_llong offset;
|
||||||
std::atomic<SDRThreadCommandQueue*> commandQueue;
|
std::atomic<SDRThreadCommandQueue*> commandQueue;
|
||||||
std::atomic<SDRThreadIQDataQueue*> iqDataOutQueue;
|
std::atomic<SDRThreadIQDataQueue*> iqDataOutQueue;
|
||||||
|
|
||||||
std::atomic<bool> terminated;
|
std::atomic_bool terminated;
|
||||||
int deviceId;
|
std::atomic_int deviceId;
|
||||||
};
|
};
|
||||||
|
@ -820,8 +820,8 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
|
|||||||
demod = wxGetApp().getDemodMgr().newThread();
|
demod = wxGetApp().getDemodMgr().newThread();
|
||||||
demod->setFrequency(freq);
|
demod->setFrequency(freq);
|
||||||
|
|
||||||
demod->setBandwidth(mgr->getLastBandwidth());
|
|
||||||
demod->setDemodulatorType(mgr->getLastDemodulatorType());
|
demod->setDemodulatorType(mgr->getLastDemodulatorType());
|
||||||
|
demod->setBandwidth(mgr->getLastBandwidth());
|
||||||
demod->setSquelchLevel(mgr->getLastSquelchLevel());
|
demod->setSquelchLevel(mgr->getLastSquelchLevel());
|
||||||
demod->setSquelchEnabled(mgr->isLastSquelchEnabled());
|
demod->setSquelchEnabled(mgr->isLastSquelchEnabled());
|
||||||
demod->setStereo(mgr->isLastStereo());
|
demod->setStereo(mgr->isLastStereo());
|
||||||
@ -907,9 +907,8 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
|
|||||||
} else {
|
} else {
|
||||||
demod = wxGetApp().getDemodMgr().newThread();
|
demod = wxGetApp().getDemodMgr().newThread();
|
||||||
demod->setFrequency(freq);
|
demod->setFrequency(freq);
|
||||||
demod->setBandwidth(bw);
|
|
||||||
|
|
||||||
demod->setDemodulatorType(mgr->getLastDemodulatorType());
|
demod->setDemodulatorType(mgr->getLastDemodulatorType());
|
||||||
|
demod->setBandwidth(bw);
|
||||||
demod->setSquelchLevel(mgr->getLastSquelchLevel());
|
demod->setSquelchLevel(mgr->getLastSquelchLevel());
|
||||||
demod->setSquelchEnabled(mgr->isLastSquelchEnabled());
|
demod->setSquelchEnabled(mgr->isLastSquelchEnabled());
|
||||||
demod->setStereo(mgr->isLastStereo());
|
demod->setStereo(mgr->isLastStereo());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user