mirror of
https://github.com/cjcliffe/CubicSDR.git
synced 2025-02-03 09:44:26 -05:00
Merge pull request #71 from cjcliffe/ppm_correction
PPM menu dialog and tuning bar tool
This commit is contained in:
commit
bad45a7eab
@ -226,6 +226,7 @@ ENDIF (APPLE)
|
|||||||
SET (cubicsdr_sources
|
SET (cubicsdr_sources
|
||||||
src/CubicSDR.cpp
|
src/CubicSDR.cpp
|
||||||
src/AppFrame.cpp
|
src/AppFrame.cpp
|
||||||
|
src/AppConfig.cpp
|
||||||
src/sdr/SDRThread.cpp
|
src/sdr/SDRThread.cpp
|
||||||
src/sdr/SDRPostThread.cpp
|
src/sdr/SDRPostThread.cpp
|
||||||
src/demod/DemodulatorPreThread.cpp
|
src/demod/DemodulatorPreThread.cpp
|
||||||
@ -267,6 +268,7 @@ SET (cubicsdr_headers
|
|||||||
src/CubicSDRDefs.h
|
src/CubicSDRDefs.h
|
||||||
src/CubicSDR.h
|
src/CubicSDR.h
|
||||||
src/AppFrame.h
|
src/AppFrame.h
|
||||||
|
src/AppConfig.h
|
||||||
src/sdr/SDRThread.h
|
src/sdr/SDRThread.h
|
||||||
src/sdr/SDRPostThread.h
|
src/sdr/SDRPostThread.h
|
||||||
src/demod/DemodulatorPreThread.h
|
src/demod/DemodulatorPreThread.h
|
||||||
|
133
src/AppConfig.cpp
Normal file
133
src/AppConfig.cpp
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
#include "AppConfig.h"
|
||||||
|
|
||||||
|
DeviceConfig::DeviceConfig() : ppm(0), deviceId("") {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceConfig::DeviceConfig(std::string deviceId) : ppm(0) {
|
||||||
|
this->deviceId = deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceConfig::setPPM(int ppm) {
|
||||||
|
this->ppm = ppm;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DeviceConfig::getPPM() {
|
||||||
|
return ppm;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceConfig::setDeviceId(std::string deviceId) {
|
||||||
|
this->deviceId = deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string DeviceConfig::getDeviceId() {
|
||||||
|
return deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceConfig::save(DataNode *node) {
|
||||||
|
node->newChild("id")->element()->set(deviceId);
|
||||||
|
DataNode *ppm_node = node->newChild("ppm");
|
||||||
|
ppm_node->element()->set((int)ppm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceConfig::load(DataNode *node) {
|
||||||
|
if (node->hasAnother("ppm")) {
|
||||||
|
DataNode *ppm_node = node->getNext("ppm");
|
||||||
|
int ppmValue = 0;
|
||||||
|
ppm_node->element()->get(ppmValue);
|
||||||
|
setPPM(ppmValue);
|
||||||
|
std::cout << "Loaded PPM for device '" << deviceId << "' at " << ppmValue << "ppm" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DeviceConfig *AppConfig::getDevice(std::string deviceId) {
|
||||||
|
DeviceConfig *conf = &deviceConfig[deviceId];
|
||||||
|
conf->setDeviceId(deviceId);
|
||||||
|
return conf;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AppConfig::getConfigDir() {
|
||||||
|
std::string dataDir = wxStandardPaths::Get().GetUserDataDir().ToStdString();
|
||||||
|
|
||||||
|
bool mkStatus = false;
|
||||||
|
|
||||||
|
if (!wxDir::Exists(dataDir)) {
|
||||||
|
mkStatus = wxDir::Make(dataDir);
|
||||||
|
} else {
|
||||||
|
mkStatus = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mkStatus) {
|
||||||
|
std::cout << "Warning, unable to initialize user data directory." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AppConfig::save() {
|
||||||
|
DataTree cfg;
|
||||||
|
|
||||||
|
cfg.rootNode()->setName("cubicsdr_config");
|
||||||
|
DataNode *devices_node = cfg.rootNode()->newChild("devices");
|
||||||
|
|
||||||
|
std::map<std::string, DeviceConfig>::iterator device_config_i;
|
||||||
|
for (device_config_i = deviceConfig.begin(); device_config_i != deviceConfig.end(); device_config_i++) {
|
||||||
|
DataNode *device_node = devices_node->newChild("device");
|
||||||
|
device_config_i->second.save(device_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cfgFileDir = getConfigDir();
|
||||||
|
|
||||||
|
wxFileName cfgFile = wxFileName(cfgFileDir, "config.xml");
|
||||||
|
std::string cfgFileName = cfgFile.GetFullPath(wxPATH_NATIVE).ToStdString();
|
||||||
|
|
||||||
|
if (!cfg.SaveToFileXML(cfgFileName)) {
|
||||||
|
std::cout << "Error saving :: configuration file '" << cfgFileName << "' is not writable!" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AppConfig::load() {
|
||||||
|
DataTree cfg;
|
||||||
|
std::string cfgFileDir = getConfigDir();
|
||||||
|
|
||||||
|
wxFileName cfgFile = wxFileName(cfgFileDir, "config.xml");
|
||||||
|
std::string cfgFileName = cfgFile.GetFullPath(wxPATH_NATIVE).ToStdString();
|
||||||
|
|
||||||
|
if (!cfgFile.Exists()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cfgFile.IsFileReadable()) {
|
||||||
|
std::cout << "Loading:: configuration file '" << cfgFileName << "'" << std::endl;
|
||||||
|
|
||||||
|
cfg.LoadFromFileXML(cfgFileName);
|
||||||
|
} else {
|
||||||
|
std::cout << "Error loading:: configuration file '" << cfgFileName << "' is not readable!" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cfg.rootNode()->hasAnother("devices")) {
|
||||||
|
DataNode *devices_node = cfg.rootNode()->getNext("devices");
|
||||||
|
|
||||||
|
while (devices_node->hasAnother("device")) {
|
||||||
|
DataNode *device_node = devices_node->getNext("device");
|
||||||
|
if (device_node->hasAnother("id")) {
|
||||||
|
std::string deviceId;
|
||||||
|
device_node->getNext("id")->element()->get(deviceId);
|
||||||
|
|
||||||
|
getDevice(deviceId)->load(device_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AppConfig::reset() {
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
40
src/AppConfig.h
Normal file
40
src/AppConfig.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <wx/stdpaths.h>
|
||||||
|
#include <wx/dir.h>
|
||||||
|
#include <wx/filename.h>
|
||||||
|
|
||||||
|
#include "DataTree.h"
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceConfig {
|
||||||
|
public:
|
||||||
|
DeviceConfig();
|
||||||
|
DeviceConfig(std::string deviceId);
|
||||||
|
|
||||||
|
void setPPM(int ppm);
|
||||||
|
int getPPM();
|
||||||
|
|
||||||
|
void setDeviceId(std::string deviceId);
|
||||||
|
std::string getDeviceId();
|
||||||
|
|
||||||
|
void save(DataNode *node);
|
||||||
|
void load(DataNode *node);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string deviceId;
|
||||||
|
int ppm;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AppConfig {
|
||||||
|
public:
|
||||||
|
std::string getConfigDir();
|
||||||
|
DeviceConfig *getDevice(std::string deviceId);
|
||||||
|
|
||||||
|
bool save();
|
||||||
|
bool load();
|
||||||
|
bool reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<std::string, DeviceConfig> deviceConfig;
|
||||||
|
};
|
@ -132,6 +132,7 @@ AppFrame::AppFrame() :
|
|||||||
wxMenu *menu = new wxMenu;
|
wxMenu *menu = new wxMenu;
|
||||||
// menu->Append(wxID_NEW);
|
// menu->Append(wxID_NEW);
|
||||||
menu->Append(wxID_SET_FREQ_OFFSET, "Set Frequency Offset");
|
menu->Append(wxID_SET_FREQ_OFFSET, "Set Frequency Offset");
|
||||||
|
menu->Append(wxID_SET_PPM, "Set Device PPM");
|
||||||
menu->Append(wxID_OPEN, "&Open Session");
|
menu->Append(wxID_OPEN, "&Open Session");
|
||||||
menu->Append(wxID_SAVE, "&Save Session");
|
menu->Append(wxID_SAVE, "&Save Session");
|
||||||
menu->Append(wxID_SAVEAS, "Save Session &As..");
|
menu->Append(wxID_SAVEAS, "Save Session &As..");
|
||||||
@ -318,6 +319,11 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
|
|||||||
if (ofs != -1) {
|
if (ofs != -1) {
|
||||||
wxGetApp().setOffset(ofs);
|
wxGetApp().setOffset(ofs);
|
||||||
}
|
}
|
||||||
|
} 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)",
|
||||||
|
"Frequency Correction", wxGetApp().getPPM(), -1000, 1000, this);
|
||||||
|
wxGetApp().setPPM(ofs);
|
||||||
|
wxGetApp().saveConfig();
|
||||||
} else if (event.GetId() == wxID_SAVE) {
|
} else if (event.GetId() == wxID_SAVE) {
|
||||||
if (!currentSessionFile.empty()) {
|
if (!currentSessionFile.empty()) {
|
||||||
saveSession(currentSessionFile);
|
saveSession(currentSessionFile);
|
||||||
@ -440,6 +446,26 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
|
|||||||
DemodulatorInstance *demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
|
DemodulatorInstance *demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
|
||||||
|
|
||||||
if (demod) {
|
if (demod) {
|
||||||
|
DemodulatorInstance *demod = wxGetApp().getDemodMgr().getLastActiveDemodulator();
|
||||||
|
|
||||||
|
if (demod->isTracking()) {
|
||||||
|
if (spectrumCanvas->getViewState()) {
|
||||||
|
long long diff = abs(demod->getFrequency() - spectrumCanvas->getCenterFrequency()) + (demod->getBandwidth()/2) + (demod->getBandwidth()/4);
|
||||||
|
|
||||||
|
if (diff > spectrumCanvas->getBandwidth()/2) {
|
||||||
|
if (demod->getBandwidth() > spectrumCanvas->getBandwidth()) {
|
||||||
|
diff = abs(demod->getFrequency() - spectrumCanvas->getCenterFrequency());
|
||||||
|
} else {
|
||||||
|
diff = diff - spectrumCanvas->getBandwidth()/2;
|
||||||
|
}
|
||||||
|
spectrumCanvas->moveCenterFrequency((demod->getFrequency() < spectrumCanvas->getCenterFrequency())?diff:-diff);
|
||||||
|
demod->setTracking(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
demod->setTracking(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (demod != activeDemodulator) {
|
if (demod != activeDemodulator) {
|
||||||
demodSignalMeter->setInputValue(demod->getSquelchLevel());
|
demodSignalMeter->setInputValue(demod->getSquelchLevel());
|
||||||
demodGainMeter->setInputValue(demod->getGain());
|
demodGainMeter->setInputValue(demod->getGain());
|
||||||
@ -526,6 +552,8 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
|
|||||||
waterfallCanvas->SetFocus();
|
waterfallCanvas->SetFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scopeCanvas->setPPMMode(demodTuner->isAltDown());
|
||||||
|
|
||||||
event.Skip();
|
event.Skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#define wxID_RT_AUDIO_DEVICE 1000
|
#define wxID_RT_AUDIO_DEVICE 1000
|
||||||
#define wxID_SET_FREQ_OFFSET 2001
|
#define wxID_SET_FREQ_OFFSET 2001
|
||||||
#define wxID_RESET 2002
|
#define wxID_RESET 2002
|
||||||
|
#define wxID_SET_PPM 2003
|
||||||
|
|
||||||
#define wxID_THEME_DEFAULT 2100
|
#define wxID_THEME_DEFAULT 2100
|
||||||
#define wxID_THEME_SHARP 2101
|
#define wxID_THEME_SHARP 2101
|
||||||
|
@ -33,12 +33,18 @@ bool CubicSDR::OnInit() {
|
|||||||
CFRelease(resourcesURL);
|
CFRelease(resourcesURL);
|
||||||
chdir(path);
|
chdir(path);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!wxApp::OnInit())
|
if (!wxApp::OnInit()) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxApp::SetAppName("CubicSDR");
|
||||||
|
|
||||||
|
config.load();
|
||||||
|
|
||||||
frequency = DEFAULT_FREQ;
|
frequency = DEFAULT_FREQ;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
ppm = 0;
|
||||||
|
|
||||||
audioVisualQueue = new DemodulatorThreadOutputQueue();
|
audioVisualQueue = new DemodulatorThreadOutputQueue();
|
||||||
audioVisualQueue->set_max_num_items(1);
|
audioVisualQueue->set_max_num_items(1);
|
||||||
@ -47,7 +53,7 @@ bool CubicSDR::OnInit() {
|
|||||||
sdrThread = new SDRThread(threadCmdQueueSDR);
|
sdrThread = new SDRThread(threadCmdQueueSDR);
|
||||||
|
|
||||||
sdrPostThread = new SDRPostThread();
|
sdrPostThread = new SDRPostThread();
|
||||||
sdrPostThread->setNumVisSamples(16384*2);
|
sdrPostThread->setNumVisSamples(16384 * 2);
|
||||||
|
|
||||||
iqPostDataQueue = new SDRThreadIQDataQueue;
|
iqPostDataQueue = new SDRThreadIQDataQueue;
|
||||||
iqVisualQueue = new DemodulatorThreadInputQueue;
|
iqVisualQueue = new DemodulatorThreadInputQueue;
|
||||||
@ -77,7 +83,7 @@ bool CubicSDR::OnInit() {
|
|||||||
choices.Add(devName);
|
choices.Add(devName);
|
||||||
}
|
}
|
||||||
|
|
||||||
int devId = wxGetSingleChoiceIndex(wxT("Devices"),wxT("Choose Input Device"),choices);
|
int devId = wxGetSingleChoiceIndex(wxT("Devices"), wxT("Choose Input Device"), choices);
|
||||||
|
|
||||||
std::cout << "Chosen: " << devId << std::endl;
|
std::cout << "Chosen: " << devId << std::endl;
|
||||||
sdrThread->setDeviceId(devId);
|
sdrThread->setDeviceId(devId);
|
||||||
@ -216,8 +222,52 @@ void CubicSDR::setDevice(int deviceId) {
|
|||||||
SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_SET_DEVICE);
|
SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_SET_DEVICE);
|
||||||
command.llong_value = deviceId;
|
command.llong_value = deviceId;
|
||||||
threadCmdQueueSDR->push(command);
|
threadCmdQueueSDR->push(command);
|
||||||
|
|
||||||
|
SDRDeviceInfo *dev = (*getDevices())[deviceId];
|
||||||
|
|
||||||
|
SDRThreadCommand command_ppm(SDRThreadCommand::SDR_THREAD_CMD_SET_PPM);
|
||||||
|
ppm = config.getDevice(dev->getDeviceId())->getPPM();
|
||||||
|
command_ppm.llong_value = ppm;
|
||||||
|
threadCmdQueueSDR->push(command_ppm);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CubicSDR::getDevice() {
|
int CubicSDR::getDevice() {
|
||||||
return sdrThread->getDeviceId();
|
return sdrThread->getDeviceId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AppConfig *CubicSDR::getConfig() {
|
||||||
|
return &config;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CubicSDR::saveConfig() {
|
||||||
|
config.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CubicSDR::setPPM(int ppm_in) {
|
||||||
|
if (sdrThread->getDeviceId() < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ppm = ppm_in;
|
||||||
|
|
||||||
|
SDRThreadCommand command(SDRThreadCommand::SDR_THREAD_CMD_SET_PPM);
|
||||||
|
command.llong_value = ppm;
|
||||||
|
threadCmdQueueSDR->push(command);
|
||||||
|
|
||||||
|
SDRDeviceInfo *dev = (*getDevices())[getDevice()];
|
||||||
|
|
||||||
|
config.getDevice(dev->getDeviceId())->setPPM(ppm_in);
|
||||||
|
config.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
int CubicSDR::getPPM() {
|
||||||
|
if (sdrThread->getDeviceId() < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
SDRDeviceInfo *dev = (*getDevices())[getDevice()];
|
||||||
|
|
||||||
|
SDRThreadCommand command_ppm(SDRThreadCommand::SDR_THREAD_CMD_SET_PPM);
|
||||||
|
ppm = config.getDevice(dev->getDeviceId())->getPPM();
|
||||||
|
|
||||||
|
return ppm;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "SDRPostThread.h"
|
#include "SDRPostThread.h"
|
||||||
#include "AudioThread.h"
|
#include "AudioThread.h"
|
||||||
#include "DemodulatorMgr.h"
|
#include "DemodulatorMgr.h"
|
||||||
|
#include "AppConfig.h"
|
||||||
|
|
||||||
#define NUM_DEMODULATORS 1
|
#define NUM_DEMODULATORS 1
|
||||||
|
|
||||||
@ -49,7 +50,14 @@ public:
|
|||||||
void bindDemodulator(DemodulatorInstance *demod);
|
void bindDemodulator(DemodulatorInstance *demod);
|
||||||
void removeDemodulator(DemodulatorInstance *demod);
|
void removeDemodulator(DemodulatorInstance *demod);
|
||||||
|
|
||||||
|
AppConfig *getConfig();
|
||||||
|
void saveConfig();
|
||||||
|
|
||||||
|
void setPPM(int ppm_in);
|
||||||
|
int getPPM();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
AppConfig config;
|
||||||
PrimaryGLContext *m_glContext;
|
PrimaryGLContext *m_glContext;
|
||||||
std::vector<SDRDeviceInfo *> devs;
|
std::vector<SDRDeviceInfo *> devs;
|
||||||
|
|
||||||
@ -57,6 +65,7 @@ private:
|
|||||||
|
|
||||||
long long frequency;
|
long long frequency;
|
||||||
long long offset;
|
long long offset;
|
||||||
|
int ppm;
|
||||||
long long sampleRate;
|
long long sampleRate;
|
||||||
|
|
||||||
SDRThread *sdrThread;
|
SDRThread *sdrThread;
|
||||||
|
@ -164,6 +164,9 @@ void DemodulatorInstance::setActive(bool state) {
|
|||||||
} else if (!active && state) {
|
} else if (!active && state) {
|
||||||
audioThread->setActive(state);
|
audioThread->setActive(state);
|
||||||
}
|
}
|
||||||
|
if (!state) {
|
||||||
|
tracking = false;
|
||||||
|
}
|
||||||
active = state;
|
active = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,3 +346,11 @@ bool DemodulatorInstance::isFollow() {
|
|||||||
void DemodulatorInstance::setFollow(bool follow) {
|
void DemodulatorInstance::setFollow(bool follow) {
|
||||||
this->follow = follow;
|
this->follow = follow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DemodulatorInstance::isTracking() {
|
||||||
|
return tracking;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DemodulatorInstance::setTracking(bool tracking) {
|
||||||
|
this->tracking = tracking;
|
||||||
|
}
|
||||||
|
@ -80,6 +80,8 @@ public:
|
|||||||
bool isFollow();
|
bool isFollow();
|
||||||
void setFollow(bool follow);
|
void setFollow(bool follow);
|
||||||
|
|
||||||
|
bool isTracking();
|
||||||
|
void setTracking(bool tracking);
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void checkBandwidth();
|
void checkBandwidth();
|
||||||
@ -98,5 +100,5 @@ private:
|
|||||||
int currentDemodType;
|
int currentDemodType;
|
||||||
int currentOutputDevice;
|
int currentOutputDevice;
|
||||||
int currentAudioSampleRate;
|
int currentAudioSampleRate;
|
||||||
bool follow;
|
bool follow, tracking;
|
||||||
};
|
};
|
||||||
|
@ -186,7 +186,7 @@ void SDRPostThread::threadMain() {
|
|||||||
DemodulatorThreadInputQueue *demodQueue = demod->threadQueueDemod;
|
DemodulatorThreadInputQueue *demodQueue = demod->threadQueueDemod;
|
||||||
|
|
||||||
if (abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) {
|
if (abs(data_in->frequency - demod->getFrequency()) > (wxGetApp().getSampleRate() / 2)) {
|
||||||
if (demod->isActive() && !demod->isFollow()) {
|
if (demod->isActive() && !demod->isFollow() && !demod->isTracking()) {
|
||||||
demod->setActive(false);
|
demod->setActive(false);
|
||||||
DemodulatorThreadIQData *dummyDataOut = new DemodulatorThreadIQData;
|
DemodulatorThreadIQData *dummyDataOut = new DemodulatorThreadIQData;
|
||||||
dummyDataOut->frequency = data_in->frequency;
|
dummyDataOut->frequency = data_in->frequency;
|
||||||
|
@ -122,8 +122,11 @@ 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;
|
||||||
if (deviceId == -1) {
|
if (deviceId == -1) {
|
||||||
deviceId = enumerate_rtl(NULL);
|
deviceId = enumerate_rtl(&devs);
|
||||||
|
} else {
|
||||||
|
enumerate_rtl(&devs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deviceId == -1) {
|
if (deviceId == -1) {
|
||||||
@ -136,10 +139,12 @@ void SDRThread::threadMain() {
|
|||||||
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();
|
||||||
|
|
||||||
rtlsdr_open(&dev, deviceId);
|
rtlsdr_open(&dev, deviceId);
|
||||||
rtlsdr_set_sample_rate(dev, sampleRate);
|
rtlsdr_set_sample_rate(dev, sampleRate);
|
||||||
rtlsdr_set_center_freq(dev, frequency - offset);
|
rtlsdr_set_center_freq(dev, frequency - offset);
|
||||||
|
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);
|
||||||
rtlsdr_reset_buffer(dev);
|
rtlsdr_reset_buffer(dev);
|
||||||
@ -164,10 +169,12 @@ void SDRThread::threadMain() {
|
|||||||
bool offset_changed = false;
|
bool offset_changed = false;
|
||||||
bool rate_changed = false;
|
bool rate_changed = false;
|
||||||
bool device_changed = false;
|
bool device_changed = false;
|
||||||
long long new_freq;
|
bool ppm_changed = false;
|
||||||
long long new_offset;
|
long long new_freq = frequency;
|
||||||
long long new_rate;
|
long long new_offset = offset;
|
||||||
int new_device;
|
long long new_rate = sampleRate;
|
||||||
|
int new_device = deviceId;
|
||||||
|
int new_ppm = ppm;
|
||||||
|
|
||||||
while (!cmdQueue->empty()) {
|
while (!cmdQueue->empty()) {
|
||||||
SDRThreadCommand command;
|
SDRThreadCommand command;
|
||||||
@ -197,6 +204,11 @@ void SDRThread::threadMain() {
|
|||||||
new_device = (int) command.llong_value;
|
new_device = (int) command.llong_value;
|
||||||
std::cout << "Set device: " << new_device << std::endl;
|
std::cout << "Set device: " << new_device << std::endl;
|
||||||
break;
|
break;
|
||||||
|
case SDRThreadCommand::SDR_THREAD_CMD_SET_PPM:
|
||||||
|
ppm_changed = true;
|
||||||
|
new_ppm = (int) command.llong_value;
|
||||||
|
std::cout << "Set PPM: " << new_ppm << std::endl;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -207,6 +219,7 @@ void SDRThread::threadMain() {
|
|||||||
rtlsdr_open(&dev, new_device);
|
rtlsdr_open(&dev, new_device);
|
||||||
rtlsdr_set_sample_rate(dev, sampleRate);
|
rtlsdr_set_sample_rate(dev, sampleRate);
|
||||||
rtlsdr_set_center_freq(dev, frequency - offset);
|
rtlsdr_set_center_freq(dev, frequency - offset);
|
||||||
|
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);
|
||||||
rtlsdr_reset_buffer(dev);
|
rtlsdr_reset_buffer(dev);
|
||||||
@ -224,6 +237,10 @@ void SDRThread::threadMain() {
|
|||||||
frequency = new_freq;
|
frequency = new_freq;
|
||||||
rtlsdr_set_center_freq(dev, frequency - offset);
|
rtlsdr_set_center_freq(dev, frequency - offset);
|
||||||
}
|
}
|
||||||
|
if (ppm_changed) {
|
||||||
|
ppm = new_ppm;
|
||||||
|
rtlsdr_set_freq_correction(dev, ppm);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rtlsdr_read_sync(dev, buf, BUF_SIZE, &n_read);
|
rtlsdr_read_sync(dev, buf, BUF_SIZE, &n_read);
|
||||||
|
@ -11,6 +11,16 @@ class SDRDeviceInfo {
|
|||||||
public:
|
public:
|
||||||
SDRDeviceInfo() : name(""), serial(""), available(false) { }
|
SDRDeviceInfo() : name(""), serial(""), available(false) { }
|
||||||
|
|
||||||
|
std::string getDeviceId() {
|
||||||
|
std::string deviceId;
|
||||||
|
|
||||||
|
deviceId.append(getName());
|
||||||
|
deviceId.append(" :: ");
|
||||||
|
deviceId.append(getSerial());
|
||||||
|
|
||||||
|
return deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
bool isAvailable() const {
|
bool isAvailable() const {
|
||||||
return available;
|
return available;
|
||||||
}
|
}
|
||||||
@ -71,7 +81,7 @@ private:
|
|||||||
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_SET_SAMPLERATE, SDR_THREAD_CMD_SET_DEVICE
|
SDR_THREAD_CMD_NULL, SDR_THREAD_CMD_TUNE, SDR_THREAD_CMD_SET_OFFSET, SDR_THREAD_CMD_SET_SAMPLERATE, SDR_THREAD_CMD_SET_PPM, SDR_THREAD_CMD_SET_DEVICE
|
||||||
};
|
};
|
||||||
|
|
||||||
SDRThreadCommand() :
|
SDRThreadCommand() :
|
||||||
|
@ -81,6 +81,18 @@ MouseTracker *InteractiveCanvas::getMouseTracker() {
|
|||||||
return &mouseTracker;
|
return &mouseTracker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool InteractiveCanvas::isAltDown() {
|
||||||
|
return altDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InteractiveCanvas::isCtrlDown() {
|
||||||
|
return ctrlDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InteractiveCanvas::isShiftDown() {
|
||||||
|
return shiftDown;
|
||||||
|
}
|
||||||
|
|
||||||
void InteractiveCanvas::OnKeyUp(wxKeyEvent& event) {
|
void InteractiveCanvas::OnKeyUp(wxKeyEvent& event) {
|
||||||
shiftDown = event.ShiftDown();
|
shiftDown = event.ShiftDown();
|
||||||
altDown = event.AltDown();
|
altDown = event.AltDown();
|
||||||
@ -88,8 +100,6 @@ void InteractiveCanvas::OnKeyUp(wxKeyEvent& event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void InteractiveCanvas::OnKeyDown(wxKeyEvent& event) {
|
void InteractiveCanvas::OnKeyDown(wxKeyEvent& event) {
|
||||||
float angle = 5.0;
|
|
||||||
|
|
||||||
shiftDown = event.ShiftDown();
|
shiftDown = event.ShiftDown();
|
||||||
altDown = event.AltDown();
|
altDown = event.AltDown();
|
||||||
ctrlDown = event.ControlDown();
|
ctrlDown = event.ControlDown();
|
||||||
@ -125,10 +135,18 @@ void InteractiveCanvas::OnMouseReleased(wxMouseEvent& event) {
|
|||||||
|
|
||||||
void InteractiveCanvas::OnMouseLeftWindow(wxMouseEvent& event) {
|
void InteractiveCanvas::OnMouseLeftWindow(wxMouseEvent& event) {
|
||||||
mouseTracker.OnMouseLeftWindow(event);
|
mouseTracker.OnMouseLeftWindow(event);
|
||||||
|
|
||||||
|
shiftDown = false;
|
||||||
|
altDown = false;
|
||||||
|
ctrlDown = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InteractiveCanvas::OnMouseEnterWindow(wxMouseEvent& event) {
|
void InteractiveCanvas::OnMouseEnterWindow(wxMouseEvent& event) {
|
||||||
mouseTracker.OnMouseEnterWindow(event);
|
mouseTracker.OnMouseEnterWindow(event);
|
||||||
|
|
||||||
|
shiftDown = event.ShiftDown();
|
||||||
|
altDown = event.AltDown();
|
||||||
|
ctrlDown = event.ControlDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InteractiveCanvas::setStatusText(std::string statusText) {
|
void InteractiveCanvas::setStatusText(std::string statusText) {
|
||||||
|
@ -25,6 +25,10 @@ public:
|
|||||||
|
|
||||||
MouseTracker *getMouseTracker();
|
MouseTracker *getMouseTracker();
|
||||||
|
|
||||||
|
bool isAltDown();
|
||||||
|
bool isCtrlDown();
|
||||||
|
bool isShiftDown();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void OnKeyDown(wxKeyEvent& event);
|
void OnKeyDown(wxKeyEvent& event);
|
||||||
void OnKeyUp(wxKeyEvent& event);
|
void OnKeyUp(wxKeyEvent& event);
|
||||||
|
@ -21,7 +21,7 @@ wxEND_EVENT_TABLE()
|
|||||||
|
|
||||||
ScopeCanvas::ScopeCanvas(wxWindow *parent, int *attribList) :
|
ScopeCanvas::ScopeCanvas(wxWindow *parent, int *attribList) :
|
||||||
wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize,
|
wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize,
|
||||||
wxFULL_REPAINT_ON_RESIZE), parent(parent), stereo(false) {
|
wxFULL_REPAINT_ON_RESIZE), parent(parent), stereo(false), ppmMode(false) {
|
||||||
|
|
||||||
glContext = new ScopeContext(this, &wxGetApp().GetContext(this));
|
glContext = new ScopeContext(this, &wxGetApp().GetContext(this));
|
||||||
}
|
}
|
||||||
@ -43,6 +43,14 @@ void ScopeCanvas::setDeviceName(std::string device_name) {
|
|||||||
deviceName.append(" ");
|
deviceName.append(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScopeCanvas::setPPMMode(bool ppmMode) {
|
||||||
|
this->ppmMode = ppmMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScopeCanvas::getPPMMode() {
|
||||||
|
return ppmMode;
|
||||||
|
}
|
||||||
|
|
||||||
void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
||||||
wxPaintDC dc(this);
|
wxPaintDC dc(this);
|
||||||
#ifdef __APPLE__ // force half-rate?
|
#ifdef __APPLE__ // force half-rate?
|
||||||
@ -75,7 +83,7 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
|||||||
glViewport(0, 0, ClientSize.x, ClientSize.y);
|
glViewport(0, 0, ClientSize.x, ClientSize.y);
|
||||||
|
|
||||||
glContext->DrawBegin();
|
glContext->DrawBegin();
|
||||||
glContext->Plot(waveform_points, stereo);
|
glContext->Plot(waveform_points, stereo, ppmMode);
|
||||||
if (!deviceName.empty()) {
|
if (!deviceName.empty()) {
|
||||||
glContext->DrawDeviceName(deviceName);
|
glContext->DrawDeviceName(deviceName);
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,9 @@ public:
|
|||||||
void setWaveformPoints(std::vector<float> &waveform_points_in);
|
void setWaveformPoints(std::vector<float> &waveform_points_in);
|
||||||
void setStereo(bool state);
|
void setStereo(bool state);
|
||||||
void setDeviceName(std::string device_name);
|
void setDeviceName(std::string device_name);
|
||||||
|
void setPPMMode(bool ppmMode);
|
||||||
|
bool getPPMMode();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void OnPaint(wxPaintEvent& event);
|
void OnPaint(wxPaintEvent& event);
|
||||||
|
|
||||||
@ -29,6 +32,7 @@ private:
|
|||||||
ScopeContext *glContext;
|
ScopeContext *glContext;
|
||||||
std::string deviceName;
|
std::string deviceName;
|
||||||
bool stereo;
|
bool stereo;
|
||||||
|
bool ppmMode;
|
||||||
// event table
|
// event table
|
||||||
wxDECLARE_EVENT_TABLE();
|
wxDECLARE_EVENT_TABLE();
|
||||||
};
|
};
|
||||||
|
@ -23,7 +23,7 @@ void ScopeContext::DrawBegin() {
|
|||||||
glDisable (GL_TEXTURE_2D);
|
glDisable (GL_TEXTURE_2D);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScopeContext::Plot(std::vector<float> &points, bool stereo) {
|
void ScopeContext::Plot(std::vector<float> &points, bool stereo, bool ppmMode) {
|
||||||
if (stereo) {
|
if (stereo) {
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
glColor3f(ThemeMgr::mgr.currentTheme->scopeBackground.r, ThemeMgr::mgr.currentTheme->scopeBackground.g, ThemeMgr::mgr.currentTheme->scopeBackground.b);
|
glColor3f(ThemeMgr::mgr.currentTheme->scopeBackground.r, ThemeMgr::mgr.currentTheme->scopeBackground.g, ThemeMgr::mgr.currentTheme->scopeBackground.b);
|
||||||
@ -81,7 +81,7 @@ void ScopeContext::Plot(std::vector<float> &points, bool stereo) {
|
|||||||
|
|
||||||
glColor3f(0.65, 0.65, 0.65);
|
glColor3f(0.65, 0.65, 0.65);
|
||||||
|
|
||||||
getFont(PrimaryGLContext::GLFONT_SIZE12).drawString("Frequency", -0.66, -1.0+hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
|
getFont(PrimaryGLContext::GLFONT_SIZE12).drawString(ppmMode?"Device PPM":"Frequency", -0.66, -1.0+hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
|
||||||
getFont(PrimaryGLContext::GLFONT_SIZE12).drawString("Bandwidth", 0.0, -1.0+hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
|
getFont(PrimaryGLContext::GLFONT_SIZE12).drawString("Bandwidth", 0.0, -1.0+hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
|
||||||
getFont(PrimaryGLContext::GLFONT_SIZE12).drawString("Center Frequency", 0.66, -1.0+hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
|
getFont(PrimaryGLContext::GLFONT_SIZE12).drawString("Center Frequency", 0.66, -1.0+hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER);
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ public:
|
|||||||
ScopeContext(ScopeCanvas *canvas, wxGLContext *sharedContext);
|
ScopeContext(ScopeCanvas *canvas, wxGLContext *sharedContext);
|
||||||
|
|
||||||
void DrawBegin();
|
void DrawBegin();
|
||||||
void Plot(std::vector<float> &points, bool stereo=false);
|
void Plot(std::vector<float> &points, bool stereo=false, bool ppmMode=false);
|
||||||
void DrawDeviceName(std::string deviceName);
|
void DrawDeviceName(std::string deviceName);
|
||||||
void DrawDivider();
|
void DrawDivider();
|
||||||
void DrawEnd();
|
void DrawEnd();
|
||||||
|
@ -28,7 +28,7 @@ wxEND_EVENT_TABLE()
|
|||||||
|
|
||||||
SpectrumCanvas::SpectrumCanvas(wxWindow *parent, int *attribList) :
|
SpectrumCanvas::SpectrumCanvas(wxWindow *parent, int *attribList) :
|
||||||
InteractiveCanvas(parent, attribList), fft_size(0), in(NULL), out(NULL), plan(NULL), fft_ceil_ma(1), fft_ceil_maa(1), fft_floor_ma(0), fft_floor_maa(
|
InteractiveCanvas(parent, attribList), fft_size(0), in(NULL), out(NULL), plan(NULL), fft_ceil_ma(1), fft_ceil_maa(1), fft_floor_ma(0), fft_floor_maa(
|
||||||
0), waterfallCanvas(NULL) {
|
0), waterfallCanvas(NULL), trackingRate(0) {
|
||||||
|
|
||||||
glContext = new SpectrumContext(this, &wxGetApp().GetContext(this));
|
glContext = new SpectrumContext(this, &wxGetApp().GetContext(this));
|
||||||
|
|
||||||
@ -175,46 +175,49 @@ void SpectrumCanvas::OnIdle(wxIdleEvent &event) {
|
|||||||
Refresh(false);
|
Refresh(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SpectrumCanvas::moveCenterFrequency(long long freqChange) {
|
||||||
|
long long freq = wxGetApp().getFrequency();
|
||||||
|
|
||||||
|
if (isView) {
|
||||||
|
if (centerFreq - freqChange < bandwidth/2) {
|
||||||
|
centerFreq = bandwidth/2;
|
||||||
|
} else {
|
||||||
|
centerFreq -= freqChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (waterfallCanvas) {
|
||||||
|
waterfallCanvas->setCenterFrequency(centerFreq);
|
||||||
|
}
|
||||||
|
|
||||||
|
long long bwOfs = (centerFreq > freq) ? ((long long) bandwidth / 2) : (-(long long) bandwidth / 2);
|
||||||
|
long long freqEdge = centerFreq + bwOfs;
|
||||||
|
|
||||||
|
if (abs(freq - freqEdge) > (wxGetApp().getSampleRate() / 2)) {
|
||||||
|
freqChange = -((centerFreq > freq) ? (freqEdge - freq - (wxGetApp().getSampleRate() / 2)) : (freqEdge - freq + (wxGetApp().getSampleRate() / 2)));
|
||||||
|
} else {
|
||||||
|
freqChange = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (freqChange) {
|
||||||
|
if (freq - freqChange < wxGetApp().getSampleRate()/2) {
|
||||||
|
freq = wxGetApp().getSampleRate()/2;
|
||||||
|
} else {
|
||||||
|
freq -= freqChange;
|
||||||
|
}
|
||||||
|
wxGetApp().setFrequency(freq);
|
||||||
|
setStatusText("Set center frequency: %s", freq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SpectrumCanvas::OnMouseMoved(wxMouseEvent& event) {
|
void SpectrumCanvas::OnMouseMoved(wxMouseEvent& event) {
|
||||||
InteractiveCanvas::OnMouseMoved(event);
|
InteractiveCanvas::OnMouseMoved(event);
|
||||||
if (mouseTracker.mouseDown()) {
|
if (mouseTracker.mouseDown()) {
|
||||||
int freqChange = mouseTracker.getDeltaMouseX() * getBandwidth();
|
int freqChange = mouseTracker.getDeltaMouseX() * getBandwidth();
|
||||||
|
|
||||||
if (freqChange != 0) {
|
if (freqChange != 0) {
|
||||||
long long freq = wxGetApp().getFrequency();
|
moveCenterFrequency(freqChange);
|
||||||
|
|
||||||
if (isView) {
|
|
||||||
if (isView) {
|
|
||||||
if (centerFreq - freqChange < bandwidth/2) {
|
|
||||||
centerFreq = bandwidth/2;
|
|
||||||
} else {
|
|
||||||
centerFreq -= freqChange;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (waterfallCanvas) {
|
|
||||||
waterfallCanvas->setCenterFrequency(centerFreq);
|
|
||||||
}
|
|
||||||
|
|
||||||
long long bwOfs = (centerFreq > freq) ? ((long long) bandwidth / 2) : (-(long long) bandwidth / 2);
|
|
||||||
long long freqEdge = centerFreq + bwOfs;
|
|
||||||
|
|
||||||
if (abs(freq - freqEdge) > (wxGetApp().getSampleRate() / 2)) {
|
|
||||||
freqChange = -((centerFreq > freq) ? (freqEdge - freq - (wxGetApp().getSampleRate() / 2)) : (freqEdge - freq + (wxGetApp().getSampleRate() / 2)));
|
|
||||||
} else {
|
|
||||||
freqChange = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (freqChange) {
|
|
||||||
if (freq - freqChange < wxGetApp().getSampleRate()/2) {
|
|
||||||
freq = wxGetApp().getSampleRate()/2;
|
|
||||||
} else {
|
|
||||||
freq -= freqChange;
|
|
||||||
}
|
|
||||||
wxGetApp().setFrequency(freq);
|
|
||||||
setStatusText("Set center frequency: %s", freq);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setStatusText("Click and drag to adjust center frequency.");
|
setStatusText("Click and drag to adjust center frequency.");
|
||||||
|
@ -24,6 +24,7 @@ public:
|
|||||||
|
|
||||||
void setData(DemodulatorThreadIQData *input);
|
void setData(DemodulatorThreadIQData *input);
|
||||||
void attachWaterfallCanvas(WaterfallCanvas *canvas_in);
|
void attachWaterfallCanvas(WaterfallCanvas *canvas_in);
|
||||||
|
void moveCenterFrequency(long long freqChange);
|
||||||
|
|
||||||
SpectrumContext* getSpectrumContext();
|
SpectrumContext* getSpectrumContext();
|
||||||
|
|
||||||
@ -51,6 +52,7 @@ private:
|
|||||||
SpectrumContext *glContext;
|
SpectrumContext *glContext;
|
||||||
WaterfallCanvas *waterfallCanvas;
|
WaterfallCanvas *waterfallCanvas;
|
||||||
int fft_size;
|
int fft_size;
|
||||||
|
int trackingRate;
|
||||||
// event table
|
// event table
|
||||||
wxDECLARE_EVENT_TABLE();
|
wxDECLARE_EVENT_TABLE();
|
||||||
};
|
};
|
||||||
|
@ -23,6 +23,8 @@ EVT_LEFT_UP(TuningCanvas::OnMouseReleased)
|
|||||||
EVT_LEAVE_WINDOW(TuningCanvas::OnMouseLeftWindow)
|
EVT_LEAVE_WINDOW(TuningCanvas::OnMouseLeftWindow)
|
||||||
EVT_ENTER_WINDOW(TuningCanvas::OnMouseEnterWindow)
|
EVT_ENTER_WINDOW(TuningCanvas::OnMouseEnterWindow)
|
||||||
EVT_MOUSEWHEEL(TuningCanvas::OnMouseWheelMoved)
|
EVT_MOUSEWHEEL(TuningCanvas::OnMouseWheelMoved)
|
||||||
|
EVT_KEY_DOWN(TuningCanvas::OnKeyDown)
|
||||||
|
EVT_KEY_UP(TuningCanvas::OnKeyUp)
|
||||||
wxEND_EVENT_TABLE()
|
wxEND_EVENT_TABLE()
|
||||||
|
|
||||||
TuningCanvas::TuningCanvas(wxWindow *parent, int *attribList) :
|
TuningCanvas::TuningCanvas(wxWindow *parent, int *attribList) :
|
||||||
@ -44,6 +46,8 @@ TuningCanvas::TuningCanvas(wxWindow *parent, int *attribList) :
|
|||||||
|
|
||||||
centerDP = -1.0 + (2.0 / 3.0) * 2.0;
|
centerDP = -1.0 + (2.0 / 3.0) * 2.0;
|
||||||
centerW = (1.0 / 3.0) * 2.0;
|
centerW = (1.0 / 3.0) * 2.0;
|
||||||
|
|
||||||
|
currentPPM = lastPPM = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
TuningCanvas::~TuningCanvas() {
|
TuningCanvas::~TuningCanvas() {
|
||||||
@ -110,10 +114,17 @@ void TuningCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
|
|||||||
break;
|
break;
|
||||||
case TUNING_HOVER_NONE:
|
case TUNING_HOVER_NONE:
|
||||||
break;
|
break;
|
||||||
}
|
case TUNING_HOVER_PPM:
|
||||||
|
glContext->DrawTunerBarIndexed(hoverIndex, hoverIndex, 11, freqDP, freqW, clr, 0.25, top, bottom); // freq
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glContext->DrawTuner(freq, 11, freqDP, freqW);
|
if (altDown) {
|
||||||
|
glContext->DrawTuner(currentPPM, 11, freqDP, freqW);
|
||||||
|
} else {
|
||||||
|
glContext->DrawTuner(freq, 11, freqDP, freqW);
|
||||||
|
}
|
||||||
glContext->DrawTuner(bw, 7, bwDP, bwW);
|
glContext->DrawTuner(bw, 7, bwDP, bwW);
|
||||||
glContext->DrawTuner(center, 11, centerDP, centerW);
|
glContext->DrawTuner(center, 11, centerDP, centerW);
|
||||||
|
|
||||||
@ -142,9 +153,10 @@ void TuningCanvas::StepTuner(ActiveState state, int exponent, bool up) {
|
|||||||
wxGetApp().setFrequency(freq);
|
wxGetApp().setFrequency(freq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
activeDemod->setTracking(true);
|
||||||
|
activeDemod->setFollow(true);
|
||||||
activeDemod->setFrequency(freq);
|
activeDemod->setFrequency(freq);
|
||||||
activeDemod->updateLabel(freq);
|
activeDemod->updateLabel(freq);
|
||||||
activeDemod->setFollow(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == TUNING_HOVER_BW) {
|
if (state == TUNING_HOVER_BW) {
|
||||||
@ -179,6 +191,25 @@ void TuningCanvas::StepTuner(ActiveState state, int exponent, bool up) {
|
|||||||
|
|
||||||
wxGetApp().setFrequency(ctr);
|
wxGetApp().setFrequency(ctr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state == TUNING_HOVER_PPM) {
|
||||||
|
if (shiftDown) {
|
||||||
|
bool carried = (long long)((currentPPM) / (exp * 10)) != (long long)((currentPPM + amount) / (exp * 10)) || (bottom && currentPPM < exp);
|
||||||
|
currentPPM += carried?(9*-amount):amount;
|
||||||
|
} else {
|
||||||
|
currentPPM += amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentPPM > 2000) {
|
||||||
|
currentPPM = 2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentPPM < -2000) {
|
||||||
|
currentPPM = -2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxGetApp().setPPM(currentPPM);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TuningCanvas::OnIdle(wxIdleEvent &event) {
|
void TuningCanvas::OnIdle(wxIdleEvent &event) {
|
||||||
@ -215,7 +246,7 @@ void TuningCanvas::OnMouseMoved(wxMouseEvent& event) {
|
|||||||
index = glContext->GetTunerDigitIndex(mouseTracker.getMouseX(), 11, freqDP, freqW); // freq
|
index = glContext->GetTunerDigitIndex(mouseTracker.getMouseX(), 11, freqDP, freqW); // freq
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
hoverIndex = index;
|
hoverIndex = index;
|
||||||
hoverState = TUNING_HOVER_FREQ;
|
hoverState = altDown?TUNING_HOVER_PPM:TUNING_HOVER_FREQ;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!index) {
|
if (!index) {
|
||||||
@ -240,15 +271,18 @@ void TuningCanvas::OnMouseMoved(wxMouseEvent& event) {
|
|||||||
} else {
|
} else {
|
||||||
switch (hoverState) {
|
switch (hoverState) {
|
||||||
case TUNING_HOVER_FREQ:
|
case TUNING_HOVER_FREQ:
|
||||||
setStatusText("Click or drag a digit to change frequency. Hold shift to disable carry.");
|
setStatusText("Click, wheel or drag a digit to change frequency. Hold ALT to change PPM. Hold SHIFT to disable carry.");
|
||||||
break;
|
break;
|
||||||
case TUNING_HOVER_BW:
|
case TUNING_HOVER_BW:
|
||||||
setStatusText("Click or drag a digit to change bandwidth. Hold shift to disable carry.");
|
setStatusText("Click, wheel or drag a digit to change bandwidth. Hold SHIFT to disable carry.");
|
||||||
break;
|
break;
|
||||||
case TUNING_HOVER_CENTER:
|
case TUNING_HOVER_CENTER:
|
||||||
setStatusText("Click or drag a digit to change center frequency. Hold shift to disable carry.");
|
setStatusText("Click, wheel or drag a digit to change center frequency. Hold SHIFT to disable carry.");
|
||||||
break;
|
break;
|
||||||
}
|
case TUNING_HOVER_PPM:
|
||||||
|
setStatusText("Click, wheel or drag a digit to change device PPM offset. Hold SHIFT to disable carry.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -305,6 +339,10 @@ void TuningCanvas::OnMouseLeftWindow(wxMouseEvent& event) {
|
|||||||
SetCursor(wxCURSOR_CROSS);
|
SetCursor(wxCURSOR_CROSS);
|
||||||
hoverIndex = 0;
|
hoverIndex = 0;
|
||||||
hoverState = TUNING_HOVER_NONE;
|
hoverState = TUNING_HOVER_NONE;
|
||||||
|
|
||||||
|
if (currentPPM != lastPPM) {
|
||||||
|
wxGetApp().saveConfig();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TuningCanvas::OnMouseEnterWindow(wxMouseEvent& event) {
|
void TuningCanvas::OnMouseEnterWindow(wxMouseEvent& event) {
|
||||||
@ -312,8 +350,17 @@ void TuningCanvas::OnMouseEnterWindow(wxMouseEvent& event) {
|
|||||||
SetCursor(wxCURSOR_ARROW);
|
SetCursor(wxCURSOR_ARROW);
|
||||||
hoverIndex = 0;
|
hoverIndex = 0;
|
||||||
hoverState = TUNING_HOVER_NONE;
|
hoverState = TUNING_HOVER_NONE;
|
||||||
|
lastPPM = currentPPM = wxGetApp().getPPM();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TuningCanvas::setHelpTip(std::string tip) {
|
void TuningCanvas::setHelpTip(std::string tip) {
|
||||||
helpTip = tip;
|
helpTip = tip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TuningCanvas::OnKeyDown(wxKeyEvent& event) {
|
||||||
|
InteractiveCanvas::OnKeyDown(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TuningCanvas::OnKeyUp(wxKeyEvent& event) {
|
||||||
|
InteractiveCanvas::OnKeyUp(event);
|
||||||
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
class TuningCanvas: public InteractiveCanvas {
|
class TuningCanvas: public InteractiveCanvas {
|
||||||
public:
|
public:
|
||||||
enum ActiveState {
|
enum ActiveState {
|
||||||
TUNING_HOVER_NONE, TUNING_HOVER_FREQ, TUNING_HOVER_BW, TUNING_HOVER_CENTER
|
TUNING_HOVER_NONE, TUNING_HOVER_FREQ, TUNING_HOVER_BW, TUNING_HOVER_PPM, TUNING_HOVER_CENTER
|
||||||
};
|
};
|
||||||
TuningCanvas(wxWindow *parent, int *attribList = NULL);
|
TuningCanvas(wxWindow *parent, int *attribList = NULL);
|
||||||
~TuningCanvas();
|
~TuningCanvas();
|
||||||
@ -33,6 +33,9 @@ private:
|
|||||||
void OnMouseReleased(wxMouseEvent& event);
|
void OnMouseReleased(wxMouseEvent& event);
|
||||||
void OnMouseEnterWindow(wxMouseEvent& event);
|
void OnMouseEnterWindow(wxMouseEvent& event);
|
||||||
void OnMouseLeftWindow(wxMouseEvent& event);
|
void OnMouseLeftWindow(wxMouseEvent& event);
|
||||||
|
void OnKeyDown(wxKeyEvent& event);
|
||||||
|
void OnKeyUp(wxKeyEvent& event);
|
||||||
|
|
||||||
void StepTuner(ActiveState state, int factor, bool up = true);
|
void StepTuner(ActiveState state, int factor, bool up = true);
|
||||||
|
|
||||||
TuningContext *glContext;
|
TuningContext *glContext;
|
||||||
@ -58,6 +61,9 @@ private:
|
|||||||
bool top;
|
bool top;
|
||||||
bool bottom;
|
bool bottom;
|
||||||
|
|
||||||
|
int currentPPM;
|
||||||
|
int lastPPM;
|
||||||
|
|
||||||
//
|
//
|
||||||
wxDECLARE_EVENT_TABLE();
|
wxDECLARE_EVENT_TABLE();
|
||||||
};
|
};
|
||||||
|
@ -820,6 +820,7 @@ void WaterfallCanvas::OnMouseReleased(wxMouseEvent& event) {
|
|||||||
mouseTracker.setHorizDragLock(false);
|
mouseTracker.setHorizDragLock(false);
|
||||||
} else {
|
} else {
|
||||||
wxGetApp().getDemodMgr().setActiveDemodulator(wxGetApp().getDemodMgr().getActiveDemodulator(), false);
|
wxGetApp().getDemodMgr().setActiveDemodulator(wxGetApp().getDemodMgr().getActiveDemodulator(), false);
|
||||||
|
wxGetApp().getDemodMgr().getActiveDemodulator()->setTracking(true);
|
||||||
nextDragState = WF_DRAG_FREQUENCY;
|
nextDragState = WF_DRAG_FREQUENCY;
|
||||||
}
|
}
|
||||||
} else if (dragState == WF_DRAG_RANGE) {
|
} else if (dragState == WF_DRAG_RANGE) {
|
||||||
|
Loading…
Reference in New Issue
Block a user