Merge pull request #499 from vsonnier/sample_rate_gui_improvements

Device Sample Rate improvements: UI, rates handled as long, misc...
This commit is contained in:
Charles J. Cliffe 2017-01-24 18:31:49 -05:00 committed by GitHub
commit 6bcf0eb56a
12 changed files with 171 additions and 58 deletions

View File

@ -709,9 +709,13 @@ void AppFrame::initDeviceParams(SDRDeviceInfo *devInfo) {
deviceChanged.store(true);
}
void AppFrame::notifyDeviceChanged() {
deviceChanged.store(true);
}
void AppFrame::updateDeviceParams() {
if (!deviceChanged.load()) {
if (!deviceChanged.load() || devInfo == nullptr) {
return;
}
@ -800,16 +804,35 @@ void AppFrame::updateDeviceParams() {
menuBar->Replace(1, newSettingsMenu, wxT("&Settings"));
settingsMenu = newSettingsMenu;
// Build sample rate menu
// Build/Rebuild the sample rate menu :
sampleRates = devInfo->getSampleRates(SOAPY_SDR_RX, 0);
sampleRateMenuItems.erase(sampleRateMenuItems.begin(),sampleRateMenuItems.end());
sampleRateMenuItems.clear();
wxMenu *newSampleRateMenu = new wxMenu;
int ofs = 0;
//Current sample rate, try to keep it as is.
long sampleRate = wxGetApp().getSampleRate();
long minRate = sampleRates.front();
long maxRate = sampleRates.back();
//If it is beyond limits, make device choose a reasonable value
if (sampleRate < minRate || sampleRate > maxRate) {
sampleRate = devInfo->getSampleRateNear(SOAPY_SDR_RX, 0, sampleRate);
}
//Check if a manual entry was previously set: if so, check its value is still within the limits of the device. If not so, reset it.
if (manualSampleRate > 0 &&
manualSampleRate < minRate || manualSampleRate > maxRate) {
manualSampleRate = -1;
}
bool checked = false;
for (vector<long>::iterator i = sampleRates.begin(); i != sampleRates.end(); i++) {
sampleRateMenuItems[wxID_BANDWIDTH_BASE+ofs] = newSampleRateMenu->AppendRadioItem(wxID_BANDWIDTH_BASE+ofs, frequencyToStr(*i));
if (sampleRate == (*i)) {
sampleRateMenuItems[wxID_BANDWIDTH_BASE+ofs]->Check(true);
checked = true;
@ -817,10 +840,26 @@ void AppFrame::updateDeviceParams() {
ofs++;
}
sampleRateMenuItems[wxID_BANDWIDTH_MANUAL] = newSampleRateMenu->AppendRadioItem(wxID_BANDWIDTH_MANUAL, wxT("Manual Entry"));
//Add a manual sample value radio button, but disabled by default in case the user
//never ever uses manual entry.
if (manualSampleRate <= 0) {
sampleRateMenuItems[wxID_BANDWIDTH_MANUAL] = newSampleRateMenu->AppendRadioItem(wxID_BANDWIDTH_MANUAL, wxT("Manual : N/A"));
sampleRateMenuItems[wxID_BANDWIDTH_MANUAL]->Enable(false);
}
else {
sampleRateMenuItems[wxID_BANDWIDTH_MANUAL] = newSampleRateMenu->AppendRadioItem(wxID_BANDWIDTH_MANUAL, wxT("Manual : ") + frequencyToStr(manualSampleRate));
sampleRateMenuItems[wxID_BANDWIDTH_MANUAL]->Enable(true);
}
//We apply the current sample rate after all
if (!checked) {
sampleRateMenuItems[wxID_BANDWIDTH_MANUAL]->Check(true);
}
//Append a normal button (NOT a radio-button) for manual entry dialog at the end
newSampleRateMenu->AppendSeparator();
sampleRateMenuItems[wxID_BANDWIDTH_MANUAL_DIALOG] = newSampleRateMenu->Append(wxID_BANDWIDTH_MANUAL_DIALOG, wxT("Manual Entry..."));
menuBar->Replace(2, newSampleRateMenu, wxT("Sample &Rate"));
sampleRateMenu = newSampleRateMenu;
@ -890,7 +929,6 @@ void AppFrame::disableRig() {
}
#endif
void AppFrame::OnMenu(wxCommandEvent& event) {
// if (event.GetId() >= wxID_RT_AUDIO_DEVICE && event.GetId() < wxID_RT_AUDIO_DEVICE + (int)devices.size()) {
@ -1129,41 +1167,51 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
bookmarkView->updateTheme();
}
switch (event.GetId()) {
case wxID_BANDWIDTH_MANUAL:
int rateHigh, rateLow;
SDRDeviceInfo *dev = wxGetApp().getDevice();
if (dev == NULL) {
break;
}
if (event.GetId() == wxID_BANDWIDTH_MANUAL) {
wxGetApp().setSampleRate(manualSampleRate);
}
else if (event.GetId() == wxID_BANDWIDTH_MANUAL_DIALOG) {
int rateHigh, rateLow;
SDRDeviceInfo *dev = wxGetApp().getDevice();
if (dev != nullptr) {
std::vector<long> sampleRates = dev->getSampleRates(SOAPY_SDR_RX, 0);
rateLow = 2000000;
rateHigh = 30000000;
//default
rateLow = MANUAL_SAMPLE_RATE_MIN;
rateHigh = MANUAL_SAMPLE_RATE_MAX;
if (sampleRates.size()) {
rateLow = sampleRates[0];
rateHigh = sampleRates[sampleRates.size()-1];
rateLow = sampleRates.front();
rateHigh = sampleRates.back();
}
long bw = wxGetNumberFromUser("\n" + dev->getName() + "\n\n "
+ "min: " + std::to_string(rateLow) + " Hz"
+ ", max: " + std::to_string(rateHigh) + " Hz\n",
"Sample Rate in Hz",
"Manual Sample Rate Entry",
wxGetApp().getSampleRate(),
rateLow,
rateHigh,
this);
+ "min: " + std::to_string(rateLow) + " Hz"
+ ", max: " + std::to_string(rateHigh) + " Hz\n",
"Sample Rate in Hz",
"Manual Sample Rate Entry",
//If a manual sample rate has already been input, recall this one.
manualSampleRate > 0? manualSampleRate :wxGetApp().getSampleRate(),
rateLow,
rateHigh,
this);
if (bw != -1) {
wxGetApp().setSampleRate(bw);
manualSampleRate = bw;
sampleRateMenuItems[wxID_BANDWIDTH_MANUAL]->Enable(true);
sampleRateMenuItems[wxID_BANDWIDTH_MANUAL]->SetItemLabel(wxT("Manual : ") + frequencyToStr(manualSampleRate));
sampleRateMenuItems[wxID_BANDWIDTH_MANUAL]->Check(true);
wxGetApp().setSampleRate(manualSampleRate);
}
break;
}
}
if (event.GetId() >= wxID_BANDWIDTH_BASE && event.GetId() < wxID_BANDWIDTH_BASE + (int)sampleRates.size()) {
else if (event.GetId() >= wxID_BANDWIDTH_BASE && event.GetId() < wxID_BANDWIDTH_BASE + (int)sampleRates.size()) {
wxGetApp().setSampleRate(sampleRates[event.GetId()-wxID_BANDWIDTH_BASE]);
}
@ -1842,18 +1890,54 @@ bool AppFrame::loadSession(std::string fileName) {
}
if (header->hasAnother("sample_rate")) {
int sample_rate = *header->getNext("sample_rate");
long sample_rate = *header->getNext("sample_rate");
SDRDeviceInfo *dev = wxGetApp().getSDRThread()->getDevice();
if (dev) {
// Try for a reasonable default sample rate.
sample_rate = dev->getSampleRateNear(SOAPY_SDR_RX, 0, sample_rate);
//retreive the available sample rates. A valid previously chosen manual
//value is constrained within these limits. If it doesn't behave, lets the device choose
//for us.
long minRate = MANUAL_SAMPLE_RATE_MIN;
long maxRate = MANUAL_SAMPLE_RATE_MAX;
std::vector<long> sampleRates = dev->getSampleRates(SOAPY_SDR_RX, 0);
if (sampleRates.size()) {
minRate = sampleRates.front();
maxRate = sampleRates.back();
}
//If it is beyond limits, make device choose a reasonable value
if (sample_rate < minRate || sample_rate > maxRate) {
sample_rate = dev->getSampleRateNear(SOAPY_SDR_RX, 0, sample_rate);
}
//scan the available sample rates and see if it matches a predifined one
int menuIndex = -1;
for (auto discreteRate : sampleRates) {
if (discreteRate == sample_rate) {
menuIndex++;
//activate Bandwidth Menu entry matching this predefined sample_rate.
sampleRateMenuItems[wxID_BANDWIDTH_BASE + menuIndex]->Check(true);
break;
}
} //end for
//this is a manual entry
if (menuIndex == -1) {
manualSampleRate = sample_rate;
sampleRateMenuItems[wxID_BANDWIDTH_MANUAL]->Enable(true);
// Apply the manual value, activate the menu entry
sampleRateMenuItems[wxID_BANDWIDTH_MANUAL]->SetItemLabel(wxString("Manual Entry : ") + frequencyToStr(sample_rate));
sampleRateMenuItems[wxID_BANDWIDTH_MANUAL]->Check(true);
}
//update applied value
wxGetApp().setSampleRate(sample_rate);
deviceChanged.store(true);
} else {
wxGetApp().setSampleRate(sample_rate);
}
}
DemodulatorInstance *loadedActiveDemod = nullptr;

View File

@ -55,6 +55,7 @@
#define wxID_DISPLAY_BOOKMARKS 2107
#define wxID_BANDWIDTH_BASE 2150
#define wxID_BANDWIDTH_MANUAL_DIALOG 2199
#define wxID_BANDWIDTH_MANUAL 2200
#define wxID_DISPLAY_BASE 2250
@ -118,6 +119,12 @@ public:
BookmarkView *getBookmarkView();
void disableSave(bool state);
//call this in case the main UI is not
//the origin of device changes / sample rate by operator,
//and must be notified back to update its UI elements
//(ex: SDR Devices dialog changing the configuration)
void notifyDeviceChanged();
#ifdef _WIN32
bool canFocus();
@ -174,6 +181,7 @@ private:
SoapySDR::ArgInfoList settingArgs;
int settingsIdMax;
std::vector<long> sampleRates;
long manualSampleRate = -1;
std::string currentSessionFile;

View File

@ -917,6 +917,10 @@ bool CubicSDR::areDevicesReady() {
return devicesReady.load();
}
void CubicSDR::notifyMainUIOfDeviceChange() {
appframe->notifyDeviceChanged();
}
bool CubicSDR::areDevicesEnumerating() {
return !sdrEnum->isTerminated();
}

View File

@ -138,6 +138,8 @@ public:
bool areDevicesEnumerating();
bool areModulesMissing();
std::string getNotification();
void notifyMainUIOfDeviceChange();
void addRemote(std::string remoteAddr);
void removeRemote(std::string remoteAddr);

View File

@ -40,4 +40,6 @@ const char filePathSeparator =
#define CHANNELIZER_RATE_MAX 500000
#define MANUAL_SAMPLE_RATE_MIN 2000000 // 2MHz
#define MANUAL_SAMPLE_RATE_MAX 200000000 // 200MHz (We are 2017+ after all)

View File

@ -260,7 +260,7 @@ void AudioThread::enumerateDevices(std::vector<RtAudio::DeviceInfo> &devs) {
std::cout << "\t\t32-bit float normalized between plus/minus 1.0." << std::endl;
}
if (nFormats & RTAUDIO_FLOAT64) {
std::cout << "\t\t32-bit float normalized between plus/minus 1.0." << std::endl;
std::cout << "\t\t64-bit float normalized between plus/minus 1.0." << std::endl;
}
std::vector<unsigned int>::iterator srate;

View File

@ -116,8 +116,8 @@ void SDRDevicesDialog::refreshDeviceProperties() {
devSettings["name"] = m_propertyGrid->Append( new wxStringProperty("Name", wxPG_LABEL, devConfig->getDeviceName()) );
devSettings["offset"] = m_propertyGrid->Append( new wxIntProperty("Offset (Hz)", wxPG_LABEL, devConfig->getOffset()) );
int currentSampleRate = wxGetApp().getSampleRate();
int deviceSampleRate = devConfig->getSampleRate();
long currentSampleRate = wxGetApp().getSampleRate();
long deviceSampleRate = devConfig->getSampleRate();
if (!deviceSampleRate) {
deviceSampleRate = selDev->getSampleRateNear(SOAPY_SDR_RX, 0, currentSampleRate);
@ -318,7 +318,7 @@ void SDRDevicesDialog::OnUseSelected( wxMouseEvent& event) {
wxGetApp().setDeviceArgs(settingArgs);
wxGetApp().setStreamArgs(streamArgs);
wxGetApp().setDevice(dev,0);
wxGetApp().notifyMainUIOfDeviceChange();
Close();
}
event.Skip();
@ -438,13 +438,14 @@ void SDRDevicesDialog::OnPropGridChanged( wxPropertyGridEvent& event ) {
DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(dev->getDeviceId());
std::string strRate = deviceArgs["sample_rate"].options[event.GetPropertyValue().GetInteger()];
int srate = 0;
long srate = 0;
try {
srate = std::stoi(strRate);
srate = std::stol(strRate);
devConfig->setSampleRate(srate);
if (dev->isActive() || !wxGetApp().getDevice()) {
wxGetApp().setSampleRate(srate);
wxGetApp().notifyMainUIOfDeviceChange();
}
} catch (std::invalid_argument e) {
// nop

View File

@ -208,7 +208,12 @@ void SDRThread::readStream(SDRThreadIQDataQueue* iqDataOutQueue) {
int n_stream_read = device->readStream(stream, buffs, mtElems, flags, timeNs);
//if the n_stream_read <= 0, bail out from reading.
if (n_stream_read <= 0) {
if (n_stream_read == 0) {
std::cout << "SDRThread::readStream(): read blocking..." << std::endl;
break;
}
else if (n_stream_read < 0) {
std::cout << "SDRThread::readStream(): read failed with code: " << n_stream_read << std::endl;
break;
}
@ -226,7 +231,7 @@ void SDRThread::readStream(SDRThreadIQDataQueue* iqDataOutQueue) {
} else {
break;
}
}
} //end while
if (n_read > 0 && !stopping && !iqDataOutQueue->full()) {
SDRThreadIQData *dataOut = buffers.getBuffer();
@ -515,7 +520,7 @@ long long SDRThread::getOffset() {
return offset.load();
}
void SDRThread::setSampleRate(int rate) {
void SDRThread::setSampleRate(long rate) {
sampleRate.store(rate);
rate_changed = true;
DeviceConfig *devConfig = deviceConfig.load();
@ -524,7 +529,7 @@ void SDRThread::setSampleRate(int rate) {
}
// std::cout << "Set sample rate: " << sampleRate.load() << std::endl;
}
int SDRThread::getSampleRate() {
long SDRThread::getSampleRate() {
return sampleRate.load();
}

View File

@ -70,8 +70,8 @@ public:
void setOffset(long long ofs);
long long getOffset();
void setSampleRate(int rate);
int getSampleRate();
void setSampleRate(long rate);
long getSampleRate();
void setPPM(int ppm);
int getPPM();
@ -109,7 +109,7 @@ protected:
std::map<std::string, std::string> settings;
std::map<std::string, bool> settingChanged;
std::atomic<uint32_t> sampleRate;
std::atomic_llong sampleRate;
std::atomic_llong frequency, offset, lock_freq;
std::atomic_int ppm, numElems, mtuElems, numChannels;
std::atomic_bool hasPPM, hasHardwareDC;

View File

@ -170,6 +170,13 @@ void GainCanvas::setHelpTip(std::string tip) {
void GainCanvas::updateGainUI() {
SDRDeviceInfo *devInfo = wxGetApp().getDevice();
//possible if we 'Refresh Devices' then devInfo becomes null
//until a new device is selected.
if (devInfo == nullptr) {
return;
}
DeviceConfig *devConfig = wxGetApp().getConfig()->getDevice(devInfo->getDeviceId());
gains = devInfo->getGains(SOAPY_SDR_RX, 0);

View File

@ -30,7 +30,7 @@ InteractiveCanvas::InteractiveCanvas(wxWindow *parent, int *dispAttrs) :
InteractiveCanvas::~InteractiveCanvas() {
}
void InteractiveCanvas::setView(long long center_freq_in, int bandwidth_in) {
void InteractiveCanvas::setView(long long center_freq_in, long long bandwidth_in) {
isView = true;
centerFreq = center_freq_in;
bandwidth = bandwidth_in;
@ -74,11 +74,11 @@ long long InteractiveCanvas::getCenterFrequency() {
}
}
void InteractiveCanvas::setBandwidth(unsigned int bandwidth_in) {
void InteractiveCanvas::setBandwidth(long long bandwidth_in) {
bandwidth = bandwidth_in;
}
unsigned int InteractiveCanvas::getBandwidth() {
long long InteractiveCanvas::getBandwidth() {
if (isView) {
return bandwidth;
} else {

View File

@ -17,15 +17,15 @@ public:
long long getFrequencyAt(float x);
long long getFrequencyAt(float x, long long iqCenterFreq, long long iqBandwidth);
virtual void setView(long long center_freq_in, int bandwidth_in);
virtual void setView(long long center_freq_in, long long bandwidth_in);
virtual void disableView();
bool getViewState();
void setCenterFrequency(long long center_freq_in);
long long getCenterFrequency();
void setBandwidth(unsigned int bandwidth_in);
unsigned int getBandwidth();
void setBandwidth(long long bandwidth_in);
long long getBandwidth();
MouseTracker *getMouseTracker();
bool isMouseInView();
@ -59,8 +59,8 @@ protected:
bool ctrlDown;
long long centerFreq;
unsigned int bandwidth;
unsigned int lastBandwidth;
long long bandwidth;
long long lastBandwidth;
bool isView;
std::string lastToolTip;