diff --git a/core/src/core.cpp b/core/src/core.cpp index c94f9471..d8f65f1e 100644 --- a/core/src/core.cpp +++ b/core/src/core.cpp @@ -51,7 +51,7 @@ namespace core { gui::waterfall.setViewOffset(0); gui::waterfall.setViewBandwidth(samplerate); sigpath::signalPath.setSampleRate(samplerate); - setViewBandwidthSlider(samplerate); + gui::mainWindow.setViewBandwidthSlider(samplerate); } }; @@ -338,7 +338,7 @@ int sdrpp_main(int argc, char *argv[]) { spdlog::info("Loading band plans color table"); bandplan::loadColorTable(bandColors); - windowInit(); + gui::mainWindow.init(); spdlog::info("Ready."); @@ -397,7 +397,7 @@ int sdrpp_main(int argc, char *argv[]) { if (winWidth > 0 && winHeight > 0) { ImGui::SetNextWindowPos(ImVec2(0, 0)); ImGui::SetNextWindowSize(ImVec2(_winWidth, _winHeight)); - drawWindow(); + gui::mainWindow.draw(); } // Rendering diff --git a/core/src/gui/gui.cpp b/core/src/gui/gui.cpp index 57c09e29..290b6c28 100644 --- a/core/src/gui/gui.cpp +++ b/core/src/gui/gui.cpp @@ -1,6 +1,7 @@ #include namespace gui { + MainWindow mainWindow; ImGui::WaterFall waterfall; FrequencySelect freqSelect; Menu menu; diff --git a/core/src/gui/gui.h b/core/src/gui/gui.h index e6a2ee5a..dea039e0 100644 --- a/core/src/gui/gui.h +++ b/core/src/gui/gui.h @@ -4,11 +4,14 @@ #include #include #include +#include namespace gui { SDRPP_EXPORT ImGui::WaterFall waterfall; SDRPP_EXPORT FrequencySelect freqSelect; SDRPP_EXPORT Menu menu; + SDRPP_EXPORT MainWindow mainWindow; + void selectSource(std::string name); }; \ No newline at end of file diff --git a/core/src/gui/main_window.cpp b/core/src/gui/main_window.cpp index cf3b0953..ff86e171 100644 --- a/core/src/gui/main_window.cpp +++ b/core/src/gui/main_window.cpp @@ -11,11 +11,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include @@ -34,89 +32,9 @@ #include #include #include +#include -int fftSize = 8192 * 8; - -std::mutex fft_mtx; -fftwf_complex *fft_in, *fft_out; -fftwf_plan p; -float* tempFFT; -float* FFTdata; -char buf[1024]; -bool experimentalZoom = false; -bool firstMenuRender = true; -bool startedWithMenuClosed = false; - -void fftHandler(dsp::complex_t* samples, int count, void* ctx) { - std::lock_guard lck(fft_mtx); - if (count != fftSize) { return; } - - memcpy(fft_in, samples, count * sizeof(dsp::complex_t)); - fftwf_execute(p); - int half = count / 2; - - // volk_32fc_s32f_power_spectrum_32f(FFTdata, (lv_32fc_t*)fft_out, count, count); - - // memcpy(tempFFT, &FFTdata[half], half * sizeof(float)); - // memmove(&FFTdata[half], FFTdata, half * sizeof(float)); - // memcpy(FFTdata, tempFFT, half * sizeof(float)); - - // float* fftBuf = gui::waterfall.getFFTBuffer(); - // if (fftBuf == NULL) { - // gui::waterfall.pushFFT(); - // return; - // } - - // memcpy(fftBuf, FFTdata, count * sizeof(float)); - - // gui::waterfall.pushFFT(); - - float* fftBuf = gui::waterfall.getFFTBuffer(); - if (fftBuf == NULL) { - gui::waterfall.pushFFT(); - return; - } - - volk_32fc_s32f_power_spectrum_32f(tempFFT, (lv_32fc_t*)fft_out, count, count); - - memcpy(fftBuf, &tempFFT[half], half * sizeof(float)); - memcpy(&fftBuf[half], tempFFT, half * sizeof(float)); - - gui::waterfall.pushFFT(); -} - -float fftMin = -70.0; -float fftMax = 0.0; -float bw = 8000000; -bool playing = false; -bool showCredits = false; -std::string audioStreamName = ""; -std::string sourceName = ""; -int menuWidth = 300; -bool grabbingMenu = false; -int newWidth = 300; -int fftHeight = 300; -bool showMenu = true; -bool centerTuning = false; -dsp::stream dummyStream; -bool demoWindow = false; - -float testSNR = 50; - -EventHandler vfoCreatedHandler; -void vfoAddedHandler(VFOManager::VFO* vfo, void* ctx) { - std::string name = vfo->getName(); - core::configManager.aquire(); - if (!core::configManager.conf["vfoOffsets"].contains(name)) { - core::configManager.release(); - return; - } - double offset = core::configManager.conf["vfoOffsets"][name]; - core::configManager.release(); - sigpath::vfoManager.setOffset(name, std::clamp(offset, -bw/2.0, bw/2.0)); -} - -void windowInit() { +void MainWindow::init() { LoadingScreen::show("Initializing UI"); gui::waterfall.init(); gui::waterfall.setRawFFTSize(fftSize); @@ -161,12 +79,13 @@ void windowInit() { fft_in = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSize); fft_out = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * fftSize); - p = fftwf_plan_dft_1d(fftSize, fft_in, fft_out, FFTW_FORWARD, FFTW_ESTIMATE); + fftwPlan = fftwf_plan_dft_1d(fftSize, fft_in, fft_out, FFTW_FORWARD, FFTW_ESTIMATE); - sigpath::signalPath.init(8000000, 20, fftSize, &dummyStream, (dsp::complex_t*)fft_in, fftHandler); + sigpath::signalPath.init(8000000, 20, fftSize, &dummyStream, (dsp::complex_t*)fft_in, fftHandler, this); sigpath::signalPath.start(); vfoCreatedHandler.handler = vfoAddedHandler; + vfoCreatedHandler.ctx = this; sigpath::vfoManager.vfoCreatedEvent.bindHandler(vfoCreatedHandler); spdlog::info("Loading modules"); @@ -238,14 +157,8 @@ void windowInit() { module_manager_menu::init(); // TODO for 0.2.5 - // Add "select file" option for the file source - // Have a good directory system on both linux and windows - // Switch to double buffering (should fix occassional underruns) // Fix gain not updated on startup, soapysdr - // TODO for 0.2.6 - // Add a module add/remove/change order menu - // Update UI settings LoadingScreen::show("Loading configuration"); core::configManager.aquire(); @@ -276,113 +189,48 @@ void windowInit() { fftHeight = core::configManager.conf["fftHeight"]; gui::waterfall.setFFTHeight(fftHeight); - centerTuning = core::configManager.conf["centerTuning"]; + tuningMode = core::configManager.conf["centerTuning"] ? tuner::TUNER_MODE_CENTER : tuner::TUNER_MODE_NORMAL; core::configManager.release(); } -void setVFO(double freq) { - double viewBW = gui::waterfall.getViewBandwidth(); - double BW = gui::waterfall.getBandwidth(); - if (gui::waterfall.selectedVFO == "") { - gui::waterfall.setViewOffset((BW / 2.0) - (viewBW / 2.0)); - gui::waterfall.setCenterFrequency(freq); - sigpath::sourceManager.tune(freq); +void MainWindow::fftHandler(dsp::complex_t* samples, int count, void* ctx) { + MainWindow* _this = (MainWindow*)ctx; + std::lock_guard lck(_this->fft_mtx); + if (count != _this->fftSize) { return; } + + memcpy(_this->fft_in, samples, count * sizeof(dsp::complex_t)); + fftwf_execute(_this->fftwPlan); + int half = count / 2; + + float* fftBuf = gui::waterfall.getFFTBuffer(); + if (fftBuf == NULL) { + gui::waterfall.pushFFT(); return; } - ImGui::WaterfallVFO* vfo = gui::waterfall.vfos[gui::waterfall.selectedVFO]; + volk_32fc_s32f_power_spectrum_32f(_this->tempFFT, (lv_32fc_t*)_this->fft_out, count, count); - double currentOff = vfo->centerOffset; - double currentTune = gui::waterfall.getCenterFrequency() + vfo->generalOffset; - double delta = freq - currentTune; + memcpy(fftBuf, &_this->tempFFT[half], half * sizeof(float)); + memcpy(&fftBuf[half], _this->tempFFT, half * sizeof(float)); - double newVFO = currentOff + delta; - double vfoBW = vfo->bandwidth; - double vfoBottom = newVFO - (vfoBW / 2.0); - double vfoTop = newVFO + (vfoBW / 2.0); - - double view = gui::waterfall.getViewOffset(); - double viewBottom = view - (viewBW / 2.0); - double viewTop = view + (viewBW / 2.0); - - double wholeFreq = gui::waterfall.getCenterFrequency(); - double bottom = -(BW / 2.0); - double top = (BW / 2.0); - - if (centerTuning) { - gui::waterfall.setViewOffset((BW / 2.0) - (viewBW / 2.0)); - gui::waterfall.setCenterFrequency(freq); - gui::waterfall.setViewOffset(0); - sigpath::vfoManager.setOffset(gui::waterfall.selectedVFO, 0); - sigpath::sourceManager.tune(freq); - return; - } - - // VFO still fints in the view - if (vfoBottom > viewBottom && vfoTop < viewTop) { - sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, newVFO); - return; - } - - // VFO too low for current SDR tuning - if (vfoBottom < bottom) { - gui::waterfall.setViewOffset((BW / 2.0) - (viewBW / 2.0)); - double newVFOOffset = (BW / 2.0) - (vfoBW / 2.0) - (viewBW / 10.0); - sigpath::vfoManager.setOffset(gui::waterfall.selectedVFO, newVFOOffset); - gui::waterfall.setCenterFrequency(freq - newVFOOffset); - sigpath::sourceManager.tune(freq - newVFOOffset); - return; - } - - // VFO too high for current SDR tuning - if (vfoTop > top) { - gui::waterfall.setViewOffset((viewBW / 2.0) - (BW / 2.0)); - double newVFOOffset = (vfoBW / 2.0) - (BW / 2.0) + (viewBW / 10.0); - sigpath::vfoManager.setOffset(gui::waterfall.selectedVFO, newVFOOffset); - gui::waterfall.setCenterFrequency(freq - newVFOOffset); - sigpath::sourceManager.tune(freq - newVFOOffset); - return; - } - - // VFO is still without the SDR's bandwidth - if (delta < 0) { - double newViewOff = vfoTop - (viewBW / 2.0) + (viewBW / 10.0); - double newViewBottom = newViewOff - (viewBW / 2.0); - double newViewTop = newViewOff + (viewBW / 2.0); - - if (newViewBottom > bottom) { - gui::waterfall.setViewOffset(newViewOff); - sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, newVFO); - return; - } - - gui::waterfall.setViewOffset((BW / 2.0) - (viewBW / 2.0)); - double newVFOOffset = (BW / 2.0) - (vfoBW / 2.0) - (viewBW / 10.0); - sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, newVFOOffset); - gui::waterfall.setCenterFrequency(freq - newVFOOffset); - sigpath::sourceManager.tune(freq - newVFOOffset); - } - else { - double newViewOff = vfoBottom + (viewBW / 2.0) - (viewBW / 10.0); - double newViewBottom = newViewOff - (viewBW / 2.0); - double newViewTop = newViewOff + (viewBW / 2.0); - - if (newViewTop < top) { - gui::waterfall.setViewOffset(newViewOff); - sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, newVFO); - return; - } - - gui::waterfall.setViewOffset((viewBW / 2.0) - (BW / 2.0)); - double newVFOOffset = (vfoBW / 2.0) - (BW / 2.0) + (viewBW / 10.0); - sigpath::vfoManager.setCenterOffset(gui::waterfall.selectedVFO, newVFOOffset); - gui::waterfall.setCenterFrequency(freq - newVFOOffset); - sigpath::sourceManager.tune(freq - newVFOOffset); - } + gui::waterfall.pushFFT(); } -void drawWindow() { +void MainWindow::vfoAddedHandler(VFOManager::VFO* vfo, void* ctx) { + MainWindow* _this = (MainWindow*)ctx; + std::string name = vfo->getName(); + core::configManager.aquire(); + if (!core::configManager.conf["vfoOffsets"].contains(name)) { + core::configManager.release(); + return; + } + double offset = core::configManager.conf["vfoOffsets"][name]; + core::configManager.release(); + sigpath::vfoManager.setOffset(name, std::clamp(offset, -_this->bw/2.0, _this->bw/2.0)); +} + +void MainWindow::draw() { ImGui::Begin("Main", NULL, WINDOW_FLAGS); ImGui::WaterfallVFO* vfo = NULL; @@ -390,11 +238,11 @@ void drawWindow() { vfo = gui::waterfall.vfos[gui::waterfall.selectedVFO]; } - // Handke VFO movement + // Handle VFO movement if (vfo != NULL) { if (vfo->centerOffsetChanged) { - if (centerTuning) { - setVFO(gui::waterfall.getCenterFrequency() + vfo->generalOffset); + if (tuningMode == tuner::TUNER_MODE_CENTER) { + tuner::tune(tuner::TUNER_MODE_CENTER, gui::waterfall.selectedVFO, gui::waterfall.getCenterFrequency() + vfo->generalOffset); } gui::freqSelect.setFrequency(gui::waterfall.getCenterFrequency() + vfo->generalOffset); gui::freqSelect.frequencyChanged = false; @@ -416,7 +264,7 @@ void drawWindow() { // Handle change in selected frequency if (gui::freqSelect.frequencyChanged) { gui::freqSelect.frequencyChanged = false; - setVFO(gui::freqSelect.frequency); + tuner::tune(tuningMode, gui::waterfall.selectedVFO, gui::freqSelect.frequency); if (vfo != NULL) { vfo->centerOffsetChanged = false; vfo->lowerOffsetChanged = false; @@ -502,12 +350,12 @@ void drawWindow() { ImGui::SameLine(); ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 9); - if (centerTuning) { + if (tuningMode == tuner::TUNER_MODE_CENTER) { ImGui::PushID(ImGui::GetID("sdrpp_ena_st_btn")); if (ImGui::ImageButton(icons::CENTER_TUNING, ImVec2(30, 30), ImVec2(0, 0), ImVec2(1, 1), 5)) { - centerTuning = false; + tuningMode = tuner::TUNER_MODE_NORMAL; core::configManager.aquire(); - core::configManager.conf["centerTuning"] = centerTuning; + core::configManager.conf["centerTuning"] = false; core::configManager.release(true); } ImGui::PopID(); @@ -515,10 +363,10 @@ void drawWindow() { else { // TODO: Might need to check if there even is a device ImGui::PushID(ImGui::GetID("sdrpp_dis_st_btn")); if (ImGui::ImageButton(icons::NORMAL_TUNING, ImVec2(30, 30), ImVec2(0, 0), ImVec2(1, 1), 5)) { - centerTuning = true; - setVFO(gui::freqSelect.frequency); + tuningMode = tuner::TUNER_MODE_CENTER; + tuner::tune(tuner::TUNER_MODE_CENTER, gui::waterfall.selectedVFO, gui::freqSelect.frequency); core::configManager.aquire(); - core::configManager.conf["centerTuning"] = centerTuning; + core::configManager.conf["centerTuning"] = true; core::configManager.release(true); } ImGui::PopID(); @@ -607,7 +455,6 @@ void drawWindow() { ImGui::Text("Center Frequency: %.0f Hz", gui::waterfall.getCenterFrequency()); ImGui::Text("Source name: %s", sourceName.c_str()); ImGui::Checkbox("Show demo window", &demoWindow); - ImGui::Checkbox("Experimental zoom", &experimentalZoom); ImGui::Text("ImGui version: %s", ImGui::GetVersion()); if (ImGui::Button("Test Bug")) { @@ -619,8 +466,6 @@ void drawWindow() { firstMenuRender = true; } - ImGui::SliderFloat("Testing SNR meter", &testSNR, 0, 100); - ImGui::Spacing(); } @@ -650,12 +495,12 @@ void drawWindow() { if (ImGui::IsKeyPressed(GLFW_KEY_LEFT) && !gui::freqSelect.digitHovered) { double nfreq = gui::waterfall.getCenterFrequency() + vfo->generalOffset - vfo->snapInterval; nfreq = roundl(nfreq / vfo->snapInterval) * vfo->snapInterval; - setVFO(nfreq); + tuner::tune(tuningMode, gui::waterfall.selectedVFO, nfreq); } if (ImGui::IsKeyPressed(GLFW_KEY_RIGHT) && !gui::freqSelect.digitHovered) { double nfreq = gui::waterfall.getCenterFrequency() + vfo->generalOffset + vfo->snapInterval; nfreq = roundl(nfreq / vfo->snapInterval) * vfo->snapInterval; - setVFO(nfreq); + tuner::tune(tuningMode, gui::waterfall.selectedVFO, nfreq); } core::configManager.aquire(); core::configManager.conf["frequency"] = gui::waterfall.getCenterFrequency(); @@ -676,8 +521,7 @@ void drawWindow() { else { nfreq = gui::waterfall.getCenterFrequency() - (gui::waterfall.getViewBandwidth() * wheel / 20.0); } - - setVFO(nfreq); + tuner::tune(tuningMode, gui::waterfall.selectedVFO, nfreq); gui::freqSelect.setFrequency(nfreq); core::configManager.aquire(); core::configManager.conf["frequency"] = gui::waterfall.getCenterFrequency(); @@ -742,15 +586,15 @@ void drawWindow() { } } -void setViewBandwidthSlider(float bandwidth) { +void MainWindow::setViewBandwidthSlider(float bandwidth) { bw = bandwidth; } -bool sdrIsRunning() { +bool MainWindow::sdrIsRunning() { return playing; } -void setFFTSize(int size) { +void MainWindow::setFFTSize(int size) { std::lock_guard lck(fft_mtx); fftSize = size; @@ -759,9 +603,9 @@ void setFFTSize(int size) { fftwf_free(fft_in); fftwf_free(fft_out); - fftwf_destroy_plan(p); + fftwf_destroy_plan(fftwPlan); fft_in = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * fftSize); fft_out = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * fftSize); - p = fftwf_plan_dft_1d(fftSize, fft_in, fft_out, FFTW_FORWARD, FFTW_ESTIMATE); + fftwPlan = fftwf_plan_dft_1d(fftSize, fft_in, fft_out, FFTW_FORWARD, FFTW_ESTIMATE); } \ No newline at end of file diff --git a/core/src/gui/main_window.h b/core/src/gui/main_window.h index a78d7158..31cdc915 100644 --- a/core/src/gui/main_window.h +++ b/core/src/gui/main_window.h @@ -1,10 +1,58 @@ #pragma once -#include "imgui.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include #define WINDOW_FLAGS ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoBackground -void windowInit(); -void drawWindow(); -void setViewBandwidthSlider(float bandwidth); -bool sdrIsRunning(); -void setFFTSize(int size); \ No newline at end of file +class MainWindow { +public: + void init(); + void draw(); + void setViewBandwidthSlider(float bandwidth); + bool sdrIsRunning(); + void setFFTSize(int size); + + // TODO: Replace with it's own class + void setVFO(double freq); + +private: + static void fftHandler(dsp::complex_t* samples, int count, void* ctx); + static void vfoAddedHandler(VFOManager::VFO* vfo, void* ctx); + + // FFT Variables + int fftSize = 8192 * 8; + std::mutex fft_mtx; + fftwf_complex *fft_in, *fft_out; + fftwf_plan fftwPlan; + float* tempFFT; + float* FFTdata; + + // GUI Variables + bool firstMenuRender = true; + bool startedWithMenuClosed = false; + float fftMin = -70.0; + float fftMax = 0.0; + float bw = 8000000; + bool playing = false; + bool showCredits = false; + std::string audioStreamName = ""; + std::string sourceName = ""; + int menuWidth = 300; + bool grabbingMenu = false; + int newWidth = 300; + int fftHeight = 300; + bool showMenu = true; + int tuningMode = tuner::TUNER_MODE_NORMAL; + dsp::stream dummyStream; + bool demoWindow = false; + + EventHandler vfoCreatedHandler; + +}; \ No newline at end of file diff --git a/core/src/gui/menus/display.cpp b/core/src/gui/menus/display.cpp index c98a25ff..fdf7b7ea 100644 --- a/core/src/gui/menus/display.cpp +++ b/core/src/gui/menus/display.cpp @@ -68,7 +68,7 @@ namespace displaymenu { break; } } - setFFTSize(FFTSizes[fftSizeId]); + gui::mainWindow.setFFTSize(FFTSizes[fftSizeId]); } @@ -100,7 +100,7 @@ namespace displaymenu { ImGui::SameLine(); ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX()); if (ImGui::Combo("##test_fft_size", &fftSizeId, FFTSizesStr)) { - setFFTSize(FFTSizes[fftSizeId]); + gui::mainWindow.setFFTSize(FFTSizes[fftSizeId]); core::configManager.aquire(); core::configManager.conf["fftSize"] = FFTSizes[fftSizeId]; core::configManager.release(true); diff --git a/core/src/gui/menus/source.cpp b/core/src/gui/menus/source.cpp index fd865daf..6c2b3ec5 100644 --- a/core/src/gui/menus/source.cpp +++ b/core/src/gui/menus/source.cpp @@ -37,7 +37,7 @@ namespace sourecmenu { } float itemWidth = ImGui::GetContentRegionAvailWidth(); - if (sdrIsRunning()) { style::beginDisabled(); } + if (gui::mainWindow.sdrIsRunning()) { style::beginDisabled(); } ImGui::SetNextItemWidth(itemWidth); if (ImGui::Combo("##source", &sourceId, items.c_str())) { @@ -47,7 +47,7 @@ namespace sourecmenu { core::configManager.release(true); } - if (sdrIsRunning()) { style::endDisabled(); } + if (gui::mainWindow.sdrIsRunning()) { style::endDisabled(); } sigpath::sourceManager.showSelectedMenu(); diff --git a/core/src/gui/tuner.cpp b/core/src/gui/tuner.cpp new file mode 100644 index 00000000..b8877cde --- /dev/null +++ b/core/src/gui/tuner.cpp @@ -0,0 +1,129 @@ +#include +#include +#include +#include + +namespace tuner { + void centerTuning(std::string vfoName, double freq) { + if (vfoName != "") { sigpath::vfoManager.setOffset(vfoName, 0); } + double BW = gui::waterfall.getBandwidth(); + double viewBW = gui::waterfall.getViewBandwidth(); + gui::waterfall.setViewOffset((BW / 2.0) - (viewBW / 2.0)); + gui::waterfall.setCenterFrequency(freq); + gui::waterfall.setViewOffset(0); + } + + void normalTuning(std::string vfoName, double freq) { + if (vfoName == "") { + centerTuning(vfoName, freq); + return; + } + + double viewBW = gui::waterfall.getViewBandwidth(); + double BW = gui::waterfall.getBandwidth(); + if (vfoName == "") { + gui::waterfall.setViewOffset((BW / 2.0) - (viewBW / 2.0)); + gui::waterfall.setCenterFrequency(freq); + sigpath::sourceManager.tune(freq); + return; + } + + ImGui::WaterfallVFO* vfo = gui::waterfall.vfos[vfoName]; + + double currentOff = vfo->centerOffset; + double currentTune = gui::waterfall.getCenterFrequency() + vfo->generalOffset; + double delta = freq - currentTune; + + double newVFO = currentOff + delta; + double vfoBW = vfo->bandwidth; + double vfoBottom = newVFO - (vfoBW / 2.0); + double vfoTop = newVFO + (vfoBW / 2.0); + + double view = gui::waterfall.getViewOffset(); + double viewBottom = view - (viewBW / 2.0); + double viewTop = view + (viewBW / 2.0); + + double wholeFreq = gui::waterfall.getCenterFrequency(); + double bottom = -(BW / 2.0); + double top = (BW / 2.0); + + // VFO still fints in the view + if (vfoBottom > viewBottom && vfoTop < viewTop) { + sigpath::vfoManager.setCenterOffset(vfoName, newVFO); + return; + } + + // VFO too low for current SDR tuning + if (vfoBottom < bottom) { + gui::waterfall.setViewOffset((BW / 2.0) - (viewBW / 2.0)); + double newVFOOffset = (BW / 2.0) - (vfoBW / 2.0) - (viewBW / 10.0); + sigpath::vfoManager.setOffset(vfoName, newVFOOffset); + gui::waterfall.setCenterFrequency(freq - newVFOOffset); + sigpath::sourceManager.tune(freq - newVFOOffset); + return; + } + + // VFO too high for current SDR tuning + if (vfoTop > top) { + gui::waterfall.setViewOffset((viewBW / 2.0) - (BW / 2.0)); + double newVFOOffset = (vfoBW / 2.0) - (BW / 2.0) + (viewBW / 10.0); + sigpath::vfoManager.setOffset(vfoName, newVFOOffset); + gui::waterfall.setCenterFrequency(freq - newVFOOffset); + sigpath::sourceManager.tune(freq - newVFOOffset); + return; + } + + // VFO is still without the SDR's bandwidth + if (delta < 0) { + double newViewOff = vfoTop - (viewBW / 2.0) + (viewBW / 10.0); + double newViewBottom = newViewOff - (viewBW / 2.0); + double newViewTop = newViewOff + (viewBW / 2.0); + + if (newViewBottom > bottom) { + gui::waterfall.setViewOffset(newViewOff); + sigpath::vfoManager.setCenterOffset(vfoName, newVFO); + return; + } + + gui::waterfall.setViewOffset((BW / 2.0) - (viewBW / 2.0)); + double newVFOOffset = (BW / 2.0) - (vfoBW / 2.0) - (viewBW / 10.0); + sigpath::vfoManager.setCenterOffset(vfoName, newVFOOffset); + gui::waterfall.setCenterFrequency(freq - newVFOOffset); + sigpath::sourceManager.tune(freq - newVFOOffset); + } + else { + double newViewOff = vfoBottom + (viewBW / 2.0) - (viewBW / 10.0); + double newViewBottom = newViewOff - (viewBW / 2.0); + double newViewTop = newViewOff + (viewBW / 2.0); + + if (newViewTop < top) { + gui::waterfall.setViewOffset(newViewOff); + sigpath::vfoManager.setCenterOffset(vfoName, newVFO); + return; + } + + gui::waterfall.setViewOffset((viewBW / 2.0) - (BW / 2.0)); + double newVFOOffset = (vfoBW / 2.0) - (BW / 2.0) + (viewBW / 10.0); + sigpath::vfoManager.setCenterOffset(vfoName, newVFOOffset); + gui::waterfall.setCenterFrequency(freq - newVFOOffset); + sigpath::sourceManager.tune(freq - newVFOOffset); + } + } + + void tune(int mode, std::string vfoName, double freq) { + switch (mode) { + case TUNER_MODE_CENTER: + centerTuning(vfoName, freq); + break; + case TUNER_MODE_NORMAL: + normalTuning(vfoName, freq); + break; + case TUNER_MODE_LOWER_HALF: + normalTuning(vfoName, freq); + break; + case TUNER_MODE_UPPER_HALF: + normalTuning(vfoName, freq); + break; + } + } +} \ No newline at end of file diff --git a/core/src/gui/tuner.h b/core/src/gui/tuner.h new file mode 100644 index 00000000..568a0a4e --- /dev/null +++ b/core/src/gui/tuner.h @@ -0,0 +1,17 @@ +#pragma once +#include + +namespace tuner { + void centerTuning(std::string vfoName, double freq); + void normalTuning(std::string vfoName, double freq); + + enum { + TUNER_MODE_CENTER, + TUNER_MODE_NORMAL, + TUNER_MODE_LOWER_HALF, + TUNER_MODE_UPPER_HALF, + _TUNER_MODE_COUNT + }; + + void tune(int mode, std::string vfoName, double freq); +} \ No newline at end of file diff --git a/core/src/signal_path/dsp.cpp b/core/src/signal_path/dsp.cpp index 0968f766..18698ddd 100644 --- a/core/src/signal_path/dsp.cpp +++ b/core/src/signal_path/dsp.cpp @@ -4,7 +4,7 @@ SignalPath::SignalPath() { } -void SignalPath::init(uint64_t sampleRate, int fftRate, int fftSize, dsp::stream* input, dsp::complex_t* fftBuffer, void fftHandler(dsp::complex_t*,int,void*)) { +void SignalPath::init(uint64_t sampleRate, int fftRate, int fftSize, dsp::stream* input, dsp::complex_t* fftBuffer, void fftHandler(dsp::complex_t*,int,void*), void* fftHandlerCtx) { this->sampleRate = sampleRate; this->fftRate = fftRate; this->fftSize = fftSize; @@ -14,7 +14,7 @@ void SignalPath::init(uint64_t sampleRate, int fftRate, int fftSize, dsp::stream reshape.init(&fftStream, fftSize, (sampleRate / fftRate) - fftSize); split.bindStream(&fftStream); - fftHandlerSink.init(&reshape.out, fftHandler, NULL); + fftHandlerSink.init(&reshape.out, fftHandler, fftHandlerCtx); } void SignalPath::setSampleRate(double sampleRate) { diff --git a/core/src/signal_path/dsp.h b/core/src/signal_path/dsp.h index f9380132..e01f3c3c 100644 --- a/core/src/signal_path/dsp.h +++ b/core/src/signal_path/dsp.h @@ -7,7 +7,7 @@ class SignalPath { public: SignalPath(); - void init(uint64_t sampleRate, int fftRate, int fftSize, dsp::stream* input, dsp::complex_t* fftBuffer, void fftHandler(dsp::complex_t*,int,void*)); + void init(uint64_t sampleRate, int fftRate, int fftSize, dsp::stream* input, dsp::complex_t* fftBuffer, void fftHandler(dsp::complex_t*,int,void*), void* fftHandlerCtx); void start(); void stop(); void setSampleRate(double sampleRate); diff --git a/core/src/signal_path/vfo_manager.cpp b/core/src/signal_path/vfo_manager.cpp index 3a65f5d8..9536a1f8 100644 --- a/core/src/signal_path/vfo_manager.cpp +++ b/core/src/signal_path/vfo_manager.cpp @@ -1,5 +1,6 @@ #include #include +#include VFOManager::VFO::VFO(std::string name, int reference, double offset, double bandwidth, double sampleRate, double minBandwidth, double maxBandwidth, bool bandwidthLocked) { this->name = name; diff --git a/core/src/signal_path/vfo_manager.h b/core/src/signal_path/vfo_manager.h index ae09434d..b6c640ed 100644 --- a/core/src/signal_path/vfo_manager.h +++ b/core/src/signal_path/vfo_manager.h @@ -1,7 +1,6 @@ #pragma once #include #include -#include #include class VFOManager { diff --git a/meteor_demodulator/src/main.cpp b/meteor_demodulator/src/main.cpp index b0ccf920..6a21ac10 100644 --- a/meteor_demodulator/src/main.cpp +++ b/meteor_demodulator/src/main.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include diff --git a/radio/src/main.cpp b/radio/src/main.cpp index d6888450..11c467d1 100644 --- a/radio/src/main.cpp +++ b/radio/src/main.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -52,7 +53,7 @@ public: dsbDemod.init(name, vfo, audioSampRate, 6000, &config); rawDemod.init(name, vfo, audioSampRate, audioSampRate, &config); cwDemod.init(name, vfo, audioSampRate, 200, &config); - + srChangeHandler.ctx = this; srChangeHandler.handler = sampleRateChangeHandler; stream.init(wfmDemod.getOutput(), srChangeHandler, audioSampRate); diff --git a/weather_sat_decoder/src/main.cpp b/weather_sat_decoder/src/main.cpp index 20143e72..8925f92c 100644 --- a/weather_sat_decoder/src/main.cpp +++ b/weather_sat_decoder/src/main.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include