Merge branch 'master' into patch-1

This commit is contained in:
Dr. Rubisco 2021-07-29 12:38:23 -04:00 committed by GitHub
commit d84273a0db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 454 additions and 406 deletions

View File

@ -47,51 +47,49 @@ void ConfigManager::save(bool lock) {
} }
void ConfigManager::enableAutoSave() { void ConfigManager::enableAutoSave() {
if (!autoSaveEnabled) { if (autoSaveEnabled) { return; }
autoSaveEnabled = true; autoSaveEnabled = true;
termFlag = false; termFlag = false;
autoSaveThread = std::thread(autoSaveWorker, this); autoSaveThread = std::thread(&ConfigManager::autoSaveWorker, this);
}
} }
void ConfigManager::disableAutoSave() { void ConfigManager::disableAutoSave() {
if (autoSaveEnabled) { if (!autoSaveEnabled) { return; }
{ {
std::lock_guard<std::mutex> lock(termMtx); std::lock_guard<std::mutex> lock(termMtx);
autoSaveEnabled = false; autoSaveEnabled = false;
termFlag = true; termFlag = true;
}
termCond.notify_one();
if (autoSaveThread.joinable()) { autoSaveThread.join(); }
} }
termCond.notify_one();
if (autoSaveThread.joinable()) { autoSaveThread.join(); }
} }
void ConfigManager::acquire() { void ConfigManager::acquire() {
mtx.lock(); mtx.lock();
} }
void ConfigManager::release(bool changed) { void ConfigManager::release(bool modified) {
this->changed |= changed; changed |= modified;
mtx.unlock(); mtx.unlock();
} }
void ConfigManager::autoSaveWorker(ConfigManager* _this) { void ConfigManager::autoSaveWorker() {
while (_this->autoSaveEnabled) { while (autoSaveEnabled) {
if (!_this->mtx.try_lock()) { if (!mtx.try_lock()) {
spdlog::warn("ConfigManager locked, waiting..."); spdlog::warn("ConfigManager locked, waiting...");
std::this_thread::sleep_for(std::chrono::milliseconds(1000)); std::this_thread::sleep_for(std::chrono::milliseconds(1000));
continue; continue;
} }
if (_this->changed) { if (changed) {
_this->changed = false; changed = false;
_this->save(false); save(false);
} }
_this->mtx.unlock(); mtx.unlock();
// Sleep but listen for wakeup call // Sleep but listen for wakeup call
{ {
std::unique_lock<std::mutex> lock(_this->termMtx); std::unique_lock<std::mutex> lock(termMtx);
_this->termCond.wait_for(lock, std::chrono::milliseconds(1000), [_this]() { return _this->termFlag; } ); termCond.wait_for(lock, std::chrono::milliseconds(1000), [this]() { return termFlag; } );
} }
} }
} }

View File

@ -17,21 +17,21 @@ public:
void enableAutoSave(); void enableAutoSave();
void disableAutoSave(); void disableAutoSave();
void acquire(); void acquire();
void release(bool changed = false); void release(bool modified = false);
json conf; json conf;
private: private:
static void autoSaveWorker(ConfigManager* _this); void autoSaveWorker();
std::string path = ""; std::string path = "";
bool changed = false; volatile bool changed = false;
bool autoSaveEnabled = false; volatile bool autoSaveEnabled = false;
std::thread autoSaveThread; std::thread autoSaveThread;
std::mutex mtx; std::mutex mtx;
std::mutex termMtx; std::mutex termMtx;
std::condition_variable termCond; std::condition_variable termCond;
bool termFlag = false; volatile bool termFlag = false;
}; };

View File

@ -206,6 +206,7 @@ int sdrpp_main(int argc, char *argv[]) {
defConfig["showWaterfall"] = true; defConfig["showWaterfall"] = true;
defConfig["source"] = ""; defConfig["source"] = "";
defConfig["decimationPower"] = 0; defConfig["decimationPower"] = 0;
defConfig["iqCorrection"] = false;
defConfig["streams"]["Radio"]["muted"] = false; defConfig["streams"]["Radio"]["muted"] = false;
defConfig["streams"]["Radio"]["sink"] = "Audio"; defConfig["streams"]["Radio"]["sink"] = "Audio";
@ -462,6 +463,11 @@ int sdrpp_main(int argc, char *argv[]) {
glfwSwapBuffers(core::window); glfwSwapBuffers(core::window);
} }
// Shut down all modules
for (auto& [name, mod] : core::moduleManager.modules) {
mod.end();
}
// Cleanup // Cleanup
ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown(); ImGui_ImplGlfw_Shutdown();
@ -472,5 +478,8 @@ int sdrpp_main(int argc, char *argv[]) {
sigpath::signalPath.stop(); sigpath::signalPath.stop();
core::configManager.disableAutoSave();
core::configManager.save();
return 0; return 0;
} }

View File

@ -24,9 +24,10 @@ namespace sdrpp_credits {
const char* libraries[] = { const char* libraries[] = {
"Dear ImGui (ocornut)", "Dear ImGui (ocornut)",
"fftw3 (fftw.org)",
"glew (Nigel Stewart)",
"glfw (Camilla Löwy)",
"json (nlohmann)", "json (nlohmann)",
"RtAudio",
"SoapySDR (PothosWare)",
"spdlog (gabime)", "spdlog (gabime)",
"Portable File Dialogs" "Portable File Dialogs"
}; };

76
core/src/dsp/correction.h Normal file
View File

@ -0,0 +1,76 @@
#pragma once
#include <dsp/block.h>
#include <dsp/stream.h>
#include <dsp/types.h>
#include <dsp/window.h>
namespace dsp {
class IQCorrector : public generic_block<IQCorrector> {
public:
IQCorrector() {}
IQCorrector(stream<complex_t>* in, float rate) { init(in, rate); }
void init(stream<complex_t>* in, float rate) {
_in = in;
correctionRate = rate;
offset.re = 0;
offset.im = 0;
generic_block<IQCorrector>::registerInput(_in);
generic_block<IQCorrector>::registerOutput(&out);
generic_block<IQCorrector>::_block_init = true;
}
void setInput(stream<complex_t>* in) {
assert(generic_block<IQCorrector>::_block_init);
std::lock_guard<std::mutex> lck(generic_block<IQCorrector>::ctrlMtx);
generic_block<IQCorrector>::tempStop();
generic_block<IQCorrector>::unregisterInput(_in);
_in = in;
generic_block<IQCorrector>::registerInput(_in);
generic_block<IQCorrector>::tempStart();
}
void setCorrectionRate(float rate) {
correctionRate = rate;
}
int run() {
int count = _in->read();
if (count < 0) { return -1; }
if (bypass) {
memcpy(out.writeBuf, _in->readBuf, count * sizeof(complex_t));
_in->flush();
if (!out.swap(count)) { return -1; }
return count;
}
for (int i = 0; i < count; i++) {
out.writeBuf[i] = _in->readBuf[i] - offset;
offset = offset + (out.writeBuf[i] * correctionRate);
}
_in->flush();
if (!out.swap(count)) { return -1; }
return count;
}
stream<complex_t> out;
// TEMPORARY FOR DEBUG PURPOSES
bool bypass = false;
complex_t offset;
private:
stream<complex_t>* _in;
float correctionRate = 0.00001;
};
}

View File

@ -15,6 +15,10 @@ namespace credits {
void show() { void show() {
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20.0f, 20.0f)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20.0f, 20.0f));
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0,0,0,0));
ImVec2 dispSize = ImGui::GetIO().DisplaySize;
ImVec2 center = ImVec2(dispSize.x/2.0f, dispSize.y/2.0f);
ImGui::SetNextWindowPos(center, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
ImGui::OpenPopup("Credits"); ImGui::OpenPopup("Credits");
ImGui::BeginPopupModal("Credits", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove); ImGui::BeginPopupModal("Credits", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove);
@ -55,11 +59,8 @@ namespace credits {
ImGui::Spacing(); ImGui::Spacing();
ImGui::Text("SDR++ v" VERSION_STR " (Built at " __TIME__ ", " __DATE__ ")"); ImGui::Text("SDR++ v" VERSION_STR " (Built at " __TIME__ ", " __DATE__ ")");
ImVec2 dispSize = ImGui::GetIO().DisplaySize;
ImVec2 winSize = ImGui::GetWindowSize();
ImGui::SetWindowPos(ImVec2(std::round((dispSize.x/2) - (winSize.x/2)), std::round((dispSize.y/2) - (winSize.y/2))));
ImGui::EndPopup(); ImGui::EndPopup();
ImGui::PopStyleVar(1); ImGui::PopStyleColor();
ImGui::PopStyleVar();
} }
} }

View File

@ -404,9 +404,11 @@ void MainWindow::draw() {
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetWindowSize().x - 387); int snrWidth = std::min<int>(300, ImGui::GetWindowSize().x - ImGui::GetCursorPosX() - 87);
ImGui::SetCursorPosX(ImGui::GetWindowSize().x - (snrWidth+87));
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5);
ImGui::SetNextItemWidth(300); ImGui::SetNextItemWidth(snrWidth);
ImGui::SNRMeter((vfo != NULL) ? gui::waterfall.selectedVFOSNR : 0); ImGui::SNRMeter((vfo != NULL) ? gui::waterfall.selectedVFOSNR : 0);
ImGui::SameLine(); ImGui::SameLine();

View File

@ -108,7 +108,7 @@ namespace displaymenu {
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::InputInt("##sdrpp_fft_rate", &fftRate, 1, 10)) { if (ImGui::InputInt("##sdrpp_fft_rate", &fftRate, 1, 10)) {
std::clamp<int>(fftRate, 1, 200); fftRate = std::max<int>(1, fftRate);
sigpath::signalPath.setFFTRate(fftRate); sigpath::signalPath.setFFTRate(fftRate);
core::configManager.acquire(); core::configManager.acquire();
core::configManager.conf["fftRate"] = fftRate; core::configManager.conf["fftRate"] = fftRate;

View File

@ -12,6 +12,7 @@ namespace sourecmenu {
double customOffset = 0.0; double customOffset = 0.0;
double effectiveOffset = 0.0; double effectiveOffset = 0.0;
int decimationPower = 0; int decimationPower = 0;
bool iqCorrection = false;
EventHandler<std::string> sourceRegisteredHandler; EventHandler<std::string> sourceRegisteredHandler;
EventHandler<std::string> sourceUnregisterHandler; EventHandler<std::string> sourceUnregisterHandler;
@ -124,6 +125,8 @@ namespace sourecmenu {
customOffset = core::configManager.conf["offset"]; customOffset = core::configManager.conf["offset"];
offsetMode = core::configManager.conf["offsetMode"]; offsetMode = core::configManager.conf["offsetMode"];
decimationPower = core::configManager.conf["decimationPower"]; decimationPower = core::configManager.conf["decimationPower"];
iqCorrection = core::configManager.conf["iqCorrection"];
sigpath::signalPath.setIQCorrection(iqCorrection);
updateOffset(); updateOffset();
refreshSources(); refreshSources();
@ -158,6 +161,13 @@ namespace sourecmenu {
sigpath::sourceManager.showSelectedMenu(); sigpath::sourceManager.showSelectedMenu();
if (ImGui::Checkbox("IQ Correction##_sdrpp_iq_corr", &iqCorrection)) {
sigpath::signalPath.setIQCorrection(iqCorrection);
core::configManager.acquire();
core::configManager.conf["iqCorrection"] = iqCorrection;
core::configManager.release(true);
}
ImGui::Text("Offset mode"); ImGui::Text("Offset mode");
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(itemWidth - ImGui::GetCursorPosX()); ImGui::SetNextItemWidth(itemWidth - ImGui::GetCursorPosX());

View File

@ -362,7 +362,7 @@ namespace ImGui {
// If the mouse wheel is moved on the frequency scale // If the mouse wheel is moved on the frequency scale
if (mouseWheel != 0 && mouseInFreq) { if (mouseWheel != 0 && mouseInFreq) {
viewOffset -= (double)mouseWheel * viewBandwidth / 20.0; viewOffset -= (double)mouseWheel * viewBandwidth / 20.0;
if (viewOffset + (viewBandwidth / 2.0) > wholeBandwidth / 2.0) { if (viewOffset + (viewBandwidth / 2.0) > wholeBandwidth / 2.0) {
double freqOffset = (viewOffset + (viewBandwidth / 2.0)) - (wholeBandwidth / 2.0); double freqOffset = (viewOffset + (viewBandwidth / 2.0)) - (wholeBandwidth / 2.0);
@ -520,7 +520,7 @@ namespace ImGui {
float pixel; float pixel;
float dataRange = waterfallMax - waterfallMin; float dataRange = waterfallMax - waterfallMin;
int count = std::min<float>(waterfallHeight, fftLines); int count = std::min<float>(waterfallHeight, fftLines);
if (rawFFTs != NULL) { if (rawFFTs != NULL && fftLines >= 0) {
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
drawDataSize = (viewBandwidth / wholeBandwidth) * rawFFTSize; drawDataSize = (viewBandwidth / wholeBandwidth) * rawFFTSize;
drawDataStart = (((double)rawFFTSize / 2.0) * (offsetRatio + 1)) - (drawDataSize / 2); drawDataStart = (((double)rawFFTSize / 2.0) * (offsetRatio + 1)) - (drawDataSize / 2);
@ -530,6 +530,12 @@ namespace ImGui {
waterfallFb[(i * dataWidth) + j] = waterfallPallet[(int)(pixel * (WATERFALL_RESOLUTION - 1))]; waterfallFb[(i * dataWidth) + j] = waterfallPallet[(int)(pixel * (WATERFALL_RESOLUTION - 1))];
} }
} }
for (int i = count; i < waterfallHeight; i++) {
for (int j = 0; j < dataWidth; j++) {
waterfallFb[(i * dataWidth) + j] = (uint32_t)255 << 24;
}
}
} }
delete[] tempData; delete[] tempData;
waterfallUpdate = true; waterfallUpdate = true;
@ -1028,15 +1034,16 @@ namespace ImGui {
void WaterFall::setRawFFTSize(int size, bool lock) { void WaterFall::setRawFFTSize(int size, bool lock) {
std::lock_guard<std::mutex> lck(buf_mtx); std::lock_guard<std::mutex> lck(buf_mtx);
rawFFTSize = size; rawFFTSize = size;
int wfSize = std::max<int>(1, waterfallHeight);
if (rawFFTs != NULL) { if (rawFFTs != NULL) {
int wfSize = std::max<int>(1, waterfallHeight);
rawFFTs = (float*)realloc(rawFFTs, rawFFTSize * wfSize * sizeof(float)); rawFFTs = (float*)realloc(rawFFTs, rawFFTSize * wfSize * sizeof(float));
} }
else { else {
int wfSize = std::max<int>(1, waterfallHeight);
rawFFTs = (float*)malloc(rawFFTSize * wfSize * sizeof(float)); rawFFTs = (float*)malloc(rawFFTSize * wfSize * sizeof(float));
} }
fftLines = 0;
memset(rawFFTs, 0, rawFFTSize * waterfallHeight * sizeof(float)); memset(rawFFTs, 0, rawFFTSize * waterfallHeight * sizeof(float));
updateWaterfallFb();
} }
void WaterFall::setBandPlanPos(int pos) { void WaterFall::setBandPlanPos(int pos) {

View File

@ -16,6 +16,7 @@ void SignalPath::init(uint64_t sampleRate, int fftRate, int fftSize, dsp::stream
// split.init(input); // split.init(input);
inputBuffer.init(input); inputBuffer.init(input);
corrector.init(&inputBuffer.out, 50.0f / sampleRate);
split.init(&inputBuffer.out); split.init(&inputBuffer.out);
reshape.init(&fftStream, fftSize, (sampleRate / fftRate) - fftSize); reshape.init(&fftStream, fftSize, (sampleRate / fftRate) - fftSize);
@ -43,6 +44,8 @@ void SignalPath::setSampleRate(double sampleRate) {
vfo.vfo->start(); vfo.vfo->start();
} }
corrector.setCorrectionRate(50.0f / sampleRate);
split.start(); split.start();
} }
@ -55,6 +58,7 @@ void SignalPath::start() {
decimator->start(); decimator->start();
} }
inputBuffer.start(); inputBuffer.start();
if (iqCorrection) { corrector.start(); }
split.start(); split.start();
reshape.start(); reshape.start();
fftHandlerSink.start(); fftHandlerSink.start();
@ -66,6 +70,7 @@ void SignalPath::stop() {
decimator->stop(); decimator->stop();
} }
inputBuffer.stop(); inputBuffer.stop();
if (iqCorrection) { corrector.stop(); }
split.stop(); split.stop();
reshape.stop(); reshape.stop();
fftHandlerSink.stop(); fftHandlerSink.stop();
@ -159,7 +164,13 @@ void SignalPath::setDecimation(int dec) {
// If no decimation, reconnect // If no decimation, reconnect
if (!dec) { if (!dec) {
split.setInput(&inputBuffer.out); if (iqCorrection) {
split.setInput(&corrector.out);
}
else {
split.setInput(&inputBuffer.out);
}
if (running) { split.start(); } if (running) { split.start(); }
core::setInputSampleRate(sourceSampleRate); core::setInputSampleRate(sourceSampleRate);
return; return;
@ -167,7 +178,17 @@ void SignalPath::setDecimation(int dec) {
// Create new decimators // Create new decimators
for (int i = 0; i < dec; i++) { for (int i = 0; i < dec; i++) {
dsp::HalfDecimator<dsp::complex_t>* decimator = new dsp::HalfDecimator<dsp::complex_t>((i == 0) ? &inputBuffer.out : &decimators[i-1]->out, &halfBandWindow); dsp::HalfDecimator<dsp::complex_t>* decimator;
if (iqCorrection && i == 0) {
decimator = new dsp::HalfDecimator<dsp::complex_t>(&corrector.out, &halfBandWindow);
}
else if (i == 0) {
decimator = new dsp::HalfDecimator<dsp::complex_t>(&inputBuffer.out, &halfBandWindow);
}
else {
decimator = new dsp::HalfDecimator<dsp::complex_t>(&decimators[i-1]->out, &halfBandWindow);
}
if (running) { decimator->start(); } if (running) { decimator->start(); }
decimators.push_back(decimator); decimators.push_back(decimator);
} }
@ -177,3 +198,32 @@ void SignalPath::setDecimation(int dec) {
// Update the DSP sample rate // Update the DSP sample rate
core::setInputSampleRate(sourceSampleRate); core::setInputSampleRate(sourceSampleRate);
} }
void SignalPath::setIQCorrection(bool enabled) {
if (iqCorrection == enabled) { return; }
if (!iqCorrection && enabled) {
if (decimation) {
decimators[0]->setInput(&corrector.out);
}
else {
split.setInput(&corrector.out);
}
if (running) { corrector.start(); }
}
else if (iqCorrection && !enabled) {
if (running) { corrector.stop(); }
if (decimation) {
decimators[0]->setInput(&inputBuffer.out);
}
else {
split.setInput(&inputBuffer.out);
}
}
iqCorrection = enabled;
if (!enabled) {
corrector.offset.re = 0;
corrector.offset.im = 0;
}
}

View File

@ -4,6 +4,7 @@
#include <map> #include <map>
#include <dsp/sink.h> #include <dsp/sink.h>
#include <dsp/decimation.h> #include <dsp/decimation.h>
#include <dsp/correction.h>
class SignalPath { class SignalPath {
public: public:
@ -24,6 +25,7 @@ public:
void stopFFT(); void stopFFT();
void setBuffering(bool enabled); void setBuffering(bool enabled);
void setDecimation(int dec); void setDecimation(int dec);
void setIQCorrection(bool enabled);
dsp::SampleFrameBuffer<dsp::complex_t> inputBuffer; dsp::SampleFrameBuffer<dsp::complex_t> inputBuffer;
double sourceSampleRate = 0; double sourceSampleRate = 0;
@ -36,6 +38,7 @@ private:
}; };
dsp::Splitter<dsp::complex_t> split; dsp::Splitter<dsp::complex_t> split;
dsp::IQCorrector corrector;
// FFT // FFT
dsp::stream<dsp::complex_t> fftStream; dsp::stream<dsp::complex_t> fftStream;
@ -53,4 +56,5 @@ private:
int inputBlockSize; int inputBlockSize;
bool bufferingEnabled = false; bool bufferingEnabled = false;
bool running = false; bool running = false;
bool iqCorrection = false;
}; };

View File

@ -1,3 +1,3 @@
#pragma once #pragma once
#define VERSION_STR "1.0.0_rc1" #define VERSION_STR "1.0.0_rc2"

View File

@ -198,19 +198,20 @@ private:
ImGui::EndTable(); ImGui::EndTable();
if (strlen(nameBuf) == 0) { style::beginDisabled(); } bool applyDisabled = (strlen(nameBuf) == 0) || (bookmarks.find(editedBookmarkName) != bookmarks.end() && editedBookmarkName != firstEditedBookmarkName);
if (applyDisabled) { style::beginDisabled(); }
if (ImGui::Button("Apply")) { if (ImGui::Button("Apply")) {
open = false; open = false;
// If editing, delete the original one // If editing, delete the original one
if (editOpen) { if (editOpen) {
bookmarks.erase(firstEeditedBookmarkName); bookmarks.erase(firstEditedBookmarkName);
} }
bookmarks[nameBuf] = editedBookmark; bookmarks[editedBookmarkName] = editedBookmark;
saveByName(selectedListName); saveByName(selectedListName);
} }
if (strlen(nameBuf) == 0) { style::endDisabled(); } if (applyDisabled) { style::endDisabled(); }
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Button("Cancel")) { if (ImGui::Button("Cancel")) {
open = false; open = false;
@ -463,7 +464,7 @@ private:
_this->editedBookmark.selected = false; _this->editedBookmark.selected = false;
_this->editOpen = true; _this->createOpen = true;
// Find new unique default name // Find new unique default name
if (_this->bookmarks.find("New Bookmark") == _this->bookmarks.end()) { if (_this->bookmarks.find("New Bookmark") == _this->bookmarks.end()) {
@ -492,7 +493,7 @@ private:
_this->editOpen = true; _this->editOpen = true;
_this->editedBookmark = _this->bookmarks[selectedNames[0]]; _this->editedBookmark = _this->bookmarks[selectedNames[0]];
_this->editedBookmarkName = selectedNames[0]; _this->editedBookmarkName = selectedNames[0];
_this->firstEeditedBookmarkName = selectedNames[0]; _this->firstEditedBookmarkName = selectedNames[0];
} }
if (selectedNames.size() != 1 && _this->selectedListName != "") { style::endDisabled(); } if (selectedNames.size() != 1 && _this->selectedListName != "") { style::endDisabled(); }
@ -679,7 +680,9 @@ private:
std::string hoveredBookmarkName; std::string hoveredBookmarkName;
if (_this->bookmarkDisplayMode == BOOKMARK_DISP_MODE_TOP) { if (_this->bookmarkDisplayMode == BOOKMARK_DISP_MODE_TOP) {
for (auto const bm : _this->waterfallBookmarks) { int count = _this->waterfallBookmarks.size();
for (int i = count-1; i >= 0; i--) {
auto& bm = _this->waterfallBookmarks[i];
double centerXpos = args.fftRectMin.x + std::round((bm.bookmark.frequency - args.lowFreq) * args.freqToPixelRatio); double centerXpos = args.fftRectMin.x + std::round((bm.bookmark.frequency - args.lowFreq) * args.freqToPixelRatio);
ImVec2 nameSize = ImGui::CalcTextSize(bm.bookmarkName.c_str()); ImVec2 nameSize = ImGui::CalcTextSize(bm.bookmarkName.c_str());
ImVec2 rectMin = ImVec2(centerXpos-(nameSize.x/2)-5, args.fftRectMin.y); ImVec2 rectMin = ImVec2(centerXpos-(nameSize.x/2)-5, args.fftRectMin.y);
@ -696,7 +699,9 @@ private:
} }
} }
else if (_this->bookmarkDisplayMode == BOOKMARK_DISP_MODE_BOTTOM) { else if (_this->bookmarkDisplayMode == BOOKMARK_DISP_MODE_BOTTOM) {
for (auto const bm : _this->waterfallBookmarks) { int count = _this->waterfallBookmarks.size();
for (int i = count-1; i >= 0; i--) {
auto& bm = _this->waterfallBookmarks[i];
double centerXpos = args.fftRectMin.x + std::round((bm.bookmark.frequency - args.lowFreq) * args.freqToPixelRatio); double centerXpos = args.fftRectMin.x + std::round((bm.bookmark.frequency - args.lowFreq) * args.freqToPixelRatio);
ImVec2 nameSize = ImGui::CalcTextSize(bm.bookmarkName.c_str()); ImVec2 nameSize = ImGui::CalcTextSize(bm.bookmarkName.c_str());
ImVec2 rectMin = ImVec2(centerXpos-(nameSize.x/2)-5, args.fftRectMax.y-nameSize.y); ImVec2 rectMin = ImVec2(centerXpos-(nameSize.x/2)-5, args.fftRectMax.y-nameSize.y);
@ -808,7 +813,7 @@ private:
std::map<std::string, FrequencyBookmark> bookmarks; std::map<std::string, FrequencyBookmark> bookmarks;
std::string editedBookmarkName = ""; std::string editedBookmarkName = "";
std::string firstEeditedBookmarkName = ""; std::string firstEditedBookmarkName = "";
FrequencyBookmark editedBookmark; FrequencyBookmark editedBookmark;
std::vector<std::string> listNames; std::vector<std::string> listNames;
@ -861,5 +866,6 @@ MOD_EXPORT void _DELETE_INSTANCE_(void* instance) {
} }
MOD_EXPORT void _END_() { MOD_EXPORT void _END_() {
// Nothing here config.disableAutoSave();
config.save();
} }

View File

@ -10,6 +10,8 @@
#include <meteor_demodulator_interface.h> #include <meteor_demodulator_interface.h>
#include <config.h> #include <config.h>
#include <options.h> #include <options.h>
#include <cctype>
#include <radio_interface.h>
#define CONCAT(a, b) ((std::string(a) + b).c_str()) #define CONCAT(a, b) ((std::string(a) + b).c_str())
#define MAX_COMMAND_LENGTH 8192 #define MAX_COMMAND_LENGTH 8192
@ -360,374 +362,248 @@ private:
// NOTE: THIS STUFF ISN'T THREADSAFE AND WILL LIKELY BREAK. // NOTE: THIS STUFF ISN'T THREADSAFE AND WILL LIKELY BREAK.
// Execute commands // If the command is empty, do nothing
if (parts.size() == 0) { return; } if (parts.size() == 0) { return; }
else if (parts[0].at(0) == '\\') { // Check to see if command is longform
parts[0].replace(0,1,""); // Remove leading backslash
if (parts[0] == "set_freq") {
std::lock_guard lck(vfoMtx);
// if number of arguments isn't correct, return error // If the command is a compound command, execute each one separately
if (parts.size() != 2) { if (parts[0].size() > 1 && parts[0][0] != '\\') {
spdlog::error("Rigctl client sent invalid command: '{0}'", cmd); std::string arguments;
resp = "RPRT 1\n"; if (parts.size() > 1) { arguments = cmd.substr(parts[0].size()); }
client->write(resp.size(), (uint8_t*)resp.c_str()); for (char c : parts[0]) {
return; commandHandler(c + arguments);
}
// If not controlling the VFO, return
if (!tuningEnabled) {
resp = "RPRT 0\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
return;
}
// Parse frequency and assign it to the VFO
long long freq = std::stoll(parts[1]);
tuner::tune(tuner::TUNER_MODE_NORMAL, selectedVfo, freq);
resp = "RPRT 0\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
} }
else if (parts[0] == "get_freq") { return;
std::lock_guard lck(vfoMtx); }
// Get center frequency of the SDR spdlog::info("Rigctl command: '{0}'", cmd);
double freq = gui::waterfall.getCenterFrequency();
// Add the offset of the VFO if it exists // Otherwise, execute the command
if (sigpath::vfoManager.vfoExists(selectedVfo)) { if (parts[0] == "F" || parts[0] == "\\set_freq") {
freq += sigpath::vfoManager.getOffset(selectedVfo); std::lock_guard lck(vfoMtx);
}
// Respond with the frequency // if number of arguments isn't correct, return error
char buf[128]; if (parts.size() != 2) {
sprintf(buf, "%" PRIu64 "\n", (uint64_t)freq);
client->write(strlen(buf), (uint8_t*)buf);
}
else if (parts[0] == "set_mode") {
std::lock_guard lck(vfoMtx);
// if number of arguments isn't correct, return error
if (parts.size() != 3) {
spdlog::error("Rigctl client sent invalid command: '{0}'", cmd);
resp = "RPRT 1\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
return;
}
// If not controlling the VFO, return
if (!tuningEnabled) {
resp = "RPRT 0\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
return;
}
// If client is querying, respond accordingly
if(parts[1] == "?") {
resp = "FM WFM AM DSB USB CW LSB RAW";
client->write(resp.size(), (uint8_t*)resp.c_str());
return;
}
// Parse mode and bandwidth
int mode;
if(parts[1] == "FM"){
mode = RADIO_IFACE_MODE_NFM;
}else if(parts[1] == "WFM"){
mode = RADIO_IFACE_MODE_WFM;
}else if(parts[1] == "AM"){
mode = RADIO_IFACE_MODE_AM;
}else if(parts[1] == "DSB"){
mode = RADIO_IFACE_MODE_DSB;
}else if(parts[1] == "USB"){
mode = RADIO_IFACE_MODE_USB;
}else if(parts[1] == "CW"){
mode = RADIO_IFACE_MODE_CW;
}else if(parts[1] == "LSB"){
mode = RADIO_IFACE_MODE_LSB;
}else if(parts[1] == "RAW"){
mode = RADIO_IFACE_MODE_RAW;
}else{
// If mode is not supported, return error
spdlog::error("Rigctl client sent invalid command: '{0}'", cmd);
resp = "RPRT 1\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
return;
}
int bandwidth = std::stoi(parts[2]);
// Set mode and bandwidth and respond
core::modComManager.callInterface(selectedVfo, RADIO_IFACE_CMD_SET_MODE, &mode, 0);
sigpath::vfoManager.setBandwidth(selectedVfo, bandwidth, true);
resp = "RPRT 0\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
}
else if (parts[0] == "get_mode") {
std::lock_guard lck(vfoMtx);
// Initialize output stream
std::stringstream buf;
// Get mode enum and parse to the output stream
int mode;
core::modComManager.callInterface(selectedVfo, RADIO_IFACE_CMD_GET_MODE, 0, &mode);
switch(mode) {
case RADIO_IFACE_MODE_NFM : buf << "FM\n";
break;
case RADIO_IFACE_MODE_WFM : buf << "WFM\n";
break;
case RADIO_IFACE_MODE_AM : buf << "AM\n";
break;
case RADIO_IFACE_MODE_DSB : buf << "DSB\n";
break;
case RADIO_IFACE_MODE_USB : buf << "USB\n";
break;
case RADIO_IFACE_MODE_CW : buf << "CW\n";
break;
case RADIO_IFACE_MODE_LSB : buf << "LSB\n";
break;
case RADIO_IFACE_MODE_RAW : buf << "RAW\n";
break;
}
// Send bandwidth to output stream and respond
buf << sigpath::vfoManager.getBandwidth(selectedVfo) << "\n";
resp = buf.str();
client->write(resp.size(), (uint8_t*)resp.c_str());
}
else if (parts[0] == "set_vfo") {
// if number of arguments isn't correct, return error
if (parts.size() != 2) {
spdlog::error("Rigctl client sent invalid command: '{0}'", cmd);
resp = "RPRT 1\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
return;
}
// Respond
resp = "RPRT 0\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
}
else if (parts[0] == "get_vfo") {
// Respond with VFO
resp = "VFO\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
}
else if (parts[0] == "recorder_start") {
std::lock_guard lck(recorderMtx);
// If not controlling the recorder, return
if (!recordingEnabled) {
resp = "RPRT 0\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
return;
}
// Send the command to the selected recorder
if (recorderType == RECORDER_TYPE_METEOR_DEMODULATOR) {
core::modComManager.callInterface(selectedRecorder, METEOR_DEMODULATOR_IFACE_CMD_START, NULL, NULL);
}
else {
core::modComManager.callInterface(selectedRecorder, RECORDER_IFACE_CMD_START, NULL, NULL);
}
// Respond with a sucess
resp = "RPRT 0\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
}
else if (parts[0] == "recorder_stop") {
std::lock_guard lck(recorderMtx);
// If not controlling the recorder, return
if (!recordingEnabled) {
resp = "RPRT 0\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
return;
}
// Send the command to the selected recorder
if (recorderType == RECORDER_TYPE_METEOR_DEMODULATOR) {
core::modComManager.callInterface(selectedRecorder, METEOR_DEMODULATOR_IFACE_CMD_STOP, NULL, NULL);
}
else {
core::modComManager.callInterface(selectedRecorder, RECORDER_IFACE_CMD_STOP, NULL, NULL);
}
// Respond with a sucess
resp = "RPRT 0\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
}
else if (parts[0] == "quit") {
// Will close automatically
}
else {
// If command is not recognized, return error
spdlog::error("Rigctl client sent invalid command: '{0}'", cmd);
resp = "RPRT 1\n"; resp = "RPRT 1\n";
client->write(resp.size(), (uint8_t*)resp.c_str()); client->write(resp.size(), (uint8_t*)resp.c_str());
return; return;
} }
// If not controlling the VFO, return
if (!tuningEnabled) {
resp = "RPRT 0\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
}
// Parse frequency and assign it to the VFO
long long freq = std::stoll(parts[1]);
tuner::tune(tuner::TUNER_MODE_NORMAL, selectedVfo, freq);
resp = "RPRT 0\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
} }
else { else if (parts[0] == "f" || parts[0] == "\\get_freq") {
for(int i = 0; i < parts[0].length(); i++){ // Loop adds support for compound commands std::lock_guard lck(vfoMtx);
if (parts[0].at(i) == 'F') {
std::lock_guard lck(vfoMtx);
// if number of arguments isn't correct, return error // Get center frequency of the SDR
if (parts.size() != 2) { double freq = gui::waterfall.getCenterFrequency();
spdlog::error("Rigctl client sent invalid command: '{0}'", cmd);
resp = "RPRT 1\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
return;
}
// If not controlling the VFO, return // Add the offset of the VFO if it exists
if (!tuningEnabled) { if (sigpath::vfoManager.vfoExists(selectedVfo)) {
resp = "RPRT 0\n"; freq += sigpath::vfoManager.getOffset(selectedVfo);
client->write(resp.size(), (uint8_t*)resp.c_str()); }
return;
}
// Parse frequency and assign it to the VFO // Respond with the frequency
long long freq = std::stoll(parts[1]); char buf[128];
tuner::tune(tuner::TUNER_MODE_NORMAL, selectedVfo, freq); sprintf(buf, "%" PRIu64 "\n", (uint64_t)freq);
resp = "RPRT 0\n"; client->write(strlen(buf), (uint8_t*)buf);
client->write(resp.size(), (uint8_t*)resp.c_str()); }
} else if (parts[0] == "M" || parts[0] == "\\set_mode") {
else if (parts[0].at(i) == 'f') { std::lock_guard lck(vfoMtx);
std::lock_guard lck(vfoMtx); resp = "RPRT 0\n";
// Get center frequency of the SDR // If client is querying, respond accordingly
double freq = gui::waterfall.getCenterFrequency(); if (parts.size() >= 2 && parts[1] == "?") {
resp = "FM WFM AM DSB USB CW LSB RAW\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
return;
}
// Add the offset of the VFO if it exists // if number of arguments isn't correct or the VFO is not "VFO", return error
if (sigpath::vfoManager.vfoExists(selectedVfo)) { if (parts.size() != 3) {
freq += sigpath::vfoManager.getOffset(selectedVfo); resp = "RPRT 1\n";
} client->write(resp.size(), (uint8_t*)resp.c_str());
return;
}
// Respond with the frequency // Check that the bandwidth is an integer
char buf[128]; for (char c : parts[2]) {
sprintf(buf, "%" PRIu64 "\n", (uint64_t)freq); if (!std::isdigit(c)) {
client->write(strlen(buf), (uint8_t*)buf);
}
else if (parts[0].at(i) == 'M') {
std::lock_guard lck(vfoMtx);
// if number of arguments isn't correct, return error
if (parts.size() != 3) {
spdlog::error("Rigctl client sent invalid command: '{0}'", cmd);
resp = "RPRT 1\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
return;
}
// If not controlling the VFO, return
if (!tuningEnabled) {
resp = "RPRT 0\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
return;
}
// If client is querying, respond accordingly
if(parts[1] == "?") {
resp = "FM WFM AM DSB USB CW LSB RAW";
client->write(resp.size(), (uint8_t*)resp.c_str());
return;
}
// Parse mode and bandwidth
int mode;
if(parts[1] == "FM"){
mode = RADIO_IFACE_MODE_NFM;
}else if(parts[1] == "WFM"){
mode = RADIO_IFACE_MODE_WFM;
}else if(parts[1] == "AM"){
mode = RADIO_IFACE_MODE_AM;
}else if(parts[1] == "DSB"){
mode = RADIO_IFACE_MODE_DSB;
}else if(parts[1] == "USB"){
mode = RADIO_IFACE_MODE_USB;
}else if(parts[1] == "CW"){
mode = RADIO_IFACE_MODE_CW;
}else if(parts[1] == "LSB"){
mode = RADIO_IFACE_MODE_LSB;
}else if(parts[1] == "RAW"){
mode = RADIO_IFACE_MODE_RAW;
}else{
// If mode is not supported, return error
spdlog::error("Rigctl client sent invalid command: '{0}'", cmd);
resp = "RPRT 1\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
return;
}
int bandwidth = std::stoi(parts[2]);
// Set mode and bandwidth and respond
core::modComManager.callInterface(selectedVfo, RADIO_IFACE_CMD_SET_MODE, &mode, 0);
sigpath::vfoManager.setBandwidth(selectedVfo, bandwidth, true);
resp = "RPRT 0\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
}
else if (parts[0].at(i) == 'm') {
std::lock_guard lck(vfoMtx);
// Initialize output stream
std::stringstream buf;
// Get mode enum and parse to the output stream
int mode;
core::modComManager.callInterface(selectedVfo, RADIO_IFACE_CMD_GET_MODE, 0, &mode);
switch(mode) {
case RADIO_IFACE_MODE_NFM : buf << "FM\n";
break;
case RADIO_IFACE_MODE_WFM : buf << "WFM\n";
break;
case RADIO_IFACE_MODE_AM : buf << "AM\n";
break;
case RADIO_IFACE_MODE_DSB : buf << "DSB\n";
break;
case RADIO_IFACE_MODE_USB : buf << "USB\n";
break;
case RADIO_IFACE_MODE_CW : buf << "CW\n";
break;
case RADIO_IFACE_MODE_LSB : buf << "LSB\n";
break;
case RADIO_IFACE_MODE_RAW : buf << "RAW\n";
break;
}
// Send bandwidth to output stream and respond
buf << sigpath::vfoManager.getBandwidth(selectedVfo) << "\n";
resp = buf.str();
client->write(resp.size(), (uint8_t*)resp.c_str());
}
else if (parts[0].at(i) == 'V') {
// if number of arguments isn't correct, return error
if (parts.size() != 3) {
spdlog::error("Rigctl client sent invalid command: '{0}'", cmd);
resp = "RPRT 1\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
return;
}
// Respond
resp = "RPRT 0\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
}
else if (parts[0].at(i) == 'v') {
// Respond with VFO
resp = "VFO\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
}
else if (parts[0].at(i) == 'q') {
// Will close automatically
}
else {
// If command is not recognized, return error
spdlog::error("Rigctl client sent invalid command: '{0}'", cmd);
resp = "RPRT 1\n"; resp = "RPRT 1\n";
client->write(resp.size(), (uint8_t*)resp.c_str()); client->write(resp.size(), (uint8_t*)resp.c_str());
return; return;
} }
} }
float newBandwidth = std::atoi(parts[2].c_str());
int newMode;
if (parts[1] == "FM") {
newMode = RADIO_IFACE_MODE_NFM;
}
else if (parts[1] == "WFM") {
newMode = RADIO_IFACE_MODE_WFM;
}
else if (parts[1] == "AM") {
newMode = RADIO_IFACE_MODE_AM;
}
else if (parts[1] == "DSB") {
newMode = RADIO_IFACE_MODE_DSB;
}
else if (parts[1] == "USB") {
newMode = RADIO_IFACE_MODE_USB;
}
else if (parts[1] == "CW") {
newMode = RADIO_IFACE_MODE_CW;
}
else if (parts[1] == "LSB") {
newMode = RADIO_IFACE_MODE_LSB;
}
else if (parts[1] == "RAW") {
newMode = RADIO_IFACE_MODE_RAW;
}
else {
resp = "RPRT 1\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
return;
}
// If tuning is enabled, set the mode and optionally the bandwidth
if (!selectedVfo.empty() && core::modComManager.getModuleName(selectedVfo) == "radio" && tuningEnabled) {
core::modComManager.callInterface(selectedVfo, RADIO_IFACE_CMD_SET_MODE, &newMode, NULL);
if (newBandwidth) {
core::modComManager.callInterface(selectedVfo, RADIO_IFACE_CMD_SET_BANDWIDTH, &newBandwidth, NULL);
}
}
client->write(resp.size(), (uint8_t*)resp.c_str());
}
else if (parts[0] == "m" || parts[0] == "\\get_mode") {
std::lock_guard lck(vfoMtx);
resp = "RAW ";
if (!selectedVfo.empty() && core::modComManager.getModuleName(selectedVfo) == "radio") {
int mode;
core::modComManager.callInterface(selectedVfo, RADIO_IFACE_CMD_GET_MODE, NULL, &mode);
if (mode == RADIO_IFACE_MODE_NFM) {
resp = "FM ";
}
else if (mode == RADIO_IFACE_MODE_WFM) {
resp = "WFM ";
}
else if (mode == RADIO_IFACE_MODE_AM) {
resp = "AM ";
}
else if (mode == RADIO_IFACE_MODE_DSB) {
resp = "DSB ";
}
else if (mode == RADIO_IFACE_MODE_USB) {
resp = "USB ";
}
else if (mode == RADIO_IFACE_MODE_CW) {
resp = "CW ";
}
else if (mode == RADIO_IFACE_MODE_LSB) {
resp = "LSB ";
}
}
if (!selectedVfo.empty()) {
resp += std::to_string((int)sigpath::vfoManager.getBandwidth(selectedVfo)) + "\n";
}
else {
resp += "0\n";
}
client->write(resp.size(), (uint8_t*)resp.c_str());
}
else if (parts[0] == "V" || parts[0] == "\\set_vfo") {
std::lock_guard lck(vfoMtx);
resp = "RPRT 0\n";
// if number of arguments isn't correct or the VFO is not "VFO", return error
if (parts.size() != 2) {
resp = "RPRT 1\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
return;
}
if (parts[1] == "?") {
resp = "VFO\n";
}
else if (parts[1] != "VFO") {
resp = "RPRT 1\n";
}
client->write(resp.size(), (uint8_t*)resp.c_str());
}
else if (parts[0] == "v" || parts[0] == "\\get_vfo") {
std::lock_guard lck(vfoMtx);
resp = "VFO\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
}
else if (parts[0] == "\\recorder_start") {
std::lock_guard lck(recorderMtx);
// If not controlling the recorder, return
if (!recordingEnabled) {
resp = "RPRT 0\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
return;
}
// Send the command to the selected recorder
if (recorderType == RECORDER_TYPE_METEOR_DEMODULATOR) {
core::modComManager.callInterface(selectedRecorder, METEOR_DEMODULATOR_IFACE_CMD_START, NULL, NULL);
}
else {
core::modComManager.callInterface(selectedRecorder, RECORDER_IFACE_CMD_START, NULL, NULL);
}
// Respond with a sucess
resp = "RPRT 0\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
}
else if (parts[0] == "\\recorder_stop") {
std::lock_guard lck(recorderMtx);
// If not controlling the recorder, return
if (!recordingEnabled) {
resp = "RPRT 0\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
return;
}
// Send the command to the selected recorder
if (recorderType == RECORDER_TYPE_METEOR_DEMODULATOR) {
core::modComManager.callInterface(selectedRecorder, METEOR_DEMODULATOR_IFACE_CMD_STOP, NULL, NULL);
}
else {
core::modComManager.callInterface(selectedRecorder, RECORDER_IFACE_CMD_STOP, NULL, NULL);
}
// Respond with a sucess
resp = "RPRT 0\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
}
else if (parts[0] == "quit") {
// Will close automatically
}
else {
// If command is not recognized, return error
spdlog::error("Rigctl client sent invalid command: '{0}'", cmd);
resp = "RPRT 1\n";
client->write(resp.size(), (uint8_t*)resp.c_str());
return;
} }
} }

View File

@ -68,7 +68,7 @@ public:
directSamplingMode = config.conf["directSamplingMode"]; directSamplingMode = config.conf["directSamplingMode"];
rtlAGC = config.conf["rtlAGC"]; rtlAGC = config.conf["rtlAGC"];
tunerAGC = config.conf["tunerAGC"]; tunerAGC = config.conf["tunerAGC"];
gain = config.conf["gainIndex"]; gain = std::clamp<int>(config.conf["gainIndex"], 0, 28);
biasTee = config.conf["biasTee"]; biasTee = config.conf["biasTee"];
offsetTuning = config.conf["offsetTuning"]; offsetTuning = config.conf["offsetTuning"];
hostStr = hostStr.substr(0, 1023); hostStr = hostStr.substr(0, 1023);
@ -127,12 +127,20 @@ private:
spdlog::warn("Setting sample rate to {0}", _this->sampleRate); spdlog::warn("Setting sample rate to {0}", _this->sampleRate);
_this->client.setFrequency(_this->freq); _this->client.setFrequency(_this->freq);
_this->client.setSampleRate(_this->sampleRate); _this->client.setSampleRate(_this->sampleRate);
_this->client.setGainMode(!_this->tunerAGC);
_this->client.setDirectSampling(_this->directSamplingMode); _this->client.setDirectSampling(_this->directSamplingMode);
_this->client.setAGCMode(_this->rtlAGC); _this->client.setAGCMode(_this->rtlAGC);
_this->client.setGainIndex(_this->gain);
_this->client.setBiasTee(_this->biasTee); _this->client.setBiasTee(_this->biasTee);
_this->client.setOffsetTuning(_this->offsetTuning); _this->client.setOffsetTuning(_this->offsetTuning);
if (_this->tunerAGC) {
_this->client.setGainMode(0);
}
else {
_this->client.setGainMode(1);
// Setting it twice because for some reason it refuses to do it on the first time
_this->client.setGainIndex(_this->gain);
}
_this->running = true; _this->running = true;
_this->workerThread = std::thread(worker, _this); _this->workerThread = std::thread(worker, _this);
spdlog::info("RTLTCPSourceModule '{0}': Start!", _this->name); spdlog::info("RTLTCPSourceModule '{0}': Start!", _this->name);
@ -229,7 +237,7 @@ private:
if (_this->tunerAGC) { style::beginDisabled(); } if (_this->tunerAGC) { style::beginDisabled(); }
ImGui::SetNextItemWidth(menuWidth); ImGui::SetNextItemWidth(menuWidth);
if (ImGui::SliderInt(CONCAT("##_gain_select_", _this->name), &_this->gain, 0, 29, "")) { if (ImGui::SliderInt(CONCAT("##_gain_select_", _this->name), &_this->gain, 0, 28, "")) {
if (_this->running) { if (_this->running) {
_this->client.setGainIndex(_this->gain); _this->client.setGainIndex(_this->gain);
} }